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.
103 lines
3.6 KiB
103 lines
3.6 KiB
|
2 days ago
|
// The normative errors of spec §69: the message convention of the Go
|
||
|
|
// reference, wrapping with a prefix and the code of an error, as
|
||
|
|
// errors_test.go of datekeys-go and the errors tests of bytes.test.ts of
|
||
|
|
// datekeys-ts. errors_spec_test.dart checks the catalogue against the spec.
|
||
|
|
|
||
|
|
import 'package:datekeys/datekeys.dart';
|
||
|
|
import 'package:test/test.dart';
|
||
|
|
|
||
|
|
void main() {
|
||
|
|
test('every code is written as the spec writes it, and printed so', () {
|
||
|
|
for (final c in ErrorCode.values) {
|
||
|
|
expect(c.code, matches(RegExp(r'^ERR_[A-Z_]+$')));
|
||
|
|
expect('$c', c.code);
|
||
|
|
}
|
||
|
|
expect(ErrorCode.values.map((c) => c.code).toSet(), hasLength(19));
|
||
|
|
});
|
||
|
|
|
||
|
|
test('a message is the context and the code, or the bare code', () {
|
||
|
|
final e = DateKeysException(
|
||
|
|
ErrorCode.integrity,
|
||
|
|
'capsule: truncated prelude',
|
||
|
|
);
|
||
|
|
expect(e.message, 'capsule: truncated prelude: ERR_INTEGRITY');
|
||
|
|
expect('$e', 'capsule: truncated prelude: ERR_INTEGRITY');
|
||
|
|
expect(e.code, ErrorCode.integrity);
|
||
|
|
expect(DateKeysException(ErrorCode.integrity).message, 'ERR_INTEGRITY');
|
||
|
|
expect(
|
||
|
|
DateKeysException(ErrorCode.invalidMagic, '').message,
|
||
|
|
'ERR_INVALID_MAGIC',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('wrapping puts a prefix before the message and keeps the code', () {
|
||
|
|
// fmt.Errorf("capsule: step 8: %w", fmt.Errorf("agewrap: %w", ErrRoundMismatch))
|
||
|
|
final err = DateKeysException(
|
||
|
|
ErrorCode.roundMismatch,
|
||
|
|
'agewrap',
|
||
|
|
).wrap('capsule: step 8');
|
||
|
|
expect(err.message, 'capsule: step 8: agewrap: ERR_ROUND_MISMATCH');
|
||
|
|
expect(errorCode(err), 'ERR_ROUND_MISMATCH');
|
||
|
|
expect(err.code, isNot(ErrorCode.integrity));
|
||
|
|
final data = DateKeysException(ErrorCode.extensionDataInvalid)
|
||
|
|
.wrap('capsule: step 4');
|
||
|
|
expect(data.message, 'capsule: step 4: ERR_EXTENSION_DATA_INVALID');
|
||
|
|
expect(data.code, ErrorCode.extensionDataInvalid);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('a failure kept as text adds no code', () {
|
||
|
|
// The failure of a relay kept as text, as provider/drand.Client keeps
|
||
|
|
// it: the error carries exactly one normative code.
|
||
|
|
final relay = DateKeysException(ErrorCode.roundMismatch, 'relay');
|
||
|
|
final err = DateKeysException(
|
||
|
|
ErrorCode.releaseUnavailable,
|
||
|
|
'drand: no relay returned a verified release for round 1000: ${relay.message}',
|
||
|
|
);
|
||
|
|
expect(errorCode(err), 'ERR_RELEASE_UNAVAILABLE');
|
||
|
|
expect(err.message, contains('ERR_ROUND_MISMATCH'));
|
||
|
|
expect(
|
||
|
|
err.message,
|
||
|
|
'drand: no relay returned a verified release for round 1000: relay: '
|
||
|
|
'ERR_ROUND_MISMATCH: ERR_RELEASE_UNAVAILABLE',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('errorCode is empty for anything but a DateKeys error', () {
|
||
|
|
expect(
|
||
|
|
errorCode(DateKeysException(ErrorCode.headInvalid)),
|
||
|
|
'ERR_HEAD_INVALID',
|
||
|
|
);
|
||
|
|
expect(errorCode(const FormatException('plain')), '');
|
||
|
|
expect(errorCode(StateError('plain')), '');
|
||
|
|
expect(errorCode(null), '');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('withContext prefixes DateKeys errors only, and keeps the stack', () {
|
||
|
|
expect(withContext('ctx', () => 1), 1);
|
||
|
|
StackTrace? inner;
|
||
|
|
DateKeysException? caught;
|
||
|
|
StackTrace? outer;
|
||
|
|
void failing() {
|
||
|
|
try {
|
||
|
|
throw DateKeysException(ErrorCode.integrity, 'inner');
|
||
|
|
} on DateKeysException catch (_, stack) {
|
||
|
|
inner = stack;
|
||
|
|
rethrow;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
withContext('ctx', failing);
|
||
|
|
} on DateKeysException catch (e, stack) {
|
||
|
|
caught = e;
|
||
|
|
outer = stack;
|
||
|
|
}
|
||
|
|
expect(caught?.message, 'ctx: inner: ERR_INTEGRITY');
|
||
|
|
expect(caught?.code, ErrorCode.integrity);
|
||
|
|
expect(inner, isNotNull);
|
||
|
|
expect('$outer', '$inner');
|
||
|
|
final plain = RangeError('plain');
|
||
|
|
expect(() => withContext('ctx', () => throw plain), throwsA(same(plain)));
|
||
|
|
});
|
||
|
|
}
|