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    *      https://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.beanutils2.converters;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.lang.reflect.Array;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.Locale;
28  
29  import org.junit.jupiter.api.AfterEach;
30  import org.junit.jupiter.api.BeforeEach;
31  import org.junit.jupiter.api.Test;
32  
33  /**
34   * Test Case for the ArrayConverter class.
35   */
36  public class ArrayConverterTest {
37  
38      /**
39       * Check that two arrays are the same.
40       *
41       * @param msg      Test prefix msg
42       * @param expected Expected Array value
43       * @param result   Result array value
44       */
45      private void checkArray(final String msg, final Object expected, final Object result) {
46          assertNotNull(expected, msg + " Expected Null");
47          assertNotNull(result, msg + " Result   Null");
48          assertTrue(result.getClass().isArray(), msg + " Result   not array");
49          assertTrue(expected.getClass().isArray(), msg + " Expected not array");
50          final int resultLth = Array.getLength(result);
51          assertEquals(Array.getLength(expected), resultLth, msg + " Size");
52          assertEquals(expected.getClass(), result.getClass(), msg + " Type");
53          for (int i = 0; i < resultLth; i++) {
54              final Object expectElement = Array.get(expected, i);
55              final Object resultElement = Array.get(result, i);
56              assertEquals(expectElement, resultElement, msg + " Element " + i);
57          }
58      }
59  
60      /** Sets Up */
61      @BeforeEach
62      public void setUp() throws Exception {
63          // empty
64      }
65  
66      /** Tear Down */
67      @AfterEach
68      public void tearDown() throws Exception {
69          // empty
70      }
71  
72      /**
73       * Test Converting using the IntegerConverter as the component Converter
74       */
75      @Test
76      public void testComponentIntegerConverter() {
77  
78          final IntegerConverter intConverter = new IntegerConverter(Integer.valueOf(0));
79          intConverter.setPattern("#,###");
80          intConverter.setLocale(Locale.US);
81          final ArrayConverter arrayConverter = new ArrayConverter(int[].class, intConverter, 0);
82          arrayConverter.setAllowedChars(new char[] { ',', '-' });
83          arrayConverter.setDelimiter(';');
84  
85          // Expected results
86          final int[] intArray = { 1111, 2222, 3333, 4444 };
87          final String stringA = "1,111; 2,222; 3,333; 4,444";
88          final String stringB = intArray[0] + ";" + intArray[1] + ";" + intArray[2] + ";" + intArray[3];
89          final String[] strArray = { "" + intArray[0], "" + intArray[1], "" + intArray[2], "" + intArray[3] };
90          final long[] longArray = { intArray[0], intArray[1], intArray[2], intArray[3] };
91          final Long[] LONGArray = { Long.valueOf(intArray[0]), Long.valueOf(intArray[1]), Long.valueOf(intArray[2]), Long.valueOf(intArray[3]) };
92          final Integer[] IntegerArray = { Integer.valueOf(intArray[0]), Integer.valueOf(intArray[1]), Integer.valueOf(intArray[2]),
93                  Integer.valueOf(intArray[3]) };
94          final ArrayList<String> strList = new ArrayList<>();
95          final ArrayList<Long> longList = new ArrayList<>();
96          for (int i = 0; i < strArray.length; i++) {
97              strList.add(strArray[i]);
98              longList.add(LONGArray[i]);
99          }
100 
101         String msg = null;
102 
103         // String --> int[]
104         msg = "String --> int[]";
105         checkArray(msg, intArray, arrayConverter.convert(int[].class, stringA));
106 
107         // String --> int[] (with braces)
108         msg = "String --> Integer[] (with braces)";
109         checkArray(msg, IntegerArray, arrayConverter.convert(Integer[].class, "{" + stringA + "}"));
110 
111         // String[] --> int[]
112         msg = "String[] --> int[]";
113         checkArray(msg, intArray, arrayConverter.convert(int[].class, strArray));
114 
115         // String[] --> Integer[]
116         msg = "String[] --> Integer[]";
117         checkArray(msg, IntegerArray, arrayConverter.convert(Integer[].class, strArray));
118 
119         // long[] --> int[]
120         msg = "long[] --> int[]";
121         checkArray(msg, intArray, arrayConverter.convert(int[].class, longArray));
122 
123         // Long --> int[]
124         msg = "Long --> int[]";
125         checkArray(msg, new int[] { LONGArray[0].intValue() }, arrayConverter.convert(int[].class, LONGArray[0]));
126 
127         // LONG[] --> int[]
128         msg = "LONG[] --> int[]";
129         checkArray(msg, intArray, arrayConverter.convert(int[].class, LONGArray));
130 
131         // Long --> String
132         msg = "Long --> String";
133         assertEquals(LONGArray[0] + "", arrayConverter.convert(String.class, LONGArray[0]), msg);
134 
135         // LONG[] --> String (first)
136         msg = "LONG[] --> String (first)";
137         assertEquals(LONGArray[0] + "", arrayConverter.convert(String.class, LONGArray), msg);
138 
139         // LONG[] --> String (all)
140         msg = "LONG[] --> String (all)";
141         arrayConverter.setOnlyFirstToString(false);
142         assertEquals(stringB, arrayConverter.convert(String.class, LONGArray), msg);
143 
144         // Collection of Long --> String
145         msg = "Collection of Long --> String";
146         assertEquals(stringB, arrayConverter.convert(String.class, longList), msg);
147 
148         // LONG[] --> String[]
149         msg = "long[] --> String[]";
150         checkArray(msg, strArray, arrayConverter.convert(String[].class, LONGArray));
151 
152         // Collection of String --> Integer[]
153         msg = "Collection of String --> Integer[]";
154         checkArray(msg, IntegerArray, arrayConverter.convert(Integer[].class, strList));
155 
156         // Collection of Long --> int[]
157         msg = "Collection of Long --> int[]";
158         checkArray(msg, intArray, arrayConverter.convert(int[].class, longList));
159     }
160 
161     /**
162      * Test Empty String
163      */
164     @Test
165     public void testEmptyString() {
166         final int[] zeroArray = {};
167         final IntegerConverter intConverter = new IntegerConverter();
168 
169         checkArray("Empty String", zeroArray, new ArrayConverter(int[].class, intConverter, -1).convert(int[].class, ""));
170         assertEquals(null, new ArrayConverter(int[].class, intConverter).convert(String.class, null), "Default String");
171     }
172 
173     /**
174      * Test Errors creating the converter
175      */
176     @Test
177     public void testErrors() {
178         assertThrows(NullPointerException.class, () -> new ArrayConverter(null, new DateConverter()));
179         assertThrows(IllegalArgumentException.class, () -> new ArrayConverter(Boolean.class, new DateConverter()));
180         assertThrows(NullPointerException.class, () -> new ArrayConverter(int[].class, null));
181     }
182 
183     /**
184      * Test Converting using the IntegerConverter as the component Converter
185      */
186     @Test
187     public void testInvalidWithDefault() {
188         final int[] zeroArray = {};
189         final int[] oneArray = new int[1];
190         final IntegerConverter intConverter = new IntegerConverter();
191 
192         assertEquals(null, new ArrayConverter(int[].class, intConverter, -1).convert(int[].class, null), "Null Default");
193         checkArray("Zero Length", zeroArray, new ArrayConverter(int[].class, intConverter, 0).convert(int[].class, null));
194         checkArray("One Length", oneArray, new ArrayConverter(Integer[].class, intConverter, 1).convert(int[].class, null));
195     }
196 
197     /**
198      * Test Converting a String[] to integer array (with leading/trailing whitespace)
199      */
200     @Test
201     public void testStringArrayToNumber() {
202 
203         // Configure Converter
204         final IntegerConverter intConverter = new IntegerConverter();
205         final ArrayConverter arrayConverter = new ArrayConverter(int[].class, intConverter);
206 
207         // Test Data
208         final String[] array = { "10", "  11", "12  ", "  13  " };
209         final ArrayList<String> list = new ArrayList<>();
210         Collections.addAll(list, array);
211 
212         // Expected results
213         String msg = null;
214         final int[] expectedInt = { 10, 11, 12, 13 };
215         final Integer[] expectedInteger = { Integer.valueOf(expectedInt[0]), Integer.valueOf(expectedInt[1]), Integer.valueOf(expectedInt[2]),
216                 Integer.valueOf(expectedInt[3]) };
217 
218         // Test String[] --> int[]
219         msg = "String[] --> int[]";
220         checkArray(msg, expectedInt, arrayConverter.convert(int[].class, array));
221 
222         // Test String[] --> Integer[]
223         msg = "String[] --> Integer[]";
224         checkArray(msg, expectedInteger, arrayConverter.convert(Integer[].class, array));
225 
226         // Test List --> int[]
227         msg = "List --> int[]";
228         checkArray(msg, expectedInt, arrayConverter.convert(int[].class, list));
229 
230         // Test List --> Integer[]
231         msg = "List --> Integer[]";
232         checkArray(msg, expectedInteger, arrayConverter.convert(Integer[].class, list));
233     }
234 
235     /**
236      * Test the Matrix!!!! (parses a String into a 2 dimensional integer array or matrix)
237      */
238     @Test
239     public void testTheMatrix() {
240 
241         // Test Date - create the Matrix!!
242         // Following String uses two delimiter:
243         // - comma (",") to separate individual numbers
244         // - semicolon (";") to separate lists of numbers
245         final String matrixString = "11,12,13 ; 21,22,23 ; 31,32,33 ; 41,42,43";
246         final int[][] expected = { new int[] { 11, 12, 13 }, new int[] { 21, 22, 23 }, new int[] { 31, 32, 33 }, new int[] { 41, 42, 43 } };
247 
248         // Construct an Integer Converter
249         final IntegerConverter integerConverter = new IntegerConverter();
250 
251         // Construct an array Converter for an integer array (i.e. int[]) using
252         // an IntegerConverter as the element converter.
253         // Uses the default comma (i.e. ",") as the delimiter between individual numbers
254         final ArrayConverter arrayConverter = new ArrayConverter(int[].class, integerConverter);
255 
256         // Construct a "Matrix" Converter which converts arrays of integer arrays using
257         // the first (int[]) Converter as the element Converter.
258         // Uses a semicolon (i.e. ";") as the delimiter to separate the different sets of numbers.
259         // Also the delimiter for the above array Converter needs to be added to this
260         // array Converter's "allowed characters"
261         final ArrayConverter matrixConverter = new ArrayConverter(int[][].class, arrayConverter);
262         matrixConverter.setDelimiter(';');
263         matrixConverter.setAllowedChars(new char[] { ',' });
264 
265         // Do the Conversion
266         final Object result = matrixConverter.convert(int[][].class, matrixString);
267 
268         // Check it actually worked OK
269         assertEquals(int[][].class, result.getClass(), "Check int[][].class");
270         final int[][] matrix = (int[][]) result;
271         assertEquals(expected.length, matrix.length, "Check int[][] length");
272         for (int i = 0; i < expected.length; i++) {
273             assertEquals(expected[i].length, matrix[i].length, "Check int[" + i + "] length");
274             for (int j = 0; j < expected[i].length; j++) {
275                 final String label = "Matrix int[" + i + "," + j + "] element";
276                 assertEquals(expected[i][j], matrix[i][j], label);
277                 // System.out.println(label + " = " + matrix[i][j]);
278             }
279         }
280     }
281 
282     /**
283      * Test for BEANUTILS-302 - throwing a NPE when underscore used
284      */
285     @Test
286     public void testUnderscore_BEANUTILS_302() {
287         final String value = "first_value,second_value";
288         final ArrayConverter<String[]> converter = new ArrayConverter(String[].class, new StringConverter());
289 
290         // test underscore not allowed (the default)
291         String[] result = converter.convert(String[].class, value);
292         assertNotNull(result, "result.null");
293         assertEquals(4, result.length, "result.length");
294         assertEquals("first", result[0], "result[0]");
295         assertEquals("value", result[1], "result[1]");
296         assertEquals("second", result[2], "result[2]");
297         assertEquals("value", result[3], "result[3]");
298 
299         // configure the converter to allow underscore
300         converter.setAllowedChars(new char[] { '.', '-', '_' });
301 
302         // test underscore allowed
303         result = converter.convert(String[].class, value);
304         assertNotNull(result, "result.null");
305         assertEquals(2, result.length, "result.length");
306         assertEquals("first_value", result[0], "result[0]");
307         assertEquals("second_value", result[1], "result[1]");
308     }
309 }