Skip to content

Commit

Permalink
fix: prop of type map with non-comparable key
Browse files Browse the repository at this point in the history
  • Loading branch information
felangel committed May 20, 2021
1 parent 0616ad9 commit 0ba67c7
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
12 changes: 5 additions & 7 deletions lib/src/equatable_utils.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'dart:collection';

import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';

Expand Down Expand Up @@ -41,11 +39,11 @@ bool _isEquatable(dynamic object) {
/// 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) {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
103 changes: 103 additions & 0 deletions test/equatable_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,109 @@ void main() {
});
});

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(
Expand Down

0 comments on commit 0ba67c7

Please sign in to comment.