Skip to content

Commit 1ba6369

Browse files
committed
test(all): update all tests to mathc the refactor
1 parent 9d2ca64 commit 1ba6369

13 files changed

Lines changed: 573 additions & 496 deletions

File tree

bot/core/cad.py

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -305,46 +305,40 @@ def get_corners(self, face_tag):
305305

306306
return corners
307307

308-
def get_curve_discretization(self):
309-
# Get mesh node tags and their coordinates
308+
def get_curve_discretization(
309+
self,
310+
) -> dict[int, tuple[list[tuple[float, float, float]], list[tuple[int, int]]]]:
311+
"""Per-curve 1D mesh: gmsh_tag -> (local_points, local_edges)."""
312+
curves: dict[
313+
int, tuple[list[tuple[float, float, float]], list[tuple[int, int]]]
314+
] = {}
310315
node_tags, coords, _ = gmsh.model.mesh.getNodes()
311-
node_id_to_index = {tag: i for i, tag in enumerate(node_tags)}
312-
# Get all the entities of dim 1
313-
elem_types, elem_tags, elem_node_tags = gmsh.model.mesh.getElements(dim=1)
314-
315-
# On transforme la liste plate [x,y,z,x,y,z] en liste de tuples [(x,y,z), ...]
316-
points_3d = []
317-
for i in range(0, len(coords), 3):
318-
points_3d.append((coords[i], coords[i + 1], coords[i + 2]))
319-
320-
# 2. Liste finale des données
321-
# Structure : (index_sommet_A, index_sommet_B, tag_courbe_origine)
322-
edges_with_metadata = []
323-
324-
# 3. Parcourir chaque "Courbe" (entité de dimension 1)
325-
entities = gmsh.model.getEntities(1)
326-
327-
for entity in entities:
328-
curve_tag = entity[1] # C'est le Tag de la courbe CAO
329-
330-
# Récupérer les éléments (segments) appartenant UNIQUEMENT à cette courbe
331-
_, _, node_tags_per_elem = gmsh.model.mesh.getElements(1, curve_tag)
316+
node_id_to_coords = {
317+
tag: (coords[i * 3], coords[i * 3 + 1], coords[i * 3 + 2])
318+
for i, tag in enumerate(node_tags)
319+
}
332320

333-
if len(node_tags_per_elem) > 0:
334-
connectivity = node_tags_per_elem[0]
321+
for entity in gmsh.model.getEntities(1):
322+
gmsh_tag = entity[1]
323+
_, _, node_tags_per_elem = gmsh.model.mesh.getElements(1, gmsh_tag)
324+
if not node_tags_per_elem:
325+
continue
335326

336-
# Parcourir les nœuds par paires pour former les arêtes
337-
for i in range(0, len(connectivity), 2):
338-
tag_a = connectivity[i]
339-
tag_b = connectivity[i + 1]
327+
connectivity = node_tags_per_elem[0]
328+
seen: dict[int, int] = {}
329+
local_points: list[tuple[float, float, float]] = []
330+
local_edges: list[tuple[int, int]] = []
340331

341-
# Conversion en indices (0, 1, 2...) pour Panda3D
342-
idx_a = node_id_to_index[tag_a]
343-
idx_b = node_id_to_index[tag_b]
332+
for i in range(0, len(connectivity), 2):
333+
for node_tag in (connectivity[i], connectivity[i + 1]):
334+
if node_tag not in seen:
335+
seen[node_tag] = len(local_points)
336+
local_points.append(node_id_to_coords[node_tag])
337+
local_edges.append((seen[connectivity[i]], seen[connectivity[i + 1]]))
344338

345-
edges_with_metadata.append((idx_a, idx_b, curve_tag))
339+
curves[gmsh_tag] = (local_points, local_edges)
346340

347-
return points_3d, edges_with_metadata
341+
return curves
348342

349343
def _discretize_curves(self):
350344
self.__synchronize()

bot/viewer/viewable.py

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import logging
66
from typing import Callable, Protocol
77

8-
import gmsh
9-
108
from bot.core.cad import CADModel
119
from bot.core.spline import SplineModel
1210
from bot.viewer.contracts import CurveDelta, ScenePayload, ViewerCommand, ViewEvent
@@ -57,7 +55,7 @@ def unbind_update(self) -> None:
5755
self._update_callback = None
5856

5957
def get_delta_load(self) -> ScenePayload:
60-
changed_curves = self._build_all_curves()
58+
changed_curves = self._build_changed_curves()
6159
flat_points, flat_edges = self._build_flat_topology(changed_curves)
6260
payload: ScenePayload = {
6361
"op": "add",
@@ -97,7 +95,7 @@ def update(self, _model: CADModel) -> None:
9795
self._update_callback(
9896
{
9997
"op": "update",
100-
"changed_curves": self._build_all_curves(),
98+
"changed_curves": self._build_changed_curves(),
10199
}
102100
)
103101

@@ -118,35 +116,13 @@ def _resolve_cad_tag_str(self, tag_str: str) -> int | None:
118116
return None
119117
return local_id
120118

121-
def _build_all_curves(self) -> dict[str, CurveDelta]:
119+
def _build_changed_curves(self) -> dict[str, CurveDelta]:
122120
changed: dict[str, CurveDelta] = {}
123121
try:
124-
node_tags, coords, _ = gmsh.model.mesh.getNodes()
125-
node_id_to_coords = {
126-
tag: (coords[i * 3], coords[i * 3 + 1], coords[i * 3 + 2])
127-
for i, tag in enumerate(node_tags)
128-
}
129-
130-
for entity in gmsh.model.getEntities(1):
131-
gmsh_tag = entity[1]
132-
_, _, node_tags_per_elem = gmsh.model.mesh.getElements(1, gmsh_tag)
133-
if not node_tags_per_elem:
134-
continue
135-
136-
connectivity = node_tags_per_elem[0]
137-
seen: dict[int, int] = {}
138-
local_points: list[tuple[float, float, float]] = []
139-
local_edges: list[tuple[int, int]] = []
140-
141-
for i in range(0, len(connectivity), 2):
142-
for node_tag in (connectivity[i], connectivity[i + 1]):
143-
if node_tag not in seen:
144-
seen[node_tag] = len(local_points)
145-
local_points.append(node_id_to_coords[node_tag])
146-
local_edges.append(
147-
(seen[connectivity[i]], seen[connectivity[i + 1]])
148-
)
149-
122+
for gmsh_tag, (
123+
local_points,
124+
local_edges,
125+
) in self._model.get_curve_discretization().items():
150126
ns_tag = encode(CAD_NS, gmsh_tag)
151127
changed[ns_tag] = pack_curve_delta(
152128
local_points,

tests/system/test_cad_workflow.py

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,21 @@
22
System tests — full CAD workflow.
33
44
These tests exercise the Model end-to-end: file loading, topology queries,
5-
point addition and render-data consistency. No Panda3D required.
5+
point addition and curve-discretization consistency. No Panda3D required.
66
"""
77

8+
import pickle
89
import unittest
9-
from bot.core.cad import Model as CADModel
10+
11+
from bot.core.cad import CADModel
1012

1113
GEO_FILE = "data/profil_1.geo"
1214

1315

16+
def _total_vertices(discretization):
17+
return sum(len(pts) for pts, _ in discretization.values())
18+
19+
1420
class TestLoadAndTopology(unittest.TestCase):
1521
"""Open profil_1.geo and verify the full topology is coherent."""
1622

@@ -48,8 +54,8 @@ def test_get_adjacent_points_returns_two_per_curve(self):
4854
self.assertEqual(2, len(self.cad.get_adjacent_points(tag)))
4955

5056

51-
class TestRenderDataCoherence(unittest.TestCase):
52-
"""Verify get_render_data() returns a consistent, picklable snapshot."""
57+
class TestCurveDiscretizationCoherence(unittest.TestCase):
58+
"""Verify get_curve_discretization() and bounds stay consistent."""
5359

5460
def setUp(self):
5561
self.cad = CADModel()
@@ -58,41 +64,48 @@ def setUp(self):
5864
def tearDown(self):
5965
self.cad.finalize()
6066

61-
def test_render_data_has_all_keys(self):
62-
data = self.cad.get_render_data()
63-
self.assertIn("points", data)
64-
self.assertIn("edges", data)
65-
self.assertIn("bounds", data)
67+
def test_discretization_has_one_entry_per_curve(self):
68+
discretization = self.cad.get_curve_discretization()
69+
self.assertEqual(len(self.cad.get_curve_tags()), len(discretization))
70+
for tag in self.cad.get_curve_tags():
71+
self.assertIn(tag, discretization)
6672

6773
def test_edges_reference_valid_point_indices(self):
68-
data = self.cad.get_render_data()
69-
n = len(data["points"])
70-
for idx_a, idx_b, _curve_tag in data["edges"]:
71-
self.assertGreaterEqual(idx_a, 0)
72-
self.assertLess(idx_a, n)
73-
self.assertGreaterEqual(idx_b, 0)
74-
self.assertLess(idx_b, n)
74+
for pts, edges in self.cad.get_curve_discretization().values():
75+
n = len(pts)
76+
for idx_a, idx_b in edges:
77+
self.assertGreaterEqual(idx_a, 0)
78+
self.assertLess(idx_a, n)
79+
self.assertGreaterEqual(idx_b, 0)
80+
self.assertLess(idx_b, n)
81+
82+
def test_bounds_has_expected_keys(self):
83+
bounds = self.cad.bounds
84+
for key in ("min", "max", "center", "size"):
85+
self.assertIn(key, bounds)
7586

7687
def test_bounds_center_is_inside_min_max(self):
77-
bounds = self.cad.get_render_data()["bounds"]
88+
bounds = self.cad.bounds
7889
for axis in range(3):
7990
self.assertGreaterEqual(bounds["center"][axis], bounds["min"][axis] - 1e-9)
8091
self.assertLessEqual(bounds["center"][axis], bounds["max"][axis] + 1e-9)
8192

8293
def test_bounds_size_matches_min_max(self):
83-
bounds = self.cad.get_render_data()["bounds"]
94+
bounds = self.cad.bounds
8495
for axis in range(3):
8596
expected = bounds["max"][axis] - bounds["min"][axis]
8697
self.assertAlmostEqual(bounds["size"][axis], expected, places=9)
8798

88-
def test_render_data_is_picklable(self):
89-
import pickle
90-
91-
data = self.cad.get_render_data()
92-
serialised = pickle.dumps(data)
99+
def test_discretization_is_picklable(self):
100+
discretization = self.cad.get_curve_discretization()
101+
serialised = pickle.dumps(discretization)
93102
restored = pickle.loads(serialised)
94-
self.assertEqual(data["bounds"], restored["bounds"])
95-
self.assertEqual(len(data["points"]), len(restored["points"]))
103+
self.assertEqual(len(discretization), len(restored))
104+
for tag, (pts, edges) in discretization.items():
105+
self.assertIn(tag, restored)
106+
restored_pts, restored_edges = restored[tag]
107+
self.assertEqual(pts, restored_pts)
108+
self.assertEqual(edges, restored_edges)
96109

97110

98111
class TestAddPointWorkflow(unittest.TestCase):
@@ -102,7 +115,6 @@ def setUp(self):
102115
self.cad = CADModel()
103116
self.cad.open(GEO_FILE)
104117
self.initial_point_count = len(self.cad.get_point_tags())
105-
self.initial_render_pts = len(self.cad.get_render_data()["points"])
106118

107119
def tearDown(self):
108120
self.cad.finalize()
@@ -118,17 +130,16 @@ def test_add_point_returns_valid_tag(self):
118130
tag = self.cad.add_point([1.0, 1.0, 0.0])
119131
self.assertIn(tag, self.cad.get_point_tags())
120132

121-
def test_add_point_updates_render_data(self):
133+
def test_add_point_updates_discretization(self):
122134
self.cad.add_point([100.0, 100.0, 0.0])
123-
new_count = len(self.cad.get_render_data()["points"])
124-
# Mesh is regenerated: number of discretisation nodes changes
135+
new_count = _total_vertices(self.cad.get_curve_discretization())
125136
self.assertGreater(new_count, 0)
126137

127138
def test_bounds_extend_when_point_is_outside(self):
128-
old_bounds = self.cad.get_render_data()["bounds"]
139+
old_bounds = self.cad.bounds
129140
far_x = old_bounds["max"][0] + 1000.0
130141
self.cad.add_point([far_x, 0.0, 0.0])
131-
new_bounds = self.cad.get_render_data()["bounds"]
142+
new_bounds = self.cad.bounds
132143
self.assertGreaterEqual(new_bounds["max"][0], far_x - 1e-6)
133144

134145
def test_cumulative_additions(self):

0 commit comments

Comments
 (0)