Browse Source

tests: add unit tests for Python loader file types

rdb 6 years ago
parent
commit
b23561d863
1 changed files with 211 additions and 0 deletions
  1. 211 0
      tests/pgraph/test_loader_types.py

+ 211 - 0
tests/pgraph/test_loader_types.py

@@ -0,0 +1,211 @@
+from panda3d.core import LoaderFileTypeRegistry, ModelRoot, Loader, LoaderOptions
+import pytest
+import tempfile
+import os
+from contextlib import contextmanager
+
+
[email protected]
+def test_filename():
+    """Fixture returning a filename to an existent .test file."""
+    fp = tempfile.NamedTemporaryFile(suffix='.test', delete=False)
+    fp.write(b"test")
+    fp.close()
+    yield fp.name
+    os.unlink(fp.name)
+
+
[email protected]
+def test_pz_filename():
+    """Fixture returning a filename to an existent .test.pz file."""
+    fp = tempfile.NamedTemporaryFile(suffix='.test.pz', delete=False)
+    fp.write(b"test")
+    fp.close()
+    yield fp.name
+    os.unlink(fp.name)
+
+
+@contextmanager
+def registered_type(type):
+    """Convenience method allowing use of register_type in a with block."""
+    registry = LoaderFileTypeRegistry.get_global_ptr()
+    registry.register_type(type)
+    yield
+    registry.unregister_type(type)
+
+
+class DummyLoader:
+    """The simplest possible successful LoaderFileType."""
+
+    extensions = ["test"]
+
+    @staticmethod
+    def load_file(path, options, record=None):
+        return ModelRoot("loaded")
+
+
+def test_loader_invalid():
+    """Tests that registering a malformed loader fails."""
+
+    class MissingExtensionsLoader:
+        pass
+
+    class InvalidTypeExtensionsLoader:
+        extensions = "abc"
+
+    class EmptyExtensionsLoader:
+        extensions = []
+
+    class InvalidExtensionsLoader:
+        extensions = [123, None]
+
+    registry = LoaderFileTypeRegistry.get_global_ptr()
+
+    with pytest.raises(Exception):
+        registry.register_type("invalid")
+
+    with pytest.raises(Exception):
+        registry.register_type(MissingExtensionsLoader)
+
+    with pytest.raises(TypeError):
+        registry.register_type(InvalidTypeExtensionsLoader)
+
+    with pytest.raises(ValueError):
+        registry.register_type(EmptyExtensionsLoader)
+
+    with pytest.raises(TypeError):
+        registry.register_type(InvalidExtensionsLoader)
+
+
+def test_loader_success(test_filename):
+    """Tests that a normal dummy loader successfully loads."""
+
+    with registered_type(DummyLoader):
+        model = Loader.get_global_ptr().load_sync(test_filename, LoaderOptions(LoaderOptions.LF_no_cache))
+        assert model is not None
+        assert model.name == "loaded"
+
+
+def test_loader_extensions(test_filename):
+    """Tests multi-extension loaders."""
+
+    class MultiExtensionLoader:
+        extensions = ["test1", "teSt2"]
+
+        @staticmethod
+        def load_file(path, options, record=None):
+            return ModelRoot("loaded")
+
+    fp1 = tempfile.NamedTemporaryFile(suffix='.test1', delete=False)
+    fp1.write(b"test1")
+    fp1.close()
+    fp2 = tempfile.NamedTemporaryFile(suffix='.TEST2', delete=False)
+    fp2.write(b"test2")
+    fp2.close()
+
+    try:
+        with registered_type(MultiExtensionLoader):
+            model1 = Loader.get_global_ptr().load_sync(fp1.name, LoaderOptions(LoaderOptions.LF_no_cache))
+            assert model1 is not None
+            assert model1.name == "loaded"
+
+            model2 = Loader.get_global_ptr().load_sync(fp2.name, LoaderOptions(LoaderOptions.LF_no_cache))
+            assert model2 is not None
+            assert model2.name == "loaded"
+    finally:
+        os.unlink(fp1.name)
+        os.unlink(fp2.name)
+
+    # Ensure that both were unregistered.
+    registry = LoaderFileTypeRegistry.get_global_ptr()
+    assert not registry.get_type_from_extension("test1")
+    assert not registry.get_type_from_extension("test2")
+
+
+def test_loader_nonexistent():
+    """Verifies that non-existent files fail before calling load_file."""
+    flag = [False]
+
+    class AssertiveLoader:
+        extensions = ["test"]
+
+        @staticmethod
+        def load_file(path, options, record=None):
+            flag[0] = True
+            assert False, "should never get here"
+
+    with registered_type(AssertiveLoader):
+        model = Loader.get_global_ptr().load_sync("/non-existent", LoaderOptions(LoaderOptions.LF_no_cache))
+        assert model is None
+        assert not flag[0]
+
+
+def test_loader_exception(test_filename):
+    """Tests for a loader that raises an exception."""
+
+    class FailingLoader:
+        extensions = ["test"]
+
+        @staticmethod
+        def load_file(path, options, record=None):
+            raise Exception("test error")
+
+    with registered_type(FailingLoader):
+        model = Loader.get_global_ptr().load_sync(test_filename, LoaderOptions(LoaderOptions.LF_no_cache))
+        assert model is None
+
+
+def test_loader_compressed(test_pz_filename):
+    """Tests for loading .pz files and the supports_compressed flag."""
+
+    class TestLoader:
+        extensions = ["test"]
+
+        @staticmethod
+        def load_file(path, options, record=None):
+            return ModelRoot("loaded")
+
+    # Test with property absent
+    with registered_type(TestLoader):
+        model = Loader.get_global_ptr().load_sync(test_pz_filename, LoaderOptions(LoaderOptions.LF_no_cache))
+        assert model is None
+
+    # Test with property False, should give same result
+    TestLoader.supports_compressed = False
+    with registered_type(TestLoader):
+        model = Loader.get_global_ptr().load_sync(test_pz_filename, LoaderOptions(LoaderOptions.LF_no_cache))
+        assert model is None
+
+    # Test with property True, should work
+    TestLoader.supports_compressed = True
+    with registered_type(TestLoader):
+        model = Loader.get_global_ptr().load_sync(test_pz_filename, LoaderOptions(LoaderOptions.LF_no_cache))
+        assert model is not None
+        assert model.name == "loaded"
+
+    # Test with property invalid type, should not register
+    TestLoader.supports_compressed = None
+    with pytest.raises(TypeError):
+        LoaderFileTypeRegistry.get_global_ptr().register_type(TestLoader)
+
+
+def test_loader_ram_cache(test_filename):
+    """Tests that the Python loader plug-ins write to the RAM cache."""
+
+    # Ensure a clean slate.
+    from panda3d.core import ModelPool
+    ModelPool.release_all_models()
+
+    with registered_type(DummyLoader):
+        model1 = Loader.get_global_ptr().load_sync(test_filename, LoaderOptions(LoaderOptions.LF_no_disk_cache | LoaderOptions.LF_allow_instance))
+        assert model1 is not None
+        assert model1.name == "loaded"
+
+        assert ModelPool.has_model(test_filename)
+        assert ModelPool.get_model(test_filename, True) == model1
+
+        model2 = Loader.get_global_ptr().load_sync(test_filename, LoaderOptions(LoaderOptions.LF_cache_only | LoaderOptions.LF_allow_instance))
+        assert model2 is not None
+        assert model1 == model2
+
+        ModelPool.release_model(model2)