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   *   https://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.harmony.pack200;
20  
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.IOException;
28  import java.util.List;
29  
30  import org.apache.commons.compress.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
31  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.AttributeLayoutElement;
32  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.Call;
33  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.Callable;
34  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.Integral;
35  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.LayoutElement;
36  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.Reference;
37  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.Replication;
38  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.Union;
39  import org.apache.commons.compress.harmony.pack200.NewAttributeBands.UnionCase;
40  import org.junit.jupiter.api.Test;
41  import org.junit.jupiter.params.ParameterizedTest;
42  import org.junit.jupiter.params.provider.ValueSource;
43  
44  /**
45   * Tests for pack200 support for non-predefined attributes
46   */
47  class NewAttributeBandsTest {
48  
49      private final class MockNewAttributeBands extends NewAttributeBands {
50  
51          MockNewAttributeBands(final int effort, final CpBands cpBands, final SegmentHeader header, final AttributeDefinition def) throws IOException {
52              super(effort, cpBands, header, def);
53          }
54  
55          public List<AttributeLayoutElement> getLayoutElements() {
56              return attributeLayoutElements;
57          }
58      }
59  
60      @Test
61      void testAddAttributes() throws IOException, Pack200Exception {
62          final CPUTF8 name = new CPUTF8("TestAttribute");
63          final CPUTF8 layout = new CPUTF8("B");
64          final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
65                  new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
66          newAttributeBands.addAttribute(new NewAttribute(null, "TestAttribute", "B", new byte[] { 27 }, null, 0, null));
67          newAttributeBands.addAttribute(new NewAttribute(null, "TestAttribute", "B", new byte[] { 56 }, null, 0, null));
68          newAttributeBands.addAttribute(new NewAttribute(null, "TestAttribute", "B", new byte[] { 3 }, null, 0, null));
69          final ByteArrayOutputStream out = new ByteArrayOutputStream();
70          newAttributeBands.pack(out);
71          // BYTE1 is used for B layouts, so we don't need to unpack to test the
72          // results
73          final byte[] bytes = out.toByteArray();
74          assertEquals(3, bytes.length);
75          assertEquals(27, bytes[0]);
76          assertEquals(56, bytes[1]);
77          assertEquals(3, bytes[2]);
78      }
79  
80      @Test
81      void testAddAttributesWithReplicationLayout() throws IOException, Pack200Exception {
82          final CPUTF8 name = new CPUTF8("TestAttribute");
83          final CPUTF8 layout = new CPUTF8("NB[SH]");
84          final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
85                  new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
86          newAttributeBands.addAttribute(new NewAttribute(null, "TestAttribute", "B", new byte[] { 1, 0, 100 }, null, 0, null));
87          final short s = -50;
88          final byte b1 = (byte) (s >>> 8);
89          final byte b2 = (byte) s;
90          newAttributeBands.addAttribute(new NewAttribute(null, "TestAttribute", "B", new byte[] { 3, 0, 5, 0, 25, b1, b2 }, null, 0, null));
91          final ByteArrayOutputStream out = new ByteArrayOutputStream();
92          newAttributeBands.pack(out);
93          final byte[] bytes = out.toByteArray();
94          assertEquals(1, bytes[0]);
95          assertEquals(3, bytes[1]);
96          final byte[] band = new byte[bytes.length - 2];
97          System.arraycopy(bytes, 2, band, 0, band.length);
98          final int[] decoded = Codec.SIGNED5.decodeInts(4, new ByteArrayInputStream(band));
99          assertEquals(4, decoded.length);
100         assertEquals(100, decoded[0]);
101         assertEquals(5, decoded[1]);
102         assertEquals(25, decoded[2]);
103         assertEquals(-50, decoded[3]);
104     }
105 
106     @Test
107     void testEmptyLayout() throws IOException {
108         final CPUTF8 name = new CPUTF8("TestAttribute");
109         final CPUTF8 layout = new CPUTF8("");
110         final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
111                 new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
112         final List<AttributeLayoutElement> layoutElements = newAttributeBands.getLayoutElements();
113         assertEquals(0, layoutElements.size());
114     }
115 
116     @ParameterizedTest
117     @ValueSource(strings = { "B", "FB", "SB", "H", "FH", "SH", "I", "FI", "SI", "PB", "OB", "OSB", "POB", "PH", "OH", "OSH", "POH", "PI", "OI", "OSI", "POI" })
118     void testIntegralLayouts(final String layoutStr) throws IOException {
119         final CPUTF8 name = new CPUTF8("TestAttribute");
120         final CPUTF8 layout = new CPUTF8(layoutStr);
121         final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
122                 new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
123         final List<AttributeLayoutElement> layoutElements = newAttributeBands.getLayoutElements();
124         assertEquals(1, layoutElements.size());
125         final Integral element = (Integral) layoutElements.get(0);
126         assertEquals(layoutStr, element.getTag());
127     }
128 
129     @Test
130     void testLayoutWithBackwardsCalls() throws Exception {
131         CPUTF8 name = new CPUTF8("TestAttribute");
132         CPUTF8 layout = new CPUTF8("[NH[(1)]][KIH][(-1)]");
133         MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
134                 new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
135         List<AttributeLayoutElement> layoutElements = newAttributeBands.getLayoutElements();
136         assertEquals(3, layoutElements.size());
137         Callable firstCallable = (Callable) layoutElements.get(0);
138         Callable secondCallable = (Callable) layoutElements.get(1);
139         Callable thirdCallable = (Callable) layoutElements.get(2);
140         List<LayoutElement> thirdBody = thirdCallable.getBody();
141         assertEquals(1, thirdBody.size());
142         Call call = (Call) thirdBody.get(0);
143         assertEquals(secondCallable, call.getCallable());
144         assertTrue(secondCallable.isBackwardsCallable());
145         assertFalse(firstCallable.isBackwardsCallable());
146         assertFalse(thirdCallable.isBackwardsCallable());
147 
148         name = new CPUTF8("TestAttribute");
149         layout = new CPUTF8("[NH[(1)]][KIH][(-2)]");
150         newAttributeBands = new MockNewAttributeBands(1, null, null, new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
151         layoutElements = newAttributeBands.getLayoutElements();
152         assertEquals(3, layoutElements.size());
153         firstCallable = (Callable) layoutElements.get(0);
154         secondCallable = (Callable) layoutElements.get(1);
155         thirdCallable = (Callable) layoutElements.get(2);
156         thirdBody = thirdCallable.getBody();
157         assertEquals(1, thirdBody.size());
158         call = (Call) thirdBody.get(0);
159         assertEquals(firstCallable, call.getCallable());
160         assertTrue(firstCallable.isBackwardsCallable());
161         assertFalse(secondCallable.isBackwardsCallable());
162         assertFalse(thirdCallable.isBackwardsCallable());
163 
164         name = new CPUTF8("TestAttribute");
165         layout = new CPUTF8("[NH[(1)]][KIH][(0)]");
166         newAttributeBands = new MockNewAttributeBands(1, null, null, new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
167         layoutElements = newAttributeBands.getLayoutElements();
168         assertEquals(3, layoutElements.size());
169         firstCallable = (Callable) layoutElements.get(0);
170         secondCallable = (Callable) layoutElements.get(1);
171         thirdCallable = (Callable) layoutElements.get(2);
172         thirdBody = thirdCallable.getBody();
173         assertEquals(1, thirdBody.size());
174         call = (Call) thirdBody.get(0);
175         assertEquals(thirdCallable, call.getCallable());
176         assertTrue(thirdCallable.isBackwardsCallable());
177         assertFalse(firstCallable.isBackwardsCallable());
178         assertFalse(secondCallable.isBackwardsCallable());
179     }
180 
181     @Test
182     void testLayoutWithCalls() throws IOException {
183         final CPUTF8 name = new CPUTF8("TestAttribute");
184         // @formatter:off
185         final CPUTF8 layout = new CPUTF8(
186           "[NH[(1)]][RSH NH[RUH(1)]][TB(66,67,73,83,90)[KIH](68)[KDH](70)[KFH](74)[KJH](99)[RSH](101)[RSH RUH](115)[RUH](91)[NH[(0)]](64)[RSH[RUH(0)]]()[]]"
187         );
188         // @formatter:on
189         final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
190                 new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
191         final List<AttributeLayoutElement> layoutElements = newAttributeBands.getLayoutElements();
192         assertEquals(3, layoutElements.size());
193         final Callable firstCallable = (Callable) layoutElements.get(0);
194         final Callable secondCallable = (Callable) layoutElements.get(1);
195         final Callable thirdCallable = (Callable) layoutElements.get(2);
196         final List<LayoutElement> firstBody = firstCallable.getBody();
197         assertEquals(1, firstBody.size());
198         final Replication rep = (Replication) firstBody.get(0);
199         final List<LayoutElement> repBody = rep.getLayoutElements();
200         assertEquals(1, repBody.size());
201         final Call call = (Call) repBody.get(0);
202         assertEquals(1, call.getCallableIndex());
203         assertEquals(secondCallable, call.getCallable());
204         assertFalse(firstCallable.isBackwardsCallable());
205         assertFalse(secondCallable.isBackwardsCallable());
206         assertFalse(thirdCallable.isBackwardsCallable());
207     }
208 
209     @ParameterizedTest
210     @ValueSource(strings = { "KIB", "KIH", "KII", "KINH", "KJH", "KDH", "KSH", "KQH", "RCH", "RSH", "RDH", "RFH", "RMH", "RIH", "RUH", "RQH", "RQNH", "RQNI" })
211     void testReferenceLayouts(final String layoutStr) throws IOException {
212         final CPUTF8 name = new CPUTF8("TestAttribute");
213         final CPUTF8 layout = new CPUTF8(layoutStr);
214         final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
215                 new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
216         final List<AttributeLayoutElement> layoutElements = newAttributeBands.getLayoutElements();
217         assertEquals(1, layoutElements.size());
218         final Reference element = (Reference) layoutElements.get(0);
219         assertEquals(layoutStr, element.getTag());
220     }
221 
222     @Test
223     void testReplicationLayouts() throws IOException {
224         final CPUTF8 name = new CPUTF8("TestAttribute");
225         final CPUTF8 layout = new CPUTF8("NH[PHOHRUHRSHH]");
226         final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
227                 new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
228         final List<AttributeLayoutElement> layoutElements = newAttributeBands.getLayoutElements();
229         assertEquals(1, layoutElements.size());
230         final Replication element = (Replication) layoutElements.get(0);
231         final Integral countElement = element.getCountElement();
232         assertEquals("H", countElement.getTag());
233         final List<LayoutElement> replicatedElements = element.getLayoutElements();
234         assertEquals(5, replicatedElements.size());
235         final Integral firstElement = (Integral) replicatedElements.get(0);
236         assertEquals("PH", firstElement.getTag());
237         final Integral secondElement = (Integral) replicatedElements.get(1);
238         assertEquals("OH", secondElement.getTag());
239         final Reference thirdElement = (Reference) replicatedElements.get(2);
240         assertEquals("RUH", thirdElement.getTag());
241         final Reference fourthElement = (Reference) replicatedElements.get(3);
242         assertEquals("RSH", fourthElement.getTag());
243         final Integral fifthElement = (Integral) replicatedElements.get(4);
244         assertEquals("H", fifthElement.getTag());
245     }
246 
247     @Test
248     void testUnionLayout() throws IOException {
249         final CPUTF8 name = new CPUTF8("TestAttribute");
250         final CPUTF8 layout = new CPUTF8("TB(55)[FH](23)[]()[RSH]");
251         final MockNewAttributeBands newAttributeBands = new MockNewAttributeBands(1, null, null,
252                 new AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout));
253         final List<AttributeLayoutElement> layoutElements = newAttributeBands.getLayoutElements();
254         assertEquals(1, layoutElements.size());
255         final Union element = (Union) layoutElements.get(0);
256         final Integral tag = element.getUnionTag();
257         assertEquals("B", tag.getTag());
258         final List<UnionCase> unionCases = element.getUnionCases();
259         assertEquals(2, unionCases.size());
260         final UnionCase firstCase = unionCases.get(0);
261         assertTrue(firstCase.hasTag(55));
262         assertFalse(firstCase.hasTag(23));
263         List<LayoutElement> body = firstCase.getBody();
264         assertEquals(1, body.size());
265         final Integral bodyElement = (Integral) body.get(0);
266         assertEquals("FH", bodyElement.getTag());
267         final UnionCase secondCase = unionCases.get(1);
268         assertTrue(secondCase.hasTag(23));
269         assertFalse(secondCase.hasTag(55));
270         body = secondCase.getBody();
271         assertEquals(0, body.size());
272         final List<LayoutElement> defaultBody = element.getDefaultCaseBody();
273         assertEquals(1, defaultBody.size());
274         final Reference ref = (Reference) defaultBody.get(0);
275         assertEquals("RSH", ref.getTag());
276     }
277 
278 }