import 'package:commons_core/commons_core.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:tane/state/trust_cubit.dart'; /// In-memory [TrustTransport]: certify/revoke act as this device's identity. class FakeTrustTransport implements TrustTransport { FakeTrustTransport(this.selfId); final String selfId; final Map> _certs = {}; // subject -> issuers /// Test helper: record an arbitrary issuer→subject vouch (to build a graph). void addCert(String issuer, String subject) => (_certs[subject] ??= {}).add(issuer); @override Future> certifiersOf(String subjectPubkey) async => _certs[subjectPubkey] ?? {}; @override Future certify({ required String subjectPubkey, Duration validity = const Duration(days: 365), String note = '', }) async => addCert(selfId, subjectPubkey); @override Future revoke({required String subjectPubkey}) async => _certs[subjectPubkey]?.remove(selfId); @override Future> allCertifications() async => [ for (final entry in _certs.entries) for (final issuer in entry.value) Certification( issuer: issuer, subject: entry.key, issuedAt: DateTime(2026), ), ]; @override Future close() async {} } void main() { const me = 'me'; const peer = 'peer'; test('loads certifier count and whether I vouch', () async { final transport = FakeTrustTransport(me); await transport.certify(subjectPubkey: peer); // I already vouch final cubit = TrustCubit(transport, peerPubkey: peer, selfPubkey: me); await cubit.load(); expect(cubit.state.certifierCount, 1); expect(cubit.state.iVouch, isTrue); expect(cubit.state.loading, isFalse); await cubit.close(); }); test('toggleVouch certifies then revokes', () async { final cubit = TrustCubit(FakeTrustTransport(me), peerPubkey: peer, selfPubkey: me); await cubit.load(); expect(cubit.state.iVouch, isFalse); await cubit.toggleVouch(); expect(cubit.state.iVouch, isTrue); expect(cubit.state.certifierCount, 1); await cubit.toggleVouch(); expect(cubit.state.iVouch, isFalse); expect(cubit.state.certifierCount, 0); await cubit.close(); }); test('a friend-of-a-friend is in your circle; a stranger is not', () async { final transport = FakeTrustTransport(me) ..addCert(me, 'friend') // you vouch for a friend ..addCert('friend', peer) // your friend vouches for the peer ..addCert('stranger', 'other'); // unrelated to you final inCircle = TrustCubit(transport, peerPubkey: peer, selfPubkey: me); await inCircle.load(); expect(inCircle.state.knownToYou, isTrue); expect(inCircle.state.tier, TrustTier.inYourCircle); await inCircle.close(); final outside = TrustCubit(transport, peerPubkey: 'other', selfPubkey: me); await outside.load(); expect(outside.state.knownToYou, isFalse); await outside.close(); }); test('tier falls back to vouched, then unknown', () async { final vouched = TrustCubit( FakeTrustTransport(me)..addCert('someone', peer), peerPubkey: peer, selfPubkey: me); await vouched.load(); expect(vouched.state.tier, TrustTier.vouched); await vouched.close(); final unknown = TrustCubit(FakeTrustTransport(me), peerPubkey: 'nobody', selfPubkey: me); await unknown.load(); expect(unknown.state.tier, TrustTier.unknown); await unknown.close(); }); test('never vouches for self', () async { final cubit = TrustCubit(FakeTrustTransport(me), peerPubkey: me, selfPubkey: me); await cubit.load(); await cubit.toggleVouch(); expect(cubit.state.iVouch, isFalse); await cubit.close(); }); test('offline (no transport) never throws', () async { final cubit = TrustCubit(null, peerPubkey: peer, selfPubkey: me); expect(cubit.isOnline, isFalse); await cubit.load(); await cubit.toggleVouch(); expect(cubit.state.loading, isFalse); await cubit.close(); }); }