2 * DictZip Library test.
4 * Copyright (C) 2021-2022 Hiroshi Miura
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * Linking this library statically or dynamically with other modules is
21 * making a combined work based on this library. Thus, the terms and
22 * conditions of the GNU General Public License cover the whole
25 * As a special exception, the copyright holders of this library give you
26 * permission to link this library with independent modules to produce an
27 * executable, regardless of the license terms of these independent
28 * modules, and to copy and distribute the resulting executable under
29 * terms of your choice, provided that you also meet, for each linked
30 * independent module, the terms and conditions of the license of that
31 * module. An independent module is a module which is not derived from
32 * or based on this library. If you modify this library, you may extend
33 * this exception to your version of the library, but you are not
34 * obligated to do so. If you do not wish to do so, delete this
35 * exception statement from your version.
39 import org.junit.jupiter.api.Assumptions;
40 import org.junit.jupiter.api.Test;
41 import org.junit.jupiter.api.io.TempDir;
43 import java.io.BufferedWriter;
45 import java.io.FileInputStream;
46 import java.io.FileOutputStream;
47 import java.io.IOException;
48 import java.io.OutputStreamWriter;
49 import java.io.PrintWriter;
50 import java.io.RandomAccessFile;
51 import java.nio.charset.StandardCharsets;
52 import java.nio.file.Path;
53 import java.nio.file.Paths;
54 import java.util.Random;
55 import java.util.zip.Deflater;
57 import static org.junit.jupiter.api.Assertions.assertEquals;
58 import static org.junit.jupiter.api.Assertions.assertTrue;
61 * Test archive creation and extraction.
63 public class DictZipFileTest {
65 private static final int BUF_LEN = 58315;
67 void prepareTextData(final Path outTextPath, final int size) throws IOException {
68 Random random = new Random();
69 File outTextFile = outTextPath.toFile();
70 try (PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
71 new FileOutputStream(outTextFile), StandardCharsets.US_ASCII)), false)) {
72 for (long i = 0; i < size; i++) {
73 int number = random.nextInt(94);
74 writer.print((char) (32 + number));
79 void prepareLargeTextData(final Path outTextPath, final int size) throws IOException {
80 Random random = new Random();
81 File outTextFile = outTextPath.toFile();
82 PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
83 new FileOutputStream(outTextFile), StandardCharsets.US_ASCII)), false);
86 for (int j = 0; j < 1000; j++) {
87 for (int i = 0; i < 99; i++) {
88 int number = random.nextInt(94);
89 writer.print((char) (32 + number));
93 outSize += 1000 * 100;
94 if (outSize >= size) {
102 * Test case to create large archive.
103 * @param tempDir JUnit5 temporary directory..
104 * @throws IOException when file wreite filed.
105 * @throws InterruptedException when external dictzip not executed well.
108 public void testFileCreation(@TempDir final Path tempDir) throws IOException, InterruptedException {
109 // Run test when running on Linux and dictzip command installed
110 Assumptions.assumeTrue(Paths.get("/usr/bin/dictzip").toFile().exists());
111 int size = (BUF_LEN * 512 + 100) / 100000 * 100000;
113 byte[] buf = new byte[BUF_LEN];
114 int[] positions = new int[] {
122 int cases = positions.length;
123 byte[] expected = new byte[cases];
125 Path outTextPath = tempDir.resolve("DictZipText.orig.txt");
126 prepareTextData(outTextPath, size);
127 File inputFile = outTextPath.toFile();
128 Path zippedPath = tempDir.resolve("DictZipText.txt.dz");
129 assertEquals(size, inputFile.length());
131 try (RandomAccessInputStream is = new RandomAccessInputStream(new RandomAccessFile(inputFile, "r"))) {
132 for (int i = 0; i < cases; i++) {
133 is.seek(positions[i]);
134 len = is.read(buf, 0, buf.length);
136 expected[i] = buf[0];
139 // create dictZip archive
140 int defLevel = Deflater.DEFAULT_COMPRESSION;
141 try (FileInputStream ins = new FileInputStream(inputFile);
142 DictZipOutputStream dout = new DictZipOutputStream(
143 new RandomAccessOutputStream(new RandomAccessFile(zippedPath.toFile(), "rws")),
144 BUF_LEN, inputFile.length(), defLevel)) {
145 while ((len = ins.read(buf, 0, BUF_LEN)) > 0) {
146 dout.write(buf, 0, len);
151 String[] command = {"/usr/bin/dictzip", "-d", "-c", "-s", null, "-e", "10", zippedPath.toAbsolutePath().toString()};
152 for (int i = 0; i < positions.length; i++) {
153 System.out.printf("seek position: %d%n", positions[i]);
154 command[4] = Integer.toString(positions[i]);
155 Process process = Runtime.getRuntime().exec(command);
156 int b = process.getInputStream().read();
157 int returnCode = process.waitFor();
158 assertEquals(0, returnCode);
159 assertEquals(expected[i], (byte) b);
164 * Test case to extract large archive file.
165 * @param tempDir JUnit5 temporary directory.
166 * @throws IOException when i/o error occurred.
167 * @throws InterruptedException when external dictzip not executed well.
170 public void testFileReadAceess(@TempDir final Path tempDir) throws IOException, InterruptedException {
171 // Run test when running on Linux and dictzip command installed
172 Assumptions.assumeTrue(Paths.get("/usr/bin/dictzip").toFile().exists());
173 int size = (BUF_LEN * 512 + 100) / 100000 * 100000;
174 // --- preparation of data
176 int numChunk = size / BUF_LEN + 1;
177 byte[] buf = new byte[BUF_LEN];
178 int[] positions = new int[] {
184 BUF_LEN * (numChunk / 2 - 1) - 10,
185 BUF_LEN * (numChunk / 2 + 1) + 10,
188 int cases = positions.length;
189 byte[] expected = new byte[cases];
190 // create archive with dictzip command
191 Path outTextPath = tempDir.resolve("DictZipText.txt");
192 prepareLargeTextData(outTextPath, size);
193 File inputFile = outTextPath.toFile();
194 assertEquals(size, inputFile.length());
196 try (RandomAccessInputStream is = new RandomAccessInputStream(new RandomAccessFile(inputFile, "r"))) {
197 for (int i = 0; i < cases; i++) {
198 is.seek(positions[i]);
199 len = is.read(buf, 0, buf.length);
201 expected[i] = buf[0];
204 // create dictzip archive with dictzip command
205 String[] command = {"/usr/bin/dictzip", outTextPath.toAbsolutePath().toString()};
206 Process process = Runtime.getRuntime().exec(command);
207 int returnCode = process.waitFor();
208 assertEquals(0, returnCode);
209 File zippedFile = tempDir.resolve("DictZipText.txt.dz").toFile();
210 // -- end of preparation
212 // read dictZip archive
213 try (DictZipInputStream din = new DictZipInputStream(new RandomAccessInputStream(new
214 RandomAccessFile(zippedFile, "r")))) {
215 for (int i = 0; i < cases; i++) {
216 System.out.printf("seek position: %d%n", positions[i]);
217 din.seek(positions[i]);
218 len = din.read(buf, 0, 10);
220 assertEquals(expected[i], buf[0], String.format("Read data invalid at position %d", positions[i]));
226 * Test case to reproduce issue #24.
228 * When seek to almost end of large dictionary, it cause error
229 * Caused by: java.util.zip.ZipException: invalid distance too far back
231 * @param tempDir JUnit5 temporary directory.
232 * @throws IOException when i/o error occurred.
233 * @throws InterruptedException when external dictzip not executed well.
236 public void testFileInputOutput(@TempDir final Path tempDir) throws IOException, InterruptedException {
237 // Run test when running on Linux and dictzip command installed
238 Assumptions.assumeTrue(Paths.get("/usr/bin/dictzip").toFile().exists());
239 int size = (BUF_LEN * 512 + 100) / 100000 * 100000;
240 // int size = 45000000; // about 45MB
241 int numChunk = size / BUF_LEN + 1;
242 byte[] buf = new byte[BUF_LEN];
243 int[] positions = new int[] {
247 BUF_LEN * (numChunk / 2 - 1) - 10,
248 BUF_LEN * (numChunk / 2 + 1) + 10,
251 int cases = positions.length;
252 byte[] expected = new byte[cases];
255 Path outTextPath = tempDir.resolve("DictZipText.txt");
256 prepareTextData(outTextPath, size);
257 File inputFile = outTextPath.toFile();
258 Path zippedPath = tempDir.resolve("DictZipText.txt.dz");
259 assertEquals(size, inputFile.length());
261 try (RandomAccessInputStream is = new RandomAccessInputStream(new RandomAccessFile(inputFile, "r"))) {
262 for (int i = 0; i < cases; i++) {
263 is.seek(positions[i]);
264 len = is.read(buf, 0, buf.length);
266 expected[i] = buf[0];
269 // create dictZip archive
270 int defLevel = Deflater.DEFAULT_COMPRESSION;
271 try (FileInputStream ins = new FileInputStream(inputFile);
272 DictZipOutputStream dout = new DictZipOutputStream(
273 new RandomAccessOutputStream(new RandomAccessFile(zippedPath.toFile(), "rws")),
274 BUF_LEN, inputFile.length(), defLevel)) {
275 while ((len = ins.read(buf, 0, BUF_LEN)) > 0) {
276 dout.write(buf, 0, len);
281 String[] command = {"/usr/bin/dictzip", "-d", "-c", "-s", null, "-e", "10", zippedPath.toAbsolutePath().toString()};
282 for (int i = 0; i < positions.length; i++) {
283 System.out.printf("seek position: %d%n", positions[i]);
284 command[4] = Integer.toString(positions[i]);
285 Process process = Runtime.getRuntime().exec(command);
286 int b = process.getInputStream().read();
287 int returnCode = process.waitFor();
288 assertEquals(0, returnCode);
289 assertEquals(expected[i], (byte) b);
291 // read dictZip archive
292 try (RandomAccessFile raf = new RandomAccessFile(zippedPath.toFile(), "r");
293 DictZipInputStream din = new DictZipInputStream(new RandomAccessInputStream(raf))) {
294 for (int i = 0; i < cases; i++) {
295 System.out.printf("seek position: %d%n", positions[i]);
296 din.seek(positions[i]);
297 len = din.read(buf, 0, 10);
299 assertEquals(expected[i], buf[0], String.format("Read data invalid at position %d", positions[i]));