1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 ./blender.bin --background -noaudio --factory-startup --python tests/python/bl_alembic_import_test.py -- --testdir /path/to/lib/tests/alembic
34 class SimpleImportTest(unittest.TestCase):
37 cls.testdir = args.testdir
40 self.assertTrue(self.testdir.exists(),
41 'Test dir %s should exist' % self.testdir)
43 # Make sure we always start with a known-empty file.
44 bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "empty.blend"))
46 def test_import_cube_hierarchy(self):
47 res = bpy.ops.wm.alembic_import(
48 filepath=str(self.testdir / "cubes-hierarchy.abc"),
49 as_background_job=False)
50 self.assertEqual({'FINISHED'}, res)
52 # The objects should be linked to scene_collection in Blender 2.8,
53 # and to scene in Blender 2.7x.
54 objects = bpy.context.scene.objects
55 self.assertEqual(13, len(objects))
58 self.assertIsNone(objects['Cube'].parent)
59 self.assertEqual(objects['Cube'], objects['Cube_001'].parent)
60 self.assertEqual(objects['Cube'], objects['Cube_002'].parent)
61 self.assertEqual(objects['Cube'], objects['Cube_003'].parent)
62 self.assertEqual(objects['Cube_003'], objects['Cube_004'].parent)
63 self.assertEqual(objects['Cube_003'], objects['Cube_005'].parent)
64 self.assertEqual(objects['Cube_003'], objects['Cube_006'].parent)
66 def test_select_after_import(self):
67 # Add a sphere, so that there is something in the scene, selected, and active,
68 # before we do the Alembic import.
69 bpy.ops.mesh.primitive_uv_sphere_add()
70 sphere = bpy.context.active_object
71 self.assertEqual('Sphere', sphere.name)
72 self.assertEqual([sphere], bpy.context.selected_objects)
74 bpy.ops.wm.alembic_import(
75 filepath=str(self.testdir / "cubes-hierarchy.abc"),
76 as_background_job=False)
78 # The active object is probably the first one that was imported, but this
79 # behaviour is not defined. At least it should be one of the cubes, and
81 self.assertNotEqual(sphere, bpy.context.active_object)
82 self.assertTrue('Cube' in bpy.context.active_object.name)
84 # All cubes should be selected, but the sphere shouldn't be.
85 for ob in bpy.data.objects:
86 self.assertEqual('Cube' in ob.name, ob.select)
88 def test_change_path(self):
91 fname = 'cube-rotating1.abc'
92 abc = self.testdir / fname
93 relpath = bpy.path.relpath(str(abc))
95 res = bpy.ops.wm.alembic_import(filepath=str(abc), as_background_job=False)
96 self.assertEqual({'FINISHED'}, res)
97 cube = bpy.context.active_object
99 # Check that the file loaded ok.
100 bpy.context.scene.frame_set(10)
101 x, y, z = cube.matrix_world.to_euler('XYZ')
102 self.assertAlmostEqual(x, 0)
103 self.assertAlmostEqual(y, 0)
104 self.assertAlmostEqual(z, math.pi / 2, places=5)
106 # Change path from absolute to relative. This should not break the animation.
107 bpy.context.scene.frame_set(1)
108 bpy.data.cache_files[fname].filepath = relpath
109 bpy.context.scene.frame_set(10)
111 x, y, z = cube.matrix_world.to_euler('XYZ')
112 self.assertAlmostEqual(x, 0)
113 self.assertAlmostEqual(y, 0)
114 self.assertAlmostEqual(z, math.pi / 2, places=5)
116 # Replace the Alembic file; this should apply new animation.
117 bpy.data.cache_files[fname].filepath = relpath.replace('1.abc', '2.abc')
118 bpy.context.scene.update()
120 x, y, z = cube.matrix_world.to_euler('XYZ')
121 self.assertAlmostEqual(x, math.pi / 2, places=5)
122 self.assertAlmostEqual(y, 0)
123 self.assertAlmostEqual(z, 0)
131 argv = [sys.argv[0]] + sys.argv[sys.argv.index('--')+1:]
135 parser = argparse.ArgumentParser()
136 parser.add_argument('--testdir', required=True, type=pathlib.Path)
137 args, remaining = parser.parse_known_args(argv)
139 unittest.main(argv=remaining)
142 if __name__ == "__main__":
144 # So a python error exits Blender itself too
150 traceback.print_exc()