Commit: 95289adbee0ee59a15b97c6166343dcb120c7a37
Author: Bastien Montagne
Date:   Tue Jun 17 14:55:42 2014 +0200
https://developer.blender.org/rB95289adbee0ee59a15b97c6166343dcb120c7a37

Add more tests to bpyunits.

Only LENGTH type for now.

This showed two limits to current BKE's units code:
* When converting string to value, we use too few precision for units' values 
(6 digits),
  not good esp. when mixing big and small units (like e.g. miles and inches). 
Will fix that
  in next commit.
* When converting values to string, 'precision' parameter ignores order of 
magnitude of the value,
  which leads to invalid results with big numbers (e.g. 1000000mi gives 
1000000.004mi with prec of 3).

===================================================================

M       source/tests/bl_pyapi_units.py

===================================================================

diff --git a/source/tests/bl_pyapi_units.py b/source/tests/bl_pyapi_units.py
index 5fa9d90..f472f8d 100644
--- a/source/tests/bl_pyapi_units.py
+++ b/source/tests/bl_pyapi_units.py
@@ -8,23 +8,64 @@ class UnitsTesting(unittest.TestCase):
     # From user typing to 'internal' Blender value.
     INPUT_TESTS = (
         # system,    type,    ref, input, value
+        ##### LENGTH
         ('IMPERIAL', 'LENGTH', "", "1ft", 0.3048),
-        ('IMPERIAL', 'LENGTH', "", "1+1ft", 0.3048 * 2),
+        ('IMPERIAL', 'LENGTH', "", "(1+1)ft", 0.3048 * 2),
+        ('IMPERIAL', 'LENGTH', "", "1mi4\"", 1609.344 + 0.0254 * 4),
+        ('METRIC',   'LENGTH', "", "0.005µm", 0.000001 * 0.005),
+        ('METRIC',   'LENGTH', "", "1e6km", 1000.0 * 1e6),
+        ('IMPERIAL', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
+        ('METRIC',   'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
+        # Using reference string to find a unit when none is given.
+        ('IMPERIAL', 'LENGTH', "33.3ft", "1", 0.3048),
+        ('METRIC',   'LENGTH', "33.3dm", "1", 0.1),
+        ('IMPERIAL', 'LENGTH', "33.3cm", "1", 0.3048),  # ref unit is not in 
IMPERIAL system, default to feet...
+        ('IMPERIAL', 'LENGTH', "33.3ft", "1\"", 0.0254),  # unused ref unit, 
since one is given already!
+        #('IMPERIAL', 'LENGTH', "", "1+1ft", 0.3048 * 2),  # Will fail with 
current code!
     )
 
     # From 'internal' Blender value to user-friendly printing
     OUTPUT_TESTS = (
         # system,    type,    prec, sep, compat, value, output
+        ##### LENGTH
         ('IMPERIAL', 'LENGTH', 3, False, False, 0.3048, "1'"),
+        ('IMPERIAL', 'LENGTH', 3, False, True,  0.3048, "1ft"),
+        ('IMPERIAL', 'LENGTH', 3, True,  False, 0.3048 * 2 + 0.0254 * 5.5, "2' 
5.5\""),
+        # Those next two fail, here again because precision ignores order 
magnitude :/
+        #('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000mi"), 
# == 1000000.004mi!!!
+        #('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000mi"), 
# == 1000000.003641mi!!!
+        ('METRIC',   'LENGTH', 3, True,  False, 1000 * 2 + 0.001 * 15, "2km 
1.5cm"),
+        ('METRIC',   'LENGTH', 3, True,  False, 1234.56789, "1km 234.6m"),
+        # Note: precision seems basically unused when using multi units!
+        ('METRIC',   'LENGTH', 9, True,  False, 1234.56789, "1km 234.6m"),
+        ('METRIC',   'LENGTH', 9, False, False, 1234.56789, "1.23456789km"),
+        ('METRIC',   'LENGTH', 9, True,  False, 1000.000123456789, "1km 
0.1mm"),
     )
 
     def test_units_inputs(self):
+        # Stolen from FBX addon!
+        def similar_values(v1, v2, e):
+            if v1 == v2:
+                return True
+            return ((abs(v1 - v2) / max(abs(v1), abs(v2))) <= e)
+
         for usys, utype, ref, inpt, val in self.INPUT_TESTS:
-            self.assertAlmostEqual(units.to_value(usys, utype, inpt, ref), val)
+            opt_val = units.to_value(usys, utype, inpt, ref)
+            # Note: Internal precision of BKE's unit.c is 6 per unit (see 
unit_scale_str(), using just %g).
+            #       Since there are multiplications etc., we can't count on 
better than 5 in result.
+            # XXX Maybe we should raise it to 8 or 9 (%.9g)?
+            # Also, almostequal is not good here, precision is fixed on 
decimal digits, not variable with
+            # magnitude of numbers (i.e. 1609.4416 ~= 1609.4456 fails even at 
5 of 'places'...).
+            self.assertTrue(similar_values(opt_val, val, 1e-5),
+                            msg="%s, %s: \"%s\" (ref: \"%s\") => %f, expected 
%f"
+                                "" % (usys, utype, inpt, ref, opt_val, val))
 
     def test_units_outputs(self):
         for usys, utype, prec, sep, compat, val, output in self.OUTPUT_TESTS:
-            self.assertEqual(units.to_string(usys, utype, val, prec, sep, 
compat), output)
+            opt_str = units.to_string(usys, utype, val, prec, sep, compat)
+            self.assertEqual(opt_str, output,
+                            msg="%s, %s: %f (precision: %d, separate units: 
%d, compat units: %d) => "
+                                "\"%s\", expected \"%s\"" % (usys, utype, val, 
prec, sep, compat, opt_str, output))
 
 
 def test_main():

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to