// The IP address that the name of an https address of a locator resolves // to, against testdata/vectors/resolved_ip.json of the draft v0.13 (spec // ยง44.1): a public address, or an address of NAT64 of 64:ff9b::/96 or of // the prefix of the network whose IPv4 address inside is public, with the // texts of locator.CheckResolvedIP of Go. @TestOn('vm') library; import 'dart:convert'; import 'dart:io'; import 'package:datekeys/src/ipaddr.dart'; import 'package:datekeys/src/locator.dart'; import 'package:test/test.dart'; typedef Json = Map; void main() { final f = jsonDecode( File('testdata/vectors/resolved_ip.json').readAsStringSync(), ) as Json; final cases = (f['cases']! as List).cast(); test('resolved_ip.json has the cases of README', () { expect(cases, hasLength(greaterThanOrEqualTo(40))); expect(cases.where((c) => c['result'] == 'ok'), isNotEmpty); expect(cases.where((c) => c['result'] == 'error'), isNotEmpty); }); for (final c in cases) { test('${c['name']}', () { final ip = parseIpAddress(c['ip']! as String)!; final nat64 = c['nat64']! as String; void check() => checkResolvedIp(ip.bytes, nat64: nat64.isEmpty ? null : nat64); if (c['result'] == 'ok') { check(); } else { expect(c['result'], 'error'); expect( check, throwsA( isA().having( (e) => e.message, 'message', c['error'], ), ), ); } }); } test('an IPv4-mapped prefix is not one of NAT64, as in Go', () { expect( () => checkResolvedIp([8, 8, 8, 8], nat64: '::ffff:0.0.0.0/96'), throwsA( isA().having( (e) => e.message, 'message', 'locator: the NAT64 prefix ::ffff:0.0.0.0/96 is not an IPv6 prefix', ), ), ); }); test('a prefix that does not parse is an ArgumentError', () { for (final s in ['64:ff9b::', '64:ff9b::/129', '64:ff9b::/-1', 'x/96']) { expect( () => checkResolvedIp([8, 8, 8, 8], nat64: s), throwsArgumentError, reason: s, ); } }); }