ZipFileTest.java
/*
* Copyright 2023 Emmanuel Bourg
*
* Licensed 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 net.jsign.zip;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import static java.nio.charset.StandardCharsets.*;
import static org.junit.Assert.*;
public class ZipFileTest {
@Test
public void getGetInputStream() throws Exception {
try (ZipFile file = new ZipFile(new File("target/test-classes/minimal.msix"))) {
InputStream in = file.getInputStream("AppxManifest.xml");
assertNotNull("input stream found", in);
String content = IOUtils.toString(in, UTF_8);
assertTrue(content.startsWith("\uFEFF<?xml"));
}
}
@Test
public void getGetInputStreamWithUnknownEntry() throws Exception {
try (ZipFile file = new ZipFile(new File("target/test-classes/minimal.msix"))) {
Exception e = assertThrows(IOException.class, () -> file.getInputStream("META-INF/MANIFEST.MF"));
assertEquals("message", "Entry not found: META-INF/MANIFEST.MF", e.getMessage());
}
}
@Test
public void getGetInputStreamWithLimit() throws Exception {
try (ZipFile file = new ZipFile(new File("target/test-classes/minimal.zip"))) {
Exception e = assertThrows(IOException.class, () -> file.getInputStream("AppxManifest.xml", 128));
assertEquals("message", "The entry AppxManifest.xml is too large to be read (1224 bytes)", e.getMessage());
}
}
@Test
public void testAddEntry() throws Exception {
File original = new File("target/test-classes/minimal.msix");
File modified = new File("target/test-classes/minimal-with-extra-entry.msix.zip");
FileUtils.copyFile(original, modified);
try (ZipFile file = new ZipFile(modified)) {
file.addEntry("hello.txt", "Hello World!".getBytes(UTF_8), true);
}
try (java.util.zip.ZipFile zip = new java.util.zip.ZipFile(modified)) {
assertNotNull(zip.getEntry("[Content_Types].xml"));
assertNotNull(zip.getEntry("hello.txt"));
}
try (ZipFile file = new ZipFile(modified)) {
InputStream in = file.getInputStream("hello.txt");
assertEquals("Hello World!", IOUtils.toString(in, UTF_8));
}
}
@Test
public void testRenameEntry() throws Exception {
File original = new File("target/test-classes/minimal.msix");
File modified = new File("target/test-classes/minimal-with-entry-renamed.msix.zip");
FileUtils.copyFile(original, modified);
try (ZipFile file = new ZipFile(modified)) {
file.renameEntry("[Content_Types].xml", "[Content_Types].old");
assertFalse(file.centralDirectory.entries.containsKey("[Content_Types].xml"));
assertTrue(file.centralDirectory.entries.containsKey("[Content_Types].old"));
assertThrows(IllegalArgumentException.class, () -> file.renameEntry("[Content_Types].old", "[Content_Types].xml.old"));
}
try (ZipFile file = new ZipFile(modified)) {
assertNull("old entry still present", file.centralDirectory.entries.get("[Content_Types].xml"));
assertNotNull("new entry missing", file.centralDirectory.entries.get("[Content_Types].old"));
}
}
@Test
public void testRemoveEntry() throws Exception {
File original = new File("target/test-classes/minimal.zip");
File modified = new File("target/test-classes/minimal-with-entries-removed.zip");
FileUtils.copyFile(original, modified);
try (ZipFile file = new ZipFile(modified)) {
// first entry
file.removeEntry("Registry.dat");
assertFalse(file.centralDirectory.entries.containsKey("Registry.dat"));
// middle entry
file.removeEntry("Resources.pri");
assertFalse(file.centralDirectory.entries.containsKey("Resources.pri"));
// last entry
file.removeEntry("[Content_Types].xml");
assertFalse(file.centralDirectory.entries.containsKey("[Content_Types].xml"));
}
try (java.util.zip.ZipFile file = new java.util.zip.ZipFile(modified)) {
assertNull("Registry.dat entry not removed", file.getEntry("Registry.dat"));
assertNull("Resources.pri entry not removed", file.getEntry("Resources.pri"));
assertNull("[Content_Types].xml entry not removed", file.getEntry("[Content_Types].xml"));
}
}
@Test
public void testMultiVolumeArchive() throws Exception {
File original = new File("target/test-classes/minimal.msix");
File modified = new File("target/test-classes/minimal-multi-volume.msix.zip");
FileUtils.copyFile(original, modified);
// patch the file to make it a multi-volume archive
try (SeekableByteChannel channel = Files.newByteChannel(modified.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
long offset = channel.size() - 22;
channel.position(offset);
EndOfCentralDirectoryRecord record = new EndOfCentralDirectoryRecord();
record.read(channel);
record.numberOfThisDisk = 1;
record.numberOfTheDiskWithTheStartOfTheCentralDirectory = 1;
channel.position(offset);
record.write(channel);
}
Exception e = assertThrows(IOException.class, () -> new ZipFile(modified));
assertEquals("message", "Multi-volume archives are not supported", e.getMessage());
}
}