3434import static org .junit .jupiter .api .Assertions .assertFalse ;
3535import static org .junit .jupiter .api .Assertions .assertNotNull ;
3636import static org .junit .jupiter .api .Assertions .assertNotSame ;
37- import static org .junit .jupiter .api .Assertions .assertNull ;
3837import static org .junit .jupiter .api .Assertions .assertSame ;
3938import static org .junit .jupiter .api .Assertions .assertTrue ;
4039import static org .mockito .Mockito .any ;
7877import java .util .Arrays ;
7978import java .util .List ;
8079import java .util .concurrent .atomic .AtomicBoolean ;
81- import java .util .concurrent .atomic .AtomicInteger ;
8280import java .util .concurrent .atomic .AtomicReference ;
8381import java .util .function .Consumer ;
84- import java .util .function .Function ;
8582import java .util .stream .Stream ;
8683
8784import bdv .tools .brightness .ConverterSetup ;
10097import ome .zarr .fiji .Pyramidal ;
10198import ome .zarr .zarrjava .ZarrJavaPyramidBackend ;
10299import ome .zarr .imglib2 .exceptions .StoreAccessException ;
100+ import ome .zarr .imglib2 .PyramidBackend ;
103101import ome .zarr .imglib2 .PyramidContents ;
102+ import ome .zarr .fiji .open .ZarrOpener ;
104103import ome .zarr .fiji .PyramidalBdv ;
105104import ome .zarr .fiji .PyramidalDataset ;
106105import ome .zarr .fijiui .open .options .ZarrOpeningSettings ;
113112
114113class ZarrOpenActionsTest
115114{
115+
116116 static Stream < ZarrReaderBackend > readerBackends ()
117117 {
118118 return Stream .of ( ZarrReaderBackend .N5 , ZarrReaderBackend .ZARR_JAVA );
119119 }
120120
121+ /**
122+ * Loads the dataset headlessly through {@link ZarrOpener#getContents()} with
123+ * the given backend, without instantiating any UI. Returns the loaded
124+ * {@link PyramidContents}; throws the relevant domain exception (e.g.
125+ * {@link ome.zarr.imglib2.exceptions.NotAMultiscaleImageException} or
126+ * {@link ome.zarr.imglib2.exceptions.MultiImageDatasetException}).
127+ * Lets tests assert that a dataset opens as a multiscale image without showing a window.
128+ */
129+ private static PyramidContents < ? > loadMultiscaleHeadless ( final URI uri , final Context context ,
130+ final ZarrReaderBackend backend )
131+ {
132+ final PyramidBackend pyramidBackend = backend .createBackend ();
133+ final ZarrOpener opener = new ZarrOpener ( uri , context , pyramidBackend , null , error -> {} );
134+ return opener .getContents ();
135+ }
136+
121137 static Stream < String > omeZarrExamples ()
122138 {
123139 return Stream .of (
@@ -290,18 +306,13 @@ void testOpenValidMultiScaleImagePath( String resource ) throws URISyntaxExcepti
290306 Path path = ZarrTestUtils .resourcePath ( resource );
291307 try (Context context = new Context ())
292308 {
293- ZarrOpenActions actions = new ZarrOpenActions ( path .toUri (), context );
294- AtomicInteger multiScaleCounter = new AtomicInteger ( 0 );
295- AtomicInteger singleScaleCounter = new AtomicInteger ( 0 );
296- Function < PyramidalDataset , Object > multiScaleOpeningCounter = dataset -> multiScaleCounter .incrementAndGet ();
297- Function < Img < ? >, Object > singleScaleOpeningCounter = img -> singleScaleCounter .incrementAndGet ();
298- actions .openImage ( multiScaleOpeningCounter , singleScaleOpeningCounter );
299- assertEquals ( 1 , multiScaleCounter .get () );
300- assertEquals ( 0 , singleScaleCounter .get () );
309+ assertNotNull ( loadMultiscaleHeadless ( path .toUri (), context , ZarrOpeningSettings .DEFAULT_READER_BACKEND ),
310+ "Expected " + resource + " to open as a multiscale image" );
301311 }
302312 }
303313
304314 @ Test
315+ @ SuppressWarnings ( "java:S1612" )
305316 void testOpenValidSingleScaleImagePath () throws URISyntaxException
306317 {
307318 String [] validPaths = {
@@ -313,19 +324,19 @@ void testOpenValidSingleScaleImagePath() throws URISyntaxException
313324 for ( String invalidPath : validPaths )
314325 {
315326 Path path = ZarrTestUtils .resourcePath ( invalidPath );
316- ZarrOpenActions actions = new ZarrOpenActions ( path .toUri (), context , null , System .out ::println );
317- AtomicInteger multiScaleCounter = new AtomicInteger ( 0 );
318- AtomicInteger singleScaleCounter = new AtomicInteger ( 0 );
319- Function < PyramidalDataset , Object > multiScaleOpeningCounter = dataset -> multiScaleCounter .incrementAndGet ();
320- Function < Img < ? >, Object > singleScaleOpeningCounter = img -> singleScaleCounter .incrementAndGet ();
321- actions .openImage ( multiScaleOpeningCounter , singleScaleOpeningCounter );
322- assertEquals ( 0 , multiScaleCounter .get () );
323- assertEquals ( 0 , singleScaleCounter .get () ); // currently not supported
327+ AtomicReference < String > capturedError = new AtomicReference <>();
328+ ZarrOpenActions actions = new ZarrOpenActions ( path .toUri (), context , null , capturedError ::set );
329+ assertDoesNotThrow ( () -> {
330+ actions .openIJWithImage ();
331+ } );
332+ assertNotNull ( capturedError .get (),
333+ "Single-scale path " + invalidPath + " should be reported as not (yet) supported" );
324334 }
325335 }
326336 }
327337
328338 @ Test
339+ @ SuppressWarnings ( "java:S1612" )
329340 void testOpenInvalidImagePaths () throws URISyntaxException
330341 {
331342 String [] invalidPaths = {
@@ -338,15 +349,16 @@ void testOpenInvalidImagePaths() throws URISyntaxException
338349 {
339350 Path path = ZarrTestUtils .resourcePath ( invalidPath );
340351 ZarrOpenActions actions = new ZarrOpenActions ( path .toUri (), context , null , System .out ::println );
341- Function < PyramidalDataset , Object > multiScaleNoOp = pyramidalDataset -> null ;
342- Function < Img < ? >, Object > singleScaleNoOp = img -> null ;
343- assertDoesNotThrow ( () -> actions . openImage ( multiScaleNoOp , singleScaleNoOp ) );
352+ assertDoesNotThrow ( () -> {
353+ actions . openIJWithImage () ;
354+ } );
344355 }
345356 }
346357 }
347358
348359 @ ParameterizedTest
349360 @ MethodSource ( "readerBackends" )
361+ @ SuppressWarnings ( "java:S1612" )
350362 void testOpenBioformats2rawCollectionRootReportsMultiImage ( ZarrReaderBackend backend ) throws URISyntaxException
351363 {
352364 Path path = ZarrTestUtils .resourcePath ( "ome/zarr/testdata/bioformats2raw_testing/bf2raw_dataset_v5.ome.zarr" );
@@ -357,13 +369,9 @@ void testOpenBioformats2rawCollectionRootReportsMultiImage( ZarrReaderBackend ba
357369 ZarrOpeningSettings settings = new ZarrOpeningSettings ();
358370 settings .setReaderBackend ( backend );
359371 ZarrOpenActions actions = new ZarrOpenActions ( path .toUri (), context , settings , errorHandler );
360- AtomicInteger multiScaleCounter = new AtomicInteger ( 0 );
361- AtomicInteger singleScaleCounter = new AtomicInteger ( 0 );
362- Function < PyramidalDataset , Object > multiScaleOpener = dataset -> multiScaleCounter .incrementAndGet ();
363- Function < Img < ? >, Object > singleScaleOpener = img -> singleScaleCounter .incrementAndGet ();
364- assertDoesNotThrow ( () -> actions .openImage ( multiScaleOpener , singleScaleOpener ) );
365- assertEquals ( 0 , multiScaleCounter .get (), "Multi-image collection must not be opened as a single multiscale image" );
366- assertEquals ( 0 , singleScaleCounter .get () );
372+ assertDoesNotThrow ( () -> {
373+ actions .openIJWithImage ();
374+ } );
367375 assertNotNull ( capturedError .get (), "Error handler should have been called for backend " + backend );
368376 assertTrue ( capturedError .get ().contains ( "multiple images" ),
369377 "Expected multi-image message from backend, got: " + capturedError .get () );
@@ -383,37 +391,24 @@ void testOpenBioformats2rawCollectionChildOpens( ZarrReaderBackend backend ) thr
383391 for ( String childPath : childPaths )
384392 {
385393 Path path = ZarrTestUtils .resourcePath ( childPath );
386- AtomicReference < String > capturedError = new AtomicReference <>();
387- Consumer < String > errorHandler = capturedError ::set ;
388- ZarrOpeningSettings settings = new ZarrOpeningSettings ();
389- settings .setReaderBackend ( backend );
390- ZarrOpenActions actions = new ZarrOpenActions ( path .toUri (), context , settings , errorHandler );
391- AtomicInteger multiScaleCounter = new AtomicInteger ( 0 );
392- AtomicInteger singleScaleCounter = new AtomicInteger ( 0 );
393- Function < PyramidalDataset , Object > multiScaleOpener = dataset -> multiScaleCounter .incrementAndGet ();
394- Function < Img < ? >, Object > singleScaleOpener = img -> singleScaleCounter .incrementAndGet ();
395- assertDoesNotThrow ( () -> actions .openImage ( multiScaleOpener , singleScaleOpener ),
396- "Opening child image " + childPath + " should not throw" );
397- assertEquals ( 1 , multiScaleCounter .get (),
398- "Child image " + childPath + " should be opened as a multiscale image" );
399- assertEquals ( 0 , singleScaleCounter .get () );
400- assertNull ( capturedError .get (),
401- "Error handler should not have been called for child " + childPath + ", got: " + capturedError .get () );
394+ assertNotNull ( loadMultiscaleHeadless ( path .toUri (), context , backend ),
395+ "Child image " + childPath + " should open as a multiscale image" );
402396 }
403397 }
404398 }
405399
406400 @ Test
401+ @ SuppressWarnings ( "java:S1612" )
407402 void testOpenNonMatchingResolution () throws URISyntaxException
408403 {
409404 try (Context context = new Context ())
410405 {
411406 Path path = ZarrTestUtils .resourcePath ( "ome/zarr/testdata/5d_testing/5d_dataset_v4.ome.zarr" );
412407 ZarrOpeningSettings settings = new ZarrOpeningSettings ( ZarrOpenBehavior .IMAGEJ_CUSTOM_RESOLUTION , 10 );
413408 ZarrOpenActions actions = new ZarrOpenActions ( path .toUri (), context , settings , System .out ::println );
414- Function < PyramidalDataset , Object > multiScaleNoOp = pyramidalDataset -> null ;
415- Function < Img < ? >, Object > singleScaleNoOp = img -> null ;
416- assertDoesNotThrow ( () -> actions . openImage ( multiScaleNoOp , singleScaleNoOp ) );
409+ assertDoesNotThrow ( () -> {
410+ actions . openIJWithImage () ;
411+ } );
417412 }
418413 }
419414
@@ -673,25 +668,17 @@ void openImageFromS3( final ZarrReaderBackend backend )
673668 {
674669 try (Context context = new Context ())
675670 {
676- final AtomicReference < String > error = new AtomicReference <>();
677- final ZarrOpeningSettings settings = new ZarrOpeningSettings ();
678- settings .setReaderBackend ( backend );
679- final ZarrOpenActions actions = new ZarrOpenActions ( S3_JANELIA_CHOROID_PLEXUS , context , settings , error ::set );
680- final AtomicInteger multiScaleCounter = new AtomicInteger ( 0 );
681- final AtomicInteger singleScaleCounter = new AtomicInteger ( 0 );
682- actions .openImage ( dataset -> multiScaleCounter .incrementAndGet (), img -> singleScaleCounter .incrementAndGet () );
683- assertNull ( error .get (), "Error handler called for backend " + backend + ": " + error .get () );
684- assertEquals ( 1 , multiScaleCounter .get () );
685- assertEquals ( 0 , singleScaleCounter .get () );
671+ final PyramidContents < ? > contents = loadMultiscaleHeadless ( S3_JANELIA_CHOROID_PLEXUS , context , backend );
672+ assertNotNull ( contents , "Expected the S3 dataset to open as a multiscale image for backend " + backend );
686673 }
687674 }
688675
689676 @ ParameterizedTest
690677 @ MethodSource ( "readerBackends" )
691- @ SuppressWarnings ( "rawtypes " )
678+ @ SuppressWarnings ( "java:S1612 " )
692679 void storeAccessErrorIsReportedToErrorHandler ( final ZarrReaderBackend backend )
693680 {
694- try ( Context context = new Context () )
681+ try (Context context = new Context ())
695682 {
696683 final URI uri = URI .create ( "s3://nonexistent-bucket/some/path" );
697684 final AtomicReference < String > capturedError = new AtomicReference <>();
@@ -700,22 +687,26 @@ void storeAccessErrorIsReportedToErrorHandler( final ZarrReaderBackend backend )
700687
701688 if ( backend == ZarrReaderBackend .ZARR_JAVA )
702689 {
703- try ( MockedConstruction < ZarrJavaPyramidBackend > mock = mockConstruction (
690+ try (MockedConstruction < ZarrJavaPyramidBackend > mock = mockConstruction (
704691 ZarrJavaPyramidBackend .class ,
705692 ( mockBackend , ctx ) -> when ( mockBackend .load ( any () ) )
706693 .thenThrow ( new StoreAccessException ( uri .toString (),
707- new RuntimeException ( "Access Denied (403)" ) ) ) ) )
694+ new RuntimeException ( "Access Denied (403)" ) ) ) ))
708695 {
709696 final ZarrOpenActions actions = new ZarrOpenActions ( uri , context , settings , capturedError ::set );
710- assertDoesNotThrow ( () -> actions .openImage ( dataset -> null , img -> null ) );
697+ assertDoesNotThrow ( () -> {
698+ actions .openIJWithImage ();
699+ } );
711700 assertEquals ( 1 , mock .constructed ().size (), "Expected exactly one ZarrJavaPyramidBackend to be constructed" );
712701 }
713702 }
714703 else
715704 {
716705 // N5 backend throws N5Exception.N5IOException immediately (local failure, no network needed)
717706 final ZarrOpenActions actions = new ZarrOpenActions ( uri , context , settings , capturedError ::set );
718- assertDoesNotThrow ( () -> actions .openImage ( dataset -> null , img -> null ) );
707+ assertDoesNotThrow ( () -> {
708+ actions .openIJWithImage ();
709+ } );
719710 }
720711
721712 assertNotNull ( capturedError .get (), "Error handler should have been called for backend " + backend );
0 commit comments