diff --git a/plugins/backups/services/ntlars.py b/plugins/backups/services/ntlars.py index 593a75c..6e65ff9 100644 --- a/plugins/backups/services/ntlars.py +++ b/plugins/backups/services/ntlars.py @@ -149,6 +149,13 @@ def _parsevalue(body): return _parsehexvalue(body) if body == '-': return 'DELETE', None + if body == '': + # "Name=" with nothing after the sign. Not strictly legal, but it + # occurs in real exports (the part marker's WJPRT.reg has KRelay1 like + # this), and failing the whole file over it would mean that machine can + # never be backed up. Treat it as an empty string so the value NAME is + # still preserved. + return 'REG_SZ', '' raise NtlarsParseError('unrecognised value form: {!r}'.format(body)) diff --git a/tests/test_plugins/test_backups.py b/tests/test_plugins/test_backups.py index 6961d1d..da531aa 100644 --- a/tests/test_plugins/test_backups.py +++ b/tests/test_plugins/test_backups.py @@ -710,3 +710,50 @@ def test_panel_label_is_rendered_in_the_site_zone(bk_app, bk_plugin): revision = _db.session.get(BackupRevision, result['backuprevisionid']) # 16:30 UTC on 2026-08-07 is 12:30 EDT. assert '12:30' in _label(revision) + + +# ============================================================================= +# REGEDIT4 / part marker exports +# ============================================================================= + +REGEDIT4REG = ( + 'REGEDIT4\r\n\r\n' + r'[HKEY_LOCAL_MACHINE\SOFTWARE\GE Aircraft Engines\DNC\General]' '\r\n' + '"MachineNo"="WJPRT"\r\n' + '"Cnc"="MARKER"\r\n\r\n' + r'[HKEY_LOCAL_MACHINE\SOFTWARE\GE Aircraft Engines\DNC\Mark]' '\r\n' + '"Port Id"="COM4"\r\n' + '"Baud"="9600"\r\n' + '"KRelay1"=\r\n' +) + + +def test_regedit4_header_is_accepted(): + """The part marker's per-machine file is REGEDIT4, not 'Windows Registry + Editor Version 5.00'.""" + projection = ntlars.parse(REGEDIT4REG.encode('utf-8')) + assert registry.NtlarsKind.embeddedmachineno(projection) == 'WJPRT' + + +def test_value_with_an_empty_right_hand_side_does_not_fail_the_file(): + """A real export contains "KRelay1=" with nothing after the sign. Raising on + it would mean that machine could never be backed up at all.""" + projection = ntlars.parse(REGEDIT4REG.encode('utf-8')) + mark = next(k for k in projection['keys'] if k['path'] == 'Mark') + assert mark['values']['KRelay1'] == {'type': 'REG_SZ', 'data': ''} + + +def test_part_marker_serial_port_survives_the_roundtrip(): + """The COM port the marker hangs off is the point of keeping this config.""" + first = ntlars.parse(REGEDIT4REG.encode('utf-8')) + second = ntlars.parse(ntlars.render(first, dialect='wow6432node')) + mark = next(k for k in second['keys'] if k['path'] == 'Mark') + assert mark['values']['Port Id']['data'] == 'COM4' + + +def test_a_marker_export_shows_the_mark_tab(): + card = dncinfo.build(ntlars.parse(REGEDIT4REG.encode('utf-8')), assetid=0) + labels = [s['label'] for s in card['sections']] + assert any('MARK' in label for label in labels) + mark = next(s for s in card['sections'] if 'MARK' in s['label']) + assert any(f['label'] == 'Port Id' and f['value'] == 'COM4' for f in mark['fields'])