refactor: v1.2.3 (#79)
diff --git a/CHANGELOG.md b/CHANGELOG.md index 042f4e3..794a33f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -1,3 +1,8 @@ +# 1.2.3 + +- docs: inline, public documentation improvements ([#78](https://github.com/felangel/equatable/pull/78)). +- refactor: stricter analysis/lint rules + # 1.2.2 - Documentation badge fixes and updates
diff --git a/README.md b/README.md index 1ef2092..8dedf25 100644 --- a/README.md +++ b/README.md
@@ -108,7 +108,7 @@ ```yaml dependencies: - equatable: ^1.2.1 + equatable: ^1.2.3 ``` Next, we need to install it: @@ -312,15 +312,13 @@ You might be wondering what the performance impact will be if you use `Equatable`. -[Performance Tests](https://github.com/felangel/equatable/raw/master/performance_tests) have been written to test how `Equatable` stacks up to manually overriding `==` and `hashCode` in terms of class instantiation as well as equality comparison. - ### Results (average over 10 runs) #### Equality Comparison A == A | Class | Runtime (μs) | | ------------------ | ------------ | -| RAW | 0.193 | +| Manual | 0.193 | | Empty Equatable | 0.191 | | Hydrated Equatable | 0.190 | @@ -328,8 +326,12 @@ | Class | Runtime (μs) | | ------------------ | ------------ | -| RAW | 0.165 | +| Manual | 0.165 | | Empty Equatable | 0.181 | | Hydrated Equatable | 0.182 | \*_Performance Tests run using: Dart VM version: 2.4.0_ + +## Maintainers + +- [Felix Angelov](https://github.com/felangel)
diff --git a/analysis_options.yaml b/analysis_options.yaml index 1fbf970..e7fcb23 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml
@@ -1 +1,81 @@ -include: package:effective_dart/analysis_options.1.2.0.yaml +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + errors: + close_sinks: ignore + +linter: + rules: + - public_member_api_docs + - annotate_overrides + - avoid_empty_else + - avoid_function_literals_in_foreach_calls + - avoid_init_to_null + - avoid_null_checks_in_equality_operators + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + - avoid_returning_null + - avoid_types_as_parameter_names + - avoid_unused_constructor_parameters + - await_only_futures + - camel_case_types + - cancel_subscriptions + - cascade_invocations + - comment_references + - constant_identifier_names + - control_flow_in_finally + - directives_ordering + - empty_catches + - empty_constructor_bodies + - empty_statements + - hash_and_equals + - implementation_imports + - invariant_booleans + - iterable_contains_unrelated_type + - library_names + - library_prefixes + - list_remove_unrelated_type + - lines_longer_than_80_chars + - no_adjacent_strings_in_list + - no_duplicate_case_values + - non_constant_identifier_names + - null_closures + - omit_local_variable_types + - only_throw_errors + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + - prefer_adjacent_string_concatenation + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_contains + - prefer_equal_for_default_values + - prefer_final_fields + - prefer_initializing_formals + - prefer_interpolation_to_compose_strings + - prefer_is_empty + - prefer_is_not_empty + - prefer_single_quotes + - prefer_typing_uninitialized_variables + - recursive_getters + - slash_for_doc_comments + - sort_constructors_first + - test_types_in_equals + - throw_in_finally + - type_init_formals + - unawaited_futures + - unnecessary_brace_in_string_interps + - unnecessary_const + - unnecessary_getters_setters + - unnecessary_lambdas + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_statements + - unnecessary_this + - unrelated_type_equality_checks + - use_rethrow_when_possible + - valid_regexps
diff --git a/example/main.dart b/example/main.dart index a1092be..c2bffdf 100644 --- a/example/main.dart +++ b/example/main.dart
@@ -1,11 +1,11 @@ import 'package:equatable/equatable.dart'; class Credentials extends Equatable { + const Credentials({this.username, this.password}); + final String username; final String password; - const Credentials({this.username, this.password}); - @override List<Object> get props => [username, password]; @@ -26,7 +26,7 @@ ]) : super(year, month, day, hour, minute, second, millisecond, microsecond); @override - List get props { + List<Object> get props { return [year, month, day, hour, minute, second, millisecond, microsecond]; } @@ -36,9 +36,9 @@ void main() { // Extending Equatable - final credentialsA = Credentials(username: 'Joe', password: 'password123'); - final credentialsB = Credentials(username: 'Bob', password: 'password!'); - final credentialsC = Credentials(username: 'Bob', password: 'password!'); + const credentialsA = Credentials(username: 'Joe', password: 'password123'); + const credentialsB = Credentials(username: 'Bob', password: 'password!'); + const credentialsC = Credentials(username: 'Bob', password: 'password!'); print(credentialsA == credentialsA); // true print(credentialsB == credentialsB); // true
diff --git a/lib/src/equatable.dart b/lib/src/equatable.dart index 8ceb57d..cd86786 100644 --- a/lib/src/equatable.dart +++ b/lib/src/equatable.dart
@@ -3,20 +3,25 @@ import './equatable_config.dart'; import './equatable_utils.dart'; +/// {@template equatable} /// A base class to facilitate [operator ==] and [hashCode] overrides. /// /// ```dart -/// class ConstTest extends Equatable { -/// const ConstTest(this.a); +/// class Person extends Equatable { +/// const Person(this.name); /// -/// final int a; +/// final String name; /// /// @override -/// List<Object> get props => [a]; +/// List<Object> get props => [name]; /// } /// ``` +/// {@endtemplate} @immutable abstract class Equatable { + /// {@macro equatable} + const Equatable(); + /// {@template equatable_props} /// The list of properies that will be used to determine whether /// two [Equatable]s are equal. @@ -37,13 +42,6 @@ // ignore: avoid_returning_null bool get stringify => null; - /// A class that helps implement equality - /// without needing to explicitly override [operator ==] and [hashCode]. - /// - /// [Equatable]s override their own [operator ==] and [hashCode] based on - /// their [props]. - const Equatable(); - @override bool operator ==(Object other) => identical(this, other) ||
diff --git a/lib/src/equatable_config.dart b/lib/src/equatable_config.dart index 3e691b7..262c2de 100644 --- a/lib/src/equatable_config.dart +++ b/lib/src/equatable_config.dart
@@ -1,8 +1,7 @@ +// ignore_for_file: avoid_classes_with_only_static_members import 'equatable.dart'; -// ignore_for_file: avoid_classes_with_only_static_members - -/// The default configurion for all [Equatable]s. +/// The default configurion for all [Equatable] instances. /// /// Currently, this config class only supports setting a default value for /// [stringify].
diff --git a/lib/src/equatable_mixin.dart b/lib/src/equatable_mixin.dart index c06a7c6..e24e184 100644 --- a/lib/src/equatable_mixin.dart +++ b/lib/src/equatable_mixin.dart
@@ -1,3 +1,4 @@ +import 'equatable.dart'; import 'equatable_config.dart'; import 'equatable_utils.dart';
diff --git a/lib/src/equatable_utils.dart b/lib/src/equatable_utils.dart index a0b7168..2c91fd4 100644 --- a/lib/src/equatable_utils.dart +++ b/lib/src/equatable_utils.dart
@@ -14,8 +14,8 @@ if (length != list2.length) return false; for (var i = 0; i < length; i++) { - final unit1 = list1[i]; - final unit2 = list2[i]; + final dynamic unit1 = list1[i]; + final dynamic unit2 = list2[i]; if (unit1 is Iterable || unit1 is Map) { if (!_equality.equals(unit1, unit2)) return false; @@ -32,8 +32,8 @@ /// https://en.wikipedia.org/wiki/Jenkins_hash_function int _combine(int hash, dynamic object) { if (object is Map) { - object.forEach((key, value) { - hash = hash ^ _combine(hash, [key, value]); + object.forEach((dynamic key, dynamic value) { + hash = hash ^ _combine(hash, <dynamic>[key, value]); }); return hash; }
diff --git a/performance_tests/README.md b/performance_tests/README.md deleted file mode 100644 index 3c10585..0000000 --- a/performance_tests/README.md +++ /dev/null
@@ -1,28 +0,0 @@ -# Equatable Performance Tests - -Benchmarks to measure how using `Equatable` will impact performance. - - -## Running the Performance Tests - -```sh -dart main.dart -``` - -## Results (average over 10 runs) - -### Equality Comparison A == A - -| Class | Runtime (microseconds) | -| ------------------ | ---------------------- | -| RAW | 0.143 | -| Empty Equatable | 0.124 | -| Hydrated Equatable | 0.126 | - -### Instantiation A() - -| Class | Runtime (microseconds) | -| ------------------ | ---------------------- | -| RAW | 0.099 | -| Empty Equatable | 0.251 | -| Hydrated Equatable | 0.121 | \ No newline at end of file
diff --git a/performance_tests/main.dart b/performance_tests/main.dart deleted file mode 100644 index cb3dc24..0000000 --- a/performance_tests/main.dart +++ /dev/null
@@ -1,132 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:benchmark_harness/benchmark_harness.dart'; - -class EmptyEquatable extends Equatable { - const EmptyEquatable(); - - @override - List<Object> get props => null; -} - -class LoginEvent extends Equatable { - final String username; - final String password; - - const LoginEvent({this.username, this.password}); - - @override - List get props => [username, password]; -} - -class LoginEventRaw { - final String username; - final String password; - - const LoginEventRaw({this.username, this.password}); - - @override - bool operator ==(Object other) => - identical(this, other) || - other is LoginEventRaw && - runtimeType == other.runtimeType && - username == other.username && - password == other.password; - - @override - int get hashCode => username.hashCode ^ password.hashCode; -} - -void main() { - print('----Comparison Report----'); - - print('RAW:'); - TemplateBenchmarkComparisonRaw().report(); - - print('Equatable:'); - TemplateBenchmarkComparison().report(); - - print('Empty Equatable:'); - TemplateBenchmarkComparisonEmpty().report(); - - print('----Instantiation Report----'); - - print('RAW:'); - TemplateBenchmarkInstantiationRaw().report(); - - print('Equatable:'); - TemplateBenchmarkInstantiation().report(); - - print('Empty Equatable:'); - TemplateBenchmarkInstantiationEmpty().report(); -} - -class TemplateBenchmarkComparisonRaw extends BenchmarkBase { - TemplateBenchmarkComparisonRaw() : super("Template"); - - LoginEventRaw eventA; - void run() { - eventA == eventA; - } - - @override - void setup() { - eventA = LoginEventRaw(username: 'username', password: 'password'); - super.setup(); - } -} - -class TemplateBenchmarkComparison extends BenchmarkBase { - TemplateBenchmarkComparison() : super("Template"); - - LoginEvent eventA; - - void run() { - eventA == eventA; - } - - @override - void setup() { - eventA = LoginEvent(username: 'username', password: 'password'); - super.setup(); - } -} - -class TemplateBenchmarkComparisonEmpty extends BenchmarkBase { - TemplateBenchmarkComparisonEmpty() : super("Template"); - - EmptyEquatable e; - - void run() { - e == e; - } - - @override - void setup() { - e = EmptyEquatable(); - super.setup(); - } -} - -class TemplateBenchmarkInstantiationRaw extends BenchmarkBase { - TemplateBenchmarkInstantiationRaw() : super("Template"); - - void run() { - LoginEventRaw(username: 'felix', password: 'password'); - } -} - -class TemplateBenchmarkInstantiation extends BenchmarkBase { - TemplateBenchmarkInstantiation() : super("Template"); - - void run() { - LoginEvent(username: 'felix', password: 'password'); - } -} - -class TemplateBenchmarkInstantiationEmpty extends BenchmarkBase { - TemplateBenchmarkInstantiationEmpty() : super("Template"); - - void run() { - EmptyEquatable(); - } -}
diff --git a/performance_tests/pubspec.yaml b/performance_tests/pubspec.yaml deleted file mode 100644 index 0547638..0000000 --- a/performance_tests/pubspec.yaml +++ /dev/null
@@ -1,9 +0,0 @@ -name: equatable_performance_tests - -environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" - -dependencies: - equatable: - path: ../ - benchmark_harness: 1.0.5
diff --git a/pubspec.yaml b/pubspec.yaml index 32d9adf..ea22d7c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml
@@ -1,6 +1,6 @@ name: equatable description: An abstract class that helps to implement equality without needing to explicitly override == and hashCode. -version: 1.2.2 +version: 1.2.3 repository: https://github.com/felangel/equatable issue_tracker: https://github.com/felangel/equatable/issues homepage: https://github.com/felangel/equatable
diff --git a/test/custom_list.dart b/test/custom_list.dart index 86b40ab..ecc49c2 100644 --- a/test/custom_list.dart +++ b/test/custom_list.dart
@@ -6,14 +6,14 @@ import 'dart:math'; class CustomList<E> implements List<E> { + CustomList(this._list, {bool growable = false}) + : _copyBeforeWrite = true, + _growable = growable; + bool _copyBeforeWrite; final bool _growable; List<E> _list; - CustomList(this._list, {growable = false}) - : _copyBeforeWrite = true, - _growable = growable; - // Read-only methods: just forward. @override @@ -83,7 +83,7 @@ Iterator<E> get iterator => _list.iterator; @override - String join([String separator = ""]) => _list.join(separator); + String join([String separator = '']) => _list.join(separator); @override E get last => _list.last;
diff --git a/test/equatable_config_test.dart b/test/equatable_config_test.dart index 961e84f..69352c6 100644 --- a/test/equatable_config_test.dart +++ b/test/equatable_config_test.dart
@@ -1,13 +1,14 @@ +// ignore_for_file: prefer_const_constructors import 'package:equatable/equatable.dart'; import 'package:test/test.dart'; class Credentials extends Equatable { + const Credentials({this.username, this.password, this.shouldStringify}); + final String username; final String password; final bool shouldStringify; - const Credentials({this.username, this.password, this.shouldStringify}); - @override List<Object> get props => [username, password]; @@ -18,14 +19,14 @@ abstract class EquatableBase with EquatableMixin {} class CredentialsMixin extends EquatableBase { + CredentialsMixin({this.username, this.password, this.shouldStringify}); + final String username; final String password; final bool shouldStringify; - CredentialsMixin({this.username, this.password, this.shouldStringify}); - @override - List get props => [username, password]; + List<Object> get props => [username, password]; @override bool get stringify => shouldStringify;
diff --git a/test/equatable_mixin_test.dart b/test/equatable_mixin_test.dart index 67ae5c2..2a2d058 100644 --- a/test/equatable_mixin_test.dart +++ b/test/equatable_mixin_test.dart
@@ -1,3 +1,4 @@ +// ignore_for_file: unrelated_type_equality_checks import 'dart:convert'; import 'package:equatable/equatable.dart'; @@ -14,66 +15,60 @@ } class SimpleEquatable<T> extends EquatableBase { - final T data; - SimpleEquatable(this.data); + final T data; + @override - List get props => [data]; + List<Object> get props => [data]; } class MultipartEquatable<T> extends EquatableBase { + MultipartEquatable(this.d1, this.d2); + final T d1; final T d2; - MultipartEquatable(this.d1, this.d2); - @override - List get props => [d1, d2]; + List<Object> get props => [d1, d2]; } class OtherEquatable extends EquatableBase { - final String data; - OtherEquatable(this.data); + final String data; + @override - List get props => [data]; + List<Object> get props => [data]; } enum Color { blonde, black, brown } 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; - ComplexEquatable({this.name, this.age, this.hairColor, this.children}); - @override - List 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 dynamic value; - EquatableData({this.key, this.value}); - @override - List get props => [key, value]; + List<Object> get props => [key, value]; } class Credentials extends EquatableBase { - final String username; - final String password; - Credentials({this.username, this.password}); - @override - List get props => [username, password]; - factory Credentials.fromJson(Map<String, dynamic> json) { return Credentials( username: json['username'] as String, @@ -81,8 +76,14 @@ ); } + final String username; + final String password; + + @override + List<Object> get props => [username, password]; + Map<String, dynamic> toJson() { - return { + return <String, dynamic>{ 'username': username, 'password': password, }; @@ -90,28 +91,19 @@ } class ComplexStringify extends ComplexEquatable { - final String name; - final int age; - final Color hairColor; - - ComplexStringify({this.name, this.age, this.hairColor}); - - @override - List get props => [name, age, hairColor]; + ComplexStringify({String name, int age, Color hairColor}) + : super(name: name, age: age, hairColor: hairColor); @override bool get stringify => true; } class ExplicitStringifyFalse extends ComplexEquatable { - final String name; - final int age; - final Color hairColor; - - ExplicitStringifyFalse({this.name, this.age, this.hairColor}); + ExplicitStringifyFalse({String name, int age, Color hairColor}) + : super(name: name, age: age, hairColor: hairColor); @override - List get props => [name, age, hairColor]; + List<Object> get props => [name, age, hairColor]; @override bool get stringify => false; @@ -121,7 +113,7 @@ NullProps(); @override - List get props => null; + List<Object> get props => null; @override bool get stringify => true; @@ -349,17 +341,17 @@ group('Multipart Equatable', () { test('should correct toString', () { - final instance = MultipartEquatable("s1", "s2"); + final instance = MultipartEquatable('s1', 's2'); expect(instance.toString(), 'MultipartEquatable<String>'); }); test('should return true when instance is the same', () { - final instance = MultipartEquatable("s1", "s2"); + final instance = MultipartEquatable('s1', 's2'); expect(instance == instance, true); }); test('should return correct hashCode', () { - final instance = MultipartEquatable("s1", "s2"); + final instance = MultipartEquatable('s1', 's2'); expect( instance.hashCode, instance.runtimeType.hashCode ^ mapPropsToHashCode(instance.props), @@ -368,31 +360,31 @@ test('should return different hashCodes when property order has changed', () { - final instance1 = MultipartEquatable("s1", "s2"); - final instance2 = MultipartEquatable("s2", "s1"); + final instance1 = MultipartEquatable('s1', 's2'); + final instance2 = MultipartEquatable('s2', 's1'); expect(instance1.hashCode == instance2.hashCode, isFalse); }); test('should return true when instances are different', () { - final instanceA = MultipartEquatable("s1", "s2"); - final instanceB = MultipartEquatable("s1", "s2"); + final instanceA = MultipartEquatable('s1', 's2'); + final instanceB = MultipartEquatable('s1', 's2'); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); test('should return false when compared to non-equatable', () { - final instanceA = MultipartEquatable("s1", "s2"); + final instanceA = MultipartEquatable('s1', 's2'); final instanceB = NonEquatable(); expect(instanceA == instanceB, false); }); test('should return false when values are different', () { - final instanceA = MultipartEquatable("s1", "s2"); - final instanceB = MultipartEquatable("s2", "s1"); + final instanceA = MultipartEquatable('s1', 's2'); + final instanceB = MultipartEquatable('s2', 's1'); expect(instanceA == instanceB, false); - final instanceC = MultipartEquatable("s1", "s1"); - final instanceD = MultipartEquatable("s2", "s1"); + final instanceC = MultipartEquatable('s1', 's1'); + final instanceD = MultipartEquatable('s2', 's1'); expect(instanceC == instanceD, false); }); }); @@ -494,36 +486,36 @@ group('Json Equatable', () { test('should correct toString', () { final instance = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect(instance.toString(), 'Credentials'); }); test('should return true when instance is the same', () { final instance = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect(instance == instance, true); }); test('should return correct hashCode', () { final instance = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect( instance.hashCode, @@ -533,20 +525,20 @@ test('should return true when instances are different', () { final instanceA = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); final instanceB = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); @@ -554,12 +546,12 @@ test('should return false when compared to non-equatable', () { final instanceA = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); final instanceB = NonEquatable(); expect(instanceA == instanceB, false); @@ -567,20 +559,20 @@ test('should return false when values are different', () { final instanceA = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); final instanceB = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"password" } - """, + ''', ) as Map<String, dynamic>); expect(instanceA == instanceB, false); }); @@ -589,20 +581,20 @@ group('To String Equatable', () { test('Complex stringify', () { final instanceA = ComplexStringify(); - final instanceB = ComplexStringify(name: "Bob", hairColor: Color.black); + final instanceB = ComplexStringify(name: 'Bob', hairColor: Color.black); final instanceC = - ComplexStringify(name: "Joe", age: 50, hairColor: Color.blonde); - expect(instanceA.toString(), 'ComplexStringify(, , )'); - expect(instanceB.toString(), 'ComplexStringify(Bob, , Color.black)'); - expect(instanceC.toString(), 'ComplexStringify(Joe, 50, Color.blonde)'); + ComplexStringify(name: 'Joe', age: 50, hairColor: Color.blonde); + expect(instanceA.toString(), 'ComplexStringify(, , , )'); + expect(instanceB.toString(), 'ComplexStringify(Bob, , Color.black, )'); + expect(instanceC.toString(), 'ComplexStringify(Joe, 50, Color.blonde, )'); }); test('with ExplicitStringifyFalse stringify', () { final instanceA = ExplicitStringifyFalse(); final instanceB = - ExplicitStringifyFalse(name: "Bob", hairColor: Color.black); + ExplicitStringifyFalse(name: 'Bob', hairColor: Color.black); final instanceC = - ExplicitStringifyFalse(name: "Joe", age: 50, hairColor: Color.blonde); + ExplicitStringifyFalse(name: 'Joe', age: 50, hairColor: Color.blonde); expect(instanceA.toString(), 'ExplicitStringifyFalse'); expect(instanceB.toString(), 'ExplicitStringifyFalse'); expect(instanceC.toString(), 'ExplicitStringifyFalse');
diff --git a/test/equatable_test.dart b/test/equatable_test.dart index 511fc5d..646538e 100644 --- a/test/equatable_test.dart +++ b/test/equatable_test.dart
@@ -1,3 +1,6 @@ +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unrelated_type_equality_checks +// ignore_for_file: prefer_collection_literals import 'dart:convert'; import 'package:equatable/equatable.dart'; @@ -9,36 +12,36 @@ class NonEquatable {} class EmptyEquatable extends Equatable { + const EmptyEquatable(); + @override List<Object> get props => []; - - const EmptyEquatable(); } class SimpleEquatable<T> extends Equatable { - final T data; - const SimpleEquatable(this.data); + final T data; + @override List<Object> get props => [data]; } class MultipartEquatable<T> extends Equatable { + MultipartEquatable(this.d1, this.d2); + final T d1; final T d2; - MultipartEquatable(this.d1, this.d2); - @override List<Object> get props => [d1, d2]; } class OtherEquatable extends Equatable { - final String data; - const OtherEquatable(this.data); + final String data; + @override List<Object> get props => [data]; } @@ -46,31 +49,28 @@ enum Color { blonde, black, brown } 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; - const ComplexEquatable({this.name, this.age, this.hairColor, this.children}); - @override List<Object> get props => [name, age, hairColor, children]; } class EquatableData extends Equatable { + const EquatableData({this.key, this.value}); + final String key; final dynamic value; - const EquatableData({this.key, this.value}); - @override List<Object> get props => [key, value]; } class Credentials extends Equatable { - final String username; - final String password; - const Credentials({this.username, this.password}); factory Credentials.fromJson(Map<String, dynamic> json) { @@ -80,8 +80,11 @@ ); } + final String username; + final String password; + Map<String, dynamic> toJson() { - return { + return <String, dynamic>{ 'username': username, 'password': password, }; @@ -92,28 +95,28 @@ } class ComplexStringify extends Equatable { + ComplexStringify({this.name, this.age, this.hairColor}); + final String name; final int age; final Color hairColor; - ComplexStringify({this.name, this.age, this.hairColor}); - @override - List get props => [name, age, hairColor]; + List<Object> get props => [name, age, hairColor]; @override bool get stringify => true; } class ExplicitStringifyFalse extends Equatable { + ExplicitStringifyFalse({this.name, this.age, this.hairColor}); + final String name; final int age; final Color hairColor; - ExplicitStringifyFalse({this.name, this.age, this.hairColor}); - @override - List get props => [name, age, hairColor]; + List<Object> get props => [name, age, hairColor]; @override bool get stringify => false; @@ -123,7 +126,7 @@ NullProps(); @override - List get props => null; + List<Object> get props => null; @override bool get stringify => true; @@ -357,17 +360,17 @@ group('Multipart Equatable', () { test('should correct toString', () { - final instance = MultipartEquatable("s1", "s2"); + final instance = MultipartEquatable('s1', 's2'); expect(instance.toString(), 'MultipartEquatable<String>'); }); test('should return true when instance is the same', () { - final instance = MultipartEquatable("s1", "s2"); + final instance = MultipartEquatable('s1', 's2'); expect(instance == instance, true); }); test('should return correct hashCode', () { - final instance = MultipartEquatable("s1", "s2"); + final instance = MultipartEquatable('s1', 's2'); expect( instance.hashCode, instance.runtimeType.hashCode ^ mapPropsToHashCode(instance.props), @@ -376,31 +379,31 @@ test('should return different hashCodes when property order has changed', () { - final instance1 = MultipartEquatable("s1", "s2"); - final instance2 = MultipartEquatable("s2", "s1"); + final instance1 = MultipartEquatable('s1', 's2'); + final instance2 = MultipartEquatable('s2', 's1'); expect(instance1.hashCode == instance2.hashCode, isFalse); }); test('should return true when instances are different', () { - final instanceA = MultipartEquatable("s1", "s2"); - final instanceB = MultipartEquatable("s1", "s2"); + final instanceA = MultipartEquatable('s1', 's2'); + final instanceB = MultipartEquatable('s1', 's2'); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); test('should return false when compared to non-equatable', () { - final instanceA = MultipartEquatable("s1", "s2"); + final instanceA = MultipartEquatable('s1', 's2'); final instanceB = NonEquatable(); expect(instanceA == instanceB, false); }); test('should return false when values are different', () { - final instanceA = MultipartEquatable("s1", "s2"); - final instanceB = MultipartEquatable("s2", "s1"); + final instanceA = MultipartEquatable('s1', 's2'); + final instanceB = MultipartEquatable('s2', 's1'); expect(instanceA == instanceB, false); - final instanceC = MultipartEquatable("s1", "s1"); - final instanceD = MultipartEquatable("s2", "s1"); + final instanceC = MultipartEquatable('s1', 's1'); + final instanceD = MultipartEquatable('s2', 's1'); expect(instanceC == instanceD, false); }); }); @@ -518,36 +521,36 @@ group('Json Equatable', () { test('should correct toString', () { final instance = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect(instance.toString(), 'Credentials'); }); test('should return true when instance is the same', () { final instance = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect(instance == instance, true); }); test('should return correct hashCode', () { final instance = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect( instance.hashCode, @@ -557,20 +560,20 @@ test('should return true when instances are different', () { final instanceA = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); final instanceB = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); @@ -578,12 +581,12 @@ test('should return false when compared to non-equatable', () { final instanceA = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); final instanceB = NonEquatable(); expect(instanceA == instanceB, false); @@ -591,20 +594,20 @@ test('should return false when values are different', () { final instanceA = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"admin" } - """, + ''', ) as Map<String, dynamic>); final instanceB = Credentials.fromJson(json.decode( - """ + ''' { "username":"Admin", "password":"password" } - """, + ''', ) as Map<String, dynamic>); expect(instanceA == instanceB, false); }); @@ -619,22 +622,22 @@ }); test('should return when values are same', () { - final instanceA = SimpleEquatable<Iterable>(["A", "B"]); - final instanceB = SimpleEquatable<Iterable>(["A", "B"]); + final instanceA = SimpleEquatable<Iterable>(<String>['A', 'B']); + final instanceB = SimpleEquatable<Iterable>(<String>['A', 'B']); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); test('should return when values are different', () { - final instanceA = SimpleEquatable<Iterable>(["A", "B"]); - final instanceB = SimpleEquatable<Iterable>(["a", "b"]); + final instanceA = SimpleEquatable<Iterable>(<String>['A', 'B']); + final instanceB = SimpleEquatable<Iterable>(<String>['a', 'b']); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); test('should return when values are different', () { - final instanceA = SimpleEquatable<Iterable>(["A", "B"]); - final instanceB = SimpleEquatable<Iterable>(["C", "D"]); + final instanceA = SimpleEquatable<Iterable>(<String>['A', 'B']); + final instanceB = SimpleEquatable<Iterable>(<String>['C', 'D']); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); @@ -642,31 +645,32 @@ group('List Equatable', () { test('should return when values are same', () { - final instanceA = SimpleEquatable<List>(["A", "B"]); - final instanceB = SimpleEquatable<List>(["A", "B"]); + final instanceA = SimpleEquatable<List>(<String>['A', 'B']); + final instanceB = SimpleEquatable<List>(<String>['A', 'B']); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); test('should return when values are different', () { - final instanceA = SimpleEquatable<List>(["A", "B"]); - final instanceB = SimpleEquatable<List>(["a", "b"]); + final instanceA = SimpleEquatable<List>(<String>['A', 'B']); + final instanceB = SimpleEquatable<List>(<String>['a', 'b']); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); test('should return when values are different', () { - final instanceA = SimpleEquatable<List>(["A", "B"]); - final instanceB = SimpleEquatable<List>(["C", "D"]); + final instanceA = SimpleEquatable<List>(<String>['A', 'B']); + final instanceB = SimpleEquatable<List>(<String>['C', 'D']); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); - test("should return when contents are same but different kind of List", + test('should return when contents are same but different kind of List', () { - final instanceA = - SimpleEquatable<List>(CustomList(["A", "B"], growable: true)); - final instanceB = SimpleEquatable<List>(["A", "B"]); + final instanceA = SimpleEquatable<List>( + CustomList<String>(['A', 'B'], growable: true), + ); + final instanceB = SimpleEquatable<List>(<String>['A', 'B']); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); @@ -674,8 +678,8 @@ test( 'should return different hashCode ' 'when instance properties are different', () { - final instanceA = SimpleEquatable<List>(["A", "B"]); - final instanceB = SimpleEquatable<List>(["B"]); + final instanceA = SimpleEquatable<List>(<String>['A', 'B']); + final instanceB = SimpleEquatable<List>(<String>['B']); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); @@ -684,7 +688,7 @@ test( 'should return different hashCode ' 'when instance properties are modified', () { - final list = ["A", "B"]; + final list = ['A', 'B']; final instanceA = SimpleEquatable<List>(list); final hashCodeA = instanceA.hashCode; list.removeLast(); @@ -695,22 +699,22 @@ group('Map Equatable', () { test('should return true when values are same', () { - final instanceA = SimpleEquatable<Map>({1: "A", 2: "B"}); - final instanceB = SimpleEquatable<Map>({1: "A", 2: "B"}); + final instanceA = SimpleEquatable<Map<int, String>>({1: 'A', 2: 'B'}); + final instanceB = SimpleEquatable<Map<int, String>>({1: 'A', 2: 'B'}); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); test('should return false when values are different', () { - final instanceA = SimpleEquatable<Map>({1: "A", 2: "B"}); - final instanceB = SimpleEquatable<Map>({1: "a", 2: "b"}); + final instanceA = SimpleEquatable<Map<int, String>>({1: 'A', 2: 'B'}); + final instanceB = SimpleEquatable<Map<int, String>>({1: 'a', 2: 'b'}); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); test('should return false when values are different', () { - final instanceA = SimpleEquatable<Map>({1: "A", 2: "B"}); - final instanceB = SimpleEquatable<Map>({1: "C", 2: "D"}); + final instanceA = SimpleEquatable<Map<int, String>>({1: 'A', 2: 'B'}); + final instanceB = SimpleEquatable<Map<int, String>>({1: 'C', 2: 'D'}); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); @@ -718,8 +722,8 @@ test( 'should return different hashCode ' 'when instance properties are different', () { - final instanceA = SimpleEquatable<Map>({1: "A", 2: "B"}); - final instanceB = SimpleEquatable<Map>({2: "B"}); + final instanceA = SimpleEquatable<Map<int, String>>({1: 'A', 2: 'B'}); + final instanceB = SimpleEquatable<Map<int, String>>({2: 'B'}); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); @@ -728,7 +732,7 @@ test( 'should return different hashCode ' 'when instance properties are modified', () { - final map = {1: "A", 2: "B"}; + final map = {1: 'A', 2: 'B'}; final instanceA = SimpleEquatable<Map>(map); final hashCodeA = instanceA.hashCode; map.remove(1); @@ -740,36 +744,52 @@ group('Set Equatable', () { test('should return when values are same', () { // ignore: prefer_collection_literals - final instanceA = SimpleEquatable<Set>(Set.from(["A", "B"])); + final instanceA = SimpleEquatable<Set<String>>( + Set.from(<String>['A', 'B']), + ); // ignore: prefer_collection_literals - final instanceB = SimpleEquatable<Set>(Set.from(["A", "B"])); + final instanceB = SimpleEquatable<Set<String>>( + Set.from(<String>['A', 'B']), + ); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); test('should return when values are same', () { // ignore: prefer_collection_literals - final instanceA = SimpleEquatable<Set>(Set.from(["A", "B", "A"])); + final instanceA = SimpleEquatable<Set<String>>( + Set.from(<String>['A', 'B', 'A']), + ); // ignore: prefer_collection_literals - final instanceB = SimpleEquatable<Set>(Set.from(["A", "B"])); + final instanceB = SimpleEquatable<Set<String>>( + Set.from(<String>['A', 'B']), + ); expect(instanceA == instanceB, true); expect(instanceA.hashCode == instanceB.hashCode, true); }); test('should return when values are different', () { // ignore: prefer_collection_literals - final instanceA = SimpleEquatable<Set>(Set.from(["A", "B"])); + final instanceA = SimpleEquatable<Set<String>>( + Set.from(<String>['A', 'B']), + ); // ignore: prefer_collection_literals - final instanceB = SimpleEquatable<Set>(Set.from(["a", "b"])); + final instanceB = SimpleEquatable<Set<String>>( + Set.from(<String>['a', 'b']), + ); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); test('should return when values are different', () { // ignore: prefer_collection_literals - final instanceA = SimpleEquatable<Set>(Set.from(["A", "B"])); + final instanceA = SimpleEquatable<Set<String>>( + Set.from(<String>['A', 'B']), + ); // ignore: prefer_collection_literals - final instanceB = SimpleEquatable<Set>(Set.from(["C", "D"])); + final instanceB = SimpleEquatable<Set<String>>( + Set.from(<String>['C', 'D']), + ); expect(instanceA != instanceB, true); expect(instanceA.hashCode != instanceB.hashCode, true); }); @@ -779,9 +799,9 @@ group('To String Equatable', () { test('with Complex stringify', () { final instanceA = ComplexStringify(); - final instanceB = ComplexStringify(name: "Bob", hairColor: Color.black); + final instanceB = ComplexStringify(name: 'Bob', hairColor: Color.black); final instanceC = - ComplexStringify(name: "Joe", age: 50, hairColor: Color.blonde); + ComplexStringify(name: 'Joe', age: 50, hairColor: Color.blonde); expect(instanceA.toString(), 'ComplexStringify(, , )'); expect(instanceB.toString(), 'ComplexStringify(Bob, , Color.black)'); expect(instanceC.toString(), 'ComplexStringify(Joe, 50, Color.blonde)'); @@ -790,9 +810,9 @@ test('with ExplicitStringifyFalse stringify', () { final instanceA = ExplicitStringifyFalse(); final instanceB = - ExplicitStringifyFalse(name: "Bob", hairColor: Color.black); + ExplicitStringifyFalse(name: 'Bob', hairColor: Color.black); final instanceC = - ExplicitStringifyFalse(name: "Joe", age: 50, hairColor: Color.blonde); + ExplicitStringifyFalse(name: 'Joe', age: 50, hairColor: Color.blonde); expect(instanceA.toString(), 'ExplicitStringifyFalse'); expect(instanceB.toString(), 'ExplicitStringifyFalse'); expect(instanceC.toString(), 'ExplicitStringifyFalse');