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