/**
 * This file is part of muCommander, http://www.mucommander.com
 *
 * muCommander is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * muCommander is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.mucommander.commons.file.archive.zip;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.mucommander.commons.file.AbstractFile;
import com.mucommander.commons.file.AbstractFileTest;
import com.mucommander.commons.file.FileFactory;
import com.mucommander.commons.file.FileOperation;
import com.mucommander.commons.file.archive.AbstractArchiveEntryFile;

/**
 * An {@link AbstractFileTest} implementation, which performs tests on {@link AbstractArchiveEntryFile}
 * entries located inside a {@link ZipArchiveFile} residing in a temporary {@link com.mucommander.commons.file.protocol.local.LocalFile}.
 *
 * @author Maxence Bernard
 */
@Test
public class ZipArchiveFileTest extends AbstractFileTest {

    /** The archive file which contains the temporary entries */
    private static ZipArchiveFile tempZipFile;

    /** id of the last temporary entry generated, to avoid collisions */
    private int entryNum;


    /////////////////////////////////////
    // AbstractFileTest implementation //
    /////////////////////////////////////

    @Override
    public AbstractFile getTemporaryFile() throws IOException {
        // use a incremental id to avoid collisions
        return tempZipFile.getDirectChild("entry"+(++entryNum));
    }

    @Override
    public FileOperation[] getSupportedOperations() {
        return new FileOperation[] {
            FileOperation.READ_FILE,
            FileOperation.WRITE_FILE,
            FileOperation.CREATE_DIRECTORY,
            FileOperation.LIST_CHILDREN,
            FileOperation.DELETE,
            FileOperation.CHANGE_DATE,
            FileOperation.CHANGE_PERMISSION,
            FileOperation.GET_FREE_SPACE,
            FileOperation.GET_TOTAL_SPACE
        };
    }


    ////////////////////////
    // Overridden methods //
    ////////////////////////

    /**
     * Overridden to create the archive file before each test.
     */
    @Override
    @BeforeMethod
    public void setUp() throws IOException {
        entryNum = 0;
        tempZipFile = (ZipArchiveFile)FileFactory.getTemporaryFile(ZipArchiveFileTest.class.getName()+".zip", false);

        // Assert that the file is not an actual archive yet
        assert !tempZipFile.isArchive();

        tempZipFile.mkfile();

        // Assert that the file is now an archive
        assert tempZipFile.isArchive();

        super.setUp();
    }

    /**
     * Overridden to delete the archive file after each test.
     */
    @Override
    @AfterMethod
    public void tearDown() throws IOException {
        // Delete all archive entries
        super.tearDown();

        // Assert that the file is still an archive
        assert tempZipFile.isArchive();

        tempZipFile.delete();

        // Assert that the file is no longer an archive
        assert !tempZipFile.isArchive();
    }

    @Override
    public void testCanonicalPath() throws IOException, NoSuchAlgorithmException {
        // TODO
        // Test temporarily disabled because if fails. The failure seems to be caused by archive file caching:
        // the change is made to the archive file denoted by its absolute path ; when accessed by the canonical path,
        // the archive file is another instance which isn't aware of the change, because the file date hasn't changed (?).
    }

//    /**
//     * Tests the Zip32 4GB limit by asserting two things:
//     * <ul>
//     *  <li>that entries can be as large as 4GB minus one byte, preventing against unsigned java int issues amongst
//     * other things.</li>
//     *  <li>that entries cannot exceed 4GB and that an IOException is thrown if trying to write more than 4Gb, rather
//     * than failing silently and leaving the Zip file corrupted.</li>
//     * </ul>
//     *
//     * @throws IOException should not happen
//     * @throws NoSuchAlgorithmException should not happen
//     */
//    public void testZip32Limit() throws IOException, NoSuchAlgorithmException {
//        // Assert a 4GB minus one byte entry can be properly compressed and uncompressed
//        ChecksumOutputStream md5Out = getMd5OutputStream(tempFile.getAppendOutputStream());
//        StreamUtils.fillWithConstant(md5Out, (byte)0, MAX_ZIP32_ENTRY_SIZE);
//        md5Out.close();
//
//        assertEquals(md5Out.getChecksum(), calculateMd5(tempFile));
//
//        // Assert that an IOException is thrown if more than 4GB is written to an entry
//        OutputStream out = tempFile.getOutputStream();
//        boolean ioExceptionThrown = false;
//        try {
//            StreamUtils.fillWithConstant(out, (byte)0, MAX_ZIP32_ENTRY_SIZE+1);
//        }
//        catch(IOException e) {
//            ioExceptionThrown = true;
//        }
//        finally {
//            out.close();
//        }
//
//        assertTrue(ioExceptionThrown);
//
//        // Todo: test Zip files larger than 4Gb as a whole (should fail gracefully)
//    }
}
