|
|
|
|
// The extension mechanism (lib/src/extension.dart), as extension.test.ts of
|
|
|
|
|
// datekeys-ts and the tests of package extension of datekeys-go: the order
|
|
|
|
|
// of the UTF-8 bytes of extension_id, the copies of the data, the registries
|
|
|
|
|
// with their places, and the rule of an encoder of spec §72 with the
|
|
|
|
|
// extensions of the specification. The texts of Go are in the differential
|
|
|
|
|
// (formats_extension.json). It reads no file: it runs on the VM and compiled
|
|
|
|
|
// to JavaScript.
|
|
|
|
|
library;
|
|
|
|
|
|
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
|
|
|
|
import 'package:datekeys/src/cbor.dart';
|
|
|
|
|
import 'package:datekeys/src/errors.dart';
|
|
|
|
|
import 'package:datekeys/src/extension.dart';
|
|
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
|
|
String codeOf(void Function() body) {
|
|
|
|
|
try {
|
|
|
|
|
body();
|
|
|
|
|
return 'ok';
|
|
|
|
|
} on DateKeysException catch (e) {
|
|
|
|
|
return e.code.code;
|
|
|
|
|
} on ArgumentError {
|
|
|
|
|
return 'error';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Extension> decodeWhole(List<int> bytes) {
|
|
|
|
|
late List<Extension> exts;
|
|
|
|
|
unmarshalCbor(
|
|
|
|
|
bytes,
|
|
|
|
|
(d) => exts = decodeExtensionArray(d),
|
|
|
|
|
(e) => encodeExtensionArray(e, exts),
|
|
|
|
|
);
|
|
|
|
|
return exts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Uint8List encodeWhole(List<Extension> exts) {
|
|
|
|
|
final e = CborEncoder();
|
|
|
|
|
encodeExtensionArray(e, exts);
|
|
|
|
|
return e.out();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A registry of org.a and org.b of version 1, with data "ok" valid.
|
|
|
|
|
final class Validator extends ExtensionRegistry {
|
|
|
|
|
const Validator();
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
bool known(String id, int version) =>
|
|
|
|
|
(id == 'org.a' || id == 'org.b') && version == 1;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Object? validateData(Extension e) =>
|
|
|
|
|
e.data != null && String.fromCharCodes(e.data!) == 'ok'
|
|
|
|
|
? null
|
|
|
|
|
: 'want "ok"';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A registry whose validator throws.
|
|
|
|
|
final class Throwing extends ExtensionRegistry {
|
|
|
|
|
const Throwing();
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
bool known(String id, int version) => true;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Object? validateData(Extension e) =>
|
|
|
|
|
throw const FormatException('cannot read');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
test('newExtension copies the data and validates the extension', () {
|
|
|
|
|
final data = Uint8List.fromList('public label'.codeUnits);
|
|
|
|
|
final e = newExtension('org.example.label', 1, data);
|
|
|
|
|
data[0] = 0x50;
|
|
|
|
|
expect(
|
|
|
|
|
e,
|
|
|
|
|
Extension('org.example.label', 1, 'public label'.codeUnits.toBytes()),
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
newExtension('a' * 256, maxExtensionVersion, [0]).id,
|
|
|
|
|
hasLength(256),
|
|
|
|
|
);
|
|
|
|
|
// 128 characters of two bytes are 256 bytes of UTF-8; 129 are too many.
|
|
|
|
|
expect(newExtension('é' * 128, 1, [0]).id, hasLength(128));
|
|
|
|
|
for (final (id, version, data) in [
|
|
|
|
|
('org.a', 1, <int>[]),
|
|
|
|
|
('', 1, [1]),
|
|
|
|
|
('org.\u{d800}', 1, [1]),
|
|
|
|
|
('a' * 257, 1, [1]),
|
|
|
|
|
('é' * 129, 1, [1]),
|
|
|
|
|
('org.a', maxExtensionVersion + 1, [1]),
|
|
|
|
|
('org.a', -1, [1]),
|
|
|
|
|
]) {
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(() => newExtension(id, version, data)),
|
|
|
|
|
'ERR_NON_CANONICAL_CBOR',
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('sorts by the UTF-8 bytes of extension_id, never UTF-16 code units', () {
|
|
|
|
|
final ids = ['\u{10000}', '\u{ff61}', 'é', 'z', 'Z', 'a\u{0}', 'a'];
|
|
|
|
|
// Dart compares UTF-16 code units.
|
|
|
|
|
expect('\u{10000}'.compareTo('\u{ff61}'), lessThan(0));
|
|
|
|
|
// 5a, 61, 61 00, 7a, c3 a9, ef bd a1, f0 90 80 80.
|
|
|
|
|
expect(
|
|
|
|
|
canonicalExtensions([for (final id in ids) Extension(id, 1)])
|
|
|
|
|
.map((e) => e.id),
|
|
|
|
|
['Z', 'a', 'a\u{0}', 'z', 'é', '\u{ff61}', '\u{10000}'],
|
|
|
|
|
);
|
|
|
|
|
expect(canonicalExtensions(const []), isEmpty);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('canonicalExtensions copies the data, and its array decodes back', () {
|
|
|
|
|
final input = [
|
|
|
|
|
Extension('org.b', 1),
|
|
|
|
|
Extension('org.a', 2, Uint8List.fromList([0x78])),
|
|
|
|
|
Extension('Z', 9),
|
|
|
|
|
];
|
|
|
|
|
final sorted = canonicalExtensions(input);
|
|
|
|
|
input[1].data![0] = 0;
|
|
|
|
|
expect(sorted[1].data, [0x78]);
|
|
|
|
|
expect(decodeWhole(encodeWhole(sorted)), sorted);
|
|
|
|
|
expect(() => sorted.add(Extension('x', 1)), throwsUnsupportedError);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('never writes an array that decodeExtensionArray rejects', () {
|
|
|
|
|
for (final exts in [
|
|
|
|
|
<Extension>[],
|
|
|
|
|
[for (var i = 0; i < 65; i++) Extension('o.$i'.padLeft(5, '0'), 1)],
|
|
|
|
|
[Extension('org.a', 1, Uint8List(0))],
|
|
|
|
|
[Extension('org.b', 1), Extension('org.a', 1)],
|
|
|
|
|
[Extension('org.a', 1), Extension('org.a', 2)],
|
|
|
|
|
[Extension('org.a', maxExtensionVersion + 1)],
|
|
|
|
|
[Extension('', 1)],
|
|
|
|
|
[Extension('org.\u{d800}', 1)],
|
|
|
|
|
]) {
|
|
|
|
|
final e = CborEncoder()..uint(0);
|
|
|
|
|
encodeExtensionArray(e, exts);
|
|
|
|
|
expect(codeOf(e.out), 'ERR_NON_CANONICAL_CBOR');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('keeps the bytes of data exactly, a leading BOM in its identifier', () {
|
|
|
|
|
// ef bb bf, the BOM, sorts after the 6f of "org.b".
|
|
|
|
|
final exts = [
|
|
|
|
|
Extension('org.b', 7),
|
|
|
|
|
Extension('\u{feff}org.a', 1, Uint8List.fromList([0xff, 0, 0xa2])),
|
|
|
|
|
];
|
|
|
|
|
final back = decodeWhole(encodeWhole(exts));
|
|
|
|
|
expect(back, exts);
|
|
|
|
|
expect(back.last.id.codeUnitAt(0), 0xfeff);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('checkDisjoint merges in canonical order without reordering', () {
|
|
|
|
|
final a = [Extension('a', 1), Extension('c', 1), Extension('e', 1)];
|
|
|
|
|
final b = [Extension('b', 1), Extension('d', 1), Extension('f', 1)];
|
|
|
|
|
checkDisjoint(a, b);
|
|
|
|
|
final unsorted = [Extension('z', 1), Extension('e', 2)];
|
|
|
|
|
expect(codeOf(() => checkDisjoint(a, unsorted)), 'ERR_NON_CANONICAL_CBOR');
|
|
|
|
|
expect(unsorted.map((e) => e.id), ['z', 'e']);
|
|
|
|
|
checkDisjoint(const [], b);
|
|
|
|
|
checkDisjoint(a, const []);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
group('registries', () {
|
|
|
|
|
final ok = Uint8List.fromList('ok'.codeUnits);
|
|
|
|
|
final ko = Uint8List.fromList('ko'.codeUnits);
|
|
|
|
|
|
|
|
|
|
test('a set knows extension_ids by version', () {
|
|
|
|
|
final s = ExtensionSet({
|
|
|
|
|
'org.a': [1, 2],
|
|
|
|
|
});
|
|
|
|
|
expect([s.known('org.a', 2), s.known('org.a', 3)], [true, false]);
|
|
|
|
|
expect(ExtensionSet().known('org.a', 1), isFalse);
|
|
|
|
|
expect(
|
|
|
|
|
knownIn(s, 'org.a', 1, ExtensionObject.head, ExtensionArray.critical),
|
|
|
|
|
isTrue,
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
knownIn(
|
|
|
|
|
null,
|
|
|
|
|
'org.a',
|
|
|
|
|
1,
|
|
|
|
|
ExtensionObject.head,
|
|
|
|
|
ExtensionArray.critical,
|
|
|
|
|
),
|
|
|
|
|
isFalse,
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('an unknown critical extension prevails over invalid data', () {
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(() => checkCritical([Extension('org.a', 1)], null)),
|
|
|
|
|
'ERR_EXTENSION_CRITICAL_UNKNOWN',
|
|
|
|
|
);
|
|
|
|
|
checkCritical(const [], null);
|
|
|
|
|
checkCritical([Extension('org.a', 1, ok)], const Validator());
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(
|
|
|
|
|
() => checkCritical([
|
|
|
|
|
Extension('org.a', 1, ok),
|
|
|
|
|
Extension('org.b', 1, ko),
|
|
|
|
|
], const Validator()),
|
|
|
|
|
),
|
|
|
|
|
'ERR_EXTENSION_DATA_INVALID',
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(
|
|
|
|
|
() => checkCritical([
|
|
|
|
|
Extension('org.b', 1, ko),
|
|
|
|
|
Extension('org.c', 1),
|
|
|
|
|
], const Validator()),
|
|
|
|
|
),
|
|
|
|
|
'ERR_EXTENSION_CRITICAL_UNKNOWN',
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('a noncritical extension with invalid data is unusable, the object '
|
|
|
|
|
'valid', () {
|
|
|
|
|
final all = [
|
|
|
|
|
Extension('org.a', 1, ok),
|
|
|
|
|
Extension('org.b', 1),
|
|
|
|
|
Extension('org.c', 1, ko),
|
|
|
|
|
];
|
|
|
|
|
expect(checkNoncritical(all, null), isEmpty);
|
|
|
|
|
final unusable = checkNoncritical(all, const Validator());
|
|
|
|
|
expect(unusable.map((u) => [u.id, u.version]), [
|
|
|
|
|
['org.b', 1],
|
|
|
|
|
]);
|
|
|
|
|
expect(unusable.single.error.code, ErrorCode.extensionDataInvalid);
|
|
|
|
|
expect('${unusable.single}', unusable.single.error.message);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('a validator that throws an Exception rejects the data', () {
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(() => checkCritical([Extension('x', 1)], const Throwing())),
|
|
|
|
|
'ERR_EXTENSION_DATA_INVALID',
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
checkNoncritical([
|
|
|
|
|
Extension('x', 1),
|
|
|
|
|
], const Throwing()).single.error.message,
|
|
|
|
|
contains('cannot read'),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('the extensions of the specification go only where spec §72 '
|
|
|
|
|
'registers them', () {
|
|
|
|
|
final note = Extension(noteExtensionId, 1, Uint8List.fromList([0x41]));
|
|
|
|
|
final capsule = Extension(
|
|
|
|
|
capsuleExtensionId,
|
|
|
|
|
1,
|
|
|
|
|
Uint8List.fromList([0xa0]),
|
|
|
|
|
);
|
Stage 7a: the default registry checks datekeys.capsule; README, changelog
StandardExtensions checks by default the data of datekeys.capsule with
checkCapsuleData, as locator.Standard of Go: when a .dkk is opened with
it, an extension whose data does not read is unusable, with the text of
Go. With validateCapsule: null it checks only that there is data, as
Go's extension.Standard without ValidateCapsule: the writer of a .dkk
keeps that one, as Go's writer does, and so do the tests of the formats
that compare with extension.Standard. Inspection and opening give Go's
results on every fixture and vector, and the tests of the locator use the
default registry.
lib/datekeys.dart exports locator.dart. The README has the section of
part 7a, its vectors and how the generator makes them; the changelog has
its entry, with its tests and its injected faults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
// Go's extension.Standard, without ValidateCapsule.
|
|
|
|
|
const std = StandardExtensions(validateCapsule: null);
|
|
|
|
|
for (final o in ExtensionObject.values) {
|
|
|
|
|
for (final a in ExtensionArray.values) {
|
|
|
|
|
final noteHere =
|
|
|
|
|
o == ExtensionObject.publicHeader &&
|
|
|
|
|
a == ExtensionArray.noncritical;
|
|
|
|
|
final capsuleHere =
|
|
|
|
|
o == ExtensionObject.accessKey && a == ExtensionArray.noncritical;
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(() => checkWrite(std, o, a, [note])),
|
|
|
|
|
noteHere ? 'ok' : 'error',
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(() => checkWrite(std, o, a, [capsule])),
|
|
|
|
|
capsuleHere ? 'ok' : 'error',
|
|
|
|
|
);
|
|
|
|
|
// Another version, or another identifier, is the application's.
|
|
|
|
|
checkWrite(std, o, a, [
|
|
|
|
|
Extension(noteExtensionId, 2),
|
|
|
|
|
Extension('org.example', 1),
|
|
|
|
|
]);
|
|
|
|
|
// A reader that knows them treats them as unknown out of place.
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(() => checkCritical([note], std, o)),
|
|
|
|
|
'ERR_EXTENSION_CRITICAL_UNKNOWN',
|
|
|
|
|
);
|
|
|
|
|
// A note without data is unusable in the noncritical array of
|
|
|
|
|
// PUBLIC_HEADER, and ignored in that of any other object.
|
|
|
|
|
expect(checkNoncritical([Extension(noteExtensionId, 1)], std, o), [
|
|
|
|
|
if (o == ExtensionObject.publicHeader) isA<Unusable>(),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(
|
|
|
|
|
() => checkWrite(
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.accessKey,
|
|
|
|
|
ExtensionArray.noncritical,
|
|
|
|
|
[Extension(capsuleExtensionId, 1)],
|
|
|
|
|
context: 'accesskey',
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
'ERR_EXTENSION_DATA_INVALID',
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
() => checkWrite(
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.accessKey,
|
|
|
|
|
ExtensionArray.critical,
|
|
|
|
|
[capsule],
|
|
|
|
|
context: 'accesskey',
|
|
|
|
|
),
|
|
|
|
|
throwsA(
|
|
|
|
|
isA<ArgumentError>().having(
|
|
|
|
|
(e) => '${e.message}',
|
|
|
|
|
'message',
|
|
|
|
|
startsWith('accesskey: extension: datekeys.capsule version 1 '),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
checkWrite(null, ExtensionObject.head, ExtensionArray.critical, [note]);
|
|
|
|
|
});
|
|
|
|
|
|
Stage 4c: the public note and the head of format 3
lib/src/note.dart ports CheckNote, NewNote and Note of package extension
of datekeys-go at c531e93: checkNote and checkNoteData check the length,
the UTF-8 and the rules of text of the declared author, in that order and
with the texts of Go, on the bytes of the note as Go reads its string;
newNote, publicNote and unusableNote, and Header.publicNote and
Header.unusableNote. StandardExtensions checks the data of a note as the
Standard of Go does, and its parameter validateNote, which could replace
those rules, is gone.
lib/src/head.dart ports DecodeHead, EncodeHead and CheckHeadEnd of
format3.go: the limit of HEAD_LEN, the type tag and the version, the CDDL
with R1 and R8 on the UTF-8 bytes of the paths, never on the UTF-16 code
units of a String, and then the comment, the declared author and the files
with the rules of pathrule and their layout, by subtraction, and R7 and R9,
as ERR_HEAD_INVALID with the text of Go, and the critical extensions of the
head. decodeWrittenHead is the decoder without the critical extensions, for
the self-check of the writer of stage 6.
The tests read open_heads.json, open_notes.json, head_schema.json with the
detail of each ERR_HEAD_INVALID, the trees of paths.json as heads of files
of 0 bytes, and the head of each fixture of format 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
test('the rules of a note are those of spec §24.1, and those of a locator '
|
|
|
|
|
'come from its validator', () {
|
|
|
|
|
final seen = <String>[];
|
|
|
|
|
final std = StandardExtensions(
|
|
|
|
|
validateCapsule: (e) {
|
|
|
|
|
seen.add('capsule');
|
|
|
|
|
return DateKeysException(
|
|
|
|
|
ErrorCode.extensionDataInvalid,
|
|
|
|
|
'a bad locator',
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
final good = Extension(noteExtensionId, 1, Uint8List.fromList([0x41]));
|
Stage 4c: the public note and the head of format 3
lib/src/note.dart ports CheckNote, NewNote and Note of package extension
of datekeys-go at c531e93: checkNote and checkNoteData check the length,
the UTF-8 and the rules of text of the declared author, in that order and
with the texts of Go, on the bytes of the note as Go reads its string;
newNote, publicNote and unusableNote, and Header.publicNote and
Header.unusableNote. StandardExtensions checks the data of a note as the
Standard of Go does, and its parameter validateNote, which could replace
those rules, is gone.
lib/src/head.dart ports DecodeHead, EncodeHead and CheckHeadEnd of
format3.go: the limit of HEAD_LEN, the type tag and the version, the CDDL
with R1 and R8 on the UTF-8 bytes of the paths, never on the UTF-16 code
units of a String, and then the comment, the declared author and the files
with the rules of pathrule and their layout, by subtraction, and R7 and R9,
as ERR_HEAD_INVALID with the text of Go, and the critical extensions of the
head. decodeWrittenHead is the decoder without the critical extensions, for
the self-check of the writer of stage 6.
The tests read open_heads.json, open_notes.json, head_schema.json with the
detail of each ERR_HEAD_INVALID, the trees of paths.json as heads of files
of 0 bytes, and the head of each fixture of format 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
// A tab breaks the rules of text of the declared author (spec §29.6).
|
|
|
|
|
final bad = Extension(noteExtensionId, 1, Uint8List.fromList([9]));
|
|
|
|
|
checkWrite(
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.publicHeader,
|
|
|
|
|
ExtensionArray.noncritical,
|
|
|
|
|
[good],
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(
|
|
|
|
|
() => checkWrite(
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.publicHeader,
|
|
|
|
|
ExtensionArray.noncritical,
|
|
|
|
|
[bad],
|
|
|
|
|
),
|
|
|
|
|
),
|
Stage 4c: the public note and the head of format 3
lib/src/note.dart ports CheckNote, NewNote and Note of package extension
of datekeys-go at c531e93: checkNote and checkNoteData check the length,
the UTF-8 and the rules of text of the declared author, in that order and
with the texts of Go, on the bytes of the note as Go reads its string;
newNote, publicNote and unusableNote, and Header.publicNote and
Header.unusableNote. StandardExtensions checks the data of a note as the
Standard of Go does, and its parameter validateNote, which could replace
those rules, is gone.
lib/src/head.dart ports DecodeHead, EncodeHead and CheckHeadEnd of
format3.go: the limit of HEAD_LEN, the type tag and the version, the CDDL
with R1 and R8 on the UTF-8 bytes of the paths, never on the UTF-16 code
units of a String, and then the comment, the declared author and the files
with the rules of pathrule and their layout, by subtraction, and R7 and R9,
as ERR_HEAD_INVALID with the text of Go, and the critical extensions of the
head. decodeWrittenHead is the decoder without the critical extensions, for
the self-check of the writer of stage 6.
The tests read open_heads.json, open_notes.json, head_schema.json with the
detail of each ERR_HEAD_INVALID, the trees of paths.json as heads of files
of 0 bytes, and the head of each fixture of format 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
'ERR_EXTENSION_DATA_INVALID',
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
checkNoncritical(
|
|
|
|
|
[bad],
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.publicHeader,
|
|
|
|
|
).single.error.message,
|
Stage 4c: the public note and the head of format 3
lib/src/note.dart ports CheckNote, NewNote and Note of package extension
of datekeys-go at c531e93: checkNote and checkNoteData check the length,
the UTF-8 and the rules of text of the declared author, in that order and
with the texts of Go, on the bytes of the note as Go reads its string;
newNote, publicNote and unusableNote, and Header.publicNote and
Header.unusableNote. StandardExtensions checks the data of a note as the
Standard of Go does, and its parameter validateNote, which could replace
those rules, is gone.
lib/src/head.dart ports DecodeHead, EncodeHead and CheckHeadEnd of
format3.go: the limit of HEAD_LEN, the type tag and the version, the CDDL
with R1 and R8 on the UTF-8 bytes of the paths, never on the UTF-16 code
units of a String, and then the comment, the declared author and the files
with the rules of pathrule and their layout, by subtraction, and R7 and R9,
as ERR_HEAD_INVALID with the text of Go, and the critical extensions of the
head. decodeWrittenHead is the decoder without the critical extensions, for
the self-check of the writer of stage 6.
The tests read open_heads.json, open_notes.json, head_schema.json with the
detail of each ERR_HEAD_INVALID, the trees of paths.json as heads of files
of 0 bytes, and the head of each fixture of format 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
contains('a public note that breaks the rules of text'),
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
checkNoncritical([good], std, ExtensionObject.publicHeader),
|
|
|
|
|
isEmpty,
|
|
|
|
|
);
|
|
|
|
|
expect(
|
|
|
|
|
codeOf(
|
|
|
|
|
() => checkWrite(
|
|
|
|
|
std,
|
|
|
|
|
ExtensionObject.accessKey,
|
|
|
|
|
ExtensionArray.noncritical,
|
|
|
|
|
[Extension(capsuleExtensionId, 1, Uint8List(1))],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
'ERR_EXTENSION_DATA_INVALID',
|
|
|
|
|
);
|
Stage 4c: the public note and the head of format 3
lib/src/note.dart ports CheckNote, NewNote and Note of package extension
of datekeys-go at c531e93: checkNote and checkNoteData check the length,
the UTF-8 and the rules of text of the declared author, in that order and
with the texts of Go, on the bytes of the note as Go reads its string;
newNote, publicNote and unusableNote, and Header.publicNote and
Header.unusableNote. StandardExtensions checks the data of a note as the
Standard of Go does, and its parameter validateNote, which could replace
those rules, is gone.
lib/src/head.dart ports DecodeHead, EncodeHead and CheckHeadEnd of
format3.go: the limit of HEAD_LEN, the type tag and the version, the CDDL
with R1 and R8 on the UTF-8 bytes of the paths, never on the UTF-16 code
units of a String, and then the comment, the declared author and the files
with the rules of pathrule and their layout, by subtraction, and R7 and R9,
as ERR_HEAD_INVALID with the text of Go, and the critical extensions of the
head. decodeWrittenHead is the decoder without the critical extensions, for
the self-check of the writer of stage 6.
The tests read open_heads.json, open_notes.json, head_schema.json with the
detail of each ERR_HEAD_INVALID, the trees of paths.json as heads of files
of 0 bytes, and the head of each fixture of format 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 days ago
|
|
|
expect(seen, ['capsule']);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension on List<int> {
|
|
|
|
|
Uint8List toBytes() => Uint8List.fromList(this);
|
|
|
|
|
}
|