diff --git a/Assets/BMapBindings/BMapSharp/BMapSharp/BMapSharp.csproj b/Assets/BMapBindings/BMapSharp/BMapSharp/BMapSharp.csproj
index 914d65b..c4b1513 100644
--- a/Assets/BMapBindings/BMapSharp/BMapSharp/BMapSharp.csproj
+++ b/Assets/BMapBindings/BMapSharp/BMapSharp/BMapSharp.csproj
@@ -5,9 +5,12 @@
enable
BMapSharp
- 1.0.0
+
BMapSharp
+ 0.4.0
yyc12345
+ The C# binding to BMap.
BearKidsTeam
+ SPDX:MIT
diff --git a/Assets/BMapBindings/BMapSharp/BMapSharpTest/Cli.cs b/Assets/BMapBindings/BMapSharp/BMapSharpTest/Cli.cs
index 4629aef..4b1b55d 100644
--- a/Assets/BMapBindings/BMapSharp/BMapSharpTest/Cli.cs
+++ b/Assets/BMapBindings/BMapSharp/BMapSharpTest/Cli.cs
@@ -26,7 +26,7 @@ namespace BMapSharpTest {
if (ballance_dir is null) {
throw new CliException("You must specify BMAP_BALLANCE_DIR environment variable before running this test.");
}
- this.BallanceDirectory = ballance_dir;
+ this.BallanceDir = ballance_dir;
var encodings = System.Environment.GetEnvironmentVariable("BMAP_ENCODINGS");
if (encodings is null) {
@@ -42,7 +42,7 @@ namespace BMapSharpTest {
///
/// The path to the Ballance directory for finding textures
///
- public string BallanceDirectory { get; private set; }
+ public string BallanceDir { get; private set; }
///
/// The name of encodings used by BMap for loading map.
///
diff --git a/Assets/BMapBindings/BMapSharp/BMapSharpTest/Program.cs b/Assets/BMapBindings/BMapSharp/BMapSharpTest/Program.cs
index dfbde1b..a2a63fe 100644
--- a/Assets/BMapBindings/BMapSharp/BMapSharpTest/Program.cs
+++ b/Assets/BMapBindings/BMapSharp/BMapSharpTest/Program.cs
@@ -33,7 +33,7 @@ namespace BMapSharpTest {
string file_name = cli.FileName;
var temp_dir_info = Directory.CreateTempSubdirectory();
string temp_dir = temp_dir_info.FullName;
- string texture_dir = Path.Combine(cli.BallanceDirectory, "Textures");
+ string texture_dir = Path.Combine(cli.BallanceDir, "Textures");
string[] encodings = cli.Encodings;
using (var reader = new BMapSharp.BMapWrapper.BMFileReader(file_name, temp_dir, texture_dir, encodings)) {
diff --git a/Assets/BMapBindings/BMapSharp/BMapSharpTest/TestSuits.cs b/Assets/BMapBindings/BMapSharp/BMapSharpTest/TestSuits.cs
index 2dcf3a1..5691731 100644
--- a/Assets/BMapBindings/BMapSharp/BMapSharpTest/TestSuits.cs
+++ b/Assets/BMapBindings/BMapSharp/BMapSharpTest/TestSuits.cs
@@ -108,15 +108,15 @@ namespace BMapSharpTest.TestSuits {
Console.WriteLine($"\tVisibility: {lit.GetVisibility()}");
Console.WriteLine($"\tMatrix: {lit.GetWorldMatrix().ToManaged()}");
- Console.WriteLine($"Type: {lit.GetLightType()}");
- Console.WriteLine($"Color: {lit.GetColor().ToManagedRGBA()}");
- Console.WriteLine($"Constant Attenuation: {lit.GetConstantAttenuation()}");
- Console.WriteLine($"Linear Attenuation: {lit.GetLinearAttenuation()}");
- Console.WriteLine($"Quadratic Attenuation: {lit.GetQuadraticAttenuation()}");
- Console.WriteLine($"Range: {lit.GetRange()}");
- Console.WriteLine($"Hot Spot: {lit.GetHotSpot()}");
- Console.WriteLine($"Falloff: {lit.GetFalloff()}");
- Console.WriteLine($"Falloff Shape: {lit.GetFalloffShape()}");
+ Console.WriteLine($"\tType: {lit.GetLightType()}");
+ Console.WriteLine($"\tColor: {lit.GetColor().ToManagedRGBA()}");
+ Console.WriteLine($"\tConstant Attenuation: {lit.GetConstantAttenuation()}");
+ Console.WriteLine($"\tLinear Attenuation: {lit.GetLinearAttenuation()}");
+ Console.WriteLine($"\tQuadratic Attenuation: {lit.GetQuadraticAttenuation()}");
+ Console.WriteLine($"\tRange: {lit.GetRange()}");
+ Console.WriteLine($"\tHot Spot: {lit.GetHotSpot()}");
+ Console.WriteLine($"\tFalloff: {lit.GetFalloff()}");
+ Console.WriteLine($"\tFalloff Shape: {lit.GetFalloffShape()}");
}
}
@@ -127,14 +127,14 @@ namespace BMapSharpTest.TestSuits {
Console.WriteLine($"\tVisibility: {cam.GetVisibility()}");
Console.WriteLine($"\tMatrix: {cam.GetWorldMatrix().ToManaged()}");
- Console.WriteLine($"Type: {cam.GetProjectionType()}");
- Console.WriteLine($"Orthographic Zoom: {cam.GetOrthographicZoom()}");
- Console.WriteLine($"Front Plane: {cam.GetFrontPlane()}");
- Console.WriteLine($"Back Plane: {cam.GetBackPlane()}");
- Console.WriteLine($"Fov: {cam.GetFov()}");
+ Console.WriteLine($"\tType: {cam.GetProjectionType()}");
+ Console.WriteLine($"\tOrthographic Zoom: {cam.GetOrthographicZoom()}");
+ Console.WriteLine($"\tFront Plane: {cam.GetFrontPlane()}");
+ Console.WriteLine($"\tBack Plane: {cam.GetBackPlane()}");
+ Console.WriteLine($"\tFov: {cam.GetFov()}");
cam.GetAspectRatio(out var width, out var height);
- Console.WriteLine($"Aspect Ratio: {width}:{height}");
+ Console.WriteLine($"\tAspect Ratio: {width}:{height}");
}
}
}
diff --git a/Assets/BMapBindings/pybmap/pyproject.toml b/Assets/BMapBindings/pybmap/pyproject.toml
index 0c3d6e7..a4bafc2 100644
--- a/Assets/BMapBindings/pybmap/pyproject.toml
+++ b/Assets/BMapBindings/pybmap/pyproject.toml
@@ -3,9 +3,8 @@ name = "pybmap"
version = "0.4.0"
description = "The Python binding to BMap."
readme = "README.md"
-authors = [
- { name = "yyc12345" }
-]
+license = "SPDX:MIT"
+authors = [{ name = "yyc12345" }]
classifiers = ["Private :: Do Not Upload"]
requires-python = ">=3.11"
dependencies = []
diff --git a/Assets/BMapBindings/pybmap/tests/cli.py b/Assets/BMapBindings/pybmap/tests/cli.py
new file mode 100644
index 0000000..500b23e
--- /dev/null
+++ b/Assets/BMapBindings/pybmap/tests/cli.py
@@ -0,0 +1,40 @@
+import os
+from pathlib import Path
+
+class CliException(Exception):
+ """Error occurs when parsing test arguments."""
+ pass
+
+class Cli:
+
+ file_name: Path
+ """
+ The path to the map for loading.
+ """
+ ballance_dir: Path
+ """
+ The path to the Ballance directory for finding textures
+ """
+ encodings: tuple[str, ...]
+ """
+ The name of encodings used by BMap for loading map.
+ """
+
+ def __init__(self) -> None:
+ file_name = os.environ.get('BMAP_FILE_NAME', None)
+ if file_name is None:
+ raise CliException('You must specify BMAP_FILE_NAME environment variable before running this test.')
+ else:
+ self.file_name = Path(file_name).resolve()
+
+ ballance_dir = os.environ.get('BMAP_BALLANCE_DIR', None)
+ if ballance_dir is None:
+ raise CliException('You must specify BMAP_BALLANCE_DIR environment variable before running this test.')
+ else:
+ self.ballance_dir = Path(ballance_dir).resolve()
+
+ encodings = os.environ.get('BMAP_ENCODINGS', None)
+ if encodings is None:
+ raise CliException('You must specify BMAP_ENCODINGS environment variable before running this test.')
+ else:
+ self.encodings = tuple(encodings.split(','))
diff --git a/Assets/BMapBindings/pybmap/tests/main.py b/Assets/BMapBindings/pybmap/tests/main.py
new file mode 100644
index 0000000..fff896a
--- /dev/null
+++ b/Assets/BMapBindings/pybmap/tests/main.py
@@ -0,0 +1,35 @@
+import os
+from pathlib import Path
+from tempfile import TemporaryDirectory
+import pybmap.bmap_wrapper as bmap
+import cli
+import testsuits
+
+def main() -> None:
+ # Parse arguments
+ try:
+ cliopts = cli.Cli()
+ except cli.CliException as e:
+ print(f'Can not launch test. Reason: {e}')
+ return
+
+ # Check BMap status.
+ # if True:
+ # print('Fail to initialize native BMap.')
+ # return
+
+ # Waiting debugger
+ input(f'Python PID is {os.getpid()}. Waiting for debugger, press any key to continue...')
+
+ # Start testbench
+ with TemporaryDirectory() as tempdir:
+ file_name = str(cliopts.file_name)
+ temp_folder = str(tempdir)
+ texture_folder = str(cliopts.ballance_dir / 'Textures')
+ encodings = cliopts.encodings
+ with bmap.BMFileReader(file_name, temp_folder, texture_folder, encodings) as reader:
+ testsuits.TestCommon.test(reader)
+ testsuits.TestEq.test(reader)
+
+if __name__ == '__main__':
+ main()
diff --git a/Assets/BMapBindings/pybmap/tests/testbench.py b/Assets/BMapBindings/pybmap/tests/testbench.py
deleted file mode 100644
index a16e2b1..0000000
--- a/Assets/BMapBindings/pybmap/tests/testbench.py
+++ /dev/null
@@ -1,178 +0,0 @@
-import os
-import argparse
-import PyBMap.bmap_wrapper as bmap
-
-def main(file_name: str, temp_folder: str, texture_folder: str, encodings: tuple[str, ...]) -> None:
- input(f'Python PID is {os.getpid()}. Waiting for debugger, press any key to continue...')
-
- # file_name: str = 'LightCameraTest.nmo'
- # temp_folder: str = 'Temp'
- # texture_folder: str = 'F:\\Ballance\\Ballance\\Textures'
- # encodings: tuple[str, ...] = ('cp1252', )
- with bmap.BMFileReader(file_name, temp_folder, texture_folder, encodings) as reader:
- test_common(reader)
- test_equatable(reader)
-
-def test_common(reader: bmap.BMFileReader):
- # print('===== Groups =====')
- # for gp in reader.get_groups():
- # print(gp.get_name())
- # for gp_item in gp.get_objects():
- # print(f'\t{gp_item.get_name()}')
-
- # print('===== 3dObjects =====')
- # for obj in reader.get_3dobjects():
- # print(obj.get_name())
-
- # current_mesh = obj.get_current_mesh()
- # mesh_name = '' if current_mesh is None else current_mesh.get_name()
- # print(f'\tMesh: {mesh_name}')
- # print(f'\tVisibility: {obj.get_visibility()}')
- # print(f'\tMatrix: {obj.get_world_matrix().to_const()}')
-
- # print('===== Meshes =====')
- # for mesh in reader.get_meshs():
- # print(mesh.get_name())
-
- # print(f'\tLit Mode: {mesh.get_lit_mode()}')
- # print(f'\tVertex Count: {mesh.get_vertex_count()}')
- # print(f'\tFace Count: {mesh.get_face_count()}')
- # print(f'\tMaterial Slot Count: {mesh.get_material_slot_count()}')
-
- # print('===== Materials =====')
- # for mtl in reader.get_materials():
- # print(mtl.get_name())
-
- # print(f'\tDiffuse: {mtl.get_diffuse().to_const_rgba()}')
- # print(f'\tAmbient: {mtl.get_ambient().to_const_rgba()}')
- # print(f'\tSpecular: {mtl.get_specular().to_const_rgba()}')
- # print(f'\tEmissive: {mtl.get_emissive().to_const_rgba()}')
-
- # print(f'\tSpecular Power: {mtl.get_specular_power()}')
-
- # print(f'\tTexture Border Color: {mtl.get_texture_border_color().to_const_rgba()}')
-
- # print(f'\tTexture Blend Mode: {mtl.get_texture_blend_mode()}')
- # print(f'\tTexture Min Mode: {mtl.get_texture_min_mode()}')
- # print(f'\tTexture Mag Mode: {mtl.get_texture_mag_mode()}')
- # print(f'\tSource Blend: {mtl.get_source_blend()}')
- # print(f'\tDest Blend: {mtl.get_dest_blend()}')
- # print(f'\tFill Mode: {mtl.get_fill_mode()}')
- # print(f'\tShade Mode: {mtl.get_shade_mode()}')
-
- # print(f'\tAlpha Test Enabled: {mtl.get_alpha_test_enabled()}')
- # print(f'\tAlpha Blend Enabled: {mtl.get_alpha_blend_enabled()}')
- # print(f'\tPerspective Correction Enabled: {mtl.get_perspective_correction_enabled()}')
- # print(f'\tZ Write Enabled: {mtl.get_z_write_enabled()}')
- # print(f'\tTwo Sided Enabled: {mtl.get_two_sided_enabled()}')
-
- # print(f'\tAlpha Ref: {mtl.get_alpha_ref()}')
-
- # print(f'\tAlpha Func: {mtl.get_alpha_func()}')
- # print(f'\tZ Func: {mtl.get_z_func()}')
-
- # print('===== Textures =====')
- # for tex in reader.get_textures():
- # print(tex.get_name())
-
- # print(f'\tFile Name: {tex.get_file_name()}')
- # print(f'\tSave Options: {tex.get_save_options()}')
- # print(f'\tVideo Format: {tex.get_video_format()}')
-
- print('===== Target Lights =====')
- for lit in reader.get_target_lights():
- print(lit.get_name())
-
- print(f'\tVisibility: {lit.get_visibility()}')
- print(f'\tMatrix: {lit.get_world_matrix().to_const()}')
-
- print(f'\tType: {lit.get_type()}')
- print(f'\tColor: {lit.get_color().to_const_rgba()}')
- print(f'\tConstant Attenuation: {lit.get_constant_attenuation()}')
- print(f'\tLinear Attenuation: {lit.get_linear_attenuation()}')
- print(f'\tQuadratic Attenuation: {lit.get_quadratic_attenuation()}')
- print(f'\tRange: {lit.get_range()}')
- print(f'\tHot Spot: {lit.get_hot_spot()}')
- print(f'\tFalloff: {lit.get_falloff()}')
- print(f'\tFalloff Shape: {lit.get_falloff_shape()}')
-
- print('===== END =====')
-
-def test_equatable(reader: bmap.BMFileReader):
- # Check requirements
- assert (reader.get_3dobject_count() >= 2), '''
- Invalid file for test IEquatable.
- We can not perform IEquatable test because the length of 3dObject is too short (must greater than 2). Please choose another file to perform.
- '''
-
- # Prepare variables
- all_3dobjects: tuple[bmap.BM3dObject, ...] = tuple(reader.get_3dobjects())
- first_3dobj: bmap.BM3dObject = all_3dobjects[0]
- second_3dobj: bmap.BM3dObject = all_3dobjects[1]
- all_3dobjects = tuple(reader.get_3dobjects())
- first_3dobj_again: bmap.BM3dObject = all_3dobjects[0]
-
- # Test set
- test_set: set[bmap.BM3dObject] = set()
-
- test_set.add(first_3dobj)
- assert len(test_set) == 1
-
- assert first_3dobj in test_set
- assert first_3dobj_again in test_set
- assert second_3dobj not in test_set
-
- test_set.add(first_3dobj_again)
- assert len(test_set) == 1
- test_set.add(second_3dobj)
- assert len(test_set) == 2
-
- assert second_3dobj in test_set
-
- # Test dict
- test_dict: dict[bmap.BM3dObject, str | None] = {}
-
- test_dict[first_3dobj] = first_3dobj.get_name()
- assert len(test_dict) == 1
-
- assert first_3dobj in test_dict
- assert first_3dobj_again in test_dict
- assert second_3dobj not in test_dict
-
- test_dict[first_3dobj_again] = first_3dobj_again.get_name()
- assert len(test_dict) == 1
- test_dict[second_3dobj] = second_3dobj.get_name()
- assert len(test_dict) == 2
-
- assert second_3dobj in test_dict
-
-if __name__ == '__main__':
- # parse argument
- parser = argparse.ArgumentParser(
- prog='PyBMap Testbench',
- description='The testbench of PyBMap.'
- )
- parser.add_argument(
- '--file-path',
- action='store', dest='file_path', required=True,
- help='The path to input Virtools file.'
- )
- parser.add_argument(
- '--temp-dir',
- action='store', dest='temp_dir', required=True,
- help='The temp folder used by BMap.'
- )
- parser.add_argument(
- '--texture-dir',
- action='store', dest='texture_dir', required=True,
- help='The texture folder containing Ballance texture resources.'
- )
- parser.add_argument(
- '--encodings',
- action='extend', nargs='+', dest='encodings', required=True,
- help='The encodings used to parse the names stroed in input Virtools file.'
- )
- args = parser.parse_args()
-
- # run main function
- main(args.file_path, args.temp_dir, args.texture_dir, tuple(args.encodings))
diff --git a/Assets/BMapBindings/pybmap/tests/testsuits.py b/Assets/BMapBindings/pybmap/tests/testsuits.py
new file mode 100644
index 0000000..7617833
--- /dev/null
+++ b/Assets/BMapBindings/pybmap/tests/testsuits.py
@@ -0,0 +1,177 @@
+import pybmap.bmap_wrapper as bmap
+from pybmap.bmap_wrapper import BMFileReader
+
+class TestCommon:
+ @staticmethod
+ def test(reader: BMFileReader) -> None:
+ print('===== Groups =====')
+ TestCommon.__test_group(reader)
+ print('===== 3dObjects =====')
+ TestCommon.__test_3dobject(reader)
+ print('===== Meshes =====')
+ TestCommon.__test_mesh(reader)
+ print('===== Materials =====')
+ TestCommon.__test_material(reader)
+ print('===== Textures =====')
+ TestCommon.__test_texture(reader)
+ print('===== Target Lights =====')
+ TestCommon.__test_target_light(reader)
+ print('===== Target Cameras =====')
+ TestCommon.__test_target_camera(reader)
+ print('===== END =====')
+
+ @staticmethod
+ def __test_group(reader: BMFileReader) -> None:
+ for gp in reader.get_groups():
+ print(gp.get_name())
+ for gp_item in gp.get_objects():
+ print(f'\t{gp_item.get_name()}')
+
+ @staticmethod
+ def __test_3dobject(reader: BMFileReader) -> None:
+ for obj in reader.get_3dobjects():
+ print(obj.get_name())
+
+ current_mesh = obj.get_current_mesh()
+ mesh_name = '' if current_mesh is None else current_mesh.get_name()
+ print(f'\tMesh: {mesh_name}')
+ print(f'\tVisibility: {obj.get_visibility()}')
+ print(f'\tMatrix: {obj.get_world_matrix().to_const()}')
+
+ @staticmethod
+ def __test_mesh(reader: BMFileReader) -> None:
+ for mesh in reader.get_meshs():
+ print(mesh.get_name())
+
+ print(f'\tLit Mode: {mesh.get_lit_mode()}')
+ print(f'\tVertex Count: {mesh.get_vertex_count()}')
+ print(f'\tFace Count: {mesh.get_face_count()}')
+ print(f'\tMaterial Slot Count: {mesh.get_material_slot_count()}')
+
+ @staticmethod
+ def __test_material(reader: BMFileReader) -> None:
+ for mtl in reader.get_materials():
+ print(mtl.get_name())
+
+ print(f'\tDiffuse: {mtl.get_diffuse().to_const_rgba()}')
+ print(f'\tAmbient: {mtl.get_ambient().to_const_rgba()}')
+ print(f'\tSpecular: {mtl.get_specular().to_const_rgba()}')
+ print(f'\tEmissive: {mtl.get_emissive().to_const_rgba()}')
+
+ print(f'\tSpecular Power: {mtl.get_specular_power()}')
+
+ print(f'\tTexture Border Color: {mtl.get_texture_border_color().to_const_rgba()}')
+
+ print(f'\tTexture Blend Mode: {mtl.get_texture_blend_mode()}')
+ print(f'\tTexture Min Mode: {mtl.get_texture_min_mode()}')
+ print(f'\tTexture Mag Mode: {mtl.get_texture_mag_mode()}')
+ print(f'\tSource Blend: {mtl.get_source_blend()}')
+ print(f'\tDest Blend: {mtl.get_dest_blend()}')
+ print(f'\tFill Mode: {mtl.get_fill_mode()}')
+ print(f'\tShade Mode: {mtl.get_shade_mode()}')
+
+ print(f'\tAlpha Test Enabled: {mtl.get_alpha_test_enabled()}')
+ print(f'\tAlpha Blend Enabled: {mtl.get_alpha_blend_enabled()}')
+ print(f'\tPerspective Correction Enabled: {mtl.get_perspective_correction_enabled()}')
+ print(f'\tZ Write Enabled: {mtl.get_z_write_enabled()}')
+ print(f'\tTwo Sided Enabled: {mtl.get_two_sided_enabled()}')
+
+ print(f'\tAlpha Ref: {mtl.get_alpha_ref()}')
+
+ print(f'\tAlpha Func: {mtl.get_alpha_func()}')
+ print(f'\tZ Func: {mtl.get_z_func()}')
+
+ @staticmethod
+ def __test_texture(reader: BMFileReader) -> None:
+ for tex in reader.get_textures():
+ print(tex.get_name())
+
+ print(f'\tFile Name: {tex.get_file_name()}')
+ print(f'\tSave Options: {tex.get_save_options()}')
+ print(f'\tVideo Format: {tex.get_video_format()}')
+
+ @staticmethod
+ def __test_target_light(reader: BMFileReader) -> None:
+ for lit in reader.get_target_lights():
+ print(lit.get_name())
+
+ print(f'\tVisibility: {lit.get_visibility()}')
+ print(f'\tMatrix: {lit.get_world_matrix().to_const()}')
+
+ print(f'\tType: {lit.get_type()}')
+ print(f'\tColor: {lit.get_color().to_const_rgba()}')
+ print(f'\tConstant Attenuation: {lit.get_constant_attenuation()}')
+ print(f'\tLinear Attenuation: {lit.get_linear_attenuation()}')
+ print(f'\tQuadratic Attenuation: {lit.get_quadratic_attenuation()}')
+ print(f'\tRange: {lit.get_range()}')
+ print(f'\tHot Spot: {lit.get_hot_spot()}')
+ print(f'\tFalloff: {lit.get_falloff()}')
+ print(f'\tFalloff Shape: {lit.get_falloff_shape()}')
+
+ @staticmethod
+ def __test_target_camera(reader: BMFileReader) -> None:
+ for cam in reader.get_target_cameras():
+ print(cam.get_name())
+
+ print(f'\tVisibility: {cam.get_visibility()}')
+ print(f'\tMatrix: {cam.get_world_matrix().to_const()}')
+
+ print(f'\tType: {cam.get_projection_type()}')
+ print(f'\tOrthographic Zoom: {cam.get_orthographic_zoom()}')
+ print(f'\tFront Plane: {cam.get_front_plane()}')
+ print(f'\tBack Plane: {cam.get_back_plane()}')
+ print(f'\tFov: {cam.get_fov()}')
+
+ (width, height) = cam.get_aspect_ratio()
+ print(f'\tAspect Ratio: {width}:{height}')
+
+class TestEq:
+ @staticmethod
+ def test(reader: BMFileReader) -> None:
+ # Check requirements
+ assert (reader.get_3dobject_count() >= 2), '''
+ Invalid file for test __eq__.
+ We can not perform __eq__ test because the length of 3dObject is too short (must greater than 2). Please choose another file to perform.
+ '''
+
+ # Prepare variables
+ all_3dobjects: tuple[bmap.BM3dObject, ...] = tuple(reader.get_3dobjects())
+ first_3dobj: bmap.BM3dObject = all_3dobjects[0]
+ second_3dobj: bmap.BM3dObject = all_3dobjects[1]
+ all_3dobjects = tuple(reader.get_3dobjects())
+ first_3dobj_again: bmap.BM3dObject = all_3dobjects[0]
+
+ # Test set
+ test_set: set[bmap.BM3dObject] = set()
+
+ test_set.add(first_3dobj)
+ assert len(test_set) == 1
+
+ assert first_3dobj in test_set
+ assert first_3dobj_again in test_set
+ assert second_3dobj not in test_set
+
+ test_set.add(first_3dobj_again)
+ assert len(test_set) == 1
+ test_set.add(second_3dobj)
+ assert len(test_set) == 2
+
+ assert second_3dobj in test_set
+
+ # Test dict
+ test_dict: dict[bmap.BM3dObject, str | None] = {}
+
+ test_dict[first_3dobj] = first_3dobj.get_name()
+ assert len(test_dict) == 1
+
+ assert first_3dobj in test_dict
+ assert first_3dobj_again in test_dict
+ assert second_3dobj not in test_dict
+
+ test_dict[first_3dobj_again] = first_3dobj_again.get_name()
+ assert len(test_dict) == 1
+ test_dict[second_3dobj] = second_3dobj.get_name()
+ assert len(test_dict) == 2
+
+ assert second_3dobj in test_dict
+