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