126 lines
5.5 KiB
Python
126 lines
5.5 KiB
Python
import json
|
|
import unittest
|
|
from copy import deepcopy
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
|
|
ROOT = Path(__file__).parents[1]
|
|
RESULT = ROOT / "tests" / "fixtures" / "rayforge-lightburn-device-import.json"
|
|
SOURCE = ROOT / "tests" / "fixtures" / "synthetic-jcz-device.lbdev"
|
|
ADDON = ROOT / "spikes" / "rayforge-jcz-no-device-addon"
|
|
sys.path.insert(0, str(ADDON))
|
|
|
|
from pirate_ray_jcz.profile_import import ( # noqa: E402
|
|
JCZProfileImportError,
|
|
import_lightburn_jcz_profile,
|
|
)
|
|
|
|
|
|
class RayforgeLightBurnDeviceImportSpikeTests(unittest.TestCase):
|
|
def test_public_fixture_is_synthetic_and_contains_no_private_identity(self):
|
|
source = json.loads(SOURCE.read_text(encoding="utf-8"))
|
|
self.assertEqual(
|
|
"synthetic public data; not a machine export",
|
|
source["FixtureProvenance"],
|
|
)
|
|
rendered = SOURCE.read_text(encoding="utf-8").lower()
|
|
self.assertNotIn("serial", rendered)
|
|
self.assertNotIn("guid", rendered)
|
|
|
|
def test_common_profile_fields_survive(self):
|
|
result = json.loads(RESULT.read_text(encoding="utf-8"))
|
|
self.assertIsNone(result["transport"])
|
|
self.assertEqual("JCZFiber", result["raw_profile"]["type"])
|
|
self.assertEqual([110, 110], result["mapped_profile"]["work_area_mm"])
|
|
self.assertEqual(
|
|
"Synthetic JCZ MOPA", result["mapped_profile"]["name"]
|
|
)
|
|
|
|
def test_jcz_specific_fields_fail_closed(self):
|
|
result = json.loads(RESULT.read_text(encoding="utf-8"))
|
|
gaps = result["gap_matrix"]
|
|
self.assertIsNone(result["mapped_profile"]["driver"])
|
|
self.assertFalse(gaps["jczfiber_driver_mapped"])
|
|
self.assertFalse(gaps["require_frame_before_start_mapped"])
|
|
self.assertFalse(gaps["cut_list_mapped"])
|
|
self.assertFalse(gaps["frequency_mapped"])
|
|
self.assertFalse(gaps["q_pulse_width_mapped"])
|
|
self.assertFalse(gaps["safe_for_jcz_use"])
|
|
|
|
def test_addon_seam_preserves_raw_values_but_blocks_encoding(self):
|
|
result = json.loads(RESULT.read_text(encoding="utf-8"))
|
|
seam = result["addon_profile_seam"]
|
|
self.assertEqual("PirateRayJCZNoDeviceDriver", seam["driver"])
|
|
self.assertIsNone(seam["transport"])
|
|
self.assertFalse(seam["encoding_allowed"])
|
|
self.assertEqual("normalized-offline-not-authorized", seam["process_metadata"]["status"])
|
|
entry = seam["process_metadata"]["cut_list"][0]
|
|
self.assertEqual(40000, entry["frequency"]["raw_value"])
|
|
self.assertEqual(40000, entry["frequency"]["value_hz"])
|
|
self.assertEqual(40, entry["frequency"]["value_khz"])
|
|
self.assertEqual(100, entry["q_pulse_width"]["raw_value"])
|
|
self.assertEqual(100, entry["q_pulse_width"]["value_ns"])
|
|
contract = seam["observed_device_contract"]
|
|
self.assertEqual([1, 4000], contract["frequency_ui_range_khz"])
|
|
self.assertEqual("IPG_YLPM", contract["fiber_type_ui_label"])
|
|
self.assertEqual(
|
|
"label-is-not-manufacturer-identity",
|
|
contract["fiber_type_identity_status"],
|
|
)
|
|
|
|
def test_addon_seam_rejects_wrong_backend_and_missing_frame_gate(self):
|
|
source = json.loads(SOURCE.read_text(encoding="utf-8"))
|
|
wrong_backend = deepcopy(source)
|
|
wrong_backend["DeviceList"][0]["Type"] = "Ruida"
|
|
with self.assertRaises(JCZProfileImportError):
|
|
import_lightburn_jcz_profile(wrong_backend)
|
|
|
|
no_frame_gate = deepcopy(source)
|
|
no_frame_gate["DeviceList"][0]["Settings"][
|
|
"RequireFrameBeforeStart"
|
|
] = False
|
|
with self.assertRaises(JCZProfileImportError):
|
|
import_lightburn_jcz_profile(no_frame_gate)
|
|
|
|
wrong_identity = deepcopy(source)
|
|
wrong_identity["SyntheticProfileId"] = "some-other-profile"
|
|
with self.assertRaises(JCZProfileImportError):
|
|
import_lightburn_jcz_profile(wrong_identity)
|
|
|
|
ambiguous_frequency = deepcopy(source)
|
|
ambiguous_frequency["DeviceList"][0]["CutList"][0][
|
|
"frequency"
|
|
] = True
|
|
with self.assertRaises(JCZProfileImportError):
|
|
import_lightburn_jcz_profile(ambiguous_frequency)
|
|
|
|
for frequency in (500, 4_001_000):
|
|
outside_range = deepcopy(source)
|
|
outside_range["DeviceList"][0]["CutList"][0]["frequency"] = frequency
|
|
with self.subTest(frequency=frequency):
|
|
with self.assertRaisesRegex(JCZProfileImportError, "outside"):
|
|
import_lightburn_jcz_profile(outside_range)
|
|
|
|
def test_observed_profile_contract_fails_closed_on_mismatch(self):
|
|
source = json.loads(SOURCE.read_text(encoding="utf-8"))
|
|
mutations = (
|
|
("wrong version", lambda doc: doc.update(AppVersion="2.2.00")),
|
|
("wrong width", lambda doc: doc["DeviceList"][0].update(Width=300)),
|
|
("q pulse disabled", lambda doc: doc["DeviceList"][0]["Settings"].update(
|
|
Laser_QPulseWidthEnabled=False)),
|
|
("wrong fiber code", lambda doc: doc["DeviceList"][0]["Settings"].update(
|
|
Laser_FiberType=2)),
|
|
("reversed frequency range", lambda doc: doc["DeviceList"][0]["Settings"].update(
|
|
Laser_MinFreq=4000, Laser_MaxFreq=1)),
|
|
)
|
|
for label, mutate in mutations:
|
|
candidate = deepcopy(source)
|
|
mutate(candidate)
|
|
with self.subTest(label=label):
|
|
with self.assertRaises(JCZProfileImportError):
|
|
import_lightburn_jcz_profile(candidate)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|