View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.commons.compress.harmony.pack200;
18  
19  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.EOFException;
28  import java.io.IOException;
29  import java.util.stream.IntStream;
30  import java.util.stream.Stream;
31  
32  import org.junit.jupiter.api.Test;
33  import org.junit.jupiter.params.ParameterizedTest;
34  import org.junit.jupiter.params.provider.Arguments;
35  import org.junit.jupiter.params.provider.MethodSource;
36  
37  /**
38   */
39  public class CodecTest {
40  
41      static Stream<Arguments> bCodings() {
42          return IntStream.rangeClosed(1, 5).mapToObj(Arguments::of);
43      }
44  
45      static Stream<Arguments> codecFamily() {
46          return Stream.of(Arguments.of((Object) CanonicalCodecFamilies.nonDeltaUnsignedCodecs1),
47                  Arguments.of((Object) CanonicalCodecFamilies.nonDeltaUnsignedCodecs2), Arguments.of((Object) CanonicalCodecFamilies.nonDeltaUnsignedCodecs3),
48                  Arguments.of((Object) CanonicalCodecFamilies.nonDeltaUnsignedCodecs4), Arguments.of((Object) CanonicalCodecFamilies.nonDeltaUnsignedCodecs5),
49                  Arguments.of((Object) CanonicalCodecFamilies.deltaUnsignedCodecs1), Arguments.of((Object) CanonicalCodecFamilies.deltaUnsignedCodecs2),
50                  Arguments.of((Object) CanonicalCodecFamilies.deltaUnsignedCodecs3), Arguments.of((Object) CanonicalCodecFamilies.deltaUnsignedCodecs4),
51                  Arguments.of((Object) CanonicalCodecFamilies.deltaUnsignedCodecs5), Arguments.of((Object) CanonicalCodecFamilies.nonDeltaSignedCodecs1),
52                  Arguments.of((Object) CanonicalCodecFamilies.nonDeltaSignedCodecs2), Arguments.of((Object) CanonicalCodecFamilies.nonDeltaDoubleSignedCodecs1),
53                  Arguments.of((Object) CanonicalCodecFamilies.deltaSignedCodecs1), Arguments.of((Object) CanonicalCodecFamilies.deltaSignedCodecs2),
54                  Arguments.of((Object) CanonicalCodecFamilies.deltaSignedCodecs3), Arguments.of((Object) CanonicalCodecFamilies.deltaSignedCodecs4),
55                  Arguments.of((Object) CanonicalCodecFamilies.deltaSignedCodecs5), Arguments.of((Object) CanonicalCodecFamilies.deltaDoubleSignedCodecs1));
56      }
57  
58      static Stream<Arguments> hCodings() {
59          return IntStream.range(0, 256).mapToObj(Arguments::of);
60      }
61  
62      private long decode(final Codec codec, final byte[] data, final long value, final long last) throws IOException, Pack200Exception {
63          final ByteArrayInputStream in = new ByteArrayInputStream(data);
64          assertEquals(value, codec.decode(in, last));
65          assertEquals(-1, in.read());
66          return value;
67      }
68  
69      private void decodeFail(final Codec codec, final byte[] data) {
70          assertThrowsExactly(EOFException.class, () -> decode(codec, data, 0, 0), "Should have detected an EOFException");
71      }
72  
73      @ParameterizedTest
74      @MethodSource("bCodings")
75      public void testBCodings(final int i) {
76          if (i == 5) {
77              assertThrows(IllegalArgumentException.class, () -> new BHSDCodec(i, 256));
78          } else {
79              assertDoesNotThrow(() -> new BHSDCodec(i, 256));
80          }
81      }
82  
83      @Test
84      public void testByte1() throws Exception {
85          for (int i = 0; i < 255; i++) {
86              decode(Codec.BYTE1, new byte[] { (byte) i }, i, 0);
87          }
88      }
89  
90      @Test
91      public void testByte1Delta() throws Exception {
92          final Codec BYTE1D = new BHSDCodec(1, 256, 0, 1);
93          long last = 0;
94          for (int i = 1; i < 255; i++) {
95              last = decode(BYTE1D, new byte[] { (byte) 1 }, i, last);
96          }
97      }
98  
99      @Test
100     public void testByte1DeltaException() throws Exception {
101         final Codec BYTE1D = new BHSDCodec(1, 256, 0, 1);
102         assertThrows(Pack200Exception.class, () -> BYTE1D.decode(new ByteArrayInputStream(new byte[] { (byte) 1 })),
103                 "Decoding with a delta stream and not passing a last value should throw an exception");
104     }
105 
106     @Test
107     public void testByte1Signed() throws Exception {
108         final Codec BYTE1S2 = new BHSDCodec(1, 256, 2);
109         decode(BYTE1S2, new byte[] { 0 }, 0, 0);
110         decode(BYTE1S2, new byte[] { 1 }, 1, 0);
111         decode(BYTE1S2, new byte[] { 2 }, 2, 0);
112         decode(BYTE1S2, new byte[] { 3 }, -1, 0);
113         decode(BYTE1S2, new byte[] { 4 }, 3, 0);
114         decode(BYTE1S2, new byte[] { 5 }, 4, 0);
115         decode(BYTE1S2, new byte[] { 6 }, 5, 0);
116         decode(BYTE1S2, new byte[] { 7 }, -2, 0);
117         decode(BYTE1S2, new byte[] { 8 }, 6, 0);
118         decode(BYTE1S2, new byte[] { 9 }, 7, 0);
119         decode(BYTE1S2, new byte[] { 10 }, 8, 0);
120         decode(BYTE1S2, new byte[] { 11 }, -3, 0);
121     }
122 
123     @Test
124     public void testCardinality() {
125         final BHSDCodec byte1 = Codec.BYTE1;
126         assertEquals(256, byte1.cardinality());
127         assertEquals(0, byte1.smallest());
128         assertEquals(255, byte1.largest());
129         assertFalse(byte1.encodes(-257));
130         assertFalse(byte1.encodes(-256));
131         assertFalse(byte1.encodes(-255));
132         assertFalse(byte1.encodes(-129));
133         assertFalse(byte1.encodes(-128));
134         assertFalse(byte1.encodes(-127));
135         assertFalse(byte1.encodes(-1));
136         assertTrue(byte1.encodes(0));
137         assertTrue(byte1.encodes(1));
138         assertTrue(byte1.encodes(255));
139         assertFalse(byte1.encodes(256));
140         final BHSDCodec byte1s = new BHSDCodec(1, 256, 1);
141         assertEquals(256, byte1s.cardinality());
142         assertEquals(-128, byte1s.smallest());
143         assertEquals(127, byte1s.largest());
144         assertFalse(byte1s.encodes(-257));
145         assertFalse(byte1s.encodes(-256));
146         assertFalse(byte1s.encodes(-255));
147         assertFalse(byte1s.encodes(-129));
148         assertTrue(byte1s.encodes(-128));
149         assertTrue(byte1s.encodes(-127));
150         assertTrue(byte1s.encodes(-1));
151         assertTrue(byte1s.encodes(0));
152         assertTrue(byte1s.encodes(1));
153         assertTrue(byte1s.encodes(127));
154         assertFalse(byte1s.encodes(128));
155         assertFalse(byte1s.encodes(129));
156         assertFalse(byte1s.encodes(255));
157         assertFalse(byte1s.encodes(256));
158         final BHSDCodec byte2s = new BHSDCodec(1, 256, 2);
159         assertEquals(256, byte2s.cardinality());
160         assertEquals(-64, byte2s.smallest());
161         assertEquals(191, byte2s.largest());
162         assertFalse(byte2s.encodes(-257));
163         assertFalse(byte2s.encodes(-256));
164         assertFalse(byte2s.encodes(-255));
165         assertFalse(byte2s.encodes(-129));
166         assertFalse(byte2s.encodes(-128));
167         assertFalse(byte2s.encodes(-127));
168         assertFalse(byte2s.encodes(-65));
169         assertTrue(byte2s.encodes(-64));
170         assertTrue(byte2s.encodes(-64));
171         assertTrue(byte2s.encodes(-1));
172         assertTrue(byte2s.encodes(0));
173         assertTrue(byte2s.encodes(1));
174         assertTrue(byte2s.encodes(127));
175         assertTrue(byte2s.encodes(128));
176         assertTrue(byte2s.encodes(191));
177         assertFalse(byte2s.encodes(192));
178         assertFalse(byte2s.encodes(256));
179     }
180 
181     @ParameterizedTest
182     @MethodSource("codecFamily")
183     public void testCodecFamilies(final BHSDCodec[] family) {
184         for (int i = 1; i < family.length; i++) {
185             final BHSDCodec previous = family[i - 1];
186             final BHSDCodec codec = family[i];
187             assertTrue(codec.largest() >= previous.largest());
188             assertTrue(codec.smallest() <= previous.smallest());
189         }
190     }
191 
192     @Test
193     public void testCodecToString() {
194         assertEquals("(1,256)", Codec.BYTE1.toString());
195         assertEquals("(3,128)", Codec.CHAR3.toString());
196         assertEquals("(5,4)", Codec.BCI5.toString());
197         assertEquals("(5,4,2)", Codec.BRANCH5.toString());
198         assertEquals("(5,64)", Codec.UNSIGNED5.toString());
199         assertEquals("(5,64,1)", Codec.SIGNED5.toString());
200         assertEquals("(5,64,0,1)", Codec.UDELTA5.toString());
201         assertEquals("(5,64,1,1)", Codec.DELTA5.toString());
202         assertEquals("(5,64,2,1)", Codec.MDELTA5.toString());
203         assertEquals("(5,64)", Codec.UNSIGNED5.toString());
204         assertEquals("(5,64,1)", Codec.SIGNED5.toString());
205         assertEquals("(5,64,1,1)", Codec.DELTA5.toString());
206         assertEquals("(5,64,2,1)", Codec.MDELTA5.toString());
207     }
208 
209     @ParameterizedTest
210     @MethodSource("hCodings")
211     public void testInvalidHCodings(final int i) {
212         assertThrows(IllegalArgumentException.class, () -> new BHSDCodec(1, i), "b=1 -> h=256");
213     }
214 
215     @Test
216     public void testUnsigned5() throws Exception {
217         decode(Codec.UNSIGNED5, new byte[] { 1 }, 1, 0);
218         decode(Codec.UNSIGNED5, new byte[] { (byte) 191 }, 191, 0);
219         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 0 }, 192, 0);
220         decode(Codec.UNSIGNED5, new byte[] { (byte) 193, 0 }, 193, 0);
221         decode(Codec.UNSIGNED5, new byte[] { (byte) 255, 0 }, 255, 0);
222         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 1 }, 256, 0);
223         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 5 }, 512, 0);
224         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 13 }, 1024, 0);
225         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 29 }, 2048, 0);
226         decode(Codec.UNSIGNED5, new byte[] { (byte) 255, (byte) 191 }, 12479, 0);
227 
228         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192, 0 }, 12480, 0);
229         decode(Codec.UNSIGNED5, new byte[] { (byte) 255, (byte) 255, (byte) 191 }, 798911, 0);
230         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192, (byte) 192, 0 }, 798912, 0);
231         decode(Codec.UNSIGNED5, new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 191 }, 51130559, 0);
232         decode(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192, (byte) 192, (byte) 192, 0 }, 51130560, 0);
233         decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192 });
234         decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192 });
235         decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192, (byte) 192 });
236         decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192, (byte) 192, (byte) 192 });
237     }
238 }