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.
135 lines
4.8 KiB
135 lines
4.8 KiB
|
2 days ago
|
// The rules of paths and texts against files: the copy of
|
||
|
|
// test/vectors/pathrule_vectors.json that pathrule_test.dart reads, a Dart
|
||
|
|
// constant for the tests compiled to JavaScript, is the JSON file byte for
|
||
|
|
// byte; the shared vectors of testdata/, paths.json and path_fold.json of
|
||
|
|
// datekeys-go, give their results; and every code point of every plane
|
||
|
|
// gives the results of Go, compared through the SHA-256 of one line per
|
||
|
|
// code point that tool/pathrule_go_vectors.go computes with the reference:
|
||
|
|
// here the planes that pathrule_test.dart leaves out.
|
||
|
|
@TestOn('vm')
|
||
|
|
library;
|
||
|
|
|
||
|
|
import 'dart:convert';
|
||
|
|
import 'dart:io';
|
||
|
|
|
||
|
|
import 'package:datekeys/src/bytes.dart';
|
||
|
|
import 'package:datekeys/src/pathrule.dart';
|
||
|
|
import 'package:datekeys/src/pathrule_tables.dart';
|
||
|
|
import 'package:test/test.dart';
|
||
|
|
|
||
|
|
import 'pathrule_planes.dart';
|
||
|
|
import 'vectors/pathrule_vectors.g.dart';
|
||
|
|
|
||
|
|
Map<String, Object?> readJson(String path) =>
|
||
|
|
jsonDecode(File(path).readAsStringSync()) as Map<String, Object?>;
|
||
|
|
|
||
|
|
String outcome(void Function() f) {
|
||
|
|
try {
|
||
|
|
f();
|
||
|
|
return 'ok';
|
||
|
|
} on PathRuleException catch (e) {
|
||
|
|
return e.message;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void main() {
|
||
|
|
test('pathrule_vectors.g.dart holds pathrule_vectors.json', () {
|
||
|
|
final file = File('test/vectors/pathrule_vectors.json').readAsStringSync();
|
||
|
|
expect(pathruleVectorsJson, file);
|
||
|
|
});
|
||
|
|
|
||
|
|
group('testdata', () {
|
||
|
|
final paths = readJson('testdata/vectors/paths.json');
|
||
|
|
final fold = readJson('testdata/vectors/path_fold.json');
|
||
|
|
|
||
|
|
test('name the tables of this library', () {
|
||
|
|
for (final f in [paths, fold]) {
|
||
|
|
expect(f['unicode_version'], unicodeVersion);
|
||
|
|
expect(f['tables_digest'], tablesDigest);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
test('paths.json: the rules of one entry', () {
|
||
|
|
final cases = (paths['paths']! as List).cast<Map<String, Object?>>();
|
||
|
|
expect(cases, hasLength(greaterThan(80)));
|
||
|
|
for (final c in cases) {
|
||
|
|
expect(
|
||
|
|
outcome(() => checkPath(c['path']! as String)),
|
||
|
|
c['result'],
|
||
|
|
reason: c['name'] as String?,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
test('paths.json: the paths of a head, from layer 3 to layer 4', () {
|
||
|
|
// A head checks R1 and R8 in its third layer (ERR_NON_CANONICAL_CBOR),
|
||
|
|
// comparing UTF-8 bytes, never UTF-16 code units; then each entry,
|
||
|
|
// with R2 to R10, and R7 and R9 over the tree (ERR_HEAD_INVALID).
|
||
|
|
// The decoder of the head, in stage 4c, does this with the CBOR; here
|
||
|
|
// it is done with the rules of pathrule.dart.
|
||
|
|
final trees = (paths['trees']! as List).cast<Map<String, Object?>>();
|
||
|
|
expect(trees, hasLength(greaterThan(10)));
|
||
|
|
var utf16Differs = false;
|
||
|
|
for (final c in trees) {
|
||
|
|
final name = c['name']! as String;
|
||
|
|
final list = (c['paths']! as List).cast<String>();
|
||
|
|
var result = 'ok';
|
||
|
|
var detail = '';
|
||
|
|
for (var i = 0; i < list.length && result == 'ok'; i++) {
|
||
|
|
final n = utf8Bytes(list[i]).length;
|
||
|
|
if (n < 1 ||
|
||
|
|
n > maxPathLen ||
|
||
|
|
(i > 0 &&
|
||
|
|
compareBytes(utf8Bytes(list[i - 1]), utf8Bytes(list[i])) >=
|
||
|
|
0)) {
|
||
|
|
result = 'ERR_NON_CANONICAL_CBOR';
|
||
|
|
}
|
||
|
|
if (i > 0 && list[i - 1].compareTo(list[i]) >= 0 && result == 'ok') {
|
||
|
|
utf16Differs = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (var i = 0; i < list.length && result == 'ok'; i++) {
|
||
|
|
final o = outcome(() => checkPath(list[i]));
|
||
|
|
if (o != 'ok') {
|
||
|
|
result = 'ERR_HEAD_INVALID';
|
||
|
|
detail = 'file ${i + 1}: $o';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (result == 'ok') {
|
||
|
|
final o = outcome(() => checkTree(list));
|
||
|
|
if (o != 'ok') {
|
||
|
|
result = 'ERR_HEAD_INVALID';
|
||
|
|
detail = o;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
expect(result, c['result'], reason: name);
|
||
|
|
expect(detail, c['detail'] ?? '', reason: name);
|
||
|
|
}
|
||
|
|
// U+FF5E before U+1F600 is in UTF-8 order, not in UTF-16 order.
|
||
|
|
expect(utf16Differs, isTrue);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('path_fold.json: the NFD and the key of R7', () {
|
||
|
|
final keys = (fold['keys']! as List).cast<Map<String, Object?>>();
|
||
|
|
expect(keys, hasLength(greaterThan(20)));
|
||
|
|
for (final c in keys) {
|
||
|
|
final s = c['segment']! as String;
|
||
|
|
expect(nfd(s), c['nfd'], reason: c['name'] as String?);
|
||
|
|
expect(pathKey(s), c['key'], reason: c['name'] as String?);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
test('every code point of the other planes gives the results of Go', () {
|
||
|
|
// Planes 0, 1 and 14 run in pathrule_test.dart, also compiled to
|
||
|
|
// JavaScript.
|
||
|
|
final vectors = jsonDecode(pathruleVectorsJson) as Map<String, Object?>;
|
||
|
|
final planes = (vectors['planes']! as List).cast<Map<String, Object?>>();
|
||
|
|
expect(planes, hasLength(17));
|
||
|
|
for (final p in planes) {
|
||
|
|
final plane = p['plane']! as int;
|
||
|
|
if (!sharedPlanes.contains(plane)) checkPlane(plane, p);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|