diff --git a/bg_atlasgen/validate_atlases.py b/bg_atlasgen/validate_atlases.py index b9568bf..6a0d7c6 100644 --- a/bg_atlasgen/validate_atlases.py +++ b/bg_atlasgen/validate_atlases.py @@ -110,8 +110,9 @@ def check_additional_references(atlas: BrainGlobeAtlas): pass -def validate_mesh_structure_pairs(atlas: BrainGlobeAtlas): - """Ensure mesh files (.obj) exist for each expected structure in the atlas.""" +def catch_missing_mesh_files(atlas: BrainGlobeAtlas): + """Checks if all the structures in the atlas have a corresponding mesh file""" + ids_from_bg_atlas_api = list(atlas.structures.keys()) atlas_path = ( @@ -126,19 +127,41 @@ def validate_mesh_structure_pairs(atlas: BrainGlobeAtlas): if file.endswith(".obj") ] - in_mesh_not_bg = [] - for id in ids_from_mesh_files: - if id not in ids_from_bg_atlas_api: - in_mesh_not_bg.append(id) - in_bg_not_mesh = [] for id in ids_from_bg_atlas_api: if id not in ids_from_mesh_files: in_bg_not_mesh.append(id) - if len(in_mesh_not_bg) or len(in_bg_not_mesh): + if len(in_bg_not_mesh) != 0: + raise AssertionError( + f"Structures with IDs {in_bg_not_mesh} are in the atlas, but don't have a corresponding mesh file." + ) + + +def catch_missing_structures(atlas: BrainGlobeAtlas): + """Checks if all the mesh files in the atlas folder are listed as a structure in the atlas""" + + ids_from_bg_atlas_api = list(atlas.structures.keys()) + + atlas_path = ( + Path(get_brainglobe_dir()) + / f"{atlas.atlas_name}_v{get_local_atlas_version(atlas.atlas_name)}" + ) + obj_path = Path(atlas_path / "meshes") + + ids_from_mesh_files = [ + int(Path(file).stem) + for file in os.listdir(obj_path) + if file.endswith(".obj") + ] + + in_mesh_not_bg = [] + for id in ids_from_mesh_files: + if id not in ids_from_bg_atlas_api: + in_mesh_not_bg.append(id) + + if len(in_mesh_not_bg) != 0: raise AssertionError( - f"Structures with ID {in_bg_not_mesh} are in the atlas, but don't have a corresponding mesh file; " f"Structures with IDs {in_mesh_not_bg} have a mesh file, but are not accessible through the atlas." ) @@ -176,7 +199,8 @@ def validate_atlas(atlas_name, version, validation_functions): open_for_visual_check, validate_checksum, check_additional_references, - validate_mesh_structure_pairs, + catch_missing_mesh_files, + catch_missing_structures, ] valid_atlases = [] diff --git a/tests/test_unit/test_validation.py b/tests/test_unit/test_validation.py index 5fcf9f0..bcffe25 100644 --- a/tests/test_unit/test_validation.py +++ b/tests/test_unit/test_validation.py @@ -7,6 +7,8 @@ from bg_atlasgen.validate_atlases import ( _assert_close, + catch_missing_mesh_files, + catch_missing_structures, validate_atlas_files, validate_mesh_matches_image_extents, ) @@ -34,6 +36,17 @@ def atlas_with_bad_reference_file(): os.rename(bad_name, good_name) +@pytest.fixture +def atlas_with_missing_structure(): + atlas = BrainGlobeAtlas("osten_mouse_100um") + modified_structures = atlas.structures.copy() + modified_structures.pop(688) + + modified_atlas = BrainGlobeAtlas("osten_mouse_100um") + modified_atlas.structures = modified_structures + return modified_atlas + + def test_validate_mesh_matches_image_extents(atlas): assert validate_mesh_matches_image_extents(atlas) @@ -69,3 +82,38 @@ def test_assert_close_negative(): AssertionError, match="differ by more than 10 times pixel size" ): _assert_close(99.5, 30, 2) + + +def test_catch_missing_mesh_files(atlas): + """ + Tests if catch_missing_mesh_files function raises an error, + when there is at least one structure in the atlas that doesn't have + a corresponding obj file. + + Expected behaviour: + True for "allen_mouse_10um" (structure 545 doesn't have an obj file): fails + the validation function, raises an error --> no output from this test function + """ + + with pytest.raises( + AssertionError, + match=r"Structures with IDs \[.*?\] are in the atlas, but don't have a corresponding mesh file.", + ): + catch_missing_mesh_files(atlas) + + +def test_catch_missing_structures(atlas_with_missing_structure): + """ + Tests if catch_missing_structures function raises an error, + when there is at least one orphan obj file (doesn't have a corresponding structure in the atlas) + + Expected behaviour: + Currently no atlas fails the validation function this way so the [] is always empty + --> this test function should always raise an error + """ + + with pytest.raises( + AssertionError, + match=r"Structures with IDs \[.*?\] have a mesh file, but are not accessible through the atlas.", + ): + catch_missing_structures(atlas_with_missing_structure)