// The shared vectors of the CBOR profile of spec ยง58, // testdata/vectors/cbor.json, as vectors_test.go of package codec of // datekeys-go: walkCbor accepts exactly the accept list, with the value // recorded for unsigned integers, and rejects the reject list with the // recorded code. @TestOn('vm') library; import 'dart:convert'; import 'dart:io'; import 'package:datekeys/datekeys.dart'; import 'package:test/test.dart'; void main() { final file = jsonDecode( File('testdata/vectors/cbor.json').readAsStringSync(), ) as Map; final walk = file['walk']! as Map; final maxDepth = walk['max_depth']! as int; final maxLen = walk['max_len']! as int; List> list(String key) => (file[key]! as List).cast>(); final accept = list('accept'); final reject = list('reject'); final schemas = list('schemas'); test('the vector file is complete', () { expect(file['spec'], specVersion); expect(accept, isNotEmpty); expect(reject, isNotEmpty); expect(maxDepth, isPositive); expect(maxLen, isPositive); }); group('accept', () { for (final v in accept) { test(v['name'], () { final input = fromHex(v['hex']! as String); walkCbor(input, maxDepth, maxLen); // An unsigned integer records its value: a JSON number up to 2^53-1 // and a decimal string above, so that no reader loses precision. final isUint = input.isNotEmpty && input[0] >> 5 == 0; expect(v.containsKey('value'), isUint); if (!isUint) return; final n = CborDecoder(input).uint64(); if (n > BigInt.from(maxSafeUint)) { expect(v['value'], '$n'); } else { expect(v['value'], n.toInt()); } }); } }); group('reject', () { for (final v in reject) { test(v['name'], () { final input = fromHex(v['hex']! as String); var code = ''; try { walkCbor(input, maxDepth, maxLen); } on DateKeysException catch (e) { code = e.code.code; } expect(code, v['error']); }); } }); // The schemas block is decoded with the decoder of each schema: Provider // Profile, PUBLIC_HEADER, CONTROL_CBOR and the body of a .dkk, which arrive // with stage 4 of docs/PLAN_dart.md. Until then the block is only read: its // shape is checked, and the objects it holds as valid are items of the // profile whose type tag peekSchema reads. group('schemas', () { const typeTags = { 'provider_profile': 'datekeys-provider-profile', 'public_header': 'datekeycap', 'control_cbor': 'datekeys-control', 'dkk_body': 'datekeys-access-key', }; final codes = {for (final c in ErrorCode.values) c.code}; test('the block is well formed', () { expect(schemas, isNotEmpty); for (final v in schemas) { expect(typeTags.keys, contains(v['schema']), reason: '${v['name']}'); expect(v['block'], isA()); expect(v['name'], isA()); expect(fromHex(v['hex']! as String), isNotEmpty); expect( v['result'] == 'ok' || codes.contains(v['result']), isTrue, reason: '${v['name']}: ${v['result']}', ); } }); test('the valid objects are items of the profile with their type tag', () { final valid = schemas.where((v) => v['result'] == 'ok').toList(); expect(valid, isNotEmpty); for (final v in valid) { final input = fromHex(v['hex']! as String); walkCbor(input, 16, input.length); expect( peekSchema(input).typeTag, typeTags[v['schema']], reason: '${v['name']}', ); } }); test( 'the vectors decode with the decoders of their schemas', () {}, skip: 'the decoders of the schemas arrive with stage 4', ); }); }