From 56e72e349b47a3115f01fb78354bbfabb07f74f5 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Tue, 26 Mar 2024 21:19:37 +0100 Subject: [PATCH 01/11] feat IListEmpty type --- example/test.dart | 9 ++++++++ lib/src/ilist/ilist.dart | 46 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 example/test.dart diff --git a/example/test.dart b/example/test.dart new file mode 100644 index 0000000..f2d877b --- /dev/null +++ b/example/test.dart @@ -0,0 +1,9 @@ +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; + +void main(List args) { + IList list = const IList.empty(); + //list = list.flush; + list = list.addAll(["abc"]); + final expanded = list.expand((p0) => p0.runes); + print(expanded); +} diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index 2947e33..a24e1eb 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -14,6 +14,50 @@ import "l_add.dart"; import "l_add_all.dart"; import "l_flat.dart"; +@immutable +class IListEmpty extends IList { + @literal + const IListEmpty([this.config = const ConfigList()]) + : super._gen(); + + @override + final ConfigList config; + + /// A empty list is always flushed, by definition. + @override + bool get isFlushed => true; + + /// Nothing happens when you flush a empty list, by definition. + @override + // ignore: non_const_call_to_literal_constructor + IListEmpty get flush => this; + + @override + int get _counter => 0; + + @override + L get _l => LFlat.unsafe([]); + + /// Hash codes must be the same for objects that are equal to each other + /// according to operator ==. + @override + int? get _hashCode { + return isDeepEquals + ? hash2(const ListEquality().hash([]), config.hashCode) + : hash2(identityHashCode(_l), config.hashCode); + } + + @override + set _hashCode(int? value) {} + + @override + bool same(IList? other) => + (other != null) && + (other is IListConst) && + identical([], (other as IListConst)._list) && + (config == other.config); +} + /// This is an [IList] which can be made constant. /// Note: Don't ever use it without the "const" keyword, because it will be unsafe. /// @@ -202,7 +246,7 @@ abstract class IList // ignore: must_be_immutable /// Create an empty [IList]. /// Use it with const: `const IList.empty()` (It's always an [IListConst]). @literal - const factory IList.empty() = IListConst.empty; + const factory IList.empty() = IListEmpty; const IList._gen(); From e75d8c02666bbbbda285879a797e2e66238aab72 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Tue, 26 Mar 2024 22:14:05 +0100 Subject: [PATCH 02/11] further improved implementation --- example/test.dart | 9 ------ lib/src/ilist/ilist.dart | 17 ++++------- test/ilist/ilist_empty_test.dart | 49 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 20 deletions(-) delete mode 100644 example/test.dart create mode 100644 test/ilist/ilist_empty_test.dart diff --git a/example/test.dart b/example/test.dart deleted file mode 100644 index f2d877b..0000000 --- a/example/test.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:fast_immutable_collections/fast_immutable_collections.dart'; - -void main(List args) { - IList list = const IList.empty(); - //list = list.flush; - list = list.addAll(["abc"]); - final expanded = list.expand((p0) => p0.runes); - print(expanded); -} diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index a24e1eb..e6ee13e 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -15,7 +15,12 @@ import "l_add_all.dart"; import "l_flat.dart"; @immutable -class IListEmpty extends IList { +class IListEmpty // ignore: must_be_immutable + extends IList { + /// Creates a empty list. + /// + /// IMPORTANT: You must always use the `const` keyword. + /// It's always wrong to use an `IListEmpty()` which is not constant. @literal const IListEmpty([this.config = const ConfigList()]) : super._gen(); @@ -29,7 +34,6 @@ class IListEmpty extends IList { /// Nothing happens when you flush a empty list, by definition. @override - // ignore: non_const_call_to_literal_constructor IListEmpty get flush => this; @override @@ -78,15 +82,6 @@ class IListConst // ignore: must_be_immutable [this.config = const ConfigList()]) : super._gen(); - /// Creates a empty constant list. - /// - /// IMPORTANT: You must always use the `const` keyword. - /// It's always wrong to use an `IListConst.empty()` which is not constant. - @literal - const IListConst.empty([this.config = const ConfigList()]) - : _list = const [], - super._gen(); - final List _list; @override diff --git a/test/ilist/ilist_empty_test.dart b/test/ilist/ilist_empty_test.dart new file mode 100644 index 0000000..b3753bb --- /dev/null +++ b/test/ilist/ilist_empty_test.dart @@ -0,0 +1,49 @@ +// Developed by Marcelo Glasberg (2021) https://glasberg.dev and https://github.com/marcglasberg +// and Philippe Fanaro https://github.com/psygo +// For more info, see: https://pub.dartlang.org/packages/fast_immutable_collections +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:test/test.dart'; + +void main() { + setUp(() { + ImmutableCollection.resetAllConfigurations(); + ImmutableCollection.autoFlush = false; + }); + + + test("Runtime Type", () { + expect(const IListEmpty(), isA()); + expect(const IListEmpty(), isA()); + expect(const IListEmpty(), isA>()); + expect(const IListEmpty(), isA>()); + + expect(const IListEmpty(), isA()); + expect(const IListEmpty(), isA()); + expect(const IListEmpty(), isA>()); + expect(const IListEmpty(), isA>()); + }); + + test("Make sure the IListEmpty can be modified and later iterated", () { + IList list = const IList.empty(); + list = list.addAll(["a", "b", "c"]); + list.forEach((_) { }); + list = list.add("d"); + list.forEach((_) { }); + list = list.remove("a"); + list.forEach((_) { }); + }); + + test("Make sure the internal list is List, and not List", () { + const l1 = IListEmpty(); + expect(l1.runtimeType.toString(), 'IListEmpty'); + + const l2 = IListConst([1, 2, 3]); + expect(l2.runtimeType.toString(), 'IListConst'); + + final l3 = l1.addAll(l2); + expect(l3.runtimeType.toString(), 'IListImpl'); + + final result = l3.where((int i) => i == 2).toList(); + expect(result, [2]); + }); +} From 6d40327cc5f75b477cb3a21df69cd9dd9897269a Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Tue, 26 Mar 2024 22:35:26 +0100 Subject: [PATCH 03/11] updated comment --- lib/src/ilist/ilist.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index e6ee13e..779f761 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -239,7 +239,7 @@ abstract class IList // ignore: must_be_immutable IList.withConfig(iterable ?? const [], defaultConfig); /// Create an empty [IList]. - /// Use it with const: `const IList.empty()` (It's always an [IListConst]). + /// Use it with const: `const IList.empty()` (It's always an [IListEmpty]). @literal const factory IList.empty() = IListEmpty; From f5cc545cfbf39583e1aca8bdcd1bc06bafeb1fe4 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 10:55:49 +0100 Subject: [PATCH 04/11] fixed .same() for IListEmpty, added test --- lib/src/ilist/ilist.dart | 3 +-- test/ilist/ilist_empty_test.dart | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index 779f761..ead7ec4 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -57,8 +57,7 @@ class IListEmpty // ignore: must_be_immutable @override bool same(IList? other) => (other != null) && - (other is IListConst) && - identical([], (other as IListConst)._list) && + (other is IListEmpty) && (config == other.config); } diff --git a/test/ilist/ilist_empty_test.dart b/test/ilist/ilist_empty_test.dart index b3753bb..7b950ea 100644 --- a/test/ilist/ilist_empty_test.dart +++ b/test/ilist/ilist_empty_test.dart @@ -46,4 +46,8 @@ void main() { final result = l3.where((int i) => i == 2).toList(); expect(result, [2]); }); + + test(".same() is working properly", () { + expect(const IList.empty().same(const IList.empty()), isTrue); + }); } From 211dbf12667fc5c59b4afc82139c724e8b194fc9 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 11:31:24 +0100 Subject: [PATCH 05/11] Added IMapEmpty and ISetEmpty --- lib/src/ilist/ilist.dart | 3 +- lib/src/imap/imap.dart | 61 +++++++++++++++++++++++++------ lib/src/iset/iset.dart | 61 +++++++++++++++++++++++++------ test/ilist/ilist_empty_test.dart | 7 ++-- test/imap/imap_empty_test.dart | 63 ++++++++++++++++++++++++++++++++ test/iset/iset_empty_test.dart | 54 +++++++++++++++++++++++++++ 6 files changed, 223 insertions(+), 26 deletions(-) create mode 100644 test/imap/imap_empty_test.dart create mode 100644 test/iset/iset_empty_test.dart diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index ead7ec4..c7ec2a1 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -14,10 +14,11 @@ import "l_add.dart"; import "l_add_all.dart"; import "l_flat.dart"; +/// This is an [IList] which is always empty. @immutable class IListEmpty // ignore: must_be_immutable extends IList { - /// Creates a empty list. + /// Creates a empty list. In most cases, you should use `const IList.empty()`. /// /// IMPORTANT: You must always use the `const` keyword. /// It's always wrong to use an `IListEmpty()` which is not constant. diff --git a/lib/src/imap/imap.dart b/lib/src/imap/imap.dart index a76fc55..bfa0e0f 100644 --- a/lib/src/imap/imap.dart +++ b/lib/src/imap/imap.dart @@ -15,6 +15,54 @@ import "m_add_all.dart"; import "m_flat.dart"; import "m_replace.dart"; +/// This is an [IMap] which is always empty. +@immutable +class IMapEmpty // ignore: must_be_immutable + extends IMap { + /// Creates a empty map. In most cases, you should use `const IMap.empty()`. + /// + /// IMPORTANT: You must always use the `const` keyword. + /// It's always wrong to use an `IMapEmpty()` which is not constant. + @literal + const IMapEmpty([this.config = const ConfigMap()]) + : super._gen(); + + @override + final ConfigMap config; + + /// A empty map is always flushed, by definition. + @override + bool get isFlushed => true; + + /// Nothing happens when you flush a empty map, by definition. + @override + IMapEmpty get flush => this; + + @override + int get _counter => 0; + + @override + M get _m => MFlat.unsafe({}); + + /// Hash codes must be the same for objects that are equal to each other + /// according to operator ==. + @override + int? get _hashCode { + return isDeepEquals + ? hash2(const MapEquality().hash({}), config.hashCode) + : hash2(identityHashCode(_m), config.hashCode); + } + + @override + set _hashCode(int? value) {} + + @override + bool same(IMap? other) => + (other != null) && + (other is IMapEmpty) && + (config == other.config); +} + /// This is an [IMap] which can be made constant. /// Note: Don't ever use it without the "const" keyword, because it will be unsafe. /// @@ -35,15 +83,6 @@ class IMapConst // ignore: must_be_immutable [this.config = const ConfigMap()]) : super._gen(); - /// Creates a empty constant map. - /// - /// IMPORTANT: You must always use the `const` keyword. - /// It's always wrong to use an `IMapConst.empty()` which is not constant. - @literal - const IMapConst.empty([this.config = const ConfigMap()]) - : _map = const {}, - super._gen(); - final Map _map; @override @@ -182,9 +221,9 @@ abstract class IMap // ignore: must_be_immutable IMap.withConfig(map, defaultConfig); /// Create an empty [IMap]. - /// Use it with const: `const IMap.empty()` (It's always an [IMapConst]). + /// Use it with const: `const IMap.empty()` (It's always an [IMapEmpty]). @literal - const factory IMap.empty() = IMapConst.empty; + const factory IMap.empty() = IMapEmpty; const IMap._gen(); diff --git a/lib/src/iset/iset.dart b/lib/src/iset/iset.dart index 18ca2ee..84818ef 100644 --- a/lib/src/iset/iset.dart +++ b/lib/src/iset/iset.dart @@ -14,6 +14,54 @@ import "s_add.dart"; import "s_add_all.dart"; import "s_flat.dart"; +/// This is an [ISet] which is always empty. +@immutable +class ISetEmpty // ignore: must_be_immutable + extends ISet { + /// Creates a empty set. In most cases, you should use `const ISet.empty()`. + /// + /// IMPORTANT: You must always use the `const` keyword. + /// It's always wrong to use an `ISetEmpty()` which is not constant. + @literal + const ISetEmpty([this.config = const ConfigSet()]) + : super._gen(); + + @override + final ConfigSet config; + + /// A empty set is always flushed, by definition. + @override + bool get isFlushed => true; + + /// Nothing happens when you flush a empty set, by definition. + @override + ISetEmpty get flush => this; + + @override + int get _counter => 0; + + @override + S get _s => SFlat.unsafe({}); + + /// Hash codes must be the same for objects that are equal to each other + /// according to operator ==. + @override + int? get _hashCode { + return isDeepEquals + ? hash2(const SetEquality().hash({}), config.hashCode) + : hash2(identityHashCode(_s), config.hashCode); + } + + @override + set _hashCode(int? value) {} + + @override + bool same(ISet? other) => + (other != null) && + (other is ISetEmpty) && + (config == other.config); +} + /// This is an [ISet] which can be made constant. /// Note: Don't ever use it without the "const" keyword, because it will be unsafe. /// @@ -37,15 +85,6 @@ class ISetConst // ignore: must_be_immutable [this.config = const ConfigSet()]) : super._gen(); - /// Creates a empty constant set. - /// - /// IMPORTANT: You must always use the `const` keyword. - /// It's always wrong to use an `ISetConst.empty()` which is not constant. - @literal - const ISetConst.empty([this.config = const ConfigSet()]) - : _set = const {}, - super._gen(); - final Set _set; @override @@ -197,9 +236,9 @@ abstract class ISet // ignore: must_be_immutable ISet.withConfig(iterable, defaultConfig); /// Create an empty [ISet]. - /// Use it with const: `const ISet.empty()` (It's always an [ISetConst]). + /// Use it with const: `const ISet.empty()` (It's always an [ISetEmpty]). @literal - const factory ISet.empty() = ISetConst.empty; + const factory ISet.empty() = ISetEmpty; const ISet._gen(); diff --git a/test/ilist/ilist_empty_test.dart b/test/ilist/ilist_empty_test.dart index 7b950ea..6f71397 100644 --- a/test/ilist/ilist_empty_test.dart +++ b/test/ilist/ilist_empty_test.dart @@ -10,7 +10,6 @@ void main() { ImmutableCollection.autoFlush = false; }); - test("Runtime Type", () { expect(const IListEmpty(), isA()); expect(const IListEmpty(), isA()); @@ -24,13 +23,15 @@ void main() { }); test("Make sure the IListEmpty can be modified and later iterated", () { + // LAddAll IList list = const IList.empty(); list = list.addAll(["a", "b", "c"]); list.forEach((_) { }); + + // LAdd + list = const IList.empty(); list = list.add("d"); list.forEach((_) { }); - list = list.remove("a"); - list.forEach((_) { }); }); test("Make sure the internal list is List, and not List", () { diff --git a/test/imap/imap_empty_test.dart b/test/imap/imap_empty_test.dart new file mode 100644 index 0000000..dffe3a6 --- /dev/null +++ b/test/imap/imap_empty_test.dart @@ -0,0 +1,63 @@ +// Developed by Marcelo Glasberg (2021) https://glasberg.dev and https://github.com/marcglasberg +// and Philippe Fanaro https://github.com/psygo +// For more info, see: https://pub.dartlang.org/packages/fast_immutable_collections +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:test/test.dart'; + +void main() { + setUp(() { + ImmutableCollection.resetAllConfigurations(); + ImmutableCollection.autoFlush = false; + }); + + test("Runtime Type", () { + expect(const IMapEmpty(), isA()); + expect(const IMapEmpty(), isA()); + expect(const IMapEmpty(), isA>()); + expect(const IMapEmpty(), isA>()); + + expect(const IMapEmpty(), isA()); + expect(const IMapEmpty(), isA()); + expect(const IMapEmpty(), isA>()); + expect(const IMapEmpty(), isA>()); + }); + + test("Make sure the IMapEmpty can be modified and later iterated", () { + // MAddAll + IMap map = const IMap.empty(); + map = map.addEntries([ + const MapEntry("a", 1), + const MapEntry("b", 2), + const MapEntry("c", 3) + ]); + map.forEach((_, __) { }); + + // MAdd + map = const IMap.empty(); + map = map.add("d", 4); + map.forEach((_, __) { }); + + // MReplace + map = const IMap.empty(); + map = map.add("d", 42); + map.forEach((_, __) { }); + }); + + test("Make sure the internal map is Map, and not Map", () { + const m1 = IMapEmpty(); + expect(m1.runtimeType.toString(), 'IMapEmpty'); + + const m2 = IMapConst({'a': 1, 'b': 2, 'c': 3}); + expect(m2.runtimeType.toString(), 'IMapConst'); + + final m3 = m1.addAll(m2); + expect(m3.runtimeType.toString(), 'IMapImpl'); + + final result = m3.where((String key, int value) => value == 2); + expect(result, {'b': 2}.lock); + }); + + test(".same() is working properly", () { + expect(const IMap.empty().same(const IMap.empty()), isTrue); + }); +} diff --git a/test/iset/iset_empty_test.dart b/test/iset/iset_empty_test.dart new file mode 100644 index 0000000..aedee8e --- /dev/null +++ b/test/iset/iset_empty_test.dart @@ -0,0 +1,54 @@ +// Developed by Marcelo Glasberg (2021) https://glasberg.dev and https://github.com/marcglasberg +// and Philippe Fanaro https://github.com/psygo +// For more info, see: https://pub.dartlang.org/packages/fast_immutable_collections +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:test/test.dart'; + +void main() { + setUp(() { + ImmutableCollection.resetAllConfigurations(); + ImmutableCollection.autoFlush = false; + }); + + test("Runtime Type", () { + expect(const ISetEmpty(), isA()); + expect(const ISetEmpty(), isA()); + expect(const ISetEmpty(), isA>()); + expect(const ISetEmpty(), isA>()); + + expect(const ISetEmpty(), isA()); + expect(const ISetEmpty(), isA()); + expect(const ISetEmpty(), isA>()); + expect(const ISetEmpty(), isA>()); + }); + + test("Make sure the ISetEmpty can be modified and later iterated", () { + // SAddAll + ISet set = const ISet.empty(); + set = set.addAll(["a", "b", "c"]); + set.forEach((_) { }); + + // SAdd + set = const ISet.empty(); + set = set.add("d"); + set.forEach((_) { }); + }); + + test("Make sure the internal set is Set, and not Set", () { + const s1 = ISetEmpty(); + expect(s1.runtimeType.toString(), 'ISetEmpty'); + + const s2 = ISetConst({1, 2, 3}); + expect(s2.runtimeType.toString(), 'ISetConst'); + + final s3 = s1.addAll(s2); + expect(s3.runtimeType.toString(), 'ISetImpl'); + + final result = s3.where((int i) => i == 2).toSet(); + expect(result, [2]); + }); + + test(".same() is working properly", () { + expect(const ISet.empty().same(const ISet.empty()), isTrue); + }); +} From dd4ee69833f7e79089d43ab2884775bdfaaf8840 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 17:45:04 +0100 Subject: [PATCH 06/11] added equality tests --- test/ilist/ilist_empty_test.dart | 21 +++++++++++++++++++++ test/imap/imap_empty_test.dart | 21 +++++++++++++++++++++ test/iset/iset_empty_test.dart | 21 +++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/test/ilist/ilist_empty_test.dart b/test/ilist/ilist_empty_test.dart index 6f71397..e4b06bf 100644 --- a/test/ilist/ilist_empty_test.dart +++ b/test/ilist/ilist_empty_test.dart @@ -51,4 +51,25 @@ void main() { test(".same() is working properly", () { expect(const IList.empty().same(const IList.empty()), isTrue); }); + + test("equality", () { + // equalItems + expect(IList(["a", "b"]).equalItems(const IList.empty()), isFalse); + expect(const IListConst(["a", "b"]).equalItems(const IList.empty()), isFalse); + + expect(IList().equalItems(const IList.empty()), isTrue); + expect(const IListConst([]).equalItems(const IList.empty()), isTrue); + expect(const IList.empty().equalItems(const IList.empty()), isTrue); + expect(const IList.empty().equalItems(const IListEmpty()), isTrue); + + + // equalItemsAndConfig + expect(IList(["a", "b"]).equalItemsAndConfig(const IList.empty()), isFalse); + expect(const IListConst(["a", "b"]).equalItemsAndConfig(const IList.empty()), isFalse); + + expect(IList().equalItemsAndConfig(const IList.empty()), isTrue); + expect(const IListConst([]).equalItemsAndConfig(const IList.empty()), isTrue); + expect(const IList.empty().equalItemsAndConfig(const IList.empty()), isTrue); + expect(const IList.empty().equalItemsAndConfig(const IListEmpty()), isTrue); + }); } diff --git a/test/imap/imap_empty_test.dart b/test/imap/imap_empty_test.dart index dffe3a6..6ad8b2e 100644 --- a/test/imap/imap_empty_test.dart +++ b/test/imap/imap_empty_test.dart @@ -60,4 +60,25 @@ void main() { test(".same() is working properly", () { expect(const IMap.empty().same(const IMap.empty()), isTrue); }); + + test("equality", () { + // equalItems + expect(IMap({1: "a", 2: "b"}).equalItems(const IMap.empty().entries), isFalse); + expect(const IMapConst({1: "a", 2: "b"}).equalItems(const IMap.empty().entries), isFalse); + + expect(IMap().equalItems(const IMap.empty().entries), isTrue); + expect(const IMapConst({}).equalItems(const IMap.empty().entries), isTrue); + expect(const IMap.empty().equalItems(const IMap.empty().entries), isTrue); + expect(const IMap.empty().equalItems(const IMapEmpty().entries), isTrue); + + + // equalItemsAndConfig + expect(IMap({1: "a", 2: "b"}).equalItemsAndConfig(const IMap.empty()), isFalse); + expect(const IMapConst({1: "a", 2: "b"}).equalItemsAndConfig(const IMap.empty()), isFalse); + + expect(IMap().equalItemsAndConfig(const IMap.empty()), isTrue); + expect(const IMapConst({}).equalItemsAndConfig(const IMap.empty()), isTrue); + expect(const IMap.empty().equalItemsAndConfig(const IMap.empty()), isTrue); + expect(const IMap.empty().equalItemsAndConfig(const IMapEmpty()), isTrue); + }); } diff --git a/test/iset/iset_empty_test.dart b/test/iset/iset_empty_test.dart index aedee8e..2890a3a 100644 --- a/test/iset/iset_empty_test.dart +++ b/test/iset/iset_empty_test.dart @@ -51,4 +51,25 @@ void main() { test(".same() is working properly", () { expect(const ISet.empty().same(const ISet.empty()), isTrue); }); + + test("equality", () { + // equalItems + expect(ISet({"a", "b"}).equalItems(const ISet.empty()), isFalse); + expect(const ISetConst({"a", "b"}).equalItems(const ISet.empty()), isFalse); + + expect(ISet().equalItems(const ISet.empty()), isTrue); + expect(const ISetConst({}).equalItems(const ISet.empty()), isTrue); + expect(const ISet.empty().equalItems(const ISet.empty()), isTrue); + expect(const ISet.empty().equalItems(const ISetEmpty()), isTrue); + + + // equalItemsAndConfig + expect(ISet({"a", "b"}).equalItemsAndConfig(const ISet.empty()), isFalse); + expect(const ISetConst({"a", "b"}).equalItemsAndConfig(const ISet.empty()), isFalse); + + expect(ISet().equalItemsAndConfig(const ISet.empty()), isTrue); + expect(const ISetConst({}).equalItemsAndConfig(const ISet.empty()), isTrue); + expect(const ISet.empty().equalItemsAndConfig(const ISet.empty()), isTrue); + expect(const ISet.empty().equalItemsAndConfig(const ISetEmpty()), isTrue); + }); } From 582fd6404571c31b91a76f9200c9b84447a0ebde Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 17:58:57 +0100 Subject: [PATCH 07/11] added tests for isEmpty / isNotEmpty --- lib/src/ilist/ilist.dart | 12 ++++++++++-- lib/src/imap/imap.dart | 12 ++++++++++-- lib/src/iset/iset.dart | 12 ++++++++++-- test/ilist/ilist_empty_test.dart | 5 +++++ test/imap/imap_empty_test.dart | 5 +++++ test/iset/iset_empty_test.dart | 5 +++++ 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index c7ec2a1..3d2c861 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -18,7 +18,7 @@ import "l_flat.dart"; @immutable class IListEmpty // ignore: must_be_immutable extends IList { - /// Creates a empty list. In most cases, you should use `const IList.empty()`. + /// Creates an empty list. In most cases, you should use `const IList.empty()`. /// /// IMPORTANT: You must always use the `const` keyword. /// It's always wrong to use an `IListEmpty()` which is not constant. @@ -29,7 +29,7 @@ class IListEmpty // ignore: must_be_immutable @override final ConfigList config; - /// A empty list is always flushed, by definition. + /// An empty list is always flushed, by definition. @override bool get isFlushed => true; @@ -37,6 +37,14 @@ class IListEmpty // ignore: must_be_immutable @override IListEmpty get flush => this; + /// An empty list is always empty, by definition + @override + bool get isEmpty => true; + + /// An empty list is always empty, by definition + @override + bool get isNotEmpty => false; + @override int get _counter => 0; diff --git a/lib/src/imap/imap.dart b/lib/src/imap/imap.dart index bfa0e0f..d0237ca 100644 --- a/lib/src/imap/imap.dart +++ b/lib/src/imap/imap.dart @@ -19,7 +19,7 @@ import "m_replace.dart"; @immutable class IMapEmpty // ignore: must_be_immutable extends IMap { - /// Creates a empty map. In most cases, you should use `const IMap.empty()`. + /// Creates an empty map. In most cases, you should use `const IMap.empty()`. /// /// IMPORTANT: You must always use the `const` keyword. /// It's always wrong to use an `IMapEmpty()` which is not constant. @@ -30,7 +30,7 @@ class IMapEmpty // ignore: must_be_immutable @override final ConfigMap config; - /// A empty map is always flushed, by definition. + /// An empty map is always flushed, by definition. @override bool get isFlushed => true; @@ -38,6 +38,14 @@ class IMapEmpty // ignore: must_be_immutable @override IMapEmpty get flush => this; + /// An empty map is always empty, by definition + @override + bool get isEmpty => true; + + /// An empty map is always empty, by definition + @override + bool get isNotEmpty => false; + @override int get _counter => 0; diff --git a/lib/src/iset/iset.dart b/lib/src/iset/iset.dart index 84818ef..4a39203 100644 --- a/lib/src/iset/iset.dart +++ b/lib/src/iset/iset.dart @@ -18,7 +18,7 @@ import "s_flat.dart"; @immutable class ISetEmpty // ignore: must_be_immutable extends ISet { - /// Creates a empty set. In most cases, you should use `const ISet.empty()`. + /// Creates an empty set. In most cases, you should use `const ISet.empty()`. /// /// IMPORTANT: You must always use the `const` keyword. /// It's always wrong to use an `ISetEmpty()` which is not constant. @@ -29,7 +29,7 @@ class ISetEmpty // ignore: must_be_immutable @override final ConfigSet config; - /// A empty set is always flushed, by definition. + /// An empty set is always flushed, by definition. @override bool get isFlushed => true; @@ -37,6 +37,14 @@ class ISetEmpty // ignore: must_be_immutable @override ISetEmpty get flush => this; + /// An empty set is always empty, by definition + @override + bool get isEmpty => true; + + /// An empty set is always empty, by definition + @override + bool get isNotEmpty => false; + @override int get _counter => 0; diff --git a/test/ilist/ilist_empty_test.dart b/test/ilist/ilist_empty_test.dart index e4b06bf..18c7c14 100644 --- a/test/ilist/ilist_empty_test.dart +++ b/test/ilist/ilist_empty_test.dart @@ -72,4 +72,9 @@ void main() { expect(const IList.empty().equalItemsAndConfig(const IList.empty()), isTrue); expect(const IList.empty().equalItemsAndConfig(const IListEmpty()), isTrue); }); + + test(".isEmpty() | .isNotEmpty()", () { + expect(const IList.empty().isEmpty, isTrue); + expect(const IList.empty().isNotEmpty, isFalse); + }); } diff --git a/test/imap/imap_empty_test.dart b/test/imap/imap_empty_test.dart index 6ad8b2e..41a6844 100644 --- a/test/imap/imap_empty_test.dart +++ b/test/imap/imap_empty_test.dart @@ -81,4 +81,9 @@ void main() { expect(const IMap.empty().equalItemsAndConfig(const IMap.empty()), isTrue); expect(const IMap.empty().equalItemsAndConfig(const IMapEmpty()), isTrue); }); + + test(".isEmpty() | .isNotEmpty()", () { + expect(const IMap.empty().isEmpty, isTrue); + expect(const IMap.empty().isNotEmpty, isFalse); + }); } diff --git a/test/iset/iset_empty_test.dart b/test/iset/iset_empty_test.dart index 2890a3a..7eba763 100644 --- a/test/iset/iset_empty_test.dart +++ b/test/iset/iset_empty_test.dart @@ -72,4 +72,9 @@ void main() { expect(const ISet.empty().equalItemsAndConfig(const ISet.empty()), isTrue); expect(const ISet.empty().equalItemsAndConfig(const ISetEmpty()), isTrue); }); + + test(".isEmpty() | .isNotEmpty()", () { + expect(const ISet.empty().isEmpty, isTrue); + expect(const ISet.empty().isNotEmpty, isFalse); + }); } From b5f63d320b1057f8d037691601a8b257ae547946 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 19:03:29 +0100 Subject: [PATCH 08/11] Added trivial getters and functions for all FooEmpty types --- lib/src/ilist/ilist.dart | 28 ++++++++++++++++++++++++++++ lib/src/imap/imap.dart | 24 ++++++++++++++++++++++++ lib/src/iset/iset.dart | 24 ++++++++++++++++++++++++ test/ilist/ilist_empty_test.dart | 27 ++++++++++++++++++++++++++- test/imap/imap_empty_test.dart | 25 ++++++++++++++++++++++++- test/iset/iset_empty_test.dart | 22 +++++++++++++++++++++- 6 files changed, 147 insertions(+), 3 deletions(-) diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index 3d2c861..bae8bfe 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -45,6 +45,34 @@ class IListEmpty // ignore: must_be_immutable @override bool get isNotEmpty => false; + /// An empty list does not contain anything, by definition + @override + bool contains(covariant T? element) => false; + + /// An empty list is always of length `0`, by definition + @override + int get length => 0; + + /// An empty list has no first element, by definition + @override + Never get first => throw StateError("No element"); + + /// An empty list has no last element, by definition + @override + Never get last => throw StateError("No element"); + + /// An empty list has no single element, by definition + @override + Never get single => throw StateError("No element"); + + /// An empty list is always the reversed version of itself, by definition + @override + IListEmpty get reversed => this; + + /// An empty list is always the cleared version of itself, by definition + @override + IListEmpty clear() => this; + @override int get _counter => 0; diff --git a/lib/src/imap/imap.dart b/lib/src/imap/imap.dart index d0237ca..718c46d 100644 --- a/lib/src/imap/imap.dart +++ b/lib/src/imap/imap.dart @@ -46,6 +46,30 @@ class IMapEmpty // ignore: must_be_immutable @override bool get isNotEmpty => false; + /// An empty map does not contain anything, by definition + @override + bool contains(K key, V value) => false; + + /// An empty map does not contain anything, by definition + @override + bool containsKey(K? key) => false; + + /// An empty map does not contain anything, by definition + @override + bool containsValue(V? value) => false; + + /// An empty map does not contain anything, by definition + @override + bool containsEntry(MapEntry entry) => false; + + /// An empty map is always of length `0`, by definition + @override + int get length => 0; + + /// An empty map is always the cleared version of itself, by definition + @override + IMapEmpty clear() => this; + @override int get _counter => 0; diff --git a/lib/src/iset/iset.dart b/lib/src/iset/iset.dart index 4a39203..5182239 100644 --- a/lib/src/iset/iset.dart +++ b/lib/src/iset/iset.dart @@ -45,6 +45,30 @@ class ISetEmpty // ignore: must_be_immutable @override bool get isNotEmpty => false; + /// An empty set does not contain anything, by definition + @override + bool contains(covariant T? element) => false; + + /// An empty set is always of length `0`, by definition + @override + int get length => 0; + + /// An empty set has no first element, by definition + @override + Never get first => throw StateError("No element"); + + /// An empty set has no last element, by definition + @override + Never get last => throw StateError("No element"); + + /// An empty set has no single element, by definition + @override + Never get single => throw StateError("No element"); + + /// An empty set is always the cleared version of itself, by definition + @override + ISetEmpty clear() => this; + @override int get _counter => 0; diff --git a/test/ilist/ilist_empty_test.dart b/test/ilist/ilist_empty_test.dart index 18c7c14..b02db80 100644 --- a/test/ilist/ilist_empty_test.dart +++ b/test/ilist/ilist_empty_test.dart @@ -73,8 +73,33 @@ void main() { expect(const IList.empty().equalItemsAndConfig(const IListEmpty()), isTrue); }); - test(".isEmpty() | .isNotEmpty()", () { + test("isEmpty | isNotEmpty", () { expect(const IList.empty().isEmpty, isTrue); expect(const IList.empty().isNotEmpty, isFalse); }); + + test("contains", () { + expect(const IList.empty().contains(Object()), isFalse); + expect(const IList.empty().contains(null), isFalse); + }); + + test("length", () { + expect(const IList.empty().length, 0); + }); + + test("fist | last | single", () { + expect(() => const IList.empty().first, throwsStateError); + expect(() => const IList.empty().last, throwsStateError); + expect(() => const IList.empty().single, throwsStateError); + }); + + test("reversed", () { + const list = IList.empty(); + expect(identical(list, list.reversed), isTrue); + }); + + test("clear()", () { + const list = IList.empty(); + expect(identical(list, list.clear()), isTrue); + }); } diff --git a/test/imap/imap_empty_test.dart b/test/imap/imap_empty_test.dart index 41a6844..a5f5e04 100644 --- a/test/imap/imap_empty_test.dart +++ b/test/imap/imap_empty_test.dart @@ -82,8 +82,31 @@ void main() { expect(const IMap.empty().equalItemsAndConfig(const IMapEmpty()), isTrue); }); - test(".isEmpty() | .isNotEmpty()", () { + test("isEmpty | isNotEmpty", () { expect(const IMap.empty().isEmpty, isTrue); expect(const IMap.empty().isNotEmpty, isFalse); }); + + test("contains | -Key | -Value | -Entry", () { + expect(const IMap.empty().contains(Object(), Object()), isFalse); + expect(const IMap.empty().contains(null, null), isFalse); + + expect(const IMap.empty().containsKey(Object()), isFalse); + expect(const IMap.empty().containsKey(null), isFalse); + + expect(const IMap.empty().containsValue(Object()), isFalse); + expect(const IMap.empty().containsValue(null), isFalse); + + expect(const IMap.empty().containsEntry(const MapEntry(Object(), Object())), isFalse); + expect(const IMap.empty().containsEntry(const MapEntry(null, null)), isFalse); + }); + + test("length", () { + expect(const IMap.empty().length, 0); + }); + + test("clear()", () { + const list = IMap.empty(); + expect(identical(list, list.clear()), isTrue); + }); } diff --git a/test/iset/iset_empty_test.dart b/test/iset/iset_empty_test.dart index 7eba763..a4ef891 100644 --- a/test/iset/iset_empty_test.dart +++ b/test/iset/iset_empty_test.dart @@ -73,8 +73,28 @@ void main() { expect(const ISet.empty().equalItemsAndConfig(const ISetEmpty()), isTrue); }); - test(".isEmpty() | .isNotEmpty()", () { + test("isEmpty | isNotEmpty", () { expect(const ISet.empty().isEmpty, isTrue); expect(const ISet.empty().isNotEmpty, isFalse); }); + + test("contains", () { + expect(const ISet.empty().contains(Object()), isFalse); + expect(const ISet.empty().contains(null), isFalse); + }); + + test("length", () { + expect(const ISet.empty().length, 0); + }); + + test("fist | last | single", () { + expect(() => const ISet.empty().first, throwsStateError); + expect(() => const ISet.empty().last, throwsStateError); + expect(() => const ISet.empty().single, throwsStateError); + }); + + test("clear()", () { + const list = ISet.empty(); + expect(identical(list, list.clear()), isTrue); + }); } From 6c98563b4b87d57fa4f29d4d84f508dc74845b38 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 19:06:12 +0100 Subject: [PATCH 09/11] made iset constructor private --- lib/src/iset/iset.dart | 4 ++-- test/iset/iset_empty_test.dart | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/src/iset/iset.dart b/lib/src/iset/iset.dart index 5182239..ba09ac2 100644 --- a/lib/src/iset/iset.dart +++ b/lib/src/iset/iset.dart @@ -23,7 +23,7 @@ class ISetEmpty // ignore: must_be_immutable /// IMPORTANT: You must always use the `const` keyword. /// It's always wrong to use an `ISetEmpty()` which is not constant. @literal - const ISetEmpty([this.config = const ConfigSet()]) + const ISetEmpty._([this.config = const ConfigSet()]) : super._gen(); @override @@ -270,7 +270,7 @@ abstract class ISet // ignore: must_be_immutable /// Create an empty [ISet]. /// Use it with const: `const ISet.empty()` (It's always an [ISetEmpty]). @literal - const factory ISet.empty() = ISetEmpty; + const factory ISet.empty() = ISetEmpty._; const ISet._gen(); diff --git a/test/iset/iset_empty_test.dart b/test/iset/iset_empty_test.dart index a4ef891..d68f17b 100644 --- a/test/iset/iset_empty_test.dart +++ b/test/iset/iset_empty_test.dart @@ -11,15 +11,15 @@ void main() { }); test("Runtime Type", () { - expect(const ISetEmpty(), isA()); - expect(const ISetEmpty(), isA()); - expect(const ISetEmpty(), isA>()); - expect(const ISetEmpty(), isA>()); - - expect(const ISetEmpty(), isA()); - expect(const ISetEmpty(), isA()); - expect(const ISetEmpty(), isA>()); - expect(const ISetEmpty(), isA>()); + expect(const ISet.empty(), isA()); + expect(const ISet.empty(), isA()); + expect(const ISet.empty(), isA>()); + expect(const ISet.empty(), isA>()); + + expect(const ISet.empty(), isA()); + expect(const ISet.empty(), isA()); + expect(const ISet.empty(), isA>()); + expect(const ISet.empty(), isA>()); }); test("Make sure the ISetEmpty can be modified and later iterated", () { @@ -35,7 +35,7 @@ void main() { }); test("Make sure the internal set is Set, and not Set", () { - const s1 = ISetEmpty(); + const s1 = ISet.empty(); expect(s1.runtimeType.toString(), 'ISetEmpty'); const s2 = ISetConst({1, 2, 3}); @@ -60,7 +60,6 @@ void main() { expect(ISet().equalItems(const ISet.empty()), isTrue); expect(const ISetConst({}).equalItems(const ISet.empty()), isTrue); expect(const ISet.empty().equalItems(const ISet.empty()), isTrue); - expect(const ISet.empty().equalItems(const ISetEmpty()), isTrue); // equalItemsAndConfig @@ -70,7 +69,6 @@ void main() { expect(ISet().equalItemsAndConfig(const ISet.empty()), isTrue); expect(const ISetConst({}).equalItemsAndConfig(const ISet.empty()), isTrue); expect(const ISet.empty().equalItemsAndConfig(const ISet.empty()), isTrue); - expect(const ISet.empty().equalItemsAndConfig(const ISetEmpty()), isTrue); }); test("isEmpty | isNotEmpty", () { From 6a1db898b47ecbfac69384f2233c0cad51e845c4 Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 19:08:38 +0100 Subject: [PATCH 10/11] made imap constructor private --- lib/src/imap/imap.dart | 4 ++-- test/imap/imap_empty_test.dart | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/src/imap/imap.dart b/lib/src/imap/imap.dart index 718c46d..3502424 100644 --- a/lib/src/imap/imap.dart +++ b/lib/src/imap/imap.dart @@ -24,7 +24,7 @@ class IMapEmpty // ignore: must_be_immutable /// IMPORTANT: You must always use the `const` keyword. /// It's always wrong to use an `IMapEmpty()` which is not constant. @literal - const IMapEmpty([this.config = const ConfigMap()]) + const IMapEmpty._([this.config = const ConfigMap()]) : super._gen(); @override @@ -255,7 +255,7 @@ abstract class IMap // ignore: must_be_immutable /// Create an empty [IMap]. /// Use it with const: `const IMap.empty()` (It's always an [IMapEmpty]). @literal - const factory IMap.empty() = IMapEmpty; + const factory IMap.empty() = IMapEmpty._; const IMap._gen(); diff --git a/test/imap/imap_empty_test.dart b/test/imap/imap_empty_test.dart index a5f5e04..9223bd4 100644 --- a/test/imap/imap_empty_test.dart +++ b/test/imap/imap_empty_test.dart @@ -11,15 +11,15 @@ void main() { }); test("Runtime Type", () { - expect(const IMapEmpty(), isA()); - expect(const IMapEmpty(), isA()); - expect(const IMapEmpty(), isA>()); - expect(const IMapEmpty(), isA>()); - - expect(const IMapEmpty(), isA()); - expect(const IMapEmpty(), isA()); - expect(const IMapEmpty(), isA>()); - expect(const IMapEmpty(), isA>()); + expect(const IMap.empty(), isA()); + expect(const IMap.empty(), isA()); + expect(const IMap.empty(), isA>()); + expect(const IMap.empty(), isA>()); + + expect(const IMap.empty(), isA()); + expect(const IMap.empty(), isA()); + expect(const IMap.empty(), isA>()); + expect(const IMap.empty(), isA>()); }); test("Make sure the IMapEmpty can be modified and later iterated", () { @@ -44,7 +44,7 @@ void main() { }); test("Make sure the internal map is Map, and not Map", () { - const m1 = IMapEmpty(); + const m1 = IMap.empty(); expect(m1.runtimeType.toString(), 'IMapEmpty'); const m2 = IMapConst({'a': 1, 'b': 2, 'c': 3}); @@ -69,7 +69,6 @@ void main() { expect(IMap().equalItems(const IMap.empty().entries), isTrue); expect(const IMapConst({}).equalItems(const IMap.empty().entries), isTrue); expect(const IMap.empty().equalItems(const IMap.empty().entries), isTrue); - expect(const IMap.empty().equalItems(const IMapEmpty().entries), isTrue); // equalItemsAndConfig @@ -79,7 +78,6 @@ void main() { expect(IMap().equalItemsAndConfig(const IMap.empty()), isTrue); expect(const IMapConst({}).equalItemsAndConfig(const IMap.empty()), isTrue); expect(const IMap.empty().equalItemsAndConfig(const IMap.empty()), isTrue); - expect(const IMap.empty().equalItemsAndConfig(const IMapEmpty()), isTrue); }); test("isEmpty | isNotEmpty", () { From e3a9ed3c4c34d1975cddbd242dae81f6037dae2f Mon Sep 17 00:00:00 2001 From: LowLevelSubmarine Date: Wed, 27 Mar 2024 19:12:19 +0100 Subject: [PATCH 11/11] made ilist constructor private --- lib/src/ilist/ilist.dart | 4 ++-- test/ilist/ilist_empty_test.dart | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/src/ilist/ilist.dart b/lib/src/ilist/ilist.dart index bae8bfe..2c22d17 100644 --- a/lib/src/ilist/ilist.dart +++ b/lib/src/ilist/ilist.dart @@ -23,7 +23,7 @@ class IListEmpty // ignore: must_be_immutable /// IMPORTANT: You must always use the `const` keyword. /// It's always wrong to use an `IListEmpty()` which is not constant. @literal - const IListEmpty([this.config = const ConfigList()]) + const IListEmpty._([this.config = const ConfigList()]) : super._gen(); @override @@ -277,7 +277,7 @@ abstract class IList // ignore: must_be_immutable /// Create an empty [IList]. /// Use it with const: `const IList.empty()` (It's always an [IListEmpty]). @literal - const factory IList.empty() = IListEmpty; + const factory IList.empty() = IListEmpty._; const IList._gen(); diff --git a/test/ilist/ilist_empty_test.dart b/test/ilist/ilist_empty_test.dart index b02db80..af6fa62 100644 --- a/test/ilist/ilist_empty_test.dart +++ b/test/ilist/ilist_empty_test.dart @@ -11,15 +11,15 @@ void main() { }); test("Runtime Type", () { - expect(const IListEmpty(), isA()); - expect(const IListEmpty(), isA()); - expect(const IListEmpty(), isA>()); - expect(const IListEmpty(), isA>()); - - expect(const IListEmpty(), isA()); - expect(const IListEmpty(), isA()); - expect(const IListEmpty(), isA>()); - expect(const IListEmpty(), isA>()); + expect(const IList.empty(), isA()); + expect(const IList.empty(), isA()); + expect(const IList.empty(), isA>()); + expect(const IList.empty(), isA>()); + + expect(const IList.empty(), isA()); + expect(const IList.empty(), isA()); + expect(const IList.empty(), isA>()); + expect(const IList.empty(), isA>()); }); test("Make sure the IListEmpty can be modified and later iterated", () { @@ -35,7 +35,7 @@ void main() { }); test("Make sure the internal list is List, and not List", () { - const l1 = IListEmpty(); + const l1 = IList.empty(); expect(l1.runtimeType.toString(), 'IListEmpty'); const l2 = IListConst([1, 2, 3]); @@ -60,7 +60,7 @@ void main() { expect(IList().equalItems(const IList.empty()), isTrue); expect(const IListConst([]).equalItems(const IList.empty()), isTrue); expect(const IList.empty().equalItems(const IList.empty()), isTrue); - expect(const IList.empty().equalItems(const IListEmpty()), isTrue); + expect(const IList.empty().equalItems(const IList.empty()), isTrue); // equalItemsAndConfig @@ -70,7 +70,7 @@ void main() { expect(IList().equalItemsAndConfig(const IList.empty()), isTrue); expect(const IListConst([]).equalItemsAndConfig(const IList.empty()), isTrue); expect(const IList.empty().equalItemsAndConfig(const IList.empty()), isTrue); - expect(const IList.empty().equalItemsAndConfig(const IListEmpty()), isTrue); + expect(const IList.empty().equalItemsAndConfig(const IList.empty()), isTrue); }); test("isEmpty | isNotEmpty", () {