Merge branch 'blender2.7'
[blender.git] / tests / python / bl_pyapi_idprop.py
1 # Apache License, Version 2.0
2
3 # ./blender.bin --background -noaudio --python tests/python/bl_pyapi_idprop.py -- --verbose
4 import bpy
5 import unittest
6 import numpy as np
7 from array import array
8
9
10 class TestHelper:
11
12     @property
13     def id(self):
14         return self._id
15
16     def setUp(self):
17         self._id = bpy.context.scene
18         assert(len(self._id.keys()) == 0 or self._id.keys() == ["cycles"])
19
20     def tearDown(self):
21         for key in list(self._id.keys()):
22             if key != "cycles":
23                 del self._id[key]
24
25     def assertAlmostEqualSeq(self, list1, list2):
26         self.assertEqual(len(list1), len(list2))
27         for v1, v2 in zip(list1, list2):
28             self.assertAlmostEqual(v1, v2, places=5)
29
30
31 class TestIdPropertyCreation(TestHelper, unittest.TestCase):
32
33     def test_name_empty(self):
34         self.id[""] = 4
35         self.assertEqual(self.id[""], 4)
36
37     def test_name_too_long(self):
38         with self.assertRaises(KeyError):
39             self.id["name" * 30] = 4
40
41     def test_int(self):
42         self.id["a"] = 2
43         self.assertEqual(self.id["a"], 2)
44         self.assertTrue(isinstance(self.id["a"], int))
45
46         with self.assertRaises(OverflowError):
47             self.id["a"] = 2 ** 31  # integer <= 2 ** 31-1
48
49     def test_double(self):
50         self.id["a"] = 2.5
51         self.assertEqual(self.id["a"], 2.5)
52         self.assertTrue(isinstance(self.id["a"], float))
53
54     def test_unicode(self):
55         self.id["a"] = "Hello World"
56         self.assertEqual(self.id["a"], "Hello World")
57         self.assertTrue(isinstance(self.id["a"], str))
58
59     def test_bytes(self):
60         self.id["a"] = b"Hello World"
61         self.assertEqual(self.id["a"], b"Hello World")
62         self.assertTrue(isinstance(self.id["a"], bytes))
63
64     def test_sequence_double_list(self):
65         mylist = [1.2, 3.4, 5.6]
66         self.id["a"] = mylist
67         self.assertEqual(self.id["a"].to_list(), mylist)
68         self.assertEqual(self.id["a"].typecode, "d")
69
70     def test_sequence_int_list(self):
71         mylist = [1, 2, 3]
72         self.id["a"] = mylist
73         self.assertEqual(self.id["a"].to_list(), mylist)
74         self.assertEqual(self.id["a"].typecode, "i")
75
76     def test_sequence_float_array(self):
77         mylist = [1.2, 3.4, 5.6]
78         self.id["a"] = array("f", mylist)
79         self.assertAlmostEqualSeq(self.id["a"].to_list(), mylist)
80         self.assertEqual(self.id["a"].typecode, "f")
81
82     def test_sequence_double_array(self):
83         mylist = [1.2, 3.4, 5.6]
84         self.id["a"] = array("d", mylist)
85         self.assertAlmostEqualSeq(self.id["a"].to_list(), mylist)
86         self.assertEqual(self.id["a"].typecode, "d")
87
88     def test_sequence_int_array(self):
89         mylist = [1, 2, 3]
90         self.id["a"] = array("i", mylist)
91         self.assertAlmostEqualSeq(self.id["a"].to_list(), mylist)
92         self.assertEqual(self.id["a"].typecode, "i")
93
94     def test_sequence_other_array(self):
95         mylist = [1, 2, 3]
96         self.id["a"] = array("Q", mylist)
97         self.assertEqual(self.id["a"].to_list(), mylist)
98
99     def test_sequence_mixed_numerical_type(self):
100         self.id["a"] = [1, 2, 3.4, 5]
101         self.assertAlmostEqualSeq(self.id["a"].to_list(), [1.0, 2.0, 3.4, 5.0])
102         self.assertEqual(self.id["a"].typecode, "d")
103
104     def test_sequence_str_list(self):
105         # I'm a bit surprised that this works
106         mylist = ["abc", "qwe"]
107         self.id["a"] = mylist
108         self.assertEqual(self.id["a"], mylist)
109
110     def test_sequence_mixed_type(self):
111         with self.assertRaises(TypeError):
112             mylist = ["abc", 3, "qwe", 3.4]
113             self.id["a"] = mylist
114
115     def test_mapping_simple(self):
116         mydict = {"1": 10, "2": "20", "3": 30.5}
117         self.id["a"] = mydict
118         self.assertEqual(self.id["a"]["1"], mydict["1"])
119         self.assertEqual(self.id["a"]["2"], mydict["2"])
120         self.assertEqual(self.id["a"]["3"], mydict["3"])
121
122     def test_mapping_complex(self):
123         mydict = {
124             "1": [1, 2, 3],
125             "2": {"1": "abc", "2": array("i", [4, 5, 6])},
126             "3": {"1": {"1": 10}, "2": b"qwe"},
127         }
128         self.id["a"] = mydict
129         self.assertEqual(self.id["a"]["1"].to_list(), [1, 2, 3])
130         self.assertEqual(self.id["a"]["2"]["1"], "abc")
131         self.assertEqual(self.id["a"]["2"]["2"].to_list(), [4, 5, 6])
132         self.assertEqual(self.id["a"]["3"]["1"]["1"], 10)
133         self.assertEqual(self.id["a"]["3"]["2"], b"qwe")
134
135         with self.assertRaises(KeyError):
136             a = self.id["a"]["2"]["a"]
137
138     def test_invalid_type(self):
139         with self.assertRaises(TypeError):
140             self.id["a"] = self
141
142
143 class TestBufferProtocol(TestHelper, unittest.TestCase):
144
145     def test_int(self):
146         self.id["a"] = array("i", [1, 2, 3, 4, 5])
147         a = np.frombuffer(self.id["a"], self.id["a"].typecode)
148         self.assertEqual(len(a), 5)
149         a[2] = 10
150         self.assertEqual(self.id["a"].to_list(), [1, 2, 10, 4, 5])
151
152     def test_float(self):
153         self.id["a"] = array("f", [1.0, 2.0, 3.0, 4.0])
154         a = np.frombuffer(self.id["a"], self.id["a"].typecode)
155         self.assertEqual(len(a), 4)
156         a[-1] = 10
157         self.assertEqual(self.id["a"].to_list(), [1.0, 2.0, 3.0, 10.0])
158
159     def test_double(self):
160         self.id["a"] = array("d", [1.0, 2.0, 3.0, 4.0])
161         a = np.frombuffer(self.id["a"], self.id["a"].typecode)
162         a[1] = 10
163         self.assertEqual(self.id["a"].to_list(), [1.0, 10.0, 3.0, 4.0])
164
165     def test_full_update(self):
166         self.id["a"] = array("i", [1, 2, 3, 4, 5, 6])
167         a = np.frombuffer(self.id["a"], self.id["a"].typecode)
168         a[:] = [10, 20, 30, 40, 50, 60]
169         self.assertEqual(self.id["a"].to_list(), [10, 20, 30, 40, 50, 60])
170
171     def test_partial_update(self):
172         self.id["a"] = array("i", [1, 2, 3, 4, 5, 6, 7, 8])
173         a = np.frombuffer(self.id["a"], self.id["a"].typecode)
174         a[1:5] = [10, 20, 30, 40]
175         self.assertEqual(self.id["a"].to_list(), [1, 10, 20, 30, 40, 6, 7, 8])
176
177     def test_copy(self):
178         self.id["a"] = array("i", [1, 2, 3, 4, 5])
179         self.id["b"] = self.id["a"]
180         self.assertEqual(self.id["a"].to_list(), self.id["b"].to_list())
181
182     def test_memview_attributes(self):
183         mylist = [1, 2, 3]
184         self.id["a"] = mylist
185
186         view1 = memoryview(self.id["a"])
187         view2 = memoryview(array("i", mylist))
188
189         self.assertEqualMemviews(view1, view2)
190
191     def assertEqualMemviews(self, view1, view2):
192         props_to_compare = (
193             "contiguous", "format", "itemsize", "nbytes", "ndim",
194             "readonly", "shape", "strides", "suboffsets"
195         )
196         for attr in props_to_compare:
197             self.assertEqual(getattr(view1, attr), getattr(view2, attr))
198
199         self.assertEqual(list(view1), list(view2))
200         self.assertEqual(view1.tobytes(), view2.tobytes())
201
202
203 if __name__ == '__main__':
204     import sys
205     sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
206     unittest.main()