feat!: nullsafety (#84)
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index e8b3d93..9c99d4f 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -5,23 +5,21 @@
branches:
- master
pull_request:
- branches:
- - master
jobs:
build:
runs-on: ubuntu-latest
container:
- image: google/dart:2.8.4
+ image: google/dart:2.12-dev
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: pub get
- name: Format
- run: dartfmt --dry-run --set-exit-if-changed .
+ run: dart format .
- name: Analyze
run: dartanalyzer --fatal-infos --fatal-warnings lib test
- name: Run tests
- run: pub run test_coverage
+ run: dart test --coverage=coverage && dart run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.packages --report-on=lib
- name: Check Code Coverage
- uses: ChicagoFlutter/lcov-cop@v1.0.0
+ uses: VeryGoodOpenSource/very_good_coverage@v1.1.1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 04dad5b..a437998 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,43 @@
+# 2.0.0
+
+- **BREAKING**: opt into null safety
+ - feat!: upgrade Dart SDK constraints to `>=2.12.0-0 <3.0.0`
+- **BREAKING**: stringify prints "null" for null properties instead of ""
+- feat: `EquatableConfig.stringify` defaults to `true` in debug mode.
+- fix: support legacy equality overrides with `EquatableMixin`
+- fix: iterable equality comparisons ([#101](https://github.com/felangel/equatable/issues/101))
+- fix: stringify instance with long properties ([#94](https://github.com/felangel/equatable/issues/94))
+- chore: update dependencies
+ - `collection: ^1.15.0`
+ - `meta: ^1.3.0`
+- docs: minor updates to `README` and `example`
+
+# 2.0.0-nullsafety.4
+
+- feat: `EquatableConfig.stringify` defaults to `true` in debug mode.
+- fix: support legacy equality overrides with `EquatableMixin`
+
+# 2.0.0-nullsafety.3
+
+- chore: update dependencies
+ - `collection: ^1.15.0`
+ - `meta: ^1.3.0`
+
+# 2.0.0-nullsafety.2
+
+- fix: iterable equality comparisons ([#101](https://github.com/felangel/equatable/issues/101))
+- fix: stringify instance with long properties ([#94](https://github.com/felangel/equatable/issues/94))
+
+# 2.0.0-nullsafety.1
+
+- **BREAKING**: stringify prints "null" for null properties instead of ""
+
+# 2.0.0-nullsafety.0
+
+- **BREAKING**: opt into null safety
+- feat!: upgrade Dart SDK constraints to `>=2.12.0-0 <3.0.0`
+- docs: minor updates to `README` and `example`
+
# 1.2.6
- fix: iterable equality comparisons ([#101](https://github.com/felangel/equatable/issues/101))
diff --git a/README.md b/README.md
index d11972c..e63982e 100644
--- a/README.md
+++ b/README.md
@@ -42,9 +42,9 @@
```dart
class Person {
- final String name;
-
const Person(this.name);
+
+ final String name;
}
```
@@ -68,10 +68,10 @@
```dart
class Person {
- final String name;
-
const Person(this.name);
+ final String name;
+
@override
bool operator ==(Object other) =>
identical(this, other) ||
@@ -108,7 +108,7 @@
```yaml
dependencies:
- equatable: ^1.2.5
+ equatable: ^2.0.0
```
Next, we need to install it:
@@ -127,9 +127,9 @@
import 'package:equatable/equatable.dart';
class Person extends Equatable {
- final String name;
+ const Person(this.name);
- Person(this.name);
+ final String name;
@override
List<Object> get props => [name];
@@ -142,9 +142,9 @@
import 'package:equatable/equatable.dart';
class Person extends Equatable {
- final String name;
+ const Person(this.name);
- Person(this.name);
+ final String name;
@override
List<Object> get props => [name];
@@ -164,10 +164,10 @@
import 'package:equatable/equatable.dart';
class Person extends Equatable {
- final String name;
-
const Person(this.name);
+ final String name;
+
@override
List<Object> get props => [name];
}
@@ -175,11 +175,11 @@
### `toString` Implementation
-Equatable can implement `toString` method including all the given props. If you want that behaviour, just include the following:
+Equatable can implement `toString` method including all the given props. If you want that behaviour for a specific `Equatable` object, just include the following:
```dart
- @override
- bool get stringify => true;
+@override
+bool get stringify => true;
```
For instance:
@@ -188,10 +188,10 @@
import 'package:equatable/equatable.dart';
class Person extends Equatable {
- final String name;
-
const Person(this.name);
+ final String name;
+
@override
List<Object> get props => [name];
@@ -219,16 +219,18 @@
If `stringify` is overridden for a specific `Equatable` class, then the value of `EquatableConfig.stringify` is ignored.
In other words, the local configuration always takes precedence over the global configuration.
+_Note: `EquatableConfig.stringify` defaults to `true` in debug mode and `false` in release mode._
+
## Recap
### Without Equatable
```dart
class Person {
- final String name;
-
const Person(this.name);
+ final String name;
+
@override
bool operator ==(Object other) =>
identical(this, other) ||
@@ -247,9 +249,9 @@
import 'package:equatable/equatable.dart';
class Person extends Equatable {
- final String name;
+ const Person(this.name);
- Person(this.name);
+ final String name;
@override
List<Object> get props => [name];
diff --git a/example/main.dart b/example/main.dart
index c2bffdf..c55197f 100644
--- a/example/main.dart
+++ b/example/main.dart
@@ -1,7 +1,7 @@
import 'package:equatable/equatable.dart';
class Credentials extends Equatable {
- const Credentials({this.username, this.password});
+ const Credentials({required this.username, required this.password});
final String username;
final String password;
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 622eeaf..bcdd28f 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -1,7 +1,7 @@
name: example
environment:
- sdk: ">=2.0.0 <3.0.0"
+ sdk: ">=2.12.0-0 <3.0.0"
dependencies:
equatable:
diff --git a/lib/src/equatable.dart b/lib/src/equatable.dart
index e7b65b8..3f2f4d0 100644
--- a/lib/src/equatable.dart
+++ b/lib/src/equatable.dart
@@ -26,7 +26,7 @@
/// The list of properties that will be used to determine whether
/// two instances are equal.
/// {@endtemplate}
- List<Object> get props;
+ List<Object?> get props;
/// {@template equatable_stringify}
/// If set to `true`, the [toString] method will be overridden to output
@@ -40,7 +40,7 @@
/// `false`.
/// {@endtemplate}
// ignore: avoid_returning_null
- bool get stringify => null;
+ bool? get stringify => null;
@override
bool operator ==(Object other) =>
diff --git a/lib/src/equatable_config.dart b/lib/src/equatable_config.dart
index 262c2de..dc07587 100644
--- a/lib/src/equatable_config.dart
+++ b/lib/src/equatable_config.dart
@@ -9,12 +9,27 @@
/// See also:
/// * [Equatable.stringify]
class EquatableConfig {
+ /// {@template stringify}
/// Global [stringify] setting for all [Equatable] instances.
///
/// If [stringify] is overridden for a particular [Equatable] instance,
/// then the local [stringify] value takes precedence
/// over [EquatableConfig.stringify].
///
- /// This value defaults to false.
- static bool stringify = false;
+ /// This value defaults to true in debug mode and false in release mode.
+ /// {@endtemplate}
+ static bool get stringify {
+ if (_stringify == null) {
+ assert(() {
+ _stringify = true;
+ return true;
+ }());
+ }
+ return _stringify ??= false;
+ }
+
+ /// {@macro stringify}
+ static set stringify(bool value) => _stringify = value;
+
+ static bool? _stringify;
}
diff --git a/lib/src/equatable_mixin.dart b/lib/src/equatable_mixin.dart
index 8253e3b..38d22e2 100644
--- a/lib/src/equatable_mixin.dart
+++ b/lib/src/equatable_mixin.dart
@@ -9,14 +9,14 @@
/// [operator ==] as well as the [hashCode] based on the provided [props].
mixin EquatableMixin {
/// {@macro equatable_props}
- List<Object> get props;
+ List<Object?> get props;
/// {@macro equatable_stringify}
// ignore: avoid_returning_null
- bool get stringify => null;
+ bool? get stringify => null;
@override
- bool operator ==(Object other) {
+ bool operator ==(Object? other) {
return identical(this, other) ||
other is EquatableMixin &&
runtimeType == other.runtimeType &&
diff --git a/lib/src/equatable_utils.dart b/lib/src/equatable_utils.dart
index c4f2268..e1da7f4 100644
--- a/lib/src/equatable_utils.dart
+++ b/lib/src/equatable_utils.dart
@@ -2,13 +2,13 @@
import 'package:equatable/equatable.dart';
/// Returns a `hashCode` for [props].
-int mapPropsToHashCode(Iterable props) =>
- _finish(props?.fold(0, _combine) ?? 0);
+int mapPropsToHashCode(Iterable? props) =>
+ _finish(props == null ? 0 : props.fold(0, _combine));
const DeepCollectionEquality _equality = DeepCollectionEquality();
/// Determines whether [list1] and [list2] are equal.
-bool equals(List list1, List list2) {
+bool equals(List? list1, List? list2) {
if (identical(list1, list2)) return true;
if (list1 == null || list2 == null) return false;
final length = list1.length;
@@ -63,5 +63,5 @@
}
/// Returns a string for [props].
-String mapPropsToString(Type runtimeType, List<Object> props) =>
- '$runtimeType(${props?.map((prop) => prop.toString())?.join(', ') ?? ""})';
+String mapPropsToString(Type runtimeType, List<Object?> props) =>
+ '$runtimeType(${props.map((prop) => prop.toString()).join(', ')})';
diff --git a/pubspec.yaml b/pubspec.yaml
index 37fd1db..700428f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,18 +1,18 @@
name: equatable
-description: An abstract class that helps to implement equality without needing to explicitly override == and hashCode.
-version: 1.2.6
+description: A Dart package that helps to implement value based equality without needing to explicitly override == and hashCode.
+version: 2.0.0
repository: https://github.com/felangel/equatable
issue_tracker: https://github.com/felangel/equatable/issues
homepage: https://github.com/felangel/equatable
documentation: https://github.com/felangel/equatable
environment:
- sdk: ">=2.0.0 <3.0.0"
+ sdk: ">=2.12.0-0 <3.0.0"
dependencies:
- collection: ^1.14.11
- meta: ^1.1.6
+ collection: ^1.15.0
+ meta: ^1.3.0
dev_dependencies:
- test: ^1.14.3
- test_coverage: ^0.4.1
+ coverage: ^0.14.2
+ test: ^1.16.0
diff --git a/test/custom_list.dart b/test/custom_list.dart
index ecc49c2..4b13834 100644
--- a/test/custom_list.dart
+++ b/test/custom_list.dart
@@ -35,7 +35,7 @@
List<T> cast<T>() => CustomList<T>(_list.cast<T>(), growable: _growable);
@override
- bool contains(Object element) => _list.contains(element);
+ bool contains(Object? element) => _list.contains(element);
@override
E elementAt(int index) => _list.elementAt(index);
@@ -50,7 +50,7 @@
E get first => _list.first;
@override
- E firstWhere(bool test(E element), {E orElse()}) =>
+ E firstWhere(bool test(E element), {E orElse()?}) =>
_list.firstWhere(test, orElse: orElse);
@override
@@ -89,14 +89,14 @@
E get last => _list.last;
@override
- int lastIndexOf(E element, [int start]) => _list.lastIndexOf(element, start);
+ int lastIndexOf(E element, [int? start]) => _list.lastIndexOf(element, start);
@override
- int lastIndexWhere(bool test(E element), [int start]) =>
+ int lastIndexWhere(bool test(E element), [int? start]) =>
_list.lastIndexWhere(test, start);
@override
- E lastWhere(bool test(E element), {E orElse()}) =>
+ E lastWhere(bool test(E element), {E orElse()?}) =>
_list.lastWhere(test, orElse: orElse);
@override
@@ -112,7 +112,7 @@
E get single => _list.single;
@override
- E singleWhere(bool test(E element), {E orElse()}) =>
+ E singleWhere(bool test(E element), {E orElse()?}) =>
_list.singleWhere(test, orElse: orElse);
@override
@@ -122,7 +122,7 @@
Iterable<E> skipWhile(bool test(E value)) => _list.skipWhile(test);
@override
- List<E> sublist(int start, [int end]) => _list.sublist(start, end);
+ List<E> sublist(int start, [int? end]) => _list.sublist(start, end);
@override
Iterable<E> take(int count) => _list.take(count);
@@ -181,13 +181,13 @@
}
@override
- void sort([int compare(E a, E b)]) {
+ void sort([int compare(E a, E b)?]) {
_maybeCopyBeforeWrite();
_list.sort(compare);
}
@override
- void shuffle([Random random]) {
+ void shuffle([Random? random]) {
_maybeCopyBeforeWrite();
_list.shuffle(random);
}
@@ -217,7 +217,7 @@
}
@override
- bool remove(Object value) {
+ bool remove(Object? value) {
_maybeCopyBeforeWrite();
return _list.remove(value);
}
@@ -259,7 +259,7 @@
}
@override
- void fillRange(int start, int end, [E fillValue]) {
+ void fillRange(int start, int end, [E? fillValue]) {
_maybeCopyBeforeWrite();
_list.fillRange(start, end, fillValue);
}
diff --git a/test/equatable_config_test.dart b/test/equatable_config_test.dart
index 69352c6..08483ba 100644
--- a/test/equatable_config_test.dart
+++ b/test/equatable_config_test.dart
@@ -3,44 +3,58 @@
import 'package:test/test.dart';
class Credentials extends Equatable {
- const Credentials({this.username, this.password, this.shouldStringify});
+ const Credentials({
+ required this.username,
+ required this.password,
+ this.shouldStringify,
+ });
final String username;
final String password;
- final bool shouldStringify;
+ final bool? shouldStringify;
@override
List<Object> get props => [username, password];
@override
- bool get stringify => shouldStringify;
+ bool? get stringify => shouldStringify;
}
abstract class EquatableBase with EquatableMixin {}
class CredentialsMixin extends EquatableBase {
- CredentialsMixin({this.username, this.password, this.shouldStringify});
+ CredentialsMixin({
+ required this.username,
+ required this.password,
+ this.shouldStringify,
+ });
final String username;
final String password;
- final bool shouldStringify;
+ final bool? shouldStringify;
@override
List<Object> get props => [username, password];
@override
- bool get stringify => shouldStringify;
+ bool? get stringify => shouldStringify;
}
void main() {
group('EquatableConfig', () {
+ late bool globalStringify;
+
+ setUp(() {
+ globalStringify = EquatableConfig.stringify;
+ });
+
tearDown(() {
- EquatableConfig.stringify = false;
+ EquatableConfig.stringify = globalStringify;
});
group('stringify', () {
- test('defaults to false', () {
- expect(EquatableConfig.stringify, isFalse);
+ test('defaults to true', () {
+ expect(EquatableConfig.stringify, isTrue);
});
test('is used when stringify is not overridden at the instance (false)',
diff --git a/test/equatable_mixin_test.dart b/test/equatable_mixin_test.dart
index 7dfe4c9..8cdb3d2 100644
--- a/test/equatable_mixin_test.dart
+++ b/test/equatable_mixin_test.dart
@@ -14,7 +14,7 @@
List<Object> get props => const [];
}
-class SimpleEquatable<T> extends EquatableBase {
+class SimpleEquatable<T extends Object> extends EquatableBase {
SimpleEquatable(this.data);
final T data;
@@ -23,7 +23,7 @@
List<Object> get props => [data];
}
-class MultipartEquatable<T> extends EquatableBase {
+class MultipartEquatable<T extends Object> extends EquatableBase {
MultipartEquatable(this.d1, this.d2);
final T d1;
@@ -47,27 +47,27 @@
class ComplexEquatable extends EquatableBase {
ComplexEquatable({this.name, this.age, this.hairColor, this.children});
- final String name;
- final int age;
- final Color hairColor;
- final List<String> children;
+ final String? name;
+ final int? age;
+ final Color? hairColor;
+ final List<String>? children;
@override
- List<Object> get props => [name, age, hairColor, children];
+ List<Object?> get props => [name, age, hairColor, children];
}
class EquatableData extends EquatableBase {
EquatableData({this.key, this.value});
- final String key;
+ final String? key;
final dynamic value;
@override
- List<Object> get props => [key, value];
+ List<Object?> get props => [key, value];
}
class Credentials extends EquatableBase {
- Credentials({this.username, this.password});
+ Credentials({required this.username, required this.password});
factory Credentials.fromJson(Map<String, dynamic> json) {
return Credentials(
@@ -91,7 +91,7 @@
}
class ComplexStringify extends ComplexEquatable {
- ComplexStringify({String name, int age, Color hairColor})
+ ComplexStringify({String? name, int? age, Color? hairColor})
: super(name: name, age: age, hairColor: hairColor);
@override
@@ -99,28 +99,18 @@
}
class ExplicitStringifyFalse extends ComplexEquatable {
- ExplicitStringifyFalse({String name, int age, Color hairColor})
+ ExplicitStringifyFalse({String? name, int? age, Color? hairColor})
: super(name: name, age: age, hairColor: hairColor);
@override
- List<Object> get props => [name, age, hairColor];
+ List<Object?> get props => [name, age, hairColor];
@override
bool get stringify => false;
}
-class NullProps extends Equatable {
- NullProps();
-
- @override
- List<Object> get props => null;
-
- @override
- bool get stringify => true;
-}
-
class IterableWithFlag<T> extends Iterable<T> with EquatableMixin {
- IterableWithFlag({this.list, this.flag});
+ IterableWithFlag({required this.list, required this.flag});
final bool flag;
final List<T> list;
@@ -132,15 +122,47 @@
Iterator<T> get iterator => list.iterator;
}
+class LegacyEqualityOverride {
+ const LegacyEqualityOverride(this.x);
+
+ final int x;
+
+ @override
+ bool operator ==(dynamic o) {
+ if (identical(this, o)) return true;
+
+ return o is LegacyEqualityOverride && o.x == x;
+ }
+
+ @override
+ int get hashCode => x.hashCode;
+}
+
+class LegacyEqualityOverrideEquatable extends LegacyEqualityOverride
+ with EquatableMixin {
+ LegacyEqualityOverrideEquatable(int x, this.y) : super(x);
+
+ final int y;
+
+ @override
+ List<Object?> get props => [x, y];
+}
+
void main() {
+ late bool globalStringify;
+
setUp(() {
- EquatableConfig.stringify = false;
+ globalStringify = EquatableConfig.stringify;
+ });
+
+ tearDown(() {
+ EquatableConfig.stringify = globalStringify;
});
group('Empty Equatable', () {
test('should correct toString', () {
final instance = EmptyEquatable();
- expect(instance.toString(), 'EmptyEquatable');
+ expect(instance.toString(), 'EmptyEquatable()');
});
test('should return true when instance is the same', () {
@@ -173,14 +195,13 @@
group('Simple Equatable (string)', () {
test('should correct toString', () {
final instance = SimpleEquatable('simple');
- expect(instance.toString(), 'SimpleEquatable<String>');
+ expect(instance.toString(), 'SimpleEquatable<String>(simple)');
});
- test('should correct toString when EquatableConfig.stringify is true', () {
- EquatableConfig.stringify = true;
+ test('should correct toString when EquatableConfig.stringify is false', () {
+ EquatableConfig.stringify = false;
final instance = SimpleEquatable('simple');
- expect(instance.toString(), 'SimpleEquatable<String>(simple)');
- EquatableConfig.stringify = null;
+ expect(instance.toString(), 'SimpleEquatable<String>');
});
test('should return true when instance is the same', () {
@@ -225,7 +246,7 @@
group('Simple Equatable (number)', () {
test('should correct toString', () {
final instance = SimpleEquatable(0);
- expect(instance.toString(), 'SimpleEquatable<int>');
+ expect(instance.toString(), 'SimpleEquatable<int>(0)');
});
test('should return true when instance is the same', () {
@@ -264,7 +285,7 @@
group('Simple Equatable (bool)', () {
test('should correct toString', () {
final instance = SimpleEquatable(true);
- expect(instance.toString(), 'SimpleEquatable<bool>');
+ expect(instance.toString(), 'SimpleEquatable<bool>(true)');
});
test('should return true when instance is the same', () {
@@ -306,7 +327,10 @@
key: 'foo',
value: 'bar',
));
- expect(instance.toString(), 'SimpleEquatable<EquatableData>');
+ expect(
+ instance.toString(),
+ 'SimpleEquatable<EquatableData>(EquatableData(foo, bar))',
+ );
});
test('should return true when instance is the same', () {
final instance = SimpleEquatable(EquatableData(
@@ -365,7 +389,7 @@
group('Multipart Equatable', () {
test('should correct toString', () {
final instance = MultipartEquatable('s1', 's2');
- expect(instance.toString(), 'MultipartEquatable<String>');
+ expect(instance.toString(), 'MultipartEquatable<String>(s1, s2)');
});
test('should return true when instance is the same', () {
@@ -420,7 +444,10 @@
hairColor: Color.black,
children: ['Bob'],
);
- expect(instance.toString(), 'ComplexEquatable');
+ expect(
+ instance.toString(),
+ 'ComplexEquatable(Joe, 40, Color.black, [Bob])',
+ );
});
test('should return true when instance is the same', () {
final instance = ComplexEquatable(
@@ -516,7 +543,7 @@
}
''',
) as Map<String, dynamic>);
- expect(instance.toString(), 'Credentials');
+ expect(instance.toString(), 'Credentials(Admin, admin)');
});
test('should return true when instance is the same', () {
@@ -633,25 +660,6 @@
});
});
- group('Null props Equatable', () {
- test('should not crash invoking equals method', () {
- final instanceA = NullProps();
- final instanceB = NullProps();
- expect(instanceA == instanceB, true);
- });
-
- test('should not crash invoking hascode method', () {
- final instanceA = NullProps();
- final instanceB = NullProps();
- expect(instanceA.hashCode == instanceB.hashCode, true);
- });
-
- test('should not crash invoking toString method', () {
- final instance = NullProps();
- expect(instance.toString(), 'NullProps()');
- });
- });
-
group('Iterable Equatable', () {
test('should be equal when different instances have same values', () {
final instanceA = IterableWithFlag(flag: true, list: [1, 2]);
@@ -693,4 +701,21 @@
expect(instanceA == instanceB, isFalse);
});
});
+
+ group('LegacyEqualityOverride', () {
+ test('should be equal when different instances have same values', () {
+ final instanceA = LegacyEqualityOverrideEquatable(0, 1);
+ final instanceB = LegacyEqualityOverrideEquatable(0, 1);
+
+ expect(instanceA == instanceB, isTrue);
+ });
+
+ test('should not be equal when different instances have different values',
+ () {
+ final instanceA = LegacyEqualityOverrideEquatable(0, 0);
+ final instanceB = LegacyEqualityOverrideEquatable(0, 1);
+
+ expect(instanceA == instanceB, isFalse);
+ });
+ });
}
diff --git a/test/equatable_test.dart b/test/equatable_test.dart
index 76c7b7d..89dca56 100644
--- a/test/equatable_test.dart
+++ b/test/equatable_test.dart
@@ -18,7 +18,7 @@
List<Object> get props => [];
}
-class SimpleEquatable<T> extends Equatable {
+class SimpleEquatable<T extends Object> extends Equatable {
const SimpleEquatable(this.data);
final T data;
@@ -27,7 +27,7 @@
List<Object> get props => [data];
}
-class MultipartEquatable<T> extends Equatable {
+class MultipartEquatable<T extends Object> extends Equatable {
MultipartEquatable(this.d1, this.d2);
final T d1;
@@ -51,27 +51,27 @@
class ComplexEquatable extends Equatable {
const ComplexEquatable({this.name, this.age, this.hairColor, this.children});
- final String name;
- final int age;
- final Color hairColor;
- final List<String> children;
+ final String? name;
+ final int? age;
+ final Color? hairColor;
+ final List<String>? children;
@override
- List<Object> get props => [name, age, hairColor, children];
+ List<Object?> get props => [name, age, hairColor, children];
}
class EquatableData extends Equatable {
- const EquatableData({this.key, this.value});
+ const EquatableData({required this.key, required this.value});
final String key;
- final dynamic value;
+ final Object value;
@override
List<Object> get props => [key, value];
}
class Credentials extends Equatable {
- const Credentials({this.username, this.password});
+ const Credentials({required this.username, required this.password});
factory Credentials.fromJson(Map<String, dynamic> json) {
return Credentials(
@@ -97,12 +97,12 @@
class ComplexStringify extends Equatable {
ComplexStringify({this.name, this.age, this.hairColor});
- final String name;
- final int age;
- final Color hairColor;
+ final String? name;
+ final int? age;
+ final Color? hairColor;
@override
- List<Object> get props => [name, age, hairColor];
+ List<Object?> get props => [name, age, hairColor];
@override
bool get stringify => true;
@@ -128,36 +128,32 @@
class ExplicitStringifyFalse extends Equatable {
ExplicitStringifyFalse({this.name, this.age, this.hairColor});
- final String name;
- final int age;
- final Color hairColor;
+ final String? name;
+ final int? age;
+ final Color? hairColor;
@override
- List<Object> get props => [name, age, hairColor];
+ List<Object?> get props => [name, age, hairColor];
@override
bool get stringify => false;
}
-class NullProps extends Equatable {
- NullProps();
-
- @override
- List<Object> get props => null;
-
- @override
- bool get stringify => true;
-}
-
void main() {
+ late bool globalStringify;
+
setUp(() {
- EquatableConfig.stringify = false;
+ globalStringify = EquatableConfig.stringify;
+ });
+
+ tearDown(() {
+ EquatableConfig.stringify = globalStringify;
});
group('Empty Equatable', () {
test('should correct toString', () {
final instance = EmptyEquatable();
- expect(instance.toString(), 'EmptyEquatable');
+ expect(instance.toString(), 'EmptyEquatable()');
});
test('should return true when instance is the same', () {
@@ -190,14 +186,13 @@
group('Simple Equatable (string)', () {
test('should correct toString', () {
final instance = SimpleEquatable('simple');
- expect(instance.toString(), 'SimpleEquatable<String>');
+ expect(instance.toString(), 'SimpleEquatable<String>(simple)');
});
- test('should correct toString when EquatableConfig.stringify is true', () {
- EquatableConfig.stringify = true;
+ test('should correct toString when EquatableConfig.stringify is false', () {
+ EquatableConfig.stringify = false;
final instance = SimpleEquatable('simple');
- expect(instance.toString(), 'SimpleEquatable<String>(simple)');
- EquatableConfig.stringify = null;
+ expect(instance.toString(), 'SimpleEquatable<String>');
});
test('should return true when instance is the same', () {
@@ -215,7 +210,7 @@
test('should return correct toString', () {
final instance = SimpleEquatable('simple');
- expect(instance.toString(), 'SimpleEquatable<String>');
+ expect(instance.toString(), 'SimpleEquatable<String>(simple)');
});
test('should return true when instances are different', () {
@@ -245,9 +240,9 @@
});
group('Simple Equatable (number)', () {
- test('should correct toString', () {
+ test('should return correct toString', () {
final instance = SimpleEquatable(0);
- expect(instance.toString(), 'SimpleEquatable<int>');
+ expect(instance.toString(), 'SimpleEquatable<int>(0)');
});
test('should return true when instance is the same', () {
@@ -286,7 +281,7 @@
group('Simple Equatable (bool)', () {
test('should correct toString', () {
final instance = SimpleEquatable(true);
- expect(instance.toString(), 'SimpleEquatable<bool>');
+ expect(instance.toString(), 'SimpleEquatable<bool>(true)');
});
test('should return true when instance is the same', () {
@@ -328,7 +323,10 @@
key: 'foo',
value: 'bar',
));
- expect(instance.toString(), 'SimpleEquatable<EquatableData>');
+ expect(
+ instance.toString(),
+ 'SimpleEquatable<EquatableData>(EquatableData(foo, bar))',
+ );
});
test('should return true when instance is the same', () {
final instance = SimpleEquatable(EquatableData(
@@ -387,7 +385,7 @@
group('Multipart Equatable', () {
test('should correct toString', () {
final instance = MultipartEquatable('s1', 's2');
- expect(instance.toString(), 'MultipartEquatable<String>');
+ expect(instance.toString(), 'MultipartEquatable<String>(s1, s2)');
});
test('should return true when instance is the same', () {
@@ -442,7 +440,10 @@
hairColor: Color.black,
children: ['Bob'],
);
- expect(instance.toString(), 'ComplexEquatable');
+ expect(
+ instance.toString(),
+ 'ComplexEquatable(Joe, 40, Color.black, [Bob])',
+ );
});
test('should return true when instance is the same', () {
final instance = ComplexEquatable(
@@ -554,7 +555,7 @@
}
''',
) as Map<String, dynamic>);
- expect(instance.toString(), 'Credentials');
+ expect(instance.toString(), 'Credentials(Admin, admin)');
});
test('should return true when instance is the same', () {
@@ -853,25 +854,6 @@
expect(instanceC.toString(), 'ExplicitStringifyFalse');
});
});
-
- group('Null props Equatable', () {
- test('should not crash invoking equals method', () {
- final instanceA = NullProps();
- final instanceB = NullProps();
- expect(instanceA == instanceB, true);
- });
-
- test('should not crash invoking hascode method', () {
- final instanceA = NullProps();
- final instanceB = NullProps();
- expect(instanceA.hashCode == instanceB.hashCode, true);
- });
-
- test('should not crash invoking toString method', () {
- final instance = NullProps();
- expect(instance.toString(), 'NullProps()');
- });
- });
}
// test that subclasses of `Equatable` can have const constructors