diff --git a/test/models/observer_config_test.dart b/test/models/observer_config_test.dart new file mode 100644 index 0000000..5eb0d6c --- /dev/null +++ b/test/models/observer_config_test.dart @@ -0,0 +1,91 @@ +// Lock tests for the Offband config models (#64 M1). +// +// The models are the data structures untrusted wire fields decode into, so the +// defensive behavior (enum fallback, numeric fallback, secret presence) is +// pinned here. All green — M1 confirms the existing draft is contract-correct. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:meshcore_open/models/observer_config.dart'; + +void main() { + group('enums fromWire / wire', () { + test('BrokerTransport round-trips + rejects unknown', () { + expect(BrokerTransport.fromWire('tcp'), BrokerTransport.tcp); + expect(BrokerTransport.fromWire('tls'), BrokerTransport.tls); + expect(BrokerTransport.fromWire('wss'), BrokerTransport.wss); + expect(BrokerTransport.fromWire('bogus'), isNull); + expect(BrokerTransport.tls.wire, 'tls'); + }); + + test('BrokerAuthType round-trips + rejects unknown', () { + expect(BrokerAuthType.fromWire('none'), BrokerAuthType.none); + expect(BrokerAuthType.fromWire('jwt'), BrokerAuthType.jwt); + expect(BrokerAuthType.fromWire('nope'), isNull); + expect(BrokerAuthType.basic.wire, 'basic'); + }); + + test('WifiStatus maps tokens, unknown -> unknown', () { + expect(WifiStatus.fromWire('StaConnected'), WifiStatus.staConnected); + expect(WifiStatus.fromWire('StaFailed'), WifiStatus.staFailed); + expect(WifiStatus.fromWire('weird'), WifiStatus.unknown); + }); + }); + + group('BrokerConfig.fromWireFields', () { + test('maps a fully-populated slot', () { + final b = BrokerConfig.fromWireFields(3, { + 'enabled': '1', + 'url': 'mqtt://h', + 'port': '8883', + 'transport': 'tls', + 'auth_type': 'jwt', + 'username': 'u', + 'password': '(set)', + 'topic_prefix': 'p', + 'jwt_refresh': '900', + }); + expect(b.slot, 3); + expect(b.enabled, isTrue); + expect(b.url, 'mqtt://h'); + expect(b.port, 8883); + expect(b.transport, BrokerTransport.tls); + expect(b.authType, BrokerAuthType.jwt); + expect(b.username, 'u'); + expect(b.passwordSet, isTrue); + expect(b.jwtRefresh, 900); + expect(b.isPopulated, isTrue); + }); + + test('defaults + enum fallback on a sparse/garbage slot', () { + final b = BrokerConfig.fromWireFields(0, { + 'transport': 'bogus', + 'auth_type': '?', + 'password': '(unset)', + }); + expect(b.url, ''); + expect(b.port, 0); + expect(b.transport, BrokerTransport.tcp); // unknown -> default + expect(b.authType, BrokerAuthType.none); // unknown -> default + expect(b.passwordSet, isFalse); // not "(set)" + expect(b.isPopulated, isFalse); // no url + }); + }); + + group('SecretField three-state', () { + test('unchanged / clear / set', () { + expect(const SecretField.unchanged(), isA()); + expect(const SecretField.clear(), isA()); + const s = SecretField.set('x'); + expect(s, isA()); + expect((s as SecretSet).value, 'x'); + }); + }); + + test('BrokerConfig.copyWith overrides selectively', () { + const b = BrokerConfig(slot: 1, url: 'a', port: 1); + final c = b.copyWith(url: 'b'); + expect(c.slot, 1); + expect(c.url, 'b'); + expect(c.port, 1); // untouched + }); +}