You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dateKeys-dart/test/locator_uri_test.dart

133 lines
4.7 KiB

// The addresses of a locator against Go (spec §44.1): checkAddressUri and
// LocatorAddress.host on the 247 addresses of testdata/vectors/locator.json
// and on the 2 800 of tool/locator_go_vectors.go, with the texts of
// locator.CheckURI and Address.Host; the parser of IP addresses against
// netip.ParseAddr and String; and the classification of publicIP on the
// bytes of addresses, as checkResolvedIp checks the IP that a name resolves
// to. Everything here runs on the VM and compiled to JavaScript, from the
// constant of locator_uris.g.dart.
library;
import 'package:datekeys/src/bytes.dart';
import 'package:datekeys/src/ipaddr.dart';
import 'package:datekeys/src/locator.dart';
import 'package:test/test.dart';
import 'locator_support.dart';
import 'vectors/locator_uris.g.dart';
import 'wordkey_support.dart' show fromWtf8;
void main() {
final v = decodeJson(locatorUrisJson);
void expectUri(List<Object?> c) {
final uri = c[0]! as String;
final want = textOf(v, c[1]);
expect(errorText(() => checkAddressUri(uri)), want, reason: uri);
final host = LocatorAddress(uri).host;
expect(host, c[2], reason: uri);
// As FuzzCheckURI of Go: the host shown is in the address as it is
// written, with no decoding.
if (want.isEmpty) expect(uri.contains(host) && host.isNotEmpty, isTrue);
}
group('checkAddressUri', () {
test('the addresses of locator.json, with the texts of Go', () {
final cases = rows(v, 'testdata');
expect(cases, hasLength(247));
cases.forEach(expectUri);
});
test('the addresses at the edges of §44.1 and drawn from a seed', () {
final cases = rows(v, 'uris');
expect(cases, hasLength(2800));
cases.forEach(expectUri);
// Every rule rejects some and some pass.
final texts = {for (final c in cases) c[1]};
expect(texts.length, greaterThan(20));
});
test('an address that is not ASCII is measured and quoted in UTF-8', () {
// Go counts the bytes of the string and quotes its first byte that is
// not of RFC 3986 as a rune, 0xc3 as U+00C3 in quotes.
final c = rows(
v,
'uris',
).firstWhere((c) => c[0] == 'https://ejemplo.org/\u00e9');
expectUri(c);
expect(textOf(v, c[1]), contains("'\u00c3'"));
// A lone surrogate is three bytes that are not UTF-8, as Go reads
// those bytes.
for (final c in rows(v, 'wtf8')) {
final uri = fromWtf8(fromHex(c[0]! as String))!;
expect(errorText(() => checkAddressUri(uri)), textOf(v, c[1]));
expect(LocatorAddress(uri).host, '');
}
});
test('Go accepts a doubled opening bracket, and a CID with one more '
'character whose bits are zero', () {
// The host of Go is strings.Trim(host, "[]"), and isCIDv1 checks only
// that the bits left over are zero, not their count: Dart does the
// same, as the vectors of Go say.
for (final uri in [
'https://[[2000::]/',
'ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdia',
]) {
final c = rows(v, 'uris').firstWhere((c) => c[0] == uri);
expect(c[1], 0, reason: uri);
expectUri(c);
}
});
});
group('IP addresses', () {
test('parseIpAddress accepts what netip.ParseAddr accepts', () {
final cases = rows(v, 'ips');
expect(cases.length, greaterThan(1500));
for (final c in cases) {
final s = c[0]! as String;
final a = parseIpAddress(s);
if (c[1] == false) {
expect(a, isNull, reason: s);
continue;
}
expect(a, isNotNull, reason: s);
expect(toHex(a!.bytes), c[2], reason: s);
expect(a.zone, c[3], reason: s);
expect('$a', c[4], reason: s);
expect(isPublicIp(a), c[5], reason: s);
}
});
test('checkResolvedIp checks the bytes of an address as publicIP', () {
for (final c in rows(v, 'public')) {
final b = fromHex(c[0]! as String);
if (c[1] == null) {
expect(() => checkResolvedIp(b), throwsArgumentError);
continue;
}
final a = IpAddress.fromBytes(b);
expect('$a', c[2]);
expect(isPublicIp(a), c[1], reason: '$a');
expect(
errorText(() => checkResolvedIp(b)),
c[1] == true
? ''
: 'locator: an https address whose name resolves to ${c[2]}, '
'an IP address that is not public',
);
}
});
test('an IPv4 address mapped in IPv6 is not public', () {
expect(
() => checkResolvedIp([...List.filled(10, 0), 0xff, 0xff, 8, 8, 8, 8]),
throwsA(isA<LocatorException>()),
);
checkResolvedIp([8, 8, 8, 8]);
expect(() => checkResolvedIp([8, 8, 8, 256]), throwsArgumentError);
});
});
}

Powered by TurnKey Linux.