Cleanup: use override/final for derived classes.
[blender.git] / tests / python / bl_pyapi_bpy_utils_units.py
1 # Apache License, Version 2.0
2
3 # ./blender.bin --background -noaudio --python tests/python/bl_pyapi_bpy_utils_units.py -- --verbose
4 import unittest
5
6 from bpy.utils import units
7
8
9 class UnitsTesting(unittest.TestCase):
10     # From user typing to 'internal' Blender value.
11     INPUT_TESTS = (
12         # system,    type,    ref, input, value
13         # LENGTH
14         ('IMPERIAL', 'LENGTH', "", "1ft", 0.3048),
15         ('IMPERIAL', 'LENGTH', "", "(1+1)ft", 0.3048 * 2),
16         ('IMPERIAL', 'LENGTH', "", "1mi4\"", 1609.344 + 0.0254 * 4),
17         ('METRIC', 'LENGTH', "", "0.005┬Ám", 0.000001 * 0.005),
18         ('METRIC', 'LENGTH', "", "1e6km", 1000.0 * 1e6),
19         ('IMPERIAL', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
20         ('METRIC', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
21         # Using reference string to find a unit when none is given.
22         ('IMPERIAL', 'LENGTH', "33.3ft", "1", 0.3048),
23         ('METRIC', 'LENGTH', "33.3dm", "1", 0.1),
24         ('IMPERIAL', 'LENGTH', "33.3cm", "1", 0.3048),  # ref unit is not in IMPERIAL system, default to feet...
25         ('IMPERIAL', 'LENGTH', "33.3ft", "1\"", 0.0254),  # unused ref unit, since one is given already!
26         ('IMPERIAL', 'LENGTH', "", "1+1ft", 0.3048 * 2),  # default unit taken from current string (feet).
27         ('METRIC', 'LENGTH', "", "1+1ft", 1.3048),  # no metric units, we default to meters.
28         ('IMPERIAL', 'LENGTH', "", "3+1in+1ft", 0.3048 * 4 + 0.0254),  # bigger unit becomes default one!
29         ('IMPERIAL', 'LENGTH', "", "(3+1)in+1ft", 0.3048 + 0.0254 * 4),
30     )
31
32     # From 'internal' Blender value to user-friendly printing
33     OUTPUT_TESTS = (
34         # system,    type,    prec, sep, compat, value, output
35         # LENGTH
36         # Note: precision handling is a bit complicated when using multi-units...
37         ('IMPERIAL', 'LENGTH', 3, False, False, 0.3048, "1'"),
38         ('IMPERIAL', 'LENGTH', 3, False, True, 0.3048, "1ft"),
39         ('IMPERIAL', 'LENGTH', 4, True, False, 0.3048 * 2 + 0.0254 * 5.5, "2' 5.5\""),
40         ('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000 mi"),
41         ('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000 mi"),
42         ('METRIC', 'LENGTH', 3, True, False, 1000 * 2 + 0.001 * 15, "2 km 2 cm"),
43         ('METRIC', 'LENGTH', 5, True, False, 1234.56789, "1 km 234.6 m"),
44         ('METRIC', 'LENGTH', 6, True, False, 1234.56789, "1 km 234.57 m"),
45         ('METRIC', 'LENGTH', 9, False, False, 1234.56789, "1.234568 km"),
46         ('METRIC', 'LENGTH', 9, True, False, 1000.000123456789, "1 km 0.123 mm"),
47     )
48
49     def test_units_inputs(self):
50         # Stolen from FBX addon!
51         def similar_values(v1, v2, e):
52             if v1 == v2:
53                 return True
54             return ((abs(v1 - v2) / max(abs(v1), abs(v2))) <= e)
55
56         for usys, utype, ref, inpt, val in self.INPUT_TESTS:
57             opt_val = units.to_value(usys, utype, inpt, str_ref_unit=ref)
58             # Note: almostequal is not good here, precision is fixed on decimal digits, not variable with
59             # magnitude of numbers (i.e. 1609.4416 ~= 1609.4456 fails even at 5 of 'places'...).
60             self.assertTrue(similar_values(opt_val, val, 1e-7),
61                             msg="%s, %s: \"%s\" (ref: \"%s\") => %f, expected %f"
62                                 "" % (usys, utype, inpt, ref, opt_val, val))
63
64     def test_units_outputs(self):
65         for usys, utype, prec, sep, compat, val, output in self.OUTPUT_TESTS:
66             opt_str = units.to_string(usys, utype, val, precision=prec, split_unit=sep, compatible_unit=compat)
67             self.assertEqual(
68                 opt_str, output,
69                 msg=(
70                     "%s, %s: %f (precision: %d, separate units: %d, compat units: %d) => "
71                     "\"%s\", expected \"%s\""
72                 ) % (usys, utype, val, prec, sep, compat, opt_str, output)
73             )
74
75
76 if __name__ == '__main__':
77     import sys
78     sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
79     unittest.main()