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.io.core;
18  
19  import java.io.InputStream;
20  import java.io.OutputStream;
21  import java.nio.charset.Charset;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.stream.Collectors;
26  import java.util.stream.Stream;
27  
28  import org.apache.commons.geometry.core.GeometryTestUtils;
29  import org.apache.commons.geometry.core.partitioning.BoundaryList;
30  import org.apache.commons.geometry.core.partitioning.test.TestLineSegment;
31  import org.apache.commons.geometry.core.partitioning.test.TestPoint2D;
32  import org.apache.commons.geometry.io.core.input.GeometryInput;
33  import org.apache.commons.geometry.io.core.output.GeometryOutput;
34  import org.apache.commons.geometry.io.core.test.StubGeometryFormat;
35  import org.apache.commons.numbers.core.Precision;
36  import org.junit.jupiter.api.Assertions;
37  import org.junit.jupiter.api.Test;
38  
39  class BoundaryIOManagerTest {
40  
41      private static final TestLineSegment SEGMENT = new TestLineSegment(TestPoint2D.ZERO, TestPoint2D.PLUS_X);
42  
43      private static final TestBoundaryList BOUNDARY_LIST = new TestBoundaryList(Collections.singletonList(SEGMENT));
44  
45      private static final GeometryFormat FMT_A = new StubGeometryFormat("testA", Arrays.asList("a", "aext"));
46  
47      private static final GeometryFormat FMT_A_ALT = new StubGeometryFormat("TESTa", Collections.singletonList("A"));
48  
49      private static final GeometryFormat FMT_B = new StubGeometryFormat("testB", Collections.singletonList("b"));
50  
51      private static final GeometryFormat FMT_B_ALT = new StubGeometryFormat("TESTb", Collections.singletonList("B"));
52  
53      private static final GeometryFormat FMT_C = new StubGeometryFormat("testC", Collections.singletonList("c"));
54  
55      private final TestManager manager = new TestManager();
56  
57      @Test
58      void testRegisterReadHandler() {
59          // arrange
60          final StubReadHandler r1 = new StubReadHandler(FMT_A);
61          final StubReadHandler r2 = new StubReadHandler(FMT_B);
62          final StubReadHandler r3 = new StubReadHandler(FMT_A_ALT);
63  
64          // act
65          manager.registerReadHandler(r1); // will be replaced by r3
66          manager.registerReadHandler(r2);
67          manager.registerReadHandler(r2); // register 2x
68          manager.registerReadHandler(r3);
69  
70          // assert
71          Assertions.assertSame(r3, manager.getReadHandlerForFormat(FMT_A));
72          Assertions.assertSame(r2, manager.getReadHandlerForFormat(FMT_B));
73  
74          Assertions.assertSame(r3, manager.getReadHandlerForFileExtension("a"));
75          Assertions.assertNull(manager.getReadHandlerForFileExtension("aext"));
76          Assertions.assertSame(r2, manager.getReadHandlerForFileExtension("b"));
77  
78          Assertions.assertEquals(Arrays.asList(r2, r3), manager.getReadHandlers());
79      }
80  
81      @Test
82      void testRegisterReadHandler_multipleFileExtensions() {
83          // arrange
84          final StubReadHandler r1 = new StubReadHandler(FMT_A);
85  
86          // act
87          manager.registerReadHandler(r1);
88  
89          // assert
90          Assertions.assertSame(r1, manager.getReadHandlerForFormat(FMT_A_ALT));
91  
92          Assertions.assertSame(r1, manager.getReadHandlerForFileExtension("A"));
93          Assertions.assertSame(r1, manager.getReadHandlerForFileExtension("AEXT"));
94      }
95  
96      @Test
97      void testRegisterReadHandler_nullAndMissingFileExt() {
98          // arrange
99          final StubGeometryFormat noExts = new StubGeometryFormat("a", null);
100         final StubGeometryFormat nullExts = new StubGeometryFormat("b", Arrays.asList("bext", null, null));
101 
102         final StubReadHandler r1 = new StubReadHandler(noExts);
103         final StubReadHandler r2 = new StubReadHandler(nullExts);
104 
105         // act
106         manager.registerReadHandler(r1);
107         manager.registerReadHandler(r2);
108 
109         // assert
110         Assertions.assertSame(r1, manager.getReadHandlerForFormat(noExts));
111         Assertions.assertNull(manager.getReadHandlerForFileExtension("a"));
112 
113         Assertions.assertSame(r2, manager.getReadHandlerForFormat(nullExts));
114         Assertions.assertSame(r2, manager.getReadHandlerForFileExtension("bext"));
115     }
116 
117     @Test
118     void testRegisterReadHandler_illegalArgs() {
119         // arrange
120         final StubReadHandler nullFmt = new StubReadHandler(null);
121         final StubReadHandler nullFmtName = new StubReadHandler(new StubGeometryFormat(null));
122 
123         // act/assert
124         GeometryTestUtils.assertThrowsWithMessage(
125                 () -> manager.registerReadHandler(null),
126                 NullPointerException.class, "Handler cannot be null");
127         GeometryTestUtils.assertThrowsWithMessage(
128                 () -> manager.registerReadHandler(nullFmt),
129                 NullPointerException.class, "Format cannot be null");
130         GeometryTestUtils.assertThrowsWithMessage(
131                 () -> manager.registerReadHandler(nullFmtName),
132                 NullPointerException.class, "Format name cannot be null");
133     }
134 
135     @Test
136     void testUnregisterReadHandler() {
137         // arrange
138         final StubReadHandler r1 = new StubReadHandler(FMT_A);
139         final StubReadHandler r2 = new StubReadHandler(FMT_B);
140 
141         manager.registerReadHandler(r1);
142         manager.registerReadHandler(r2);
143 
144         // act
145         manager.unregisterReadHandler(r1);
146 
147         // assert
148         Assertions.assertNull(manager.getReadHandlerForFormat(FMT_A));
149         Assertions.assertSame(r2, manager.getReadHandlerForFormat(FMT_B));
150 
151         Assertions.assertEquals(Arrays.asList(r2), manager.getReadHandlers());
152     }
153 
154     @Test
155     void testUnregisterReadHandler_argsNotRegistered() {
156         // arrange
157         final StubReadHandler r1 = new StubReadHandler(FMT_A);
158         final StubReadHandler r2 = new StubReadHandler(FMT_B);
159 
160         manager.registerReadHandler(r1);
161 
162         // act
163         manager.unregisterReadHandler(null);
164         manager.unregisterReadHandler(r2);
165 
166         // assert
167         Assertions.assertEquals(Arrays.asList(r1), manager.getReadHandlers());
168     }
169 
170     @Test
171     void testGetReadHandlerForFormat() {
172         // arrange
173         final StubReadHandler r1 = new StubReadHandler(FMT_A);
174         final StubReadHandler r2 = new StubReadHandler(FMT_B);
175 
176         manager.registerReadHandler(r1);
177         manager.registerReadHandler(r2);
178 
179         // act/assert
180         Assertions.assertSame(r1, manager.getReadHandlerForFormat(FMT_A));
181         Assertions.assertSame(r1, manager.getReadHandlerForFormat(FMT_A_ALT));
182         Assertions.assertSame(r2, manager.getReadHandlerForFormat(FMT_B));
183         Assertions.assertSame(r2, manager.getReadHandlerForFormat(FMT_B_ALT));
184 
185         Assertions.assertNull(manager.getReadHandlerForFormat(null));
186         Assertions.assertNull(manager.getReadHandlerForFormat(FMT_C));
187     }
188 
189     @Test
190     void testGetReadHandlerForFileExtension() {
191         // arrange
192         final StubReadHandler r1 = new StubReadHandler(FMT_A);
193         final StubReadHandler r2 = new StubReadHandler(FMT_B);
194 
195         manager.registerReadHandler(r1);
196         manager.registerReadHandler(r2);
197 
198         // act/assert
199         Assertions.assertSame(r1, manager.getReadHandlerForFileExtension("a"));
200         Assertions.assertSame(r1, manager.getReadHandlerForFileExtension("A"));
201         Assertions.assertSame(r1, manager.getReadHandlerForFileExtension("aext"));
202         Assertions.assertSame(r1, manager.getReadHandlerForFileExtension("AeXt"));
203 
204         Assertions.assertSame(r2, manager.getReadHandlerForFileExtension("b"));
205         Assertions.assertSame(r2, manager.getReadHandlerForFileExtension("B"));
206 
207         Assertions.assertNull(manager.getReadHandlerForFileExtension(null));
208         Assertions.assertNull(manager.getReadHandlerForFileExtension(""));
209         Assertions.assertNull(manager.getReadHandlerForFileExtension("c"));
210     }
211 
212     @Test
213     void testRequireReadHandler() {
214         // arrange
215         final StubReadHandler r1 = new StubReadHandler(FMT_A);
216         final GeometryInput aInput = new StubGeometryInput("/some/path/to/a/file.AEXT");
217         final GeometryInput bInput = new StubGeometryInput("/some/path/to/a/file.b");
218         final GeometryInput noFileExt = new StubGeometryInput("/some/path/to/a/file");
219         final GeometryInput nullFileName = new StubGeometryInput(null);
220 
221         manager.registerReadHandler(r1);
222 
223         // act/assert
224         Assertions.assertSame(r1, manager.requireReadHandler(bInput, FMT_A));
225         Assertions.assertSame(r1, manager.requireReadHandler(noFileExt, FMT_A));
226         Assertions.assertSame(r1, manager.requireReadHandler(aInput, null));
227 
228         GeometryTestUtils.assertThrowsWithMessage(
229                 () -> manager.requireReadHandler(aInput, FMT_B),
230                 IllegalArgumentException.class, "Failed to find handler for format \"testB\"");
231 
232         GeometryTestUtils.assertThrowsWithMessage(
233                 () -> manager.requireReadHandler(bInput, null),
234                 IllegalArgumentException.class, "Failed to find handler for file extension \"b\"");
235 
236         GeometryTestUtils.assertThrowsWithMessage(
237                 () -> manager.requireReadHandler(noFileExt, null),
238                 IllegalArgumentException.class,
239                 "Failed to find handler: no format specified and no file extension available");
240 
241         GeometryTestUtils.assertThrowsWithMessage(
242                 () -> manager.requireReadHandler(nullFileName, null),
243                 IllegalArgumentException.class,
244                 "Failed to find handler: no format specified and no file extension available");
245     }
246 
247     @Test
248     void testGetReadFormats() {
249         // arrange
250         final StubReadHandler r1 = new StubReadHandler(FMT_A);
251         final StubReadHandler r2 = new StubReadHandler(FMT_B);
252         final StubReadHandler r3 = new StubReadHandler(FMT_B);
253 
254         manager.registerReadHandler(r1);
255         manager.registerReadHandler(r2);
256         manager.registerReadHandler(r3);
257 
258         // act
259         final List<GeometryFormat> formats = manager.getReadFormats();
260 
261         // assert
262         Assertions.assertEquals(2, formats.size());
263         Assertions.assertEquals(Arrays.asList(FMT_A, FMT_B), formats);
264     }
265 
266     @Test
267     void testGetReadFormats_empty() {
268         // act/assert
269         Assertions.assertEquals(0, manager.getReadFormats().size());
270     }
271 
272     @Test
273     void testRegisterWriteHandler() {
274         // arrange
275         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
276         final StubWriteHandler w2 = new StubWriteHandler(FMT_B);
277         final StubWriteHandler w3 = new StubWriteHandler(FMT_A_ALT);
278 
279         // act
280         manager.registerWriteHandler(w1); // will be replaced by w3
281         manager.registerWriteHandler(w2);
282         manager.registerWriteHandler(w2); // register 2x
283         manager.registerWriteHandler(w3);
284 
285         // assert
286         Assertions.assertSame(w3, manager.getWriteHandlerForFormat(FMT_A));
287         Assertions.assertSame(w2, manager.getWriteHandlerForFormat(FMT_B));
288 
289         Assertions.assertSame(w3, manager.getWriteHandlerForFileExtension("a"));
290         Assertions.assertNull(manager.getWriteHandlerForFileExtension("aext"));
291         Assertions.assertSame(w2, manager.getWriteHandlerForFileExtension("b"));
292 
293         Assertions.assertEquals(Arrays.asList(w2, w3), manager.getWriteHandlers());
294     }
295 
296     @Test
297     void testRegisterWriteHandler_multipleFileExtensions() {
298         // arrange
299         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
300 
301         // act
302         manager.registerWriteHandler(w1);
303 
304         // assert
305         Assertions.assertSame(w1, manager.getWriteHandlerForFormat(FMT_A_ALT));
306 
307         Assertions.assertSame(w1, manager.getWriteHandlerForFileExtension("A"));
308         Assertions.assertSame(w1, manager.getWriteHandlerForFileExtension("AEXT"));
309     }
310 
311     @Test
312     void testRegisterWriteHandler_nullAndMissingFileExt() {
313         // arrange
314         final StubGeometryFormat noExts = new StubGeometryFormat("a", null);
315         final StubGeometryFormat nullExts = new StubGeometryFormat("b", Arrays.asList("bext", null, null));
316 
317         final StubWriteHandler w1 = new StubWriteHandler(noExts);
318         final StubWriteHandler w2 = new StubWriteHandler(nullExts);
319 
320         // act
321         manager.registerWriteHandler(w1);
322         manager.registerWriteHandler(w2);
323 
324         // assert
325         Assertions.assertSame(w1, manager.getWriteHandlerForFormat(noExts));
326         Assertions.assertNull(manager.getWriteHandlerForFileExtension("a"));
327 
328         Assertions.assertEquals(w2, manager.getWriteHandlerForFormat(nullExts));
329         Assertions.assertEquals(w2, manager.getWriteHandlerForFileExtension("bext"));
330     }
331 
332     @Test
333     void testUnregisterWriteHandler() {
334         // arrange
335         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
336         final StubWriteHandler w2 = new StubWriteHandler(FMT_B);
337 
338         manager.registerWriteHandler(w1);
339         manager.registerWriteHandler(w2);
340 
341         // act
342         manager.unregisterWriteHandler(w1);
343 
344         // assert
345         Assertions.assertNull(manager.getWriteHandlerForFormat(FMT_A));
346         Assertions.assertSame(w2, manager.getWriteHandlerForFormat(FMT_B));
347 
348         Assertions.assertEquals(Arrays.asList(w2), manager.getWriteHandlers());
349     }
350 
351     @Test
352     void testUnregisterWriteHandler_argsNotRegistered() {
353         // arrange
354         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
355         final StubWriteHandler w2 = new StubWriteHandler(FMT_B);
356         final StubWriteHandler w3 = new StubWriteHandler(FMT_C);
357 
358         manager.registerWriteHandler(w1);
359         manager.registerWriteHandler(w2);
360 
361         // act
362         manager.unregisterWriteHandler(null);
363         manager.unregisterWriteHandler(w3);
364 
365         // assert
366         Assertions.assertEquals(Arrays.asList(w1, w2), manager.getWriteHandlers());
367     }
368 
369     @Test
370     void testGetWriteFormats() {
371         // arrange
372         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
373         final StubWriteHandler w2 = new StubWriteHandler(FMT_B);
374         final StubWriteHandler w3 = new StubWriteHandler(FMT_B);
375 
376         manager.registerWriteHandler(w1);
377         manager.registerWriteHandler(w2);
378         manager.registerWriteHandler(w3);
379 
380         // act
381         final List<GeometryFormat> formats = manager.getWriteFormats();
382 
383         // assert
384         Assertions.assertEquals(2, formats.size());
385         Assertions.assertEquals(Arrays.asList(FMT_A, FMT_B), formats);
386     }
387 
388     @Test
389     void testGetWriteFormats_empty() {
390         // act/assert
391         Assertions.assertEquals(0, manager.getWriteFormats().size());
392     }
393 
394     @Test
395     void testRegisterWriteHandler_illegalArgs() {
396         // act/assert
397         GeometryTestUtils.assertThrowsWithMessage(
398                 () -> manager.registerWriteHandler(null),
399                 NullPointerException.class, "Handler cannot be null");
400         GeometryTestUtils.assertThrowsWithMessage(
401                 () -> manager.registerWriteHandler(new StubWriteHandler(null)),
402                 NullPointerException.class, "Format cannot be null");
403         GeometryTestUtils.assertThrowsWithMessage(
404                 () -> manager.registerWriteHandler(new StubWriteHandler(new StubGeometryFormat(null))),
405                 NullPointerException.class, "Format name cannot be null");
406     }
407 
408     @Test
409     void testGetWriteHandlerForFormat() {
410         // arrange
411         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
412         final StubWriteHandler w2 = new StubWriteHandler(FMT_B);
413 
414         manager.registerWriteHandler(w1);
415         manager.registerWriteHandler(w2);
416 
417         // act/assert
418         Assertions.assertSame(w1, manager.getWriteHandlerForFormat(FMT_A));
419         Assertions.assertSame(w1, manager.getWriteHandlerForFormat(FMT_A_ALT));
420         Assertions.assertSame(w2, manager.getWriteHandlerForFormat(FMT_B));
421         Assertions.assertSame(w2, manager.getWriteHandlerForFormat(FMT_B_ALT));
422 
423         Assertions.assertNull(manager.getWriteHandlerForFormat(null));
424         Assertions.assertNull(manager.getWriteHandlerForFormat(FMT_C));
425     }
426 
427     @Test
428     void testGetWriteHandlerForFileExtension() {
429         // arrange
430         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
431         final StubWriteHandler w2 = new StubWriteHandler(FMT_B);
432 
433         manager.registerWriteHandler(w1);
434         manager.registerWriteHandler(w2);
435 
436         // act/assert
437         Assertions.assertSame(w1, manager.getWriteHandlerForFileExtension("a"));
438         Assertions.assertSame(w1, manager.getWriteHandlerForFileExtension("A"));
439         Assertions.assertSame(w1, manager.getWriteHandlerForFileExtension("aext"));
440         Assertions.assertSame(w1, manager.getWriteHandlerForFileExtension("AeXt"));
441 
442         Assertions.assertSame(w2, manager.getWriteHandlerForFileExtension("b"));
443         Assertions.assertSame(w2, manager.getWriteHandlerForFileExtension("B"));
444 
445         Assertions.assertNull(manager.getWriteHandlerForFileExtension(null));
446         Assertions.assertNull(manager.getWriteHandlerForFileExtension(""));
447         Assertions.assertNull(manager.getWriteHandlerForFileExtension("c"));
448     }
449 
450     @Test
451     void testRequireWriteHandler() {
452         // arrange
453         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
454         final GeometryOutput aInput = new StubGeometryOutput("/some/path/to/a/file.AEXT");
455         final GeometryOutput bInput = new StubGeometryOutput("/some/path/to/a/file.b");
456         final GeometryOutput noFileExt = new StubGeometryOutput("/some/path/to/a/file");
457         final GeometryOutput nullFileName = new StubGeometryOutput(null);
458 
459         manager.registerWriteHandler(w1);
460 
461         // act/assert
462         Assertions.assertSame(w1, manager.requireWriteHandler(bInput, FMT_A));
463         Assertions.assertSame(w1, manager.requireWriteHandler(noFileExt, FMT_A));
464         Assertions.assertSame(w1, manager.requireWriteHandler(aInput, null));
465 
466         GeometryTestUtils.assertThrowsWithMessage(
467                 () -> manager.requireWriteHandler(aInput, FMT_B),
468                 IllegalArgumentException.class, "Failed to find handler for format \"testB\"");
469 
470         GeometryTestUtils.assertThrowsWithMessage(
471                 () -> manager.requireWriteHandler(bInput, null),
472                 IllegalArgumentException.class, "Failed to find handler for file extension \"b\"");
473 
474         GeometryTestUtils.assertThrowsWithMessage(
475                 () -> manager.requireWriteHandler(noFileExt, null),
476                 IllegalArgumentException.class,
477                 "Failed to find handler: no format specified and no file extension available");
478 
479         GeometryTestUtils.assertThrowsWithMessage(
480                 () -> manager.requireWriteHandler(nullFileName, null),
481                 IllegalArgumentException.class,
482                 "Failed to find handler: no format specified and no file extension available");
483     }
484 
485     @Test
486     void testRead_formatGiven() {
487         // arrange
488         final StubReadHandler r1 = new StubReadHandler(FMT_A);
489         manager.registerReadHandler(r1);
490 
491         final StubGeometryInput in = new StubGeometryInput(null);
492         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-4);
493 
494         // act
495         final TestBoundaryList result = manager.read(in, FMT_A_ALT, precision);
496 
497         // assert
498         Assertions.assertSame(BOUNDARY_LIST, result);
499         Assertions.assertSame(in, r1.inArg);
500         Assertions.assertSame(precision, r1.precisionArg);
501     }
502 
503     @Test
504     void testRead_noFormatGiven() {
505         // arrange
506         final StubReadHandler r1 = new StubReadHandler(FMT_A);
507         manager.registerReadHandler(r1);
508 
509         final StubGeometryInput in = new StubGeometryInput("file.aeXT");
510         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-4);
511 
512         // act
513         final TestBoundaryList result = manager.read(in, null, precision);
514 
515         // assert
516         Assertions.assertSame(BOUNDARY_LIST, result);
517         Assertions.assertSame(in, r1.inArg);
518         Assertions.assertSame(precision, r1.precisionArg);
519     }
520 
521     @Test
522     void testRead_handlerNotFound() {
523         // arrange
524         final StubReadHandler r1 = new StubReadHandler(FMT_A);
525         manager.registerReadHandler(r1);
526 
527         final StubGeometryInput inputA = new StubGeometryInput("file.a");
528         final StubGeometryInput inputB = new StubGeometryInput("file.b");
529         final StubGeometryInput inputNull = new StubGeometryInput(null);
530 
531         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-4);
532 
533         // act/assert
534         Assertions.assertThrows(IllegalArgumentException.class,
535                 () -> manager.read(inputA, FMT_B, precision));
536         Assertions.assertThrows(IllegalArgumentException.class,
537                 () -> manager.read(inputB, null, precision));
538         Assertions.assertThrows(IllegalArgumentException.class,
539                 () -> manager.read(inputNull, null, precision));
540     }
541 
542     @Test
543     void testBoundaries_formatGiven() {
544         // arrange
545         final StubReadHandler r1 = new StubReadHandler(FMT_A);
546         manager.registerReadHandler(r1);
547 
548         final StubGeometryInput in = new StubGeometryInput(null);
549         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-4);
550 
551         // act
552         final Stream<TestLineSegment> result = manager.boundaries(in, FMT_A_ALT, precision);
553 
554         // assert
555         Assertions.assertEquals(BOUNDARY_LIST.getBoundaries(), result.collect(Collectors.toList()));
556         Assertions.assertSame(in, r1.inArg);
557         Assertions.assertSame(precision, r1.precisionArg);
558     }
559 
560     @Test
561     void testBoundaries_noFormatGiven() {
562         // arrange
563         final StubReadHandler r1 = new StubReadHandler(FMT_A);
564         manager.registerReadHandler(r1);
565 
566         final StubGeometryInput in = new StubGeometryInput("file.aeXT");
567         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-4);
568 
569         // act
570         final Stream<TestLineSegment> result = manager.boundaries(in, null, precision);
571 
572         // assert
573         Assertions.assertEquals(BOUNDARY_LIST.getBoundaries(), result.collect(Collectors.toList()));
574         Assertions.assertSame(in, r1.inArg);
575         Assertions.assertSame(precision, r1.precisionArg);
576     }
577 
578     @Test
579     void testBoundaries_handlerNotFound() {
580         // arrange
581         final StubReadHandler r1 = new StubReadHandler(FMT_A);
582         manager.registerReadHandler(r1);
583 
584         final StubGeometryInput inputA = new StubGeometryInput("file.a");
585         final StubGeometryInput inputB = new StubGeometryInput("file.b");
586         final StubGeometryInput inputNull = new StubGeometryInput(null);
587 
588         final Precision.DoubleEquivalence precision = Precision.doubleEquivalenceOfEpsilon(1e-4);
589 
590         // act/assert
591         Assertions.assertThrows(IllegalArgumentException.class,
592                 () -> manager.boundaries(inputA, FMT_B, precision));
593         Assertions.assertThrows(IllegalArgumentException.class,
594                 () -> manager.boundaries(inputB, null, precision));
595         Assertions.assertThrows(IllegalArgumentException.class,
596                 () -> manager.boundaries(inputNull, null, precision));
597     }
598 
599     @Test
600     void testWrite_formatGiven() {
601         // arrange
602         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
603         manager.registerWriteHandler(w1);
604 
605         final TestBoundaryList src = BOUNDARY_LIST;
606         final StubGeometryOutput out = new StubGeometryOutput(null);
607 
608         // act
609         manager.write(BOUNDARY_LIST, out, FMT_A_ALT);
610 
611         // assert
612         Assertions.assertSame(src, w1.list);
613         Assertions.assertSame(out, w1.outArg);
614     }
615 
616     @Test
617     void testWrite_noFormatGiven() {
618         // arrange
619         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
620         manager.registerWriteHandler(w1);
621 
622         final TestBoundaryList src = BOUNDARY_LIST;
623         final StubGeometryOutput out = new StubGeometryOutput("file.aeXT");
624 
625         // act
626         manager.write(src, out, null);
627 
628         // assert
629         Assertions.assertSame(src, w1.list);
630         Assertions.assertSame(out, w1.outArg);
631     }
632 
633     @Test
634     void testWrite_handlerNotFound() {
635         // arrange
636         final StubWriteHandler w1 = new StubWriteHandler(FMT_A);
637         manager.registerWriteHandler(w1);
638 
639         final StubGeometryOutput outputA = new StubGeometryOutput("file.a");
640         final StubGeometryOutput outputB = new StubGeometryOutput("file.b");
641         final StubGeometryOutput nullOutput = new StubGeometryOutput(null);
642 
643         final TestBoundaryList src = BOUNDARY_LIST;
644 
645         // act/assert
646         Assertions.assertThrows(IllegalArgumentException.class,
647                 () -> manager.write(src, outputA, FMT_B));
648         Assertions.assertThrows(IllegalArgumentException.class,
649                 () -> manager.write(src, outputB, null));
650         Assertions.assertThrows(IllegalArgumentException.class,
651                 () -> manager.write(src, nullOutput, null));
652     }
653 
654     private static final class TestManager
655         extends BoundaryIOManager<TestLineSegment, TestBoundaryList, StubReadHandler, StubWriteHandler> {
656     }
657 
658     private static final class TestBoundaryList extends BoundaryList<TestPoint2D, TestLineSegment> {
659 
660         TestBoundaryList(final List<? extends TestLineSegment> boundaries) {
661             super(boundaries);
662         }
663     }
664 
665     private static final class StubGeometryInput implements GeometryInput {
666 
667         private final String fileName;
668 
669         StubGeometryInput(final String fileName) {
670             this.fileName = fileName;
671         }
672 
673         /** {@inheritDoc} */
674         @Override
675         public String getFileName() {
676             return fileName;
677         }
678 
679         /** {@inheritDoc} */
680         @Override
681         public Charset getCharset() {
682             throw new UnsupportedOperationException();
683         }
684 
685         /** {@inheritDoc} */
686         @Override
687         public InputStream getInputStream() {
688             throw new UnsupportedOperationException();
689         }
690 
691     }
692 
693     private static final class StubGeometryOutput implements GeometryOutput {
694 
695         private final String fileName;
696 
697         StubGeometryOutput(final String fileName) {
698             this.fileName = fileName;
699         }
700 
701         /** {@inheritDoc} */
702         @Override
703         public String getFileName() {
704             return fileName;
705         }
706 
707         /** {@inheritDoc} */
708         @Override
709         public Charset getCharset() {
710             throw new UnsupportedOperationException();
711         }
712 
713         /** {@inheritDoc} */
714         @Override
715         public OutputStream getOutputStream() {
716             throw new UnsupportedOperationException();
717         }
718     }
719 
720     private static final class StubReadHandler implements BoundaryReadHandler<TestLineSegment, TestBoundaryList> {
721 
722         private final GeometryFormat fmt;
723 
724         private GeometryInput inArg;
725 
726         private Precision.DoubleEquivalence precisionArg;
727 
728         StubReadHandler(final GeometryFormat fmt) {
729             this.fmt = fmt;
730         }
731 
732         /** {@inheritDoc} */
733         @Override
734         public GeometryFormat getFormat() {
735             return fmt;
736         }
737 
738         /** {@inheritDoc} */
739         @Override
740         public TestBoundaryList read(final GeometryInput in, final Precision.DoubleEquivalence precision) {
741             this.inArg = in;
742             this.precisionArg = precision;
743 
744             return BOUNDARY_LIST;
745         }
746 
747         /** {@inheritDoc} */
748         @Override
749         public Stream<TestLineSegment> boundaries(final GeometryInput in,
750                 final Precision.DoubleEquivalence precision) {
751             this.inArg = in;
752             this.precisionArg = precision;
753 
754             return BOUNDARY_LIST.boundaryStream();
755         }
756     }
757 
758     private static final class StubWriteHandler implements BoundaryWriteHandler<TestLineSegment, TestBoundaryList> {
759 
760         private GeometryFormat fmt;
761 
762         private TestBoundaryList list;
763 
764         private GeometryOutput outArg;
765 
766         StubWriteHandler(final GeometryFormat fmt) {
767             this.fmt = fmt;
768         }
769 
770         /** {@inheritDoc} */
771         @Override
772         public GeometryFormat getFormat() {
773             return fmt;
774         }
775 
776         /** {@inheritDoc} */
777         @Override
778         public void write(final TestBoundaryList boundarySource, final GeometryOutput out) {
779             this.list = boundarySource;
780             this.outArg = out;
781         }
782     }
783 }