diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_formula.py | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/tests/test_formula.py b/tests/test_formula.py new file mode 100644 index 0000000..8074e5a --- /dev/null +++ b/tests/test_formula.py @@ -0,0 +1,96 @@ +# generat3D - evaluate Daz DSON scenes and write .dbz files +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import unittest + +from generat3d import Error +from generat3d.formula import Graph + + +def push(key): + return {"op": "push", "key": key} + + +def val(v): + return {"op": "push", "val": v} + + +class GraphTest(unittest.TestCase): + def setUp(self): + self.g = Graph() + self.g.add_prop("a", 0.5) + self.g.add_prop("b") + self.g.add_prop("c", 0.0, 0.0, 1.0, clamped=True) + + def test_base_values(self): + self.assertEqual(self.g.evaluate(), {"a": 0.5, "b": 0.0, "c": 0.0}) + + def test_sum_stage(self): + self.g.add_formula("b", [push("a"), val(2), {"op": "mult"}]) + self.g.add_formula("b", [push("a"), val(1), {"op": "add"}]) + self.assertEqual(self.g.evaluate()["b"], 1.0 + 1.5) + + def test_mult_stage(self): + self.g.set_value("b", 3.0) + self.g.add_formula("b", [push("a")], stage="mult") + self.assertEqual(self.g.evaluate()["b"], 1.5) + + def test_chain_and_clamp(self): + self.g.add_formula("b", [push("a"), val(4), {"op": "mult"}]) + self.g.add_formula("c", [push("b")]) + out = self.g.evaluate() + self.assertEqual(out["b"], 2.0) + self.assertEqual(out["c"], 1.0) + + def test_sub_div_neg(self): + self.g.add_formula("b", [val(1), push("a"), {"op": "sub"}, val(4), {"op": "div"}, + {"op": "neg"}]) + self.assertEqual(self.g.evaluate()["b"], -0.125) + + def test_unknown_input_drops_formula(self): + self.g.add_formula("b", [push("missing")]) + self.g.add_formula("b", [val(7)]) + self.assertEqual(self.g.evaluate()["b"], 7) + + def test_output_without_prop_is_ignored(self): + self.g.add_formula("nowhere", [val(1)]) + self.assertNotIn("nowhere", self.g.evaluate()) + + def test_cycle_is_fatal(self): + self.g.add_formula("a", [push("b")]) + self.g.add_formula("b", [push("a")]) + with self.assertRaisesRegex(Error, "formula cycle: a -> b -> a"): + self.g.evaluate() + + def test_unknown_op_is_fatal(self): + self.g.add_formula("b", [val(1), {"op": "pow"}], source="/data/x.dsf#m") + with self.assertRaisesRegex(Error, r"/data/x.dsf#m: unknown formula operation 'pow'"): + self.g.evaluate() + + def test_unknown_stage_is_fatal(self): + with self.assertRaisesRegex(Error, "unknown formula stage 'avg'"): + self.g.add_formula("b", [val(1)], stage="avg") + + def test_stack_errors_are_fatal(self): + self.g.add_formula("b", [{"op": "add"}], source="f") + with self.assertRaisesRegex(Error, "f: malformed formula for b"): + self.g.evaluate() + + def test_leftover_stack_is_fatal(self): + self.g.add_formula("b", [val(1), val(2)], source="f") + with self.assertRaisesRegex(Error, "f: malformed formula for b"): + self.g.evaluate() |
