OSDN Git Service

Adjust for checkstyle warnings
[dictzip-java/dictzip-java.git] / dictzip-lib / src / test / java / org / dict / zip / DictZipFileTest.java
1 /*
2  * DictZip Library test.
3  *
4  * Copyright (C) 2021-2022 Hiroshi Miura
5  *
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.
10  *
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.
15  *
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.
19  *
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
23  * combination.
24  *
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.
36  */
37 package org.dict.zip;
38
39 import org.junit.jupiter.api.Assumptions;
40 import org.junit.jupiter.api.Test;
41 import org.junit.jupiter.api.io.TempDir;
42
43 import java.io.BufferedWriter;
44 import java.io.File;
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;
56
57 import static org.junit.jupiter.api.Assertions.assertEquals;
58 import static org.junit.jupiter.api.Assertions.assertTrue;
59
60 /**
61  * Test archive creation and extraction.
62  */
63 public class DictZipFileTest {
64
65     private static final int BUF_LEN = 58315;
66
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));
75             }
76         }
77     }
78
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);
84         int outSize = 0;
85         while (true) {
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));
90                 }
91                 writer.print("\n");
92             }
93             outSize += 1000 * 100;
94             if (outSize >= size) {
95                 writer.close();
96                 break;
97             }
98         }
99     }
100
101     /**
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.
106      */
107     @Test
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;
112         int len;
113         byte[] buf = new byte[BUF_LEN];
114         int[] positions = new int[] {
115                 BUF_LEN - 10,
116                 BUF_LEN + 10,
117                 BUF_LEN * 2 + 10,
118                 BUF_LEN * 256 - 10,
119                 BUF_LEN * 256 + 10,
120                 size - BUF_LEN + 5
121         };
122         int cases = positions.length;
123         byte[] expected = new byte[cases];
124         // create data
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());
130         // get expectations
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);
135                 assertTrue(len > 0);
136                 expected[i] = buf[0];
137             }
138         }
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);
147             }
148             dout.finish();
149         }
150         // check archive
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);
160         }
161     }
162
163     /**
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.
168      */
169     @Test
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
175         int len;
176         int numChunk = size / BUF_LEN + 1;
177         byte[] buf = new byte[BUF_LEN];
178         int[] positions = new int[] {
179                 BUF_LEN - 10,
180                 BUF_LEN + 10,
181                 BUF_LEN * 2 + 10,
182                 BUF_LEN * 256 - 10,
183                 BUF_LEN * 256 + 10,
184                 BUF_LEN * (numChunk / 2 - 1) - 10,
185                 BUF_LEN * (numChunk / 2 + 1) + 10,
186                 size - BUF_LEN + 5
187         };
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());
195         // get expectations
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);
200                 assertTrue(len > 0);
201                 expected[i] = buf[0];
202             }
203         }
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
211
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);
219                 assertTrue(len > 0);
220                 assertEquals(expected[i], buf[0], String.format("Read data invalid at position %d", positions[i]));
221             }
222         }
223     }
224
225     /**
226      * Test case to reproduce issue #24.
227      * <p>
228      *     When seek to almost end of large dictionary, it cause error
229      *     Caused by: java.util.zip.ZipException: invalid distance too far back
230      * </p>
231      * @param tempDir JUnit5 temporary directory.
232      * @throws IOException when i/o error occurred.
233      * @throws InterruptedException when external dictzip not executed well.
234      */
235     @Test
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[] {
244                 BUF_LEN - 10,
245                 BUF_LEN + 10,
246                 BUF_LEN * 2 + 10,
247                 BUF_LEN * (numChunk / 2 - 1) - 10,
248                 BUF_LEN * (numChunk / 2 + 1) + 10,
249                 size - BUF_LEN + 5
250         };
251         int cases = positions.length;
252         byte[] expected = new byte[cases];
253         int len;
254         // create data
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());
260         // get expectations
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);
265                 assertTrue(len > 0);
266                 expected[i] = buf[0];
267             }
268         }
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);
277             }
278             dout.finish();
279         }
280         // check archive
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);
290         }
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);
298                 assertTrue(len > 0);
299                 assertEquals(expected[i], buf[0], String.format("Read data invalid at position %d", positions[i]));
300             }
301         }
302     }
303 }