a6fd1f5034
CurvesGeometry has no ".selection" attribute when all control points are selected. The earlier code assumed that the attribute always exists. Also Python tests are added for the "extrude" operator. Pull Request: https://projects.blender.org/blender/blender/pulls/117095
193 lines
6.8 KiB
Python
193 lines
6.8 KiB
Python
# SPDX-FileCopyrightText: 2020-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
from abc import ABC, abstractmethod
|
|
import bpy
|
|
import os
|
|
import sys
|
|
|
|
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
|
from modules.mesh_test import RunTest
|
|
|
|
|
|
class CurvesTest(ABC):
|
|
|
|
def __init__(self, test_object_name, exp_object_name, test_name=None):
|
|
self.test_object_name = test_object_name
|
|
self.exp_object_name = exp_object_name
|
|
self.test_object = bpy.data.objects[self.test_object_name]
|
|
self.expected_object = bpy.data.objects[self.exp_object_name]
|
|
self.verbose = os.getenv("BLENDER_VERBOSE") is not None
|
|
|
|
if test_name:
|
|
self.test_name = test_name
|
|
else:
|
|
filepath = bpy.data.filepath
|
|
self.test_name = bpy.path.display_name_from_filepath(filepath)
|
|
self._failed_tests_list = []
|
|
|
|
def create_evaluated_object(self):
|
|
"""
|
|
Creates an evaluated object.
|
|
"""
|
|
bpy.context.view_layer.objects.active = self.test_object
|
|
|
|
# Duplicate test object.
|
|
bpy.ops.object.mode_set(mode="OBJECT")
|
|
bpy.ops.object.select_all(action="DESELECT")
|
|
bpy.context.view_layer.objects.active = self.test_object
|
|
|
|
self.test_object.select_set(True)
|
|
bpy.ops.object.duplicate()
|
|
self.evaluated_object = bpy.context.active_object
|
|
self.evaluated_object.name = "evaluated_object"
|
|
|
|
@staticmethod
|
|
def _print_result(result):
|
|
"""
|
|
Prints the comparison, selection and validation result.
|
|
"""
|
|
print("Results:")
|
|
for key in result:
|
|
print("{} : {}".format(key, result[key][1]))
|
|
print()
|
|
|
|
def run_test(self):
|
|
"""
|
|
Runs a single test, runs it again if test file is updated.
|
|
"""
|
|
print("\nSTART {} test.".format(self.test_name))
|
|
|
|
self.create_evaluated_object()
|
|
self.apply_operations()
|
|
|
|
result = self.compare_objects(self.evaluated_object, self.expected_object)
|
|
|
|
# Initializing with True to get correct resultant of result_code booleans.
|
|
success = True
|
|
inside_loop_flag = False
|
|
for key in result:
|
|
inside_loop_flag = True
|
|
success = success and result[key][0]
|
|
|
|
# Check "success" is actually evaluated and is not the default True value.
|
|
if not inside_loop_flag:
|
|
success = False
|
|
|
|
if success:
|
|
self.print_passed_test_result(result)
|
|
# Clean up.
|
|
if self.verbose:
|
|
print("Cleaning up...")
|
|
# Delete evaluated_test_object.
|
|
bpy.ops.object.delete()
|
|
return True
|
|
|
|
else:
|
|
self.print_failed_test_result(result)
|
|
return False
|
|
|
|
@abstractmethod
|
|
def apply_operations(self, evaluated_test_object_name):
|
|
pass
|
|
|
|
@staticmethod
|
|
def compare_curves(evaluated_curves, expected_curves):
|
|
if len(evaluated_curves.attributes.items()) != len(expected_curves.attributes.items()):
|
|
print("Attribute count doesn't match")
|
|
|
|
for a_idx, attribute in evaluated_curves.attributes.items():
|
|
expected_attribute = expected_curves.attributes[a_idx]
|
|
|
|
if len(attribute.data.items()) != len(expected_attribute.data.items()):
|
|
print("Attribute data length doesn't match")
|
|
|
|
value_attr_name = ('vector' if attribute.data_type == 'FLOAT_VECTOR'
|
|
or attribute.data_type == 'FLOAT2' else
|
|
'color' if attribute.data_type == 'FLOAT_COLOR' else 'value')
|
|
|
|
for v_idx, attribute_value in attribute.data.items():
|
|
if getattr(
|
|
attribute_value,
|
|
value_attr_name) != getattr(
|
|
expected_attribute.data[v_idx],
|
|
value_attr_name):
|
|
print("Attribute '{}' values do not match".format(attribute.name))
|
|
return False
|
|
|
|
return True
|
|
|
|
def compare_objects(self, evaluated_object, expected_object):
|
|
result_codes = {}
|
|
|
|
equal = self.compare_curves(evaluated_object.data, expected_object.data)
|
|
|
|
result_codes['Curves Comparison'] = (equal, evaluated_object.data)
|
|
return result_codes
|
|
|
|
def print_failed_test_result(self, result):
|
|
"""
|
|
Print results for failed test.
|
|
"""
|
|
print("FAILED {} test with the following: ".format(self.test_name))
|
|
|
|
def print_passed_test_result(self, result):
|
|
"""
|
|
Print results for passing test.
|
|
"""
|
|
print("PASSED {} test successfully.".format(self.test_name))
|
|
|
|
|
|
class CurvesOpTest(CurvesTest):
|
|
|
|
def __init__(self, test_name, test_object_name, exp_object_name, operators_stack):
|
|
super().__init__(test_object_name, exp_object_name, test_name)
|
|
self.operators_stack = operators_stack
|
|
|
|
def apply_operations(self):
|
|
for operator_name in self.operators_stack:
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
curves_operator = getattr(bpy.ops.curves, operator_name)
|
|
|
|
try:
|
|
retval = curves_operator()
|
|
except AttributeError:
|
|
raise AttributeError("bpy.ops.curves has no attribute {}".format(operator_name))
|
|
except TypeError as ex:
|
|
raise TypeError("Incorrect operator parameters {!r} raised {!r}".format([], ex))
|
|
|
|
if retval != {'FINISHED'}:
|
|
raise RuntimeError("Unexpected operator return value: {}".format(operator_name))
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
|
|
|
|
def main():
|
|
tests = [
|
|
CurvesOpTest("Extrude 1 Point Curve", "a_test1PointCurve", "a_test1PointCurveExpected", ['extrude']),
|
|
CurvesOpTest("Extrude Middle Points", "b_testMiddlePoints", "b_testMiddlePointsExpected", ['extrude']),
|
|
CurvesOpTest("Extrude End Points", "c_testEndPoints", "c_testEndPointsExpected", ['extrude']),
|
|
CurvesOpTest("Extrude Neighbors In Separate Curves", "d_testNeighborsInCurves", "d_testNeighborsInCurvesExpected", ['extrude']),
|
|
CurvesOpTest("Extrude Edge Curves", "e_testEdgeCurves", "e_testEdgeCurvesExpected", ['extrude']),
|
|
CurvesOpTest("Extrude Middle Curve", "f_testMiddleCurve", "f_testMiddleCurveExpected", ['extrude']),
|
|
CurvesOpTest("Extrude All Points", "g_testAllPoints", "g_testAllPointsExpected", ['extrude'])
|
|
]
|
|
|
|
curves_extrude_test = RunTest(tests)
|
|
|
|
command = list(sys.argv)
|
|
for i, cmd in enumerate(command):
|
|
if cmd == "--run-all-tests":
|
|
curves_extrude_test.do_compare = True
|
|
curves_extrude_test.run_all_tests()
|
|
break
|
|
elif cmd == "--run-test":
|
|
curves_extrude_test.do_compare = False
|
|
name = command[i + 1]
|
|
curves_extrude_test.run_test(name)
|
|
break
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|