- geometry: property guard hex nut across-flats (regression guard) - gui tests: rewrite to ASCII + cover _type_name/_mass helper paths - coverage: source=fastengen, omit gui.py (UI headless); total 87% - build: license-files for setuptools, sdist+wheel OK - tasks.md: P4 recorded
80 lines
2.7 KiB
Python
80 lines
2.7 KiB
Python
"""Tests for the tkinter GUI logic (window creation avoided: pure logic + helpers)."""
|
|
from __future__ import annotations
|
|
|
|
from fastengen.gui import MainWindow
|
|
|
|
|
|
def _fake_cat(records, models_dir):
|
|
"""Minimal catalog stub for GUI logic tests."""
|
|
class _Rec:
|
|
def __init__(self, r):
|
|
self.id = r["id"]
|
|
self.designation = r["designation"]
|
|
self.standard = r["standard"]
|
|
self.material = r["material"]
|
|
self.type = r["type"]
|
|
self.model_file = r.get("model_file", "bolt_M8_100.step")
|
|
self.attributes = r.get("attributes", {})
|
|
|
|
class _Cat:
|
|
def __init__(self, recs, md):
|
|
self._recs = [_Rec(r) for r in recs]
|
|
self.models_dir = md
|
|
self.catalog_path = ":memory:"
|
|
|
|
def all(self):
|
|
return list(self._recs)
|
|
|
|
def __len__(self):
|
|
return len(self._recs)
|
|
|
|
def __getitem__(self, rid):
|
|
for r in self._recs:
|
|
if r.id == rid:
|
|
return r
|
|
raise KeyError(rid)
|
|
|
|
def __contains__(self, rid):
|
|
return any(r.id == rid for r in self._recs)
|
|
|
|
return _Cat(records, models_dir)
|
|
|
|
|
|
def test_type_name_filter():
|
|
assert MainWindow._type_name("bolt", "all") is True
|
|
assert MainWindow._type_name("nut", "nut") is True
|
|
assert MainWindow._type_name("bolt", "bolt") is True
|
|
assert MainWindow._type_name("bolt_set", "bolt") is True
|
|
assert MainWindow._type_name("nut", "bolt") is False
|
|
assert MainWindow._type_name("self_tacker", "selftacker") is True
|
|
assert MainWindow._type_name("potay", "selftacker") is True
|
|
assert MainWindow._type_name("washer", "selftacker") is False
|
|
# screw / potay belong to selftacker filter
|
|
assert MainWindow._type_name("screw", "selftacker") is True
|
|
assert MainWindow._type_name("nut", "washer") is False
|
|
assert MainWindow._type_name("stud", "stud") is True
|
|
|
|
|
|
def _no_root_mass(r):
|
|
# _mass depends only on self.cat.models_dir; provide a stub carrying .cat
|
|
class _Stub:
|
|
cat = _fake_cat([], "out")
|
|
return MainWindow._mass(_Stub(), r)
|
|
|
|
|
|
def test_mass_helpers_paths():
|
|
# record without model_file -> mass_for_rec returns None -> em-dash
|
|
class _RecNoModel:
|
|
model_file = None
|
|
type = "bolt"
|
|
assert _no_root_mass(_RecNoModel()) == "\u2014"
|
|
|
|
# real model in out/ -> numeric string with per-piece mass (no crash)
|
|
real = _fake_cat([{"id": "bolt_M8_100", "designation": "Bolt M8",
|
|
"standard": "GOST 7805-70", "material": "Steel 8.8",
|
|
"type": "bolt", "attributes": {}}], "out")["bolt_M8_100"]
|
|
m = _no_root_mass(real)
|
|
assert isinstance(m, str)
|
|
assert m != "\u2014"
|
|
assert m.strip().replace(".", "").isdigit()
|