1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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()
|