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.geometry.core.internal;
18  
19  import org.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.Test;
21  
22  class SimpleTupleFormatTest {
23  
24      private static final double EPS = 1e-10;
25  
26      private static final String OPEN_PAREN = "(";
27      private static final String CLOSE_PAREN = ")";
28  
29      private static final DoubleFunction1N<Stub1D> FACTORY_1D = v -> {
30          Stub1D result = new Stub1D();
31          result.v = v;
32  
33          return result;
34      };
35  
36      private static final DoubleFunction2N<Stub2D> FACTORY_2D = (v1, v2) -> {
37          Stub2D result = new Stub2D();
38          result.v1 = v1;
39          result.v2 = v2;
40  
41          return result;
42      };
43  
44      private static final DoubleFunction3N<Stub3D> FACTORY_3D = (v1, v2, v3) -> {
45          Stub3D result = new Stub3D();
46          result.v1 = v1;
47          result.v2 = v2;
48          result.v3 = v3;
49  
50          return result;
51      };
52  
53      @Test
54      void testConstructor() {
55          // act
56          final SimpleTupleFormat formatter = new SimpleTupleFormat("|", "{", "}");
57  
58          // assert
59          Assertions.assertEquals("|", formatter.getSeparator());
60          Assertions.assertEquals("{", formatter.getPrefix());
61          Assertions.assertEquals("}", formatter.getSuffix());
62      }
63  
64      @Test
65      void testConstructor_defaultSeparator() {
66          // act
67          final SimpleTupleFormat formatter = new SimpleTupleFormat("{", "}");
68  
69          // assert
70          Assertions.assertEquals(",", formatter.getSeparator());
71          Assertions.assertEquals("{", formatter.getPrefix());
72          Assertions.assertEquals("}", formatter.getSuffix());
73      }
74  
75      @Test
76      void testFormat1D() {
77          // arrange
78          final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
79  
80          // act/assert
81          Assertions.assertEquals("(1.0)", formatter.format(1.0));
82          Assertions.assertEquals("(-1.0)", formatter.format(-1.0));
83          Assertions.assertEquals("(NaN)", formatter.format(Double.NaN));
84          Assertions.assertEquals("(-Infinity)", formatter.format(Double.NEGATIVE_INFINITY));
85          Assertions.assertEquals("(Infinity)", formatter.format(Double.POSITIVE_INFINITY));
86      }
87  
88      @Test
89      void testFormat1D_noPrefixSuffix() {
90          // arrange
91          final SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
92  
93          // act/assert
94          Assertions.assertEquals("1.0", formatter.format(1.0));
95          Assertions.assertEquals("-1.0", formatter.format(-1.0));
96          Assertions.assertEquals("NaN", formatter.format(Double.NaN));
97          Assertions.assertEquals("-Infinity", formatter.format(Double.NEGATIVE_INFINITY));
98          Assertions.assertEquals("Infinity", formatter.format(Double.POSITIVE_INFINITY));
99      }
100 
101     @Test
102     void testFormat2D() {
103         // arrange
104         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
105 
106         // act/assert
107         Assertions.assertEquals("(1.0, -1.0)", formatter.format(1.0, -1.0));
108         Assertions.assertEquals("(-1.0, 1.0)", formatter.format(-1.0, 1.0));
109         Assertions.assertEquals("(NaN, -Infinity)", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY));
110         Assertions.assertEquals("(-Infinity, Infinity)", formatter.format(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
111     }
112 
113     @Test
114     void testFormat2D_noPrefixSuffix() {
115         // arrange
116         final SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
117 
118         // act/assert
119         Assertions.assertEquals("1.0, -1.0", formatter.format(1.0, -1.0));
120         Assertions.assertEquals("-1.0, 1.0", formatter.format(-1.0, 1.0));
121         Assertions.assertEquals("NaN, -Infinity", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY));
122         Assertions.assertEquals("-Infinity, Infinity", formatter.format(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
123     }
124 
125     @Test
126     void testFormat3D() {
127         // arrange
128         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
129 
130         // act/assert
131         Assertions.assertEquals("(1.0, 0.0, -1.0)", formatter.format(1.0, 0.0, -1.0));
132         Assertions.assertEquals("(-1.0, 1.0, 0.0)", formatter.format(-1.0, 1.0, 0.0));
133         Assertions.assertEquals("(NaN, -Infinity, Infinity)", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
134     }
135 
136     @Test
137     void testFormat3D_noPrefixSuffix() {
138         // arrange
139         final SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
140 
141         // act/assert
142         Assertions.assertEquals("1.0, 0.0, -1.0", formatter.format(1.0, 0.0, -1.0));
143         Assertions.assertEquals("-1.0, 1.0, 0.0", formatter.format(-1.0, 1.0, 0.0));
144         Assertions.assertEquals("NaN, -Infinity, Infinity", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
145     }
146 
147     @Test
148     void testFormat4D() {
149         // arrange
150         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
151 
152         // act/assert
153         Assertions.assertEquals("(1.0, 0.0, -1.0, 2.0)", formatter.format(1.0, 0.0, -1.0, 2.0));
154         Assertions.assertEquals("(-1.0, 1.0, 0.0, 2.0)", formatter.format(-1.0, 1.0, 0.0, 2.0));
155         Assertions.assertEquals("(NaN, -Infinity, Infinity, NaN)", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN));
156     }
157 
158     @Test
159     void testFormat4D_noPrefixSuffix() {
160         // arrange
161         final SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
162 
163         // act/assert
164         Assertions.assertEquals("1.0, 0.0, -1.0, 2.0", formatter.format(1.0, 0.0, -1.0, 2.0));
165         Assertions.assertEquals("-1.0, 1.0, 0.0, 2.0", formatter.format(-1.0, 1.0, 0.0, 2.0));
166         Assertions.assertEquals("NaN, -Infinity, Infinity, NaN", formatter.format(Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN));
167     }
168 
169     @Test
170     void testFormat_longTokens() {
171         // arrange
172         final SimpleTupleFormat formatter = new SimpleTupleFormat("||", "<<", ">>");
173 
174         // act/assert
175         Assertions.assertEquals("<<1.0>>", formatter.format(1.0));
176         Assertions.assertEquals("<<1.0|| 2.0>>", formatter.format(1.0, 2.0));
177         Assertions.assertEquals("<<1.0|| 2.0|| 3.0>>", formatter.format(1.0, 2.0, 3.0));
178     }
179 
180     @Test
181     void testParse1D() {
182         // arrange
183         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
184 
185         // act/assert
186         checkParse1D(formatter, "(1)", 1.0);
187         checkParse1D(formatter, "(-1)", -1.0);
188 
189         checkParse1D(formatter, "(0.01)", 0.01);
190         checkParse1D(formatter, "(-1e-2)", -0.01);
191 
192         checkParse1D(formatter, "(100)", 100);
193         checkParse1D(formatter, "(-1e2)", -100);
194 
195         checkParse1D(formatter, " (\n 1 \t) ", 1);
196         checkParse1D(formatter, "\n ( -1 \t)\r\n", -1);
197 
198         checkParse1D(formatter, "(1, )", 1.0);
199         checkParse1D(formatter, "(-1, )", -1.0);
200 
201         checkParse1D(formatter, "(NaN)", Double.NaN);
202         checkParse1D(formatter, "(-Infinity)", Double.NEGATIVE_INFINITY);
203         checkParse1D(formatter, "(Infinity)", Double.POSITIVE_INFINITY);
204     }
205 
206     @Test
207     void testParse1D_noPrefixSuffix() {
208         // arrange
209         final SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
210 
211         // act/assert
212         checkParse1D(formatter, "1", 1.0);
213         checkParse1D(formatter, "-1", -1.0);
214 
215         checkParse1D(formatter, "0.01", 0.01);
216         checkParse1D(formatter, "-1e-2", -0.01);
217 
218         checkParse1D(formatter, "100", 100);
219         checkParse1D(formatter, "-1e2", -100);
220 
221         checkParse1D(formatter, " \n 1 \t ", 1);
222         checkParse1D(formatter, "\n  -1 \t\r\n", -1);
223 
224         checkParse1D(formatter, "1, ", 1.0);
225         checkParse1D(formatter, "-1, ", -1.0);
226 
227         checkParse1D(formatter, "NaN", Double.NaN);
228         checkParse1D(formatter, "-Infinity", Double.NEGATIVE_INFINITY);
229         checkParse1D(formatter, "Infinity", Double.POSITIVE_INFINITY);
230     }
231 
232     @Test
233     void testParse1D_failure() {
234         // arrange
235         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
236 
237         // act/assert
238         checkParse1DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
239         checkParse1DFailure(formatter, "(1 ", "index 3: expected \")\" but found \"\"");
240 
241         checkParse1DFailure(formatter, "(abc)", "unable to parse number from string \"abc\"");
242 
243         checkParse1DFailure(formatter, "(1) 1", "index 4: unexpected content");
244     }
245 
246     @Test
247     void testParse2D() {
248         // arrange
249         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
250 
251         // act/assert
252         checkParse2D(formatter, "(1,-2)", 1.0, -2.0);
253         checkParse2D(formatter, "(2,-1)", 2.0, -1.0);
254 
255         checkParse2D(formatter, "(0.01, -0.02)", 0.01, -0.02);
256         checkParse2D(formatter, "(-1e-2,2e-2)", -0.01, 0.02);
257 
258         checkParse2D(formatter, "(100,  -1e2)", 100, -100);
259 
260         checkParse2D(formatter, " (\n 1 , 2 \t) ", 1, 2);
261         checkParse2D(formatter, "\n ( -1 , -2 \t)\r\n", -1, -2);
262 
263         checkParse2D(formatter, "(1, 2, )", 1.0, 2.0);
264         checkParse2D(formatter, "(-1, -2,)", -1.0, -2.0);
265 
266         checkParse2D(formatter, "(NaN, -Infinity)", Double.NaN, Double.NEGATIVE_INFINITY);
267         checkParse2D(formatter, "(-Infinity, Infinity)", Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
268     }
269 
270     @Test
271     void testParse2D_noPrefixSuffix() {
272         // arrange
273         final SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
274 
275         // act/assert
276         checkParse2D(formatter, "1,-2", 1.0, -2.0);
277         checkParse2D(formatter, "2,-1", 2.0, -1.0);
278 
279         checkParse2D(formatter, "0.01, -0.02", 0.01, -0.02);
280         checkParse2D(formatter, "-1e-2,2e-2", -0.01, 0.02);
281 
282         checkParse2D(formatter, "100,  -1e2", 100, -100);
283 
284         checkParse2D(formatter, " \n 1 , 2 \t ", 1, 2);
285         checkParse2D(formatter, "\n  -1 , -2 \t\r\n", -1, -2);
286 
287         checkParse2D(formatter, "1, 2, ", 1.0, 2.0);
288         checkParse2D(formatter, "-1, -2,", -1.0, -2.0);
289 
290         checkParse2D(formatter, "NaN, -Infinity", Double.NaN, Double.NEGATIVE_INFINITY);
291         checkParse2D(formatter, "-Infinity, Infinity", Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
292     }
293 
294     @Test
295     void testParse2D_failure() {
296         // arrange
297         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
298 
299         // act/assert
300         checkParse2DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
301         checkParse2DFailure(formatter, "(1, 2 ", "index 6: expected \")\" but found \"\"");
302 
303         checkParse2DFailure(formatter, "(0,abc)", "index 3: unable to parse number from string \"abc\"");
304 
305         checkParse2DFailure(formatter, "(1, 2) 1", "index 7: unexpected content");
306     }
307 
308     @Test
309     void testParse3D() {
310         // arrange
311         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
312 
313         // act/assert
314         checkParse3D(formatter, "(1,-2,3)", 1.0, -2.0, 3.0);
315         checkParse3D(formatter, "(2,-1,3)", 2.0, -1.0, 3.0);
316 
317         checkParse3D(formatter, "(0.01, -0.02, 0.3)", 0.01, -0.02, 0.3);
318         checkParse3D(formatter, "(-1e-2,2e-2,-3E-1)", -0.01, 0.02, -0.3);
319 
320         checkParse3D(formatter, "(100,  -1e2,2E10)", 100, -100, 2e10);
321 
322         checkParse3D(formatter, " (\n 1 , 2 , 3 \t) ", 1, 2, 3);
323         checkParse3D(formatter, "\n ( -1 , -2 ,  -3 \t)\r\n", -1, -2, -3);
324 
325         checkParse3D(formatter, "(1, 2, 3, )", 1.0, 2.0, 3.0);
326         checkParse3D(formatter, "(-1, -2, -3,)", -1.0, -2.0, -3.0);
327 
328         checkParse3D(formatter, "(NaN, -Infinity, Infinity)", Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
329     }
330 
331     @Test
332     void testParse3D_noPrefixSuffix() {
333         // arrange
334         final SimpleTupleFormat formatter = new SimpleTupleFormat(null, null);
335 
336         // act/assert
337         checkParse3D(formatter, "1,-2,3", 1.0, -2.0, 3.0);
338         checkParse3D(formatter, "2,-1,3", 2.0, -1.0, 3.0);
339 
340         checkParse3D(formatter, "0.01, -0.02, 0.3", 0.01, -0.02, 0.3);
341         checkParse3D(formatter, "-1e-2,2e-2,-3E-1", -0.01, 0.02, -0.3);
342 
343         checkParse3D(formatter, "100,  -1e2,2E10", 100, -100, 2e10);
344 
345         checkParse3D(formatter, " \n 1 , 2 , 3 \t ", 1, 2, 3);
346         checkParse3D(formatter, "\n  -1 , -2 ,  -3 \t\r\n", -1, -2, -3);
347 
348         checkParse3D(formatter, "1, 2, 3, ", 1.0, 2.0, 3.0);
349         checkParse3D(formatter, "-1, -2, -3,", -1.0, -2.0, -3.0);
350 
351         checkParse3D(formatter, "NaN, -Infinity, Infinity", Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
352     }
353 
354     @Test
355     void testParse3D_failure() {
356         // arrange
357         final SimpleTupleFormat formatter = new SimpleTupleFormat(OPEN_PAREN, CLOSE_PAREN);
358 
359         // act/assert
360         checkParse3DFailure(formatter, "", "index 0: expected \"(\" but found \"\"");
361         checkParse3DFailure(formatter, "(1, 2, 3", "index 8: expected \")\" but found \"\"");
362 
363         checkParse3DFailure(formatter, "(0,0,abc)", "index 5: unable to parse number from string \"abc\"");
364 
365         checkParse3DFailure(formatter, "(1, 2, 3) 1", "index 10: unexpected content");
366     }
367 
368     @Test
369     void testParse_longTokens() {
370         // arrange
371         final SimpleTupleFormat formatter = new SimpleTupleFormat("||", "<<", ">>");
372 
373         // act/assert
374         checkParse1D(formatter, "<<1.0>>", 1.0);
375         checkParse2D(formatter, "<<1.0|| 2.0>>", 1.0, 2.0);
376         checkParse3D(formatter, "<<1.0|| 2.0|| 3.0>>", 1.0, 2.0, 3.0);
377     }
378 
379     @Test
380     void testParse_longTokens_failure() {
381         // arrange
382         final SimpleTupleFormat formatter = new SimpleTupleFormat("||", "<<", ">>");
383 
384         // act/assert
385         checkParse1DFailure(formatter, "<", "index 0: expected \"<<\" but found \"<\"");
386         checkParse1DFailure(formatter, "<1.0>>", "index 0: expected \"<<\" but found \"<1\"");
387         checkParse2DFailure(formatter, "<<1.0| 2.0>>", "index 2: unable to parse number from string \"1.0| 2.0\"");
388         checkParse3DFailure(formatter, "<<1.0|| 2.0|| 3.0>", "index 13: unable to parse number from string \" 3.0>\"");
389     }
390 
391     @Test
392     void testDefaultInstance() {
393         // act
394         final SimpleTupleFormat formatter = SimpleTupleFormat.getDefault();
395 
396         // assert
397         Assertions.assertEquals(",", formatter.getSeparator());
398         Assertions.assertEquals("(", formatter.getPrefix());
399         Assertions.assertEquals(")", formatter.getSuffix());
400 
401         Assertions.assertEquals("(1.0, 2.0)", formatter.format(1, 2));
402     }
403 
404     private void checkParse1D(final SimpleTupleFormat formatter, final String str, final double v) {
405         final Stub1D result = formatter.parse(str, FACTORY_1D);
406 
407         Assertions.assertEquals(v, result.v, EPS);
408     }
409 
410     private void checkParse1DFailure(final SimpleTupleFormat formatter, final String str, final String msgSubstr) {
411         try {
412             formatter.parse(str, FACTORY_1D);
413             Assertions.fail("Operation should have failed");
414         } catch (final IllegalArgumentException exc) {
415             final String excMsg = exc.getMessage();
416             Assertions.assertTrue(excMsg.contains(msgSubstr), "Expected message to contain [" + msgSubstr + "] but was [" + excMsg + "]");
417         }
418     }
419 
420     private void checkParse2D(final SimpleTupleFormat formatter, final String str, final double v1, final double v2) {
421         final Stub2D result = formatter.parse(str, FACTORY_2D);
422 
423         Assertions.assertEquals(v1, result.v1, EPS);
424         Assertions.assertEquals(v2, result.v2, EPS);
425     }
426 
427     private void checkParse2DFailure(final SimpleTupleFormat formatter, final String str, final String msgSubstr) {
428         try {
429             formatter.parse(str, FACTORY_2D);
430             Assertions.fail("Operation should have failed");
431         } catch (final IllegalArgumentException exc) {
432             final String excMsg = exc.getMessage();
433             Assertions.assertTrue(excMsg.contains(msgSubstr),
434                     "Expected message to contain [" + msgSubstr + "] but was [" + excMsg + "]");
435         }
436     }
437 
438     private void checkParse3D(final SimpleTupleFormat formatter, final String str, final double v1, final double v2, final double v3) {
439         final Stub3D result = formatter.parse(str, FACTORY_3D);
440 
441         Assertions.assertEquals(v1, result.v1, EPS);
442         Assertions.assertEquals(v2, result.v2, EPS);
443         Assertions.assertEquals(v3, result.v3, EPS);
444     }
445 
446     private void checkParse3DFailure(final SimpleTupleFormat formatter, final String str, final String msgSubstr) {
447         try {
448             formatter.parse(str, FACTORY_3D);
449             Assertions.fail("Operation should have failed");
450         } catch (final IllegalArgumentException exc) {
451             final String excMsg = exc.getMessage();
452             Assertions.assertTrue(excMsg.contains(msgSubstr),
453                     "Expected message to contain [" + msgSubstr + "] but was [" + excMsg + "]");
454         }
455     }
456 
457     private static class Stub1D {
458         private double v;
459     }
460 
461     private static class Stub2D {
462         private double v1;
463         private double v2;
464     }
465 
466     private static class Stub3D {
467         private double v1;
468         private double v2;
469         private double v3;
470     }
471 }