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.
dateKeys-dart/test/cbor_vectors_test.dart

114 lines
3.6 KiB

Stage 1: the CBOR profile of section 58, as package codec of Go lib/src/cbor.dart is the port of codec/codec.go: CborEncoder, CborDecoder, unmarshalCbor, peekSchema, checkSchema and walkCbor, with the same reads, the same checks in the same order and the same error texts, such as "codec: offset 0: 23 is not in its shortest form (initial byte 0x18): ERR_NON_CANONICAL_CBOR". Integers are exact on the VM and on the web, where an int is a double and the bit operators work on 32 bits. An argument of eight bytes is read as two halves of 32 bits, and is an int up to 2^53-1 and a BigInt above, map keys and the numbers of the error texts included. uint returns an int, since every schema bounds its integers at 2^53-1, and uint64 a BigInt. The map that peekSchema reads is bounded at 2^63-1, Go's math.MaxInt, on the web too. Two kinds of text are of Dart only. CborEncoder.uint refuses an int outside 0..2^53-1 and uint64 a BigInt outside 0..2^64-1, with the text of datekeys-ts, where Go's uint64 cannot hold such a value. And the only invalid text that a Dart String holds is a lone surrogate: the error quotes it as Go quotes its bytes in generalized UTF-8. The tests port codec_test.go, internal_test.go and vectors_test.go, with the texts that Go prints, and cbor.test.ts. The fuzz targets are properties over seeded inputs, checked against a reference encoder and decoder written apart, as internal/cbortest. cbor.json runs its 36 accept and 67 reject vectors with the walk limits and the values; its 172 schema vectors are read and wait for the schema decoders of stage 4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 days ago
// 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<String, Object?>;
final walk = file['walk']! as Map<String, Object?>;
final maxDepth = walk['max_depth']! as int;
final maxLen = walk['max_len']! as int;
List<Map<String, Object?>> list(String key) =>
(file[key]! as List).cast<Map<String, Object?>>();
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, in
// formats_vectors_test.dart. Here its shape is checked, and the objects it
// holds as valid are items of the profile whose type tag peekSchema reads.
Stage 1: the CBOR profile of section 58, as package codec of Go lib/src/cbor.dart is the port of codec/codec.go: CborEncoder, CborDecoder, unmarshalCbor, peekSchema, checkSchema and walkCbor, with the same reads, the same checks in the same order and the same error texts, such as "codec: offset 0: 23 is not in its shortest form (initial byte 0x18): ERR_NON_CANONICAL_CBOR". Integers are exact on the VM and on the web, where an int is a double and the bit operators work on 32 bits. An argument of eight bytes is read as two halves of 32 bits, and is an int up to 2^53-1 and a BigInt above, map keys and the numbers of the error texts included. uint returns an int, since every schema bounds its integers at 2^53-1, and uint64 a BigInt. The map that peekSchema reads is bounded at 2^63-1, Go's math.MaxInt, on the web too. Two kinds of text are of Dart only. CborEncoder.uint refuses an int outside 0..2^53-1 and uint64 a BigInt outside 0..2^64-1, with the text of datekeys-ts, where Go's uint64 cannot hold such a value. And the only invalid text that a Dart String holds is a lone surrogate: the error quotes it as Go quotes its bytes in generalized UTF-8. The tests port codec_test.go, internal_test.go and vectors_test.go, with the texts that Go prints, and cbor.test.ts. The fuzz targets are properties over seeded inputs, checked against a reference encoder and decoder written apart, as internal/cbortest. cbor.json runs its 36 accept and 67 reject vectors with the walk limits and the values; its 172 schema vectors are read and wait for the schema decoders of stage 4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 days ago
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<String>());
expect(v['name'], isA<String>());
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']}',
);
}
});
});
}

Powered by TurnKey Linux.