diff --git a/CHANGELOG.md b/CHANGELOG.md index 55e47778..234b572b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.0.7 + +- revert: `equals` in `equatable_utils` ([#190](https://github.com/felangel/equatable/issues/190)) +- fix: explicitly handle num equality comparisons ([#189](https://github.com/felangel/equatable/issues/189)) + # 2.0.6 - perf: improve equality comparison performance ([#173](https://github.com/felangel/equatable/issues/173)) diff --git a/lib/src/equatable_utils.dart b/lib/src/equatable_utils.dart index 8e65b7cc..1c9ff42b 100644 --- a/lib/src/equatable_utils.dart +++ b/lib/src/equatable_utils.dart @@ -6,6 +6,15 @@ int mapPropsToHashCode(Iterable? props) { return _finish(props == null ? 0 : props.fold(0, _combine)); } +/// Determines whether two lists ([a] and [b]) are equal. +// See https://github.com/felangel/equatable/issues/187. +@pragma('vm:prefer-inline') +bool equals(List? a, List? b) { + if (identical(a, b)) return true; + if (a == null || b == null) return false; + return iterableEquals(a, b); +} + /// Determines whether two iterables are equal. @pragma('vm:prefer-inline') bool iterableEquals(Iterable a, Iterable b) { @@ -21,6 +30,10 @@ bool iterableEquals(Iterable a, Iterable b) { return true; } +/// Determines whether two numbers are equal. +@pragma('vm:prefer-inline') +bool numEquals(num a, num b) => a == b; + /// Determines whether two sets are equal. bool setEquals(Set a, Set b) { if (identical(a, b)) return true; @@ -45,7 +58,9 @@ bool mapEquals(Map a, Map b) { @pragma('vm:prefer-inline') bool objectsEquals(Object? a, Object? b) { if (identical(a, b)) return true; - if (_isEquatable(a) && _isEquatable(b)) { + if (a is num && b is num) { + return numEquals(a, b); + } else if (_isEquatable(a) && _isEquatable(b)) { return a == b; } else if (a is Set && b is Set) { return setEquals(a, b); diff --git a/pubspec.yaml b/pubspec.yaml index 7760ec6d..e7880be3 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.6 +version: 2.0.7 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_utils_test.dart b/test/equatable_utils_test.dart index f9182b82..c5a7955e 100644 --- a/test/equatable_utils_test.dart +++ b/test/equatable_utils_test.dart @@ -1,6 +1,6 @@ import 'package:equatable/equatable.dart'; import 'package:equatable/src/equatable_utils.dart'; -import 'package:test/test.dart'; +import 'package:test/test.dart' hide equals; class Person with EquatableMixin { Person({required this.name}); @@ -16,19 +16,33 @@ void main() { final alice = Person(name: 'Alice'); final aliceCopy = Person(name: 'Alice'); + group('equals', () { + test('returns true when both are null', () { + expect(equals(null, null), isTrue); + }); + + test('returns false when one is null', () { + expect(equals(null, []), isFalse); + expect(equals([], null), isFalse); + }); + }); + group('iterableEquals', () { test('returns true for identical props', () { final value = [Object()]; expect(iterableEquals(value, value), isTrue); + expect(equals(value, value), isTrue); }); test('returns true for empty iterables', () { expect(iterableEquals([], []), isTrue); + expect(equals([], []), isTrue); }); test('returns false when props differ in length', () { final object = Object(); expect(iterableEquals([object], [object, object]), isFalse); + expect(equals([object], [object, object]), isFalse); }); test('uses == when props are equatable', () { @@ -37,12 +51,19 @@ void main() { expect(iterableEquals([alice], [bob]), isFalse); expect(iterableEquals([bob], [alice]), isFalse); expect(iterableEquals([alice, null], [alice, -1]), isFalse); + + expect(equals([alice], [aliceCopy]), isTrue); + expect(equals([bob], [bob]), isTrue); + expect(equals([alice], [bob]), isFalse); + expect(equals([bob], [alice]), isFalse); + expect(equals([alice, null], [alice, -1]), isFalse); }); test('returns false for iterables with different elements', () { final iterable1 = [1, 2, 3]; final iterable2 = [1, 2, 4]; expect(iterableEquals(iterable1, iterable2), isFalse); + expect(equals(iterable1, iterable2), isFalse); }); test( @@ -51,6 +72,7 @@ void main() { final iterable1 = [1, 2, 3]; final iterable2 = [1, 3, 2]; expect(iterableEquals(iterable1, iterable2), isFalse); + expect(equals(iterable1, iterable2), isFalse); }); test('returns true for nested identical iterables', () { @@ -63,6 +85,7 @@ void main() { [alice, bob], ]; expect(iterableEquals(iterable1, iterable2), isTrue); + expect(equals(iterable1, iterable2), isTrue); }); test('returns false for nested iterables with different elements', () { @@ -75,6 +98,7 @@ void main() { [3, 5], ]; expect(iterableEquals(iterable1, iterable2), isFalse); + expect(equals(iterable1, iterable2), isFalse); }); }); @@ -268,5 +292,22 @@ void main() { test('returns false for different types', () { expect(objectsEquals(1, '1'), isFalse); }); + + test('returns true when two nums have the same value (int and double)', () { + const num a = 0; + const num b = 0.0; + expect(objectsEquals(a, b), isTrue); + }); + + test('returns true when two nums are identical', () { + const num a = 0; + expect(objectsEquals(a, a), isTrue); + }); + + test('returns false when two nums have different values', () { + const num a = 0; + const num b = 1; + expect(objectsEquals(a, b), isFalse); + }); }); }