View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.compressors.bzip2;
20  
21  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  
24  import java.io.BufferedInputStream;
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.nio.ByteBuffer;
30  import java.nio.channels.Channels;
31  import java.nio.channels.ReadableByteChannel;
32  import java.util.Arrays;
33  
34  import org.junit.jupiter.api.AfterEach;
35  import org.junit.jupiter.api.BeforeAll;
36  import org.junit.jupiter.api.BeforeEach;
37  import org.junit.jupiter.api.Test;
38  
39  /**
40   * Testcase porting a test from Python's testsuite.
41   *
42   * @see "https://issues.apache.org/jira/browse/COMPRESS-253"
43   */
44  public class PythonTruncatedBzip2Test {
45  
46      // @formatter:off
47      private static final String TEXT = "root:x:0:0:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:\ndaemon:x:2:2:daemon:/sbin:\nadm:x:3:4:adm:/var/adm:\nlp:x:4:7:"
48              + "lp:/var/spool/lpd:\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8"
49              + ":12:mail:/var/spool/mail:\nnews:x:9:13:news:/var/spool/news:\nuucp:x:10:14:uucp:/var/spool/uucp:\noperator:x:11:0:operator:/root:\ngames:x:12"
50              + ":100:games:/usr/games:\ngopher:x:13:30:gopher:/usr/lib/gopher-data:\nftp:x:14:50:FTP User:/var/ftp:/bin/bash\nnobody:x:65534:65534:Nobody:"
51              + "/home:\npostfix:x:100:101:postfix:/var/spool/postfix:\nniemeyer:x:500:500::/home/niemeyer:/bin/bash\npostgres:x:101:102:PostgreSQL Server:"
52              + "/var/lib/pgsql:/bin/bash\nmysql:x:102:103:MySQL server:/var/lib/mysql:/bin/bash\nwww:x:103:104::/var/www:/bin/false\n";
53      // @formatter:on
54  
55      private static byte[] DATA;
56      private static byte[] TRUNCATED_DATA;
57  
58      @BeforeAll
59      public static void initializeTestData() throws IOException {
60          final ByteArrayOutputStream out = new ByteArrayOutputStream();
61          try (BZip2CompressorOutputStream bz2out = new BZip2CompressorOutputStream(out)) {
62              bz2out.write(TEXT.getBytes(), 0, TEXT.getBytes().length);
63          }
64          DATA = out.toByteArray();
65  
66          // Drop the eos_magic field (6 bytes) and CRC (4 bytes).
67          TRUNCATED_DATA = Arrays.copyOfRange(DATA, 0, DATA.length - 10);
68      }
69  
70      @SuppressWarnings("resource") // Caller closes
71      private static ReadableByteChannel makeBZ2C(final InputStream source) throws IOException {
72          final BufferedInputStream bin = new BufferedInputStream(source);
73          final BZip2CompressorInputStream bZin = new BZip2CompressorInputStream(bin, true);
74          return Channels.newChannel(bZin);
75      }
76  
77      private ReadableByteChannel bz2Channel;
78  
79      @AfterEach
80      public void closeChannel() throws IOException {
81          bz2Channel.close();
82          bz2Channel = null;
83      }
84  
85      @BeforeEach
86      public void initializeChannel() throws IOException {
87          this.bz2Channel = makeBZ2C(new ByteArrayInputStream(TRUNCATED_DATA));
88      }
89  
90      @Test
91      public void testPartialReadTruncatedData() throws IOException {
92          // with BZ2File(self.filename) as f:
93          // self.assertEqual(f.read(len(self.TEXT)), self.TEXT)
94          // self.assertRaises(EOFError, f.read, 1)
95  
96          final int length = TEXT.length();
97          final ByteBuffer buffer1 = ByteBuffer.allocate(length);
98          bz2Channel.read(buffer1);
99  
100         assertArrayEquals(Arrays.copyOfRange(TEXT.getBytes(), 0, length), buffer1.array());
101 
102         // subsequent read should throw
103         final ByteBuffer buffer2 = ByteBuffer.allocate(1);
104         assertThrows(IOException.class, () -> bz2Channel.read(buffer2), "The read should have thrown.");
105     }
106 
107     @Test
108     public void testTruncatedData() {
109         // with BZ2File(self.filename) as f:
110         // self.assertRaises(EOFError, f.read)
111         final ByteBuffer buffer = ByteBuffer.allocate(8192);
112         assertThrows(IOException.class, () -> bz2Channel.read(buffer));
113     }
114 }