/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.net.ftp.parser;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPFileEntryParser;
import org.apache.commons.net.ftp.FTPListParseEngine;

/**
 * @version $Id: VMSFTPEntryParserTest.java 1697433 2015-08-24 15:11:40Z sebb $
 */
public class VMSFTPEntryParserTest extends FTPParseTestFramework
{
    private static final String[] badsamples =
    {

        "1-JUN.LIS;2              9/9           JUN-2-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)",
        "1-JUN.LIS;2              a/9           2-JUN-98 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)",
        "DATA.DIR; 1              1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (,RWED,RWED,RE)",
        "120196.TXT;1           118/126        14-APR-1997 12:45:27 PM  [GROUP,OWNER]    (RWED,,RWED,RE)",
        "30CHARBAR.TXT;1         11/18          2-JUN-1998 08:38:42  [GROUP-1,OWNER]    (RWED,RWED,RWED,RE)",
        "A.;2                    18/18          1-JUL-1998 08:43:20  [GROUP,OWNER]    (RWED2,RWED,RWED,RE)",
        "AA.;2                  152/153        13-FED-1997 08:13:43  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
        "Directory USER1:[TEMP]\r\n\r\n",
        "\r\nTotal 14 files"
    };

    // CHECKSTYLE:OFF (long lines)
    private static final String[] goodsamples =
    {
        "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
        "1-JUN.LIS;3              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)",
        "1-JUN.LIS;2              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)",
        "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [TRANSLATED]     (,RWED,RWED,RE)",
        "120196.TXT;1           118/126        14-APR-1997 12:45:27  [GROUP,OWNER]    (RWED,,RWED,RE)",
        "30CHARBAR.TXT;1         11/18          2-JUN-1998 08:38:42  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
        "A.;2                    18/18          1-JUL-1998 08:43:20  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
        "AA.;2                  152/153        13-FEB-1997 08:13:43  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
        "UCX$REXECD_STARTUP.LOG;1098\r\n                         4/15         24-FEB-2003 13:17:24  [POSTWARE,LP]    (RWED,RWED,RE,)",
        "UNARCHIVE.COM;1          2/15          7-JUL-1997 16:37:45  [POSTWARE,LP]    (RWE,RWE,RWE,RE)",
        "UNXMERGE.COM;15          1/15         20-AUG-1996 13:59:50  [POSTWARE,LP]    (RWE,RWE,RWE,RE)",
        "UNXTEMP.COM;7            1/15         15-AUG-1996 14:10:38  [POSTWARE,LP]    (RWE,RWE,RWE,RE)",
        "UNZIP_AND_ATTACH_FILES.COM;12\r\n                        14/15         24-JUL-2002 14:35:40  [TRANSLATED]    (RWE,RWE,RWE,RE)",
        "UNZIP_AND_ATTACH_FILES.SAV;1\r\n                        14/15         17-JAN-2002 11:13:53  [POSTWARE,LP]    (RWE,RWED,RWE,RE)",
        "FREEWARE40.DIR;1        27/36         16-FEB-1999 10:01:46  [AP_HTTPD,APACHE$WWW                               (RWE,RWE,RE,RE)",
        "1-JUN.LIS;1              9/9           2-jun-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
    };
    // CHECKSTYLE:ON

    private static final String fullListing = "Directory USER1:[TEMP]\r\n\r\n"+
    "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)\r\n"+
    "2-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
    "3-JUN.LIS;1              9/9           3-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
    "3-JUN.LIS;4              9/9           7-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
    "3-JUN.LIS;2              9/9           4-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
    "3-JUN.LIS;3              9/9           6-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,)\r\n"+
    "\r\nTotal 6 files";

    /**
     * @see junit.framework.TestCase#TestCase(String)
     */
    public VMSFTPEntryParserTest(String name)
    {
        super(name);
    }

    public void testWholeListParse() throws IOException
    {
        VMSFTPEntryParser parser = new VMSFTPEntryParser();
        parser.configure(null);
        FTPListParseEngine engine = new FTPListParseEngine(parser);
        engine.readServerList(
                new ByteArrayInputStream(fullListing.getBytes()), null); // use default encoding
        FTPFile[] files = engine.getFiles();
        assertEquals(6, files.length);
        assertFileInListing(files, "2-JUN.LIS");
        assertFileInListing(files, "3-JUN.LIS");
        assertFileInListing(files, "1-JUN.LIS");
        assertFileNotInListing(files, "1-JUN.LIS;1");

    }

    public void testWholeListParseWithVersioning() throws IOException
    {

        VMSFTPEntryParser parser = new VMSVersioningFTPEntryParser();
        parser.configure(null);
        FTPListParseEngine engine = new FTPListParseEngine(parser);
        engine.readServerList(
                new ByteArrayInputStream(fullListing.getBytes()), null); // use default encoding
        FTPFile[] files = engine.getFiles();
        assertEquals(3, files.length);
        assertFileInListing(files, "1-JUN.LIS;1");
        assertFileInListing(files, "2-JUN.LIS;1");
        assertFileInListing(files, "3-JUN.LIS;4");
        assertFileNotInListing(files, "3-JUN.LIS;1");
        assertFileNotInListing(files, "3-JUN.LIS");

    }

    public void assertFileInListing(FTPFile[] listing, String name) {
        for (FTPFile element : listing)
        {
            if (name.equals(element.getName())) {
                return;
            }
        }
        fail("File " + name + " not found in supplied listing");
    }
    public void assertFileNotInListing(FTPFile[] listing, String name) {
        for (FTPFile element : listing)
        {
            if (name.equals(element.getName())) {
                fail("Unexpected File " + name + " found in supplied listing");
            }
        }
    }

    @Override
    public void testParseFieldsOnDirectory() throws Exception
    {

        FTPFile dir = getParser().parseFTPEntry(
            "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)");
        assertTrue("Should be a directory.",
                   dir.isDirectory());
        assertEquals("DATA.DIR",
                     dir.getName());
        assertEquals(512,
                     dir.getSize());
        assertEquals("Tue Jun 02 07:32:04 1998",
                     df.format(dir.getTimestamp().getTime()));
        assertEquals("GROUP",
                     dir.getGroup());
        assertEquals("OWNER",
                     dir.getUser());
        checkPermisions(dir, 0775);


        dir = getParser().parseFTPEntry(
                "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [TRANSLATED]    (RWED,RWED,,RE)");
        assertTrue("Should be a directory.",
                           dir.isDirectory());
        assertEquals("DATA.DIR",
                             dir.getName());
        assertEquals(512,
                             dir.getSize());
        assertEquals("Tue Jun 02 07:32:04 1998",
                             df.format(dir.getTimestamp().getTime()));
        assertEquals(null,
                     dir.getGroup());
        assertEquals("TRANSLATED",
                     dir.getUser());
        checkPermisions(dir, 0705);
    }

    @Override
    public void testParseFieldsOnFile() throws Exception
    {
        FTPFile file = getParser().parseFTPEntry(
            "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RW,R)");
        assertTrue("Should be a file.",
                   file.isFile());
        assertEquals("1-JUN.LIS",
                     file.getName());
        assertEquals(9 * 512,
                     file.getSize());
        assertEquals("Tue Jun 02 07:32:04 1998",
                     df.format(file.getTimestamp().getTime()));
        assertEquals("GROUP",
                     file.getGroup());
        assertEquals("OWNER",
                     file.getUser());
        checkPermisions(file, 0764);


        file = getParser().parseFTPEntry("1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [TRANSLATED]    (RWED,RD,,)");
        assertTrue("Should be a file.",
                   file.isFile());
        assertEquals("1-JUN.LIS",
                     file.getName());
        assertEquals(9 * 512,
                     file.getSize());
        assertEquals("Tue Jun 02 07:32:04 1998",
                     df.format(file.getTimestamp().getTime()));
        assertEquals(null,
                     file.getGroup());
        assertEquals("TRANSLATED",
                     file.getUser());
        checkPermisions(file, 0400);
    }

    public void testDefaultPrecision() {
        testPrecision(
                "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [TRANSLATED]    (RWED,RD,,)", CalendarUnit.SECOND);
    }

    public void testRecentPrecision() {
        // Not used
    }

    @Override
    protected String[] getBadListing()
    {

        return (badsamples);
    }

    @Override
    protected String[] getGoodListing()
    {

        return (goodsamples);
    }

    @Override
    protected FTPFileEntryParser getParser()
    {
        ConfigurableFTPFileEntryParserImpl parser =
            new VMSFTPEntryParser();
        parser.configure(null);
        return parser;
    }

    protected FTPFileEntryParser getVersioningParser()
    {
        ConfigurableFTPFileEntryParserImpl parser =
            new VMSVersioningFTPEntryParser();
        parser.configure(null);
        return parser;
    }

    /*
     * Verify that the VMS parser does NOT  set the permissions.
     */
    private void checkPermisions(FTPFile dir, int octalPerm)
    {
        int permMask = 1<<8;
        assertTrue("Owner should not have read permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.USER_ACCESS,
                                      FTPFile.READ_PERMISSION));
        permMask >>= 1;
        assertTrue("Owner should not have write permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.USER_ACCESS,
                                      FTPFile.WRITE_PERMISSION));
        permMask >>= 1;
        assertTrue("Owner should not have execute permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.USER_ACCESS,
                                      FTPFile.EXECUTE_PERMISSION));
        permMask >>= 1;
        assertTrue("Group should not have read permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.GROUP_ACCESS,
                                      FTPFile.READ_PERMISSION));
        permMask >>= 1;
        assertTrue("Group should not have write permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.GROUP_ACCESS,
                                      FTPFile.WRITE_PERMISSION));
        permMask >>= 1;
        assertTrue("Group should not have execute permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.GROUP_ACCESS,
                                      FTPFile.EXECUTE_PERMISSION));
        permMask >>= 1;
        assertTrue("World should not have read permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.WORLD_ACCESS,
                                      FTPFile.READ_PERMISSION));
        permMask >>= 1;
        assertTrue("World should not have write permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.WORLD_ACCESS,
                                      FTPFile.WRITE_PERMISSION));
        permMask >>= 1;
        assertTrue("World should not have execute permission.",
                ((permMask & octalPerm) != 0) == dir.hasPermission(FTPFile.WORLD_ACCESS,
                                      FTPFile.EXECUTE_PERMISSION));
    }
}
