// The head of format 3 against Go: test/vectors/open_heads.json, which // tool/open_go_vectors.go writes with capsule.DecodeHead and EncodeHead of // the reference; testdata/vectors/head_schema.json, with the detail of each // ERR_HEAD_INVALID; and the trees of testdata/vectors/paths.json, each a // head of files of 0 bytes, through the decoder of the head, from layer 3 // to layer 4. @TestOn('vm') library; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:datekeys/datekeys.dart'; import 'package:datekeys/src/sha256.dart' show sha256; import 'package:test/test.dart'; import 'open_vectors_support.dart'; Json readJson(String path) => jsonDecode(File(path).readAsStringSync()) as Json; void main() { final heads = readJson('test/vectors/open_heads.json'); test('open_heads.json: every head decodes as in Go', () { expect(heads['spec'], specVersion); final cases = (heads['decode']! as List).cast(); expect(cases, hasLength(greaterThan(300))); checkDecodeCases(cases); // Every kind of result, and both orders of U+FF5E and U+1F600. expect( {for (final c in cases) c['result']}, { 'ok', 'ERR_NON_CANONICAL_CBOR', 'ERR_UNSUPPORTED_VERSION', 'ERR_HEAD_INVALID', 'ERR_EXTENSION_CRITICAL_UNKNOWN', }, ); }); test('open_heads.json: every head encodes as in Go', () { final cases = (heads['encode']! as List).cast(); expect(cases, hasLength(greaterThan(20))); checkEncodeCases(cases); }); test('head_schema.json: the result and the detail of each head', () { final f = readJson('testdata/vectors/head_schema.json'); expect(f['spec'], specVersion); final cases = (f['heads']! as List).cast(); expect(cases, hasLength(63)); for (final c in cases) { final b = fromHex(c['hex']! as String); var result = 'ok'; var detail = ''; try { decodeHead(b); } on DateKeysException catch (e) { result = e.code.code; if (e.code == ErrorCode.headInvalid) { detail = headDetail(e); } } expect(result, c['result'], reason: c['name'] as String?); expect(detail, c['detail'] ?? '', reason: c['name'] as String?); } }); test('paths.json: the trees, as heads of files of 0 bytes', () { final f = readJson('testdata/vectors/paths.json'); final trees = (f['trees']! as List).cast(); expect(trees, hasLength(greaterThan(10))); final empty = sha256(Uint8List(0)); for (final c in trees) { // TreeHead of the reference: a zero salt and a file of 0 bytes for // each path, in the order given. final b = encodeHead( Head( salt: Uint8List(saltSize), files: [ for (final p in (c['paths']! as List).cast()) HeadFile(path: p, size: 0, start: 0, end: 0, sha256: empty), ], ), ); var result = 'ok'; var detail = ''; try { decodeHead(b); } on DateKeysException catch (e) { result = e.code.code; if (e.code == ErrorCode.headInvalid) detail = headDetail(e); } expect(result, c['result'], reason: c['name'] as String?); expect(detail, c['detail'] ?? '', reason: c['name'] as String?); } }); test('the files of every format 3 fixture, from its record', () { final names = Directory('testdata/fixtures') .listSync() .map((f) => f.uri.pathSegments.last) .where((n) => n.startsWith('format3_') && n.endsWith('.json')) .where((n) => !n.endsWith('.inspect.json') && !n.contains('.dkk')) .toList(); expect(names, hasLength(14)); for (final n in names) { final r = readJson('testdata/fixtures/$n'); final hb = fromHex(r['head_cbor']! as String); final h = decodeHead(hb); expect(toHex(h.salt), r['salt'], reason: n); expect( [h.comment, h.author], [r['comment'] ?? '', r['declared_author'] ?? ''], reason: n, ); expect( [ for (final f in h.files) { 'path': f.path, 'size': f.size, 'start': f.start, 'end': f.end, 'sha256': toHex(f.sha256), if (f.mtime != null) 'mtime': f.mtime, }, ], r['files'] ?? [], reason: n, ); expect(encodeHead(h), hb, reason: n); } }); }