File: curves_extrude.py

package info (click to toggle)
blender 4.3.2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 309,564 kB
  • sloc: cpp: 2,385,210; python: 330,236; ansic: 280,972; xml: 2,446; sh: 972; javascript: 317; makefile: 170
file content (194 lines) | stat: -rw-r--r-- 6,980 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# 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()