Skip to content

Commit b1f29d8

Browse files
committed
test: add unit tests for custom equals functionality in observable collections
1 parent d13d88d commit b1f29d8

File tree

4 files changed

+618
-0
lines changed

4 files changed

+618
-0
lines changed

mobx/lib/src/api/observable_collections/observable_list.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,34 @@ Atom _observableListAtom<T>(ReactiveContext? context, String? name) {
1010
///
1111
/// As the name suggests, this is the Observable-counterpart to the standard Dart `List<T>`.
1212
///
13+
/// ## Custom Equality
14+
///
15+
/// You can provide a custom `equals` parameter to control when values are considered
16+
/// equal. This is useful for optimizing change detection or implementing custom
17+
/// equality semantics:
18+
///
19+
/// ```dart
20+
/// // Only notify changes when names are different
21+
/// final list = ObservableList<Person>(
22+
/// equals: (a, b) => a?.name == b?.name
23+
/// );
24+
///
25+
/// // Deep equality for nested structures
26+
/// final list = ObservableList<List<int>>(
27+
/// equals: (a, b) {
28+
/// if (a == null && b == null) return true;
29+
/// if (a == null || b == null) return false;
30+
/// return a.length == b.length &&
31+
/// a.asMap().entries.every((e) => e.value == b[e.key]);
32+
/// }
33+
/// );
34+
/// ```
35+
///
36+
/// Note: Bulk operations like `replaceRange` and `setRange` always trigger
37+
/// notifications for performance reasons, regardless of the custom equals function.
38+
///
39+
/// ## Basic Usage
40+
///
1341
/// ```dart
1442
/// final list = ObservableList<int>.of([1]);
1543
///

mobx/lib/src/api/observable_collections/observable_map.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ Atom _observableMapAtom<K, V>(ReactiveContext? context, String? name) {
1010
///
1111
/// As the name suggests, this is the Observable-counterpart to the standard Dart `Map<K,V>`.
1212
///
13+
/// ## Custom Equality for Values
14+
///
15+
/// You can provide a custom `equals` parameter to control when values are considered
16+
/// equal. This only affects value comparisons - keys are always compared using standard
17+
/// equality:
18+
///
19+
/// ```dart
20+
/// // Only notify changes when person names are different
21+
/// final map = ObservableMap<String, Person>(
22+
/// equals: (a, b) => a?.name == b?.name
23+
/// );
24+
///
25+
/// map['key'] = Person('Alice', 25);
26+
/// map['key'] = Person('Alice', 30); // No notification - same name
27+
/// ```
28+
///
29+
/// ## Basic Usage
30+
///
1331
/// ```dart
1432
/// final map = ObservableMap<String, int>.of({'first': 1});
1533
///

mobx/lib/src/api/observable_collections/observable_set.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,27 @@ Atom _observableSetAtom<T>(ReactiveContext context, String? name) =>
55

66
/// ObservableSet provides a reactive set that notifies changes when a member is added or removed.
77
///
8+
/// ## Custom Equality
9+
///
10+
/// You can provide a custom `equals` parameter to determine set membership.
11+
/// This is particularly useful when you need custom equality semantics:
12+
///
13+
/// ```dart
14+
/// // Case-insensitive string set
15+
/// final set = ObservableSet<String>(
16+
/// equals: (a, b) => a?.toLowerCase() == b?.toLowerCase()
17+
/// );
18+
///
19+
/// set.add('Hello');
20+
/// set.add('HELLO'); // Won't be added - considered equal
21+
/// set.contains('hello'); // Returns true
22+
/// ```
23+
///
24+
/// When using custom equals, the set behaves consistently across all operations
25+
/// including `add`, `contains`, `remove`, and `lookup`.
26+
///
27+
/// ## Basic Usage
28+
///
829
/// ```dart
930
/// final set = ObservableSet.of([1, 2, 3]);
1031
///

0 commit comments

Comments
 (0)