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.
96 lines
2.9 KiB
96 lines
2.9 KiB
|
2 days ago
|
// The exhaustive comparison of the rules of paths and texts with Go: for each
|
||
|
|
// code point of a plane, one line per function, hashed with SHA-256, against
|
||
|
|
// the digests of test/vectors/pathrule_vectors.json, which
|
||
|
|
// tool/pathrule_go_vectors.go computes with the same lines.
|
||
|
|
|
||
|
|
import 'dart:typed_data';
|
||
|
|
|
||
|
|
import 'package:datekeys/src/bytes.dart';
|
||
|
|
import 'package:datekeys/src/pathrule.dart';
|
||
|
|
import 'package:datekeys/src/sha256.dart';
|
||
|
|
import 'package:test/test.dart';
|
||
|
|
|
||
|
|
/// Lines of ASCII added to a SHA-256 through a buffer of 64 KiB.
|
||
|
|
final class LineHash {
|
||
|
|
final _hash = Sha256();
|
||
|
|
final _buffer = Uint8List(1 << 16);
|
||
|
|
var _length = 0;
|
||
|
|
|
||
|
|
void add(String line) {
|
||
|
|
if (_length + line.length > _buffer.length) _flush();
|
||
|
|
for (var i = 0; i < line.length; i++) {
|
||
|
|
final c = line.codeUnitAt(i);
|
||
|
|
if (c >= 0x80) throw ArgumentError.value(line, 'line', 'not ASCII');
|
||
|
|
_buffer[_length++] = c;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void _flush() {
|
||
|
|
_hash.add(_buffer, 0, _length);
|
||
|
|
_length = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
String finish() {
|
||
|
|
_flush();
|
||
|
|
return toHex(_hash.finish());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
String _hexUpper(int r) => r.toRadixString(16).toUpperCase();
|
||
|
|
|
||
|
|
String _outcome(void Function() f) {
|
||
|
|
try {
|
||
|
|
f();
|
||
|
|
return 'ok';
|
||
|
|
} on PathRuleException catch (e) {
|
||
|
|
return e.message;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// The planes whose code points pathrule_test.dart checks, also compiled to
|
||
|
|
/// JavaScript: the BMP, the SMP and plane 14, of the tags and of the
|
||
|
|
/// variation selectors. pathrule_vm_test.dart checks the others.
|
||
|
|
const sharedPlanes = [0, 1, 14];
|
||
|
|
|
||
|
|
/// The names of the digests of a plane, in the order of the lines.
|
||
|
|
const planeFunctions = [
|
||
|
|
'props',
|
||
|
|
'nfd',
|
||
|
|
'fold',
|
||
|
|
'key',
|
||
|
|
'path',
|
||
|
|
'comment',
|
||
|
|
'author',
|
||
|
|
];
|
||
|
|
|
||
|
|
/// Checks every code point of [plane] against [digests], the entry of the
|
||
|
|
/// plane in the vectors: for each code point r, its string is its UTF-8, or
|
||
|
|
/// U+FFFD for a surrogate, as Go's string(rune(r)) writes it.
|
||
|
|
void checkPlane(int plane, Map<String, Object?> digests) {
|
||
|
|
final replacement = Uint8List.fromList([0xef, 0xbf, 0xbd]);
|
||
|
|
final h = [for (final _ in planeFunctions) LineHash()];
|
||
|
|
for (var r = plane << 16; r <= (plane << 16 | 0xffff); r++) {
|
||
|
|
final s = r >= 0xd800 && r <= 0xdfff
|
||
|
|
? replacement
|
||
|
|
: utf8Bytes(String.fromCharCode(r));
|
||
|
|
final x = _hexUpper(r);
|
||
|
|
h[0].add(
|
||
|
|
'$x ${isAssigned(r)} ${isDefaultIgnorable(r)} ${_hexUpper(lower(r))}\n',
|
||
|
|
);
|
||
|
|
h[1].add('$x ${toHex(nfdUtf8(s))}\n');
|
||
|
|
h[2].add('$x ${toHex(foldUtf8(s))}\n');
|
||
|
|
h[3].add('$x ${toHex(pathKeyUtf8(s))}\n');
|
||
|
|
h[4].add('$x ${_outcome(() => checkPathUtf8(s))}\n');
|
||
|
|
h[5].add('$x ${_outcome(() => checkCommentUtf8(s))}\n');
|
||
|
|
h[6].add('$x ${_outcome(() => checkAuthorUtf8(s))}\n');
|
||
|
|
}
|
||
|
|
expect(digests['plane'], plane);
|
||
|
|
for (var i = 0; i < planeFunctions.length; i++) {
|
||
|
|
expect(
|
||
|
|
h[i].finish(),
|
||
|
|
digests[planeFunctions[i]],
|
||
|
|
reason: 'plane $plane, ${planeFunctions[i]}',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|