Skip to content

Commit 0ba67c7

Browse files
committed
fix: prop of type map with non-comparable key
1 parent 0616ad9 commit 0ba67c7

File tree

4 files changed

+113
-8
lines changed

4 files changed

+113
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 2.0.2
2+
3+
- fix: `Map` prop with non-comparable key
4+
15
# 2.0.1
26

37
- fix: `hashCode` should be the same for equal objects (`Map` fix)

lib/src/equatable_utils.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import 'dart:collection';
2-
31
import 'package:collection/collection.dart';
42
import 'package:equatable/equatable.dart';
53

@@ -41,11 +39,11 @@ bool _isEquatable(dynamic object) {
4139
/// https://en.wikipedia.org/wiki/Jenkins_hash_function
4240
int _combine(int hash, dynamic object) {
4341
if (object is Map) {
44-
SplayTreeMap<dynamic, dynamic>.of(object).forEach(
45-
(dynamic key, dynamic value) {
46-
hash = hash ^ _combine(hash, <dynamic>[key, value]);
47-
},
48-
);
42+
object.keys
43+
.sorted((dynamic a, dynamic b) => a.hashCode - b.hashCode)
44+
.forEach((dynamic key) {
45+
hash = hash ^ _combine(hash, <dynamic>[key, object[key]]);
46+
});
4947
return hash;
5048
}
5149
if (object is Iterable) {

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: equatable
22
description: A Dart package that helps to implement value based equality without needing to explicitly override == and hashCode.
3-
version: 2.0.1
3+
version: 2.0.2
44
repository: https://github.com/felangel/equatable
55
issue_tracker: https://github.com/felangel/equatable/issues
66
homepage: https://github.com/felangel/equatable

test/equatable_test.dart

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,109 @@ void main() {
363363
});
364364
});
365365

366+
group('Simple Equatable (map custom key)', () {
367+
test('should correct toString', () {
368+
final instance = SimpleEquatable(<SimpleEquatable<String>, dynamic>{});
369+
expect(
370+
instance.toString(),
371+
'SimpleEquatable<Map<SimpleEquatable<String>, dynamic>>({})',
372+
);
373+
});
374+
375+
test('should return true when instance is the same', () {
376+
final instance = SimpleEquatable(
377+
{
378+
SimpleEquatable<String>('a'): 1,
379+
SimpleEquatable<String>('b'): 2,
380+
SimpleEquatable<String>('c'): 3
381+
},
382+
);
383+
expect(instance == instance, true);
384+
});
385+
386+
test('should return correct hashCode', () {
387+
final instance = SimpleEquatable(
388+
{
389+
SimpleEquatable<String>('a'): 1,
390+
SimpleEquatable<String>('b'): 2,
391+
SimpleEquatable<String>('c'): 3
392+
},
393+
);
394+
expect(
395+
instance.hashCode,
396+
instance.runtimeType.hashCode ^ mapPropsToHashCode(instance.props),
397+
);
398+
});
399+
400+
test('should have same hashCode when values are equal', () {
401+
final instanceA = SimpleEquatable(
402+
{
403+
SimpleEquatable<String>('a'): 1,
404+
SimpleEquatable<String>('b'): 2,
405+
SimpleEquatable<String>('c'): 3
406+
},
407+
);
408+
final instanceB = SimpleEquatable(
409+
{
410+
SimpleEquatable<String>('b'): 2,
411+
SimpleEquatable<String>('a'): 1,
412+
SimpleEquatable<String>('c'): 3
413+
},
414+
);
415+
expect(instanceA == instanceB, true);
416+
expect(instanceA.hashCode, instanceB.hashCode);
417+
});
418+
419+
test('should return true when instances are different', () {
420+
final instanceA = SimpleEquatable(
421+
{
422+
SimpleEquatable<String>('a'): 1,
423+
SimpleEquatable<String>('b'): 2,
424+
SimpleEquatable<String>('c'): 3
425+
},
426+
);
427+
final instanceB = SimpleEquatable(
428+
{
429+
SimpleEquatable<String>('a'): 1,
430+
SimpleEquatable<String>('b'): 2,
431+
SimpleEquatable<String>('c'): 3
432+
},
433+
);
434+
expect(instanceA == instanceB, true);
435+
expect(instanceA.hashCode == instanceB.hashCode, true);
436+
});
437+
438+
test('should return false when compared to non-equatable', () {
439+
final instanceA = SimpleEquatable(
440+
{
441+
SimpleEquatable<String>('a'): 1,
442+
SimpleEquatable<String>('b'): 2,
443+
SimpleEquatable<String>('c'): 3
444+
},
445+
);
446+
final instanceB = NonEquatable();
447+
expect(instanceA == instanceB, false);
448+
});
449+
450+
test('should return false when values are different', () {
451+
final instanceA = SimpleEquatable(
452+
{
453+
SimpleEquatable<String>('a'): 1,
454+
SimpleEquatable<String>('b'): 2,
455+
SimpleEquatable<String>('c'): 3
456+
},
457+
);
458+
final instanceB = SimpleEquatable(
459+
{
460+
SimpleEquatable<String>('a'): 1,
461+
SimpleEquatable<String>('b'): 2,
462+
SimpleEquatable<String>('c'): 2
463+
},
464+
);
465+
expect(instanceA == instanceB, false);
466+
});
467+
});
468+
366469
group('Simple Equatable (Equatable)', () {
367470
test('should correct toString', () {
368471
final instance = SimpleEquatable(EquatableData(

0 commit comments

Comments
 (0)