From 0f2c7b9890617e0e766aff0092cd11fbf1bdc862 Mon Sep 17 00:00:00 2001 From: gmpassos Date: Wed, 10 Jun 2026 18:25:53 -0300 Subject: [PATCH 1/3] v1.9.32 - Expanded test coverage - Expanded tests for bones_api_utils_collections and Arguments. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 12 + lib/src/bones_api_base.dart | 2 +- lib/src/bones_api_test_utils_freeport.dart | 1 + pubspec.yaml | 2 +- test/bones_api_arguments_test.dart | 38 ++ test/bones_api_condition_test.dart | 5 +- test/bones_api_session_test.dart | 5 +- test/bones_api_types_test.dart | 10 +- test/bones_api_utils_collection_test.dart | 447 +++++++++++++++++++++ 9 files changed, 516 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f60dc457..f8d5b1f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## 1.9.32 + +- Tests: + - Expanded coverage of `bones_api_utils_collections`: + - `isEqualsDeep` / `isEqualsListDeep` / `isEqualsIterableDeep` / `isEqualsSetDeep` / `isEqualsMapDeep` (including nested structures, `null`/identity edge cases and custom `valueEquality`). + - `intersectsIterableDeep`. + - `deepCopy` / `deepCopyList` / `deepCopySet` / `deepCopyMap` (typed fast paths, `Uint8List`/`Int8List`, and copy independence). + - `MapAsCacheExtension` (`getCached`, `getCachedNullable`, `getCachedAsync`, `getCachedAsyncNullable`, `getIfCached`, `checkCacheLimit`). + - `MapOfCachesExtension` (`getMultiCached*`, `isEquivalentContext` wildcard semantics, `equivalentCaches`). + - `RecordExtension.positionalParametersLength`. + - Expanded coverage of `Arguments`: case-sensitive keys, trailing single-dash flags, the trailing double-dash error path, `keysAbbreviations` and `toArgumentsList`. + ## 1.9.31 - Bug fixes: diff --git a/lib/src/bones_api_base.dart b/lib/src/bones_api_base.dart index de2336ec..be124627 100644 --- a/lib/src/bones_api_base.dart +++ b/lib/src/bones_api_base.dart @@ -48,7 +48,7 @@ typedef APILogger = /// Bones API Library class. class BonesAPI { // ignore: constant_identifier_names - static const String VERSION = '1.9.31'; + static const String VERSION = '1.9.32'; static bool _boot = false; diff --git a/lib/src/bones_api_test_utils_freeport.dart b/lib/src/bones_api_test_utils_freeport.dart index ec199182..5d7e669d 100644 --- a/lib/src/bones_api_test_utils_freeport.dart +++ b/lib/src/bones_api_test_utils_freeport.dart @@ -5,6 +5,7 @@ import 'package:docker_commander/docker_commander_vm.dart'; final Set _initFreePorts = {}; +@override Future resolveFreePort(int port) { var startPort = port - 100; var endPort = port + 100; diff --git a/pubspec.yaml b/pubspec.yaml index b06f3f6e..d537d474 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: bones_api description: Bones_API - A powerful API backend framework for Dart. It comes with a built-in HTTP Server, route handler, entity handler, SQL translator, and DB adapters. -version: 1.9.31 +version: 1.9.32 homepage: https://github.com/Colossus-Services/bones_api environment: diff --git a/test/bones_api_arguments_test.dart b/test/bones_api_arguments_test.dart index ef7ebf55..17ac7026 100644 --- a/test/bones_api_arguments_test.dart +++ b/test/bones_api_arguments_test.dart @@ -86,5 +86,43 @@ void main() { equals('-v --address host --port 80 --list 1 --list 2 --list 3'), ); }); + + test('caseSensitive keys', () async { + var argsInsensitive = Arguments.parseLine('-Address host'); + expect(argsInsensitive.parameters, equals({'address': 'host'})); + + var argsSensitive = Arguments.parseLine('-Address host', caseSensitive: true); + expect(argsSensitive.parameters, equals({'Address': 'host'})); + }); + + test('trailing single-dash key becomes a flag', () async { + var args = Arguments.parseLine('x -v'); + expect(args.flags, equals({'v'})); + expect(args.parameters, isEmpty); + expect(args.args, equals(['x'])); + }); + + test('trailing double-dash parameter with no value throws', () async { + expect( + () => Arguments.parseLine('x --foo'), + throwsA(isA()), + ); + }); + + test('keysAbbreviations inverts abbreviations', () async { + var args = Arguments.parseLine( + '-a host', + abbreviations: {'a': 'address', 'v': 'verbose'}, + ); + expect( + args.keysAbbreviations, + equals({'address': 'a', 'verbose': 'v'}), + ); + }); + + test('toArgumentsList', () async { + var args = Arguments.parseLine('x -a 1 -f'); + expect(args.toArgumentsList(), equals(['-f', '--a', '1'])); + }); }); } diff --git a/test/bones_api_condition_test.dart b/test/bones_api_condition_test.dart index 2ac742eb..ef7ac546 100644 --- a/test/bones_api_condition_test.dart +++ b/test/bones_api_condition_test.dart @@ -538,7 +538,10 @@ void main() { expect(await enc.resolveValueToType(7, int), equals(7)); // A multi-element list can't be resolved to a primitive: - expect(() => enc.resolveValueToType([1, 2], int), throwsArgumentError); + expect( + () => enc.resolveValueToType([1, 2], int), + throwsArgumentError, + ); }); }); diff --git a/test/bones_api_session_test.dart b/test/bones_api_session_test.dart index 94f46969..2e006757 100644 --- a/test/bones_api_session_test.dart +++ b/test/bones_api_session_test.dart @@ -20,7 +20,10 @@ void main() { isFalse, ); // Exactly at the timeout (elapsed == timeout is NOT expired): - expect(session.isExpired(timeout, now: lastAccess.add(timeout)), isFalse); + expect( + session.isExpired(timeout, now: lastAccess.add(timeout)), + isFalse, + ); // Past the timeout window: expect( session.isExpired(timeout, now: lastAccess.add(Duration(seconds: 11))), diff --git a/test/bones_api_types_test.dart b/test/bones_api_types_test.dart index bb093f9a..cbb1a486 100644 --- a/test/bones_api_types_test.dart +++ b/test/bones_api_types_test.dart @@ -270,7 +270,10 @@ void main() { test('range validation', () async { // Valid boundaries: expect(Time(0, 0, 0, 0, 0).toString(), equals('00:00:00')); - expect(Time(23, 59, 59, 999, 999).toString(), equals('23:59:59.999999')); + expect( + Time(23, 59, 59, 999, 999).toString(), + equals('23:59:59.999999'), + ); // millisecond/microsecond must be in range 0..999 (1000 is invalid): expect(() => Time(0, 0, 0, 1000), throwsArgumentError); @@ -285,7 +288,10 @@ void main() { test('fromBytes string format', () async { // 8-byte ASCII string "20:11:31" must be parsed as a string, not as // binary-encoded microseconds: - expect(Time.fromBytes('20:11:31'.codeUnits), equals(Time(20, 11, 31))); + expect( + Time.fromBytes('20:11:31'.codeUnits), + equals(Time(20, 11, 31)), + ); expect( Time.fromBytes('20:11:31.123'.codeUnits), diff --git a/test/bones_api_utils_collection_test.dart b/test/bones_api_utils_collection_test.dart index 6da583a0..18d1a263 100644 --- a/test/bones_api_utils_collection_test.dart +++ b/test/bones_api_utils_collection_test.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:bones_api/bones_api.dart'; import 'package:test/test.dart'; @@ -78,4 +80,449 @@ void main() { expect(s1.toList(), unorderedEquals(['b'])); }); }); + + group('isEqualsDeep', () { + test('primitives and identity', () { + expect(isEqualsDeep(1, 1), isTrue); + expect(isEqualsDeep('a', 'a'), isTrue); + expect(isEqualsDeep(1, 2), isFalse); + expect(isEqualsDeep(null, null), isTrue); + expect(isEqualsDeep(null, 1), isFalse); + expect(isEqualsDeep(1, null), isFalse); + + var o = Object(); + expect(isEqualsDeep(o, o), isTrue); + }); + + test('lists', () { + expect(isEqualsListDeep([1, 2, 3], [1, 2, 3]), isTrue); + expect(isEqualsListDeep([1, 2, 3], [1, 2, 4]), isFalse); + expect(isEqualsListDeep([1, 2], [1, 2, 3]), isFalse); + expect(isEqualsListDeep(null, [1]), isFalse); + expect(isEqualsListDeep([1], null), isFalse); + expect(isEqualsListDeep(null, null), isTrue); + + var l = [1, 2]; + expect(isEqualsListDeep(l, l), isTrue); + + // nested + expect( + isEqualsDeep( + [ + [1, 2], + [3, 4], + ], + [ + [1, 2], + [3, 4], + ], + ), + isTrue, + ); + expect( + isEqualsDeep( + [ + [1, 2], + ], + [ + [1, 9], + ], + ), + isFalse, + ); + }); + + test('iterables', () { + expect(isEqualsIterableDeep([1, 2].map((e) => e), [1, 2]), isTrue); + expect(isEqualsIterableDeep([1, 2].where((e) => true), [1, 3]), isFalse); + expect(isEqualsIterableDeep([1].map((e) => e), [1, 2]), isFalse); + expect(isEqualsIterableDeep(null, [1]), isFalse); + expect(isEqualsIterableDeep([1], null), isFalse); + expect(isEqualsIterableDeep(null, null), isTrue); + }); + + test('sets', () { + expect(isEqualsSetDeep({1, 2, 3}, {3, 2, 1}), isTrue); + expect(isEqualsSetDeep({1, 2}, {1, 2, 3}), isFalse); + expect(isEqualsSetDeep({1, 2}, {1, 9}), isFalse); + expect(isEqualsSetDeep(null, {1}), isFalse); + expect(isEqualsSetDeep({1}, null), isFalse); + expect(isEqualsSetDeep(null, null), isTrue); + + var s = {1, 2}; + expect(isEqualsSetDeep(s, s), isTrue); + }); + + test('maps', () { + expect(isEqualsMapDeep({'a': 1, 'b': 2}, {'b': 2, 'a': 1}), isTrue); + expect(isEqualsMapDeep({'a': 1}, {'a': 2}), isFalse); + expect(isEqualsMapDeep({'a': 1}, {'a': 1, 'b': 2}), isFalse); + expect(isEqualsMapDeep({'a': 1}, {'b': 1}), isFalse); + expect(isEqualsMapDeep(null, {'a': 1}), isFalse); + expect(isEqualsMapDeep({'a': 1}, null), isFalse); + expect(isEqualsMapDeep(null, null), isTrue); + + var m = {'a': 1}; + expect(isEqualsMapDeep(m, m), isTrue); + + // nested via isEqualsDeep dispatch + expect( + isEqualsDeep( + { + 'a': [1, 2], + }, + { + 'a': [1, 2], + }, + ), + isTrue, + ); + }); + + test('dispatch via isEqualsDeep', () { + expect(isEqualsDeep([1, 2], [1, 2]), isTrue); + expect(isEqualsDeep({1, 2}, {2, 1}), isTrue); + expect(isEqualsDeep({'a': 1}, {'a': 1}), isTrue); + // List vs Set -> not equal + expect(isEqualsDeep([1, 2], {1, 2}), isFalse); + }); + + test('valueEquality', () { + bool ciEquals(Object? a, Object? b) => + a.toString().toLowerCase() == b.toString().toLowerCase(); + + expect(isEqualsDeep('ABC', 'abc'), isFalse); + expect(isEqualsDeep('ABC', 'abc', valueEquality: ciEquals), isTrue); + expect( + isEqualsDeep(['ABC'], ['abc'], valueEquality: ciEquals), + isTrue, + ); + }); + }); + + group('intersectsIterableDeep', () { + test('basic', () { + expect(intersectsIterableDeep([1, 2, 3], [4, 5, 2]), isTrue); + expect(intersectsIterableDeep([1, 2, 3], [4, 5, 6]), isFalse); + expect(intersectsIterableDeep([], [1]), isFalse); + expect(intersectsIterableDeep([1], []), isFalse); + expect(intersectsIterableDeep(null, [1]), isFalse); + expect(intersectsIterableDeep([1], null), isFalse); + + var l = [1, 2]; + expect(intersectsIterableDeep(l, l), isTrue); + }); + + test('deep elements', () { + expect( + intersectsIterableDeep( + [ + [1, 2], + ], + [ + [9, 9], + [1, 2], + ], + ), + isTrue, + ); + }); + }); + + group('deepCopy', () { + test('primitives', () { + expect(deepCopy(null), isNull); + expect(deepCopy('abc'), equals('abc')); + expect(deepCopy(42), equals(42)); + expect(deepCopy(3.14), equals(3.14)); + expect(deepCopy(true), equals(true)); + }); + + test('list copies are independent', () { + List original = [ + [1, 2], + [3, 4], + ]; + var copy = deepCopy(original) as List; + expect(copy, equals(original)); + expect(identical(copy, original), isFalse); + expect(identical(copy[0], original[0]), isFalse); + + (copy[0] as List)[0] = 99; + expect((original[0] as List)[0], equals(1)); + }); + + test('deepCopyList typed fast paths', () { + expect(deepCopyList(null), isNull); + expect(deepCopyList([]), equals([])); + expect(deepCopyList(['a', 'b']), equals(['a', 'b'])); + expect(deepCopyList([1, 2]), equals([1, 2])); + expect(deepCopyList([1.0, 2.0]), equals([1.0, 2.0])); + expect(deepCopyList([1, 2.0]), equals([1, 2.0])); + expect(deepCopyList([true, false]), equals([true, false])); + + var bytes = Uint8List.fromList([1, 2, 3]); + var bytesCopy = deepCopyList(bytes)!; + expect(bytesCopy, equals([1, 2, 3])); + expect(identical(bytesCopy, bytes), isFalse); + + var i8 = Int8List.fromList([1, -2, 3]); + var i8Copy = deepCopyList(i8)!; + expect(i8Copy, equals([1, -2, 3])); + expect(identical(i8Copy, i8), isFalse); + }); + + test('deepCopySet typed fast paths', () { + expect(deepCopySet(null), isNull); + expect(deepCopySet({}), equals({})); + expect(deepCopySet({'a'}), equals({'a'})); + expect(deepCopySet({1, 2}), equals({1, 2})); + expect(deepCopySet({1.0}), equals({1.0})); + expect(deepCopySet({1, 2.0}), equals({1, 2.0})); + expect(deepCopySet({true}), equals({true})); + + var original = >{ + [1, 2], + }; + var copy = deepCopySet(original)!; + expect(copy.first, equals([1, 2])); + expect(identical(copy.first, original.first), isFalse); + }); + + test('deepCopyMap typed fast paths', () { + expect(deepCopyMap(null), isNull); + expect(deepCopyMap({}), equals({})); + expect(deepCopyMap({'a': 'b'}), equals({'a': 'b'})); + expect(deepCopyMap({'a': 1}), equals({'a': 1})); + expect(deepCopyMap({'a': 1.0}), equals({'a': 1.0})); + expect(deepCopyMap({'a': 1}), equals({'a': 1})); + expect(deepCopyMap({'a': true}), equals({'a': true})); + + var original = >{ + 'k': [1, 2], + }; + var copy = deepCopyMap(original)!; + expect(copy['k'], equals([1, 2])); + expect(identical(copy['k'], original['k']), isFalse); + }); + + test('deepCopy dispatch for Set/Iterable/Map', () { + var s = deepCopy({1, 2})!; + expect(s, equals({1, 2})); + + var it = deepCopy([1, 2, 3].map((e) => e * 2))!; + expect(it, equals([2, 4, 6])); + + var m = deepCopy({'a': 1})!; + expect(m, equals({'a': 1})); + }); + }); + + group('MapAsCacheExtension', () { + test('getCached caches the computed value', () { + var cache = {}; + var calls = 0; + + var v1 = cache.getCached('a', () { + calls++; + return 10; + }); + expect(v1, equals(10)); + + var v2 = cache.getCached('a', () { + calls++; + return 20; + }); + expect(v2, equals(10)); + expect(calls, equals(1)); + }); + + test('getCachedNullable does not cache null', () { + var cache = {}; + var calls = 0; + + var v = cache.getCachedNullable('a', () { + calls++; + return null; + }); + expect(v, isNull); + expect(cache.containsKey('a'), isFalse); + + var v2 = cache.getCachedNullable('a', () { + calls++; + return 5; + }); + expect(v2, equals(5)); + expect(cache['a'], equals(5)); + expect(calls, equals(2)); + }); + + test('getIfCached returns current value', () { + var cache = {'a': 1}; + expect(cache.getIfCached('a'), equals(1)); + expect(cache.getIfCached('b'), isNull); + }); + + test('getCachedAsync caches resolved value', () async { + var cache = {}; + var calls = 0; + + var v1 = await cache.getCachedAsync('a', () async { + calls++; + return 7; + }); + expect(v1, equals(7)); + + var v2 = await cache.getCachedAsync('a', () async { + calls++; + return 99; + }); + expect(v2, equals(7)); + expect(calls, equals(1)); + }); + + test('getCachedAsyncNullable does not cache null', () async { + var cache = {}; + + var v = await cache.getCachedAsyncNullable('a', () async => null); + expect(v, isNull); + expect(cache.containsKey('a'), isFalse); + + var v2 = await cache.getCachedAsyncNullable('a', () async => 3); + expect(v2, equals(3)); + expect(cache['a'], equals(3)); + }); + + test('checkCacheLimit evicts oldest entries', () { + var cache = {}; + for (var i = 0; i < 5; ++i) { + cache['k$i'] = i; + } + + expect(cache.checkCacheLimit(null), equals(0)); + expect(cache.length, equals(5)); + + var deleted = cache.checkCacheLimit(3); + expect(deleted, equals(2)); + expect(cache.length, equals(3)); + // first-inserted keys evicted + expect(cache.containsKey('k0'), isFalse); + expect(cache.containsKey('k1'), isFalse); + expect(cache.containsKey('k4'), isTrue); + + var cleared = cache.checkCacheLimit(0); + expect(cleared, equals(3)); + expect(cache.isEmpty, isTrue); + }); + + test('getCached enforces cacheLimit', () { + var cache = {}; + // Eviction runs before insertion, so length stays bounded near the limit. + for (var i = 0; i < 10; ++i) { + cache.getCached('k$i', () => i, cacheLimit: 2); + } + expect(cache.length, lessThanOrEqualTo(3)); + expect(cache.length, greaterThanOrEqualTo(2)); + }); + }); + + group('MapOfCachesExtension', () { + test('getMultiCached reuses equivalent (wildcard) cache', () { + var caches = <(String, bool), Map>{}; + + // Populate a wildcard cache (second field == true matches any query). + caches.populateMultiCache('k1', ('a', true), () => {}, 100); + + var computerCalled = false; + var v = caches.getMultiCached('k1', ('a', false), () => {}, () { + computerCalled = true; + return 999; + }); + + expect(v, equals(100)); + expect(computerCalled, isFalse); + }); + + test('getMultiCached computes and caches on miss', () { + var caches = <(String, bool), Map>{}; + + var v = caches.getMultiCached('k', ('a', false), () => {}, () => 42); + expect(v, equals(42)); + + // Now cached in its own context. + var v2 = caches.getMultiCached('k', ('a', false), () => {}, () => 0); + expect(v2, equals(42)); + }); + + test('getMultiCachedNullable does not cache null', () { + var caches = <(String, bool), Map>{}; + + var v = caches.getMultiCachedNullable( + 'k', + ('a', false), + () => {}, + () => null, + ); + expect(v, isNull); + + var v2 = caches.getMultiCachedNullable( + 'k', + ('a', false), + () => {}, + () => 5, + ); + expect(v2, equals(5)); + }); + + test('getMultiCachedAsync resolves and caches', () async { + var caches = <(String, bool), Map>{}; + + var v = await caches.getMultiCachedAsync( + 'k', + ('a', false), + () => {}, + () async => 11, + ); + expect(v, equals(11)); + + var v2 = await caches.getMultiCachedAsync( + 'k', + ('a', false), + () => {}, + () async => 0, + ); + expect(v2, equals(11)); + }); + + test('isEquivalentContext wildcard semantics', () { + var caches = <(String, bool), Map>{}; + expect(caches.isEquivalentContext(('a', false), ('a', false)), isTrue); + expect(caches.isEquivalentContext(('a', true), ('a', false)), isTrue); + expect(caches.isEquivalentContext(('a', false), ('a', true)), isFalse); + expect(caches.isEquivalentContext(('a', false), ('b', false)), isFalse); + }); + + test('equivalentCaches excludes exact-context match', () { + var caches = <(String, bool), Map>{}; + caches.populateMultiCache('k', ('a', true), () => {}, 1); + caches.populateMultiCache('k', ('a', false), () => {}, 2); + + var equivalents = caches.equivalentCaches(('a', false)).toList(); + // Only the wildcard ('a', true) is equivalent; ('a', false) itself excluded. + expect(equivalents.length, equals(1)); + expect(equivalents.first['k'], equals(1)); + }); + }); + + group('RecordExtension', () { + test('positionalParametersLength', () { + expect((1,).positionalParametersLength, equals(1)); + expect((1, 2).positionalParametersLength, equals(2)); + expect((1, 2, 3).positionalParametersLength, equals(3)); + expect((1, 2, 3, 4).positionalParametersLength, equals(4)); + expect((1, 2, 3, 4, 5).positionalParametersLength, equals(5)); + // Cached on second access. + expect((9, 8).positionalParametersLength, equals(2)); + }); + }); } From 0b31d0197f1474f55d32fa57aaf3a1a461189c89 Mon Sep 17 00:00:00 2001 From: gmpassos Date: Wed, 10 Jun 2026 18:47:52 -0300 Subject: [PATCH 2/3] dart format --- test/bones_api_arguments_test.dart | 15 +++++------ test/bones_api_condition_test.dart | 5 +--- test/bones_api_session_test.dart | 5 +--- test/bones_api_types_test.dart | 10 ++----- test/bones_api_utils_collection_test.dart | 32 ++++++++++++++++------- 5 files changed, 32 insertions(+), 35 deletions(-) diff --git a/test/bones_api_arguments_test.dart b/test/bones_api_arguments_test.dart index 17ac7026..9b6df844 100644 --- a/test/bones_api_arguments_test.dart +++ b/test/bones_api_arguments_test.dart @@ -91,7 +91,10 @@ void main() { var argsInsensitive = Arguments.parseLine('-Address host'); expect(argsInsensitive.parameters, equals({'address': 'host'})); - var argsSensitive = Arguments.parseLine('-Address host', caseSensitive: true); + var argsSensitive = Arguments.parseLine( + '-Address host', + caseSensitive: true, + ); expect(argsSensitive.parameters, equals({'Address': 'host'})); }); @@ -103,10 +106,7 @@ void main() { }); test('trailing double-dash parameter with no value throws', () async { - expect( - () => Arguments.parseLine('x --foo'), - throwsA(isA()), - ); + expect(() => Arguments.parseLine('x --foo'), throwsA(isA())); }); test('keysAbbreviations inverts abbreviations', () async { @@ -114,10 +114,7 @@ void main() { '-a host', abbreviations: {'a': 'address', 'v': 'verbose'}, ); - expect( - args.keysAbbreviations, - equals({'address': 'a', 'verbose': 'v'}), - ); + expect(args.keysAbbreviations, equals({'address': 'a', 'verbose': 'v'})); }); test('toArgumentsList', () async { diff --git a/test/bones_api_condition_test.dart b/test/bones_api_condition_test.dart index ef7ac546..2ac742eb 100644 --- a/test/bones_api_condition_test.dart +++ b/test/bones_api_condition_test.dart @@ -538,10 +538,7 @@ void main() { expect(await enc.resolveValueToType(7, int), equals(7)); // A multi-element list can't be resolved to a primitive: - expect( - () => enc.resolveValueToType([1, 2], int), - throwsArgumentError, - ); + expect(() => enc.resolveValueToType([1, 2], int), throwsArgumentError); }); }); diff --git a/test/bones_api_session_test.dart b/test/bones_api_session_test.dart index 2e006757..94f46969 100644 --- a/test/bones_api_session_test.dart +++ b/test/bones_api_session_test.dart @@ -20,10 +20,7 @@ void main() { isFalse, ); // Exactly at the timeout (elapsed == timeout is NOT expired): - expect( - session.isExpired(timeout, now: lastAccess.add(timeout)), - isFalse, - ); + expect(session.isExpired(timeout, now: lastAccess.add(timeout)), isFalse); // Past the timeout window: expect( session.isExpired(timeout, now: lastAccess.add(Duration(seconds: 11))), diff --git a/test/bones_api_types_test.dart b/test/bones_api_types_test.dart index cbb1a486..bb093f9a 100644 --- a/test/bones_api_types_test.dart +++ b/test/bones_api_types_test.dart @@ -270,10 +270,7 @@ void main() { test('range validation', () async { // Valid boundaries: expect(Time(0, 0, 0, 0, 0).toString(), equals('00:00:00')); - expect( - Time(23, 59, 59, 999, 999).toString(), - equals('23:59:59.999999'), - ); + expect(Time(23, 59, 59, 999, 999).toString(), equals('23:59:59.999999')); // millisecond/microsecond must be in range 0..999 (1000 is invalid): expect(() => Time(0, 0, 0, 1000), throwsArgumentError); @@ -288,10 +285,7 @@ void main() { test('fromBytes string format', () async { // 8-byte ASCII string "20:11:31" must be parsed as a string, not as // binary-encoded microseconds: - expect( - Time.fromBytes('20:11:31'.codeUnits), - equals(Time(20, 11, 31)), - ); + expect(Time.fromBytes('20:11:31'.codeUnits), equals(Time(20, 11, 31))); expect( Time.fromBytes('20:11:31.123'.codeUnits), diff --git a/test/bones_api_utils_collection_test.dart b/test/bones_api_utils_collection_test.dart index 18d1a263..63db1731 100644 --- a/test/bones_api_utils_collection_test.dart +++ b/test/bones_api_utils_collection_test.dart @@ -193,10 +193,7 @@ void main() { expect(isEqualsDeep('ABC', 'abc'), isFalse); expect(isEqualsDeep('ABC', 'abc', valueEquality: ciEquals), isTrue); - expect( - isEqualsDeep(['ABC'], ['abc'], valueEquality: ciEquals), - isTrue, - ); + expect(isEqualsDeep(['ABC'], ['abc'], valueEquality: ciEquals), isTrue); }); }); @@ -434,10 +431,15 @@ void main() { caches.populateMultiCache('k1', ('a', true), () => {}, 100); var computerCalled = false; - var v = caches.getMultiCached('k1', ('a', false), () => {}, () { - computerCalled = true; - return 999; - }); + var v = caches.getMultiCached( + 'k1', + ('a', false), + () => {}, + () { + computerCalled = true; + return 999; + }, + ); expect(v, equals(100)); expect(computerCalled, isFalse); @@ -446,11 +448,21 @@ void main() { test('getMultiCached computes and caches on miss', () { var caches = <(String, bool), Map>{}; - var v = caches.getMultiCached('k', ('a', false), () => {}, () => 42); + var v = caches.getMultiCached( + 'k', + ('a', false), + () => {}, + () => 42, + ); expect(v, equals(42)); // Now cached in its own context. - var v2 = caches.getMultiCached('k', ('a', false), () => {}, () => 0); + var v2 = caches.getMultiCached( + 'k', + ('a', false), + () => {}, + () => 0, + ); expect(v2, equals(42)); }); From 97801143148a683a381888664a3de542600bbccc Mon Sep 17 00:00:00 2001 From: gmpassos Date: Wed, 10 Jun 2026 18:51:12 -0300 Subject: [PATCH 3/3] Remove invalid @override annotation on top-level resolveFreePort Co-Authored-By: Claude Opus 4.8 --- lib/src/bones_api_test_utils_freeport.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/bones_api_test_utils_freeport.dart b/lib/src/bones_api_test_utils_freeport.dart index 5d7e669d..ec199182 100644 --- a/lib/src/bones_api_test_utils_freeport.dart +++ b/lib/src/bones_api_test_utils_freeport.dart @@ -5,7 +5,6 @@ import 'package:docker_commander/docker_commander_vm.dart'; final Set _initFreePorts = {}; -@override Future resolveFreePort(int port) { var startPort = port - 100; var endPort = port + 100;