import 'package:block2_spike/block2_spike.dart'; import 'package:test/test.dart'; /// Pure web-of-trust rules (Duniter: N certs from members + within distance D). /// This is the `commons_core`-worthy piece: deterministic, no I/O. void main() { final now = DateTime(2026, 7, 10); Certification cert(String a, String b, {DateTime? expires, bool revoked = false}) => Certification( issuer: a, subject: b, issuedAt: DateTime(2026), expiresAt: expires, revoked: revoked, ); test('seeds are always members', () { final wot = WebOfTrust.fromCertifications([], now: now); expect( wot.members(seeds: {'s1'}, threshold: 5, maxDistance: 5), contains('s1'), ); }); test('reaches the threshold from member certifiers → becomes known', () { final seeds = {'s1', 's2', 's3', 's4', 's5'}; final certs = [for (final s in seeds) cert(s, 'newcomer')]; final wot = WebOfTrust.fromCertifications(certs, now: now); final members = wot.members(seeds: seeds, threshold: 5, maxDistance: 5); expect(members, contains('newcomer')); }); test('below the threshold stays unknown', () { final seeds = {'s1', 's2', 's3', 's4', 's5'}; final certs = [cert('s1', 'x'), cert('s2', 'x')]; // only 2 of 5 final wot = WebOfTrust.fromCertifications(certs, now: now); expect( wot.members(seeds: seeds, threshold: 5, maxDistance: 5), isNot(contains('x')), ); }); test('membership is transitive via a fixpoint (needs a to count for b)', () { final seeds = {'s1', 's2'}; final certs = [ cert('s1', 'a'), cert('s2', 'a'), // a: 2 member certs → member cert('a', 'b'), cert('s2', 'b'), // b: certified by a (now member) + s2 ]; final wot = WebOfTrust.fromCertifications(certs, now: now); final members = wot.members(seeds: seeds, threshold: 2, maxDistance: 5); expect(members, containsAll(['a', 'b'])); }); test('distance rule cuts off far-away nodes even if well-certified', () { // s → a → b → c → d → e chain; only s is a seed; threshold 1. final seeds = {'s'}; final certs = [ cert('s', 'a'), cert('a', 'b'), cert('b', 'c'), cert('c', 'd'), cert('d', 'e'), ]; final wot = WebOfTrust.fromCertifications(certs, now: now); final members = wot.members(seeds: seeds, threshold: 1, maxDistance: 2); expect(members, containsAll(['a', 'b'])); // dist 1 and 2 expect(members, isNot(contains('c'))); // dist 3 > maxDistance expect(members, isNot(contains('e'))); }); test('expired and revoked certifications do not count', () { final seeds = {'s1', 's2', 's3', 's4', 's5'}; final certs = [ cert('s1', 'x'), cert('s2', 'x'), cert('s3', 'x'), cert('s4', 'x', expires: DateTime(2020)), // expired cert('s5', 'x', revoked: true), // revoked ]; final wot = WebOfTrust.fromCertifications(certs, now: now); expect(wot.certifierCount('x'), 3, reason: 'expired+revoked dropped'); expect( wot.members(seeds: seeds, threshold: 5, maxDistance: 5), isNot(contains('x')), ); }); test('self-certification is ignored', () { final wot = WebOfTrust.fromCertifications([cert('a', 'a')], now: now); expect(wot.certifierCount('a'), 0); }); }