"""orca_filaments.py parser robustness (code review finding). No dedicated test file existed for parse_profile()/parse_profile_bytes()/ clean_name() before this - existing tests only used pre-parsed profile dicts as fixtures, never exercised the actual parsing logic. """ import json import logging from orca_filaments import clean_name, first_str, parse_profile, parse_profile_bytes def test_clean_name_strips_base_suffix(): assert clean_name("PolyTerra PLA @base") == "PolyTerra PLA" def test_clean_name_strips_printer_and_nozzle_suffix(): assert clean_name("Anycubic PLA @Anycubic Kobra X 0.4 nozzle") == "Anycubic PLA" def test_clean_name_strips_bare_nozzle_suffix(): assert clean_name("Anker Generic PLA 0.4 nozzle") == "Anker Generic PLA" def test_clean_name_returns_raw_when_stripping_leaves_nothing(): """An all-suffix name has nothing left after stripping - falls back to the original raw string rather than returning an empty string.""" assert clean_name("@base") == "@base" def test_first_str_unwraps_single_element_list(): assert first_str(["PLA"]) == "PLA" def test_first_str_passes_through_plain_string(): assert first_str("PLA") == "PLA" def test_first_str_returns_default_for_empty_list(): assert first_str([], "fallback") == "fallback" def test_first_str_returns_default_for_other_types(): assert first_str(42, "fallback") == "fallback" assert first_str(None, "fallback") == "fallback" def test_parse_profile_rejects_non_dict(): assert parse_profile([1, 2, 3]) is None assert parse_profile("not a dict") is None assert parse_profile(None) is None def test_parse_profile_rejects_stub_without_id_or_parent(): data = {"type": "filament"} # no inherits, no filament_id assert parse_profile(data) is None def test_parse_profile_rejects_instantiation_false(): data = {"type": "filament", "filament_id": "GFL01", "instantiation": "false"} assert parse_profile(data) is None def test_parse_profile_minimal_valid_profile(): data = { "type": "filament", "filament_id": "GFL01", "name": "Generic PLA", "filament_vendor": ["Generic"], "filament_type": ["PLA"], "default_filament_colour": ["#FFFFFF"], } result = parse_profile(data) assert result == { "id": "GFL01", "name": "Generic PLA", "vendor": "Generic", "type": "PLA", "color": "#FFFFFF", } def test_parse_profile_name_as_list_does_not_crash(): """Regression guard: `name` wasn't previously routed through first_str() like the other fields are, unlike filament_vendor/filament_type/ default_filament_colour just below it - a list value here used to raise TypeError inside clean_name()'s re.sub().""" data = { "type": "filament", "filament_id": "GFL02", "name": ["Geeetech PLA Basic"], "filament_vendor": ["Geeetech"], "filament_type": ["PLA"], } result = parse_profile(data) assert result is not None assert result["name"] == "Geeetech PLA Basic" def test_parse_profile_missing_name_falls_back_to_filament_id(): data = {"type": "filament", "filament_id": "GFL03", "filament_vendor": ["Generic"]} result = parse_profile(data) assert result["name"] == "GFL03" def test_parse_profile_missing_optional_fields_default_to_empty_string(): data = {"type": "filament", "filament_id": "GFL04", "name": "Mystery Filament"} result = parse_profile(data) assert result["type"] == "" assert result["color"] == "" assert result["vendor"] == "Generic" # no path_vendor given either def test_parse_profile_inherits_via_by_name(): parent = {"type": "filament", "filament_id": "GFL05", "filament_vendor": ["Geeetech"], "filament_type": ["PLA"]} child = {"type": "filament", "inherits": "Geeetech PLA @base", "name": "Geeetech PLA Basic"} by_name = {"Geeetech PLA @base": [parent]} result = parse_profile(child, by_name=by_name) assert result is not None assert result["id"] == "GFL05" assert result["vendor"] == "Geeetech" assert result["type"] == "PLA" def test_parse_profile_inherits_via_system_index(): system_index = [{ "id": "GFL06", "name": "Geeetech PLA", "vendor": "Geeetech", "type": "PLA", "color": "", }] user_profile = {"type": "filament", "inherits": "Geeetech PLA @base", "name": "My Geeetech Override"} result = parse_profile(user_profile, system_index=system_index) assert result is not None assert result["id"] == "GFL06" assert result["vendor"] == "Geeetech" def test_parse_profile_inherits_cycle_does_not_infinite_loop(): """A inherits B, B inherits A - _resolve()'s hard depth=5 bound must terminate this rather than recursing forever.""" a = {"type": "filament", "inherits": "B"} b = {"type": "filament", "inherits": "A"} by_name = {"A": [a], "B": [b]} # Neither profile has a filament_id anywhere in the cycle - must return # None (not hang, not crash) after exhausting the depth limit. result = parse_profile(a, by_name=by_name) assert result is None def test_parse_profile_duplicate_system_names_logs_and_uses_last(caplog): """clean_name() deliberately collapses variant-suffixed names onto the same cleaned name - sys_by_name's last-write-wins overwrite on collision is expected, but must now be observable via a debug log instead of silent.""" system_index = [ {"id": "GFL07", "name": "PolyTerra PLA", "vendor": "Polymaker", "type": "PLA", "color": ""}, {"id": "GFL08", "name": "PolyTerra PLA", "vendor": "Polymaker", "type": "PLA", "color": ""}, ] user_profile = {"type": "filament", "inherits": "PolyTerra PLA @base", "name": "Override"} with caplog.at_level(logging.DEBUG, logger="kobrax.filaments"): result = parse_profile(user_profile, system_index=system_index) assert result is not None assert result["id"] == "GFL08" # last one wins, as before assert any("duplicate system profile name" in r.message for r in caplog.records) def test_parse_profile_bytes_valid_json(): blob = json.dumps({ "type": "filament", "filament_id": "GFL09", "name": "Test PLA", "filament_vendor": ["Test"], "filament_type": ["PLA"], }).encode("utf-8") result = parse_profile_bytes(blob) assert result is not None assert result["id"] == "GFL09" def test_parse_profile_bytes_malformed_json_returns_none(): assert parse_profile_bytes(b"{not valid json") is None def test_parse_profile_bytes_non_dict_json_returns_none(): assert parse_profile_bytes(b"[1, 2, 3]") is None assert parse_profile_bytes(b'"just a string"') is None assert parse_profile_bytes(b"42") is None