Anim: Unit tests for "Insert Needed" #116419
|
@ -395,6 +395,75 @@ class InsertAvailableTest(AbstractKeyframingTest, unittest.TestCase):
|
|||
bpy.data.objects.remove(keyed_object, do_unlink=True)
|
||||
|
||||
|
||||
class InsertNeededTest(AbstractKeyframingTest, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
bpy.context.scene.tool_settings.use_keyframe_insert_auto = True
|
||||
bpy.context.preferences.edit.use_keyframe_insert_needed = True
|
||||
bpy.context.preferences.edit.use_keyframe_insert_available = False
|
||||
|
||||
def tearDown(self):
|
||||
bpy.context.scene.tool_settings.use_keyframe_insert_auto = False
|
||||
bpy.context.preferences.edit.use_keyframe_insert_needed = False
|
||||
|
||||
def test_insert_needed_object(self):
|
||||
keyed_object = _create_animation_object()
|
||||
|
||||
with bpy.context.temp_override(**_get_view3d_context()):
|
||||
bpy.context.scene.frame_set(1)
|
||||
bpy.ops.transform.translate(value=(-1, 0, 0))
|
||||
bpy.context.scene.frame_set(5)
|
||||
bpy.ops.transform.translate(value=(1, 0, 0))
|
||||
|
||||
action = keyed_object.animation_data.action
|
||||
self.assertTrue(_fcurve_paths_match(action.fcurves, ["location"]))
|
||||
|
||||
# With "Insert Needed" enabled it has to key all location channels first,
|
||||
# before it can add keys only to the channels where values have actually
|
||||
|
||||
# changed.
|
||||
expected_keys = {
|
||||
"location": (2, 1, 1)
|
||||
}
|
||||
|
||||
Sybren A. Stüvel
commented
This seems to be a teardown, basically to prevent this test from influencing the next one. This should be done in a teardown function (docs), so that it's ensured to be run even when the test itself fails. This seems to be a teardown, basically to prevent this test from influencing the next one. This should be done in a teardown function ([docs](https://docs.python.org/3/library/unittest.html#unittest.TestCase.tearDown)), so that it's ensured to be run even when the test itself fails.
thanks, did not know that was a thing. Also made an override to the I will check the other tests to see if they can be refactored with thanks, did not know that was a thing. Also made an override to the `setUp` function so it is a bit clearer which user prefs are set
I will check the other tests to see if they can be refactored with `setUp` and `tearDown`. Different PR though
Sybren A. Stüvel
commented
The The `bpy.data.objects.remove(keyed_object, do_unlink=True)` call also should be in the teardown though, otherwise the object will stay there when the test fails.
I don't think this is an issue because the base class
I don't think this is an issue because the base class `AbstractKeyframingTest` has the `setUp` function:
```
def setUp(self):
super().setUp()
bpy.ops.wm.read_homefile(use_factory_startup=True)
```
Sybren A. Stüvel
commented
In that case the object removal code can be removed altogether -- either it's worth calling (and thus ensuring it gets called), or it's worth removing. When in doubt, throw it into the canal! In that case the object removal code can be removed altogether -- either it's worth calling (and thus ensuring it gets called), or it's worth removing. When in doubt, throw it into the canal!
|
||||
self.assertEqual(len(action.fcurves), 3)
|
||||
|
||||
for fcurve in action.fcurves:
|
||||
if fcurve.data_path not in expected_keys:
|
||||
raise AssertionError(f"Did not expect a key on {fcurve.data_path}")
|
||||
self.assertEqual(expected_keys[fcurve.data_path][fcurve.array_index], len(fcurve.keyframe_points))
|
||||
|
||||
def test_insert_needed_bone(self):
|
||||
armature_obj = _create_armature()
|
||||
|
||||
bpy.ops.object.mode_set(mode='POSE')
|
||||
with bpy.context.temp_override(**_get_view3d_context()):
|
||||
bpy.context.scene.frame_set(1)
|
||||
bpy.ops.transform.translate(value=(-1, 0, 0), orient_type='LOCAL')
|
||||
bpy.context.scene.frame_set(5)
|
||||
bpy.ops.transform.translate(value=(1, 0, 0), orient_type='LOCAL')
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
action = armature_obj.animation_data.action
|
||||
bone_path = f"pose.bones[\"{_BONE_NAME}\"]"
|
||||
self.assertTrue(_fcurve_paths_match(action.fcurves, [f"{bone_path}.location"]))
|
||||
|
||||
# With "Insert Needed" enabled it has to key all location channels first,
|
||||
# before it can add keys only to the channels where values have actually
|
||||
# changed.
|
||||
expected_keys = {
|
||||
f"{bone_path}.location": (2, 1, 1)
|
||||
}
|
||||
|
||||
self.assertEqual(len(action.fcurves), 3)
|
||||
|
||||
for fcurve in action.fcurves:
|
||||
if fcurve.data_path not in expected_keys:
|
||||
raise AssertionError(f"Did not expect a key on {fcurve.data_path}")
|
||||
self.assertEqual(expected_keys[fcurve.data_path][fcurve.array_index], len(fcurve.keyframe_points))
|
||||
|
||||
|
||||
def main():
|
||||
global args
|
||||
import argparse
|
||||
|
|
This should check that
len(expected_keys) == len(action.fcurves)
. Otherwise the test will succeed when there are no FCurves at all. In other words, the current test doesn't detect missing FCurves, it just detects unexpected ones.explicitly checking for 3 F-Curves
self.assertEqual(len(action.fcurves), 3)
Yeah, my code wouldn't work well ;-) But you got the point of it!