fix: prop of type map with non-comparable key
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c04cc49..93cd5e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 2.0.2
+
+- fix: `Map` prop with non-comparable key
+
# 2.0.1
- fix: `hashCode` should be the same for equal objects (`Map` fix)
diff --git a/lib/src/equatable_utils.dart b/lib/src/equatable_utils.dart
index 50dbb2b..4a18c5b 100644
--- a/lib/src/equatable_utils.dart
+++ b/lib/src/equatable_utils.dart
@@ -1,5 +1,3 @@
-import 'dart:collection';
-
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
@@ -41,11 +39,11 @@
/// https://en.wikipedia.org/wiki/Jenkins_hash_function
int _combine(int hash, dynamic object) {
if (object is Map) {
- SplayTreeMap<dynamic, dynamic>.of(object).forEach(
- (dynamic key, dynamic value) {
- hash = hash ^ _combine(hash, <dynamic>[key, value]);
- },
- );
+ object.keys
+ .sorted((dynamic a, dynamic b) => a.hashCode - b.hashCode)
+ .forEach((dynamic key) {
+ hash = hash ^ _combine(hash, <dynamic>[key, object[key]]);
+ });
return hash;
}
if (object is Iterable) {
diff --git a/pubspec.yaml b/pubspec.yaml
index a9fe7e7..ee845ad 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: equatable
description: A Dart package that helps to implement value based equality without needing to explicitly override == and hashCode.
-version: 2.0.1
+version: 2.0.2
repository: https://github.com/felangel/equatable
issue_tracker: https://github.com/felangel/equatable/issues
homepage: https://github.com/felangel/equatable
diff --git a/test/equatable_test.dart b/test/equatable_test.dart
index 3809e0d..5cc93ea 100644
--- a/test/equatable_test.dart
+++ b/test/equatable_test.dart
@@ -363,6 +363,109 @@
});
});
+ group('Simple Equatable (map custom key)', () {
+ test('should correct toString', () {
+ final instance = SimpleEquatable(<SimpleEquatable<String>, dynamic>{});
+ expect(
+ instance.toString(),
+ 'SimpleEquatable<Map<SimpleEquatable<String>, dynamic>>({})',
+ );
+ });
+
+ test('should return true when instance is the same', () {
+ final instance = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ expect(instance == instance, true);
+ });
+
+ test('should return correct hashCode', () {
+ final instance = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ expect(
+ instance.hashCode,
+ instance.runtimeType.hashCode ^ mapPropsToHashCode(instance.props),
+ );
+ });
+
+ test('should have same hashCode when values are equal', () {
+ final instanceA = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ final instanceB = SimpleEquatable(
+ {
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ expect(instanceA == instanceB, true);
+ expect(instanceA.hashCode, instanceB.hashCode);
+ });
+
+ test('should return true when instances are different', () {
+ final instanceA = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ final instanceB = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ expect(instanceA == instanceB, true);
+ expect(instanceA.hashCode == instanceB.hashCode, true);
+ });
+
+ test('should return false when compared to non-equatable', () {
+ final instanceA = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ final instanceB = NonEquatable();
+ expect(instanceA == instanceB, false);
+ });
+
+ test('should return false when values are different', () {
+ final instanceA = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 3
+ },
+ );
+ final instanceB = SimpleEquatable(
+ {
+ SimpleEquatable<String>('a'): 1,
+ SimpleEquatable<String>('b'): 2,
+ SimpleEquatable<String>('c'): 2
+ },
+ );
+ expect(instanceA == instanceB, false);
+ });
+ });
+
group('Simple Equatable (Equatable)', () {
test('should correct toString', () {
final instance = SimpleEquatable(EquatableData(