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.flatfile;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.IOException;
21  import java.util.Arrays;
22  
23  import org.apache.commons.flatfile.DynamicField;
24  import org.apache.commons.flatfile.EntityArray;
25  import org.apache.commons.flatfile.FieldSupport.Overflow;
26  import org.apache.commons.flatfile.FieldSupport.Underflow;
27  
28  /**
29   * Test dynamic fields.
30   */
31  public class DynamicFieldTest extends EntityParserTestBase {
32      private static final int BUFFER_SIZE = 20;
33  
34      private static final byte[] SMALL_BYTES = new byte[0];
35      private static final byte[] LARGE_BYTES = new byte[1024];
36  
37      static {
38          Arrays.fill(LARGE_BYTES, (byte) 'a');
39      }
40  
41      public void test1() throws Exception {
42          DynamicField df = get("df1");
43          assertEquals(0, df.length());
44          assertBounds(df, 0, 1);
45          assertLoad(df);
46      }
47  
48      public void test2() throws Exception {
49          DynamicField df = get("df2");
50          assertEquals(0, df.length());
51          assertBounds(df, DynamicField.Bounds.DEFAULT.getMinimum(), 1);
52          assertLoad(df);
53      }
54  
55      public void test3() throws Exception {
56          DynamicField df = get("df3");
57          assertEquals(0, df.length());
58          assertBounds(df, 0, DynamicField.Bounds.DEFAULT.getMaximum());
59          assertLoad(df);
60      }
61  
62      public void test4() throws Exception {
63          DynamicField df = get("df4");
64          assertEquals(0, df.length());
65          assertBounds(df, DynamicField.Bounds.DEFAULT);
66          assertLoad(df);
67      }
68  
69      public void test5() throws Exception {
70          DynamicField df = get("df5");
71          assertEquals(3, df.length());
72          byte[] foo = "foo".getBytes();
73          assertEquals(foo, df.getValue());
74          assertBounds(df, DynamicField.Bounds.DEFAULT);
75          assertLoad(df);
76      }
77  
78      public void test6() throws Exception {
79          DynamicField df = get("df6");
80          assertEquals(0, df.length());
81          assertBounds(df, 0, 0);
82          assertLoad(df);
83      }
84  
85      public void test7() throws Exception {
86          DynamicField df = get("df7");
87          assertEquals(0, df.length());
88          assertBounds(df, DynamicField.Bounds.DEFAULT.getMinimum(), 0);
89          assertLoad(df);
90      }
91  
92      public void test8() throws Exception {
93          DynamicField df = get("df8");
94          assertBounds(df, 1, 1);
95          assertEquals(new byte[] { ' ' }, df.getValue());
96          assertLoad(df);
97      }
98  
99      public void test9() throws Exception {
100         DynamicField df = get("df9");
101         assertBounds(df, 1, 3);
102         assertEquals(" ".getBytes(), df.getValue());
103         assertLoad(df);
104     }
105 
106     public void testUnboundedArray() throws Exception {
107         EntityArray a = (EntityArray) entityFactory.getEntity("unboundedArray");
108         assertEquals(0, a.length());
109         a.getChild(1).setValue("foo".getBytes());
110         assertEquals("foo".getBytes(), a.getValue());
111     }
112 
113     public void testUnboundedDelimitedArray() throws Exception {
114         EntityArray a = (EntityArray) entityFactory
115                 .getEntity("unboundedDelimitedArray");
116         assertEquals("---".getBytes(), a.getValue());
117         a.getChild(1).setValue("foo".getBytes());
118         assertEquals("-foo--".getBytes(), a.getValue());
119     }
120 
121     public void testBoundedArray() throws Exception {
122         EntityArray a = (EntityArray) entityFactory.getEntity("boundedArray");
123         assertEquals("   ".getBytes(), a.getValue());
124         a.getChild(1).setValue("foo".getBytes());
125         assertEquals(" foo ".getBytes(), a.getValue());
126     }
127 
128     public void testBoundedDelimitedArray() throws Exception {
129         EntityArray a = (EntityArray) entityFactory
130                 .getEntity("boundedDelimitedArray");
131         assertEquals(" \n \n \n".getBytes(), a.getValue());
132         a.getChild(1).setValue("foo".getBytes());
133         assertEquals(" \nfoo\n \n".getBytes(), a.getValue());
134 
135     }
136 
137     public void testNestedUncertainty() throws Exception {
138         EntityArray a = (EntityArray) entityFactory
139                 .getEntity("nestedUncertainty");
140         assertTrue(a.isSizable());
141         a.setSize(10);
142         assertEquals(SMALL_BYTES, a.getValue());
143         StringBuffer buf = new StringBuffer();
144         for (int i = 0; i < 10; i++) {
145             byte[] b = new byte[i + 1];
146             Arrays.fill(b, (byte) ((int) 'a' + i));
147             buf.append(new String(b));
148             a.getChild(i).setValue(b);
149         }
150         assertEquals(buf.toString().getBytes(), a.getValue());
151     }
152 
153     private void assertBounds(DynamicField df, int min, int max) {
154         assertBounds(df, new DynamicField.Bounds(min, max));
155     }
156 
157     private void assertBounds(DynamicField df, DynamicField.Bounds bounds) {
158         assertEquals(bounds, df.getBounds());
159         testValue(df, SMALL_BYTES);
160         testValue(df, LARGE_BYTES);
161     }
162 
163     private void assertLoad(DynamicField df) throws IOException {
164         df.readFrom(new ByteArrayInputStream(LARGE_BYTES));
165         int max = df.getBounds().getMaximum();
166         int expectedLength = Math.min(max, LARGE_BYTES.length);
167         assertEquals(expectedLength, df.length());
168         byte[] expec;
169         if (LARGE_BYTES.length < max) {
170             expec = LARGE_BYTES;
171         } else {
172             expec = new byte[max];
173             System.arraycopy(LARGE_BYTES, 0, expec, 0, expec.length);
174         }
175         assertEquals(expec, df.getValue());
176     }
177 
178     private void testValue(DynamicField df, byte[] value) {
179         int len = value.length;
180         int min = df.getBounds().getMinimum();
181         int max = df.getBounds().getMaximum();
182         if (df.getUnderflow() == Underflow.ERROR && len < min
183                 || df.getOverflow() == Overflow.ERROR && len > max) {
184             byte[] old = df.getValue();
185             try {
186                 df.setValue(value);
187                 fail(new String(value));
188             } catch (IllegalArgumentException e) {
189                 assertEquals(old, df.getValue());
190             }
191         } else {
192             df.setValue(value);
193             assertTrue(len < min || len > max
194                     || Arrays.equals(value, df.getValue()));
195         }
196     }
197 
198     private DynamicField get(String name) {
199         return (DynamicField) entityFactory.getEntity(name);
200     }
201 
202     /**
203      * Detailed comparison
204      * @param a
205      * @param b
206      */
207     private void assertEquals(byte[] a, byte[] b) {
208         if (a != b) {
209             if (a == null || b == null) {
210                 fail();
211             }
212             assertEquals(a.length, b.length);
213             byte[] checkA = new byte[BUFFER_SIZE];
214             byte[] checkB = new byte[BUFFER_SIZE];
215             int cur = 0;
216             while (cur < a.length) {
217                 int len = Math.min(BUFFER_SIZE, a.length - cur);
218                 System.arraycopy(a, cur, checkA, 0, len);
219                 System.arraycopy(b, cur, checkB, 0, len);
220                 if (len < BUFFER_SIZE) {
221                     Arrays.fill(checkA, len, BUFFER_SIZE, (byte) 0);
222                     Arrays.fill(checkB, len, BUFFER_SIZE, (byte) 0);
223                 }
224                 if (!Arrays.equals(checkA, checkB)) {
225                     String stringA = new String(checkA, 0, len);
226                     String stringB = new String(checkB, 0, len);
227                     fail("difference in (" + cur + " - " + (cur + len - 1)
228                             + "); expected \"" + stringA + "\" but was \""
229                             + stringB + "\"");
230                 }
231                 cur += len;
232             }
233         }
234     }
235 
236     protected String getSource() {
237         return "dynamicField.test";
238     }
239 
240 }