rrousselGit / freezed

Code generation for immutable classes that has a simple syntax/API without compromising on the features.
https://pub.dev/packages/freezed
1.93k stars 237 forks source link

Equatable comparison issue #732

Closed dlewis2017 closed 2 years ago

dlewis2017 commented 2 years ago

Description I'm using freezed for most of my classes and when trying to test them via bloc_test I get the following error: WARNING: Please ensure state instances extend Equatable, override == and hashCode, or implement Comparable. Alternatively, consider using Matchers in the expect of the blocTest rather than concrete state instances. Among other error messages indicating that the objects are not equal. At first I thought the issue was with bloc_test not picking up the == override properly, but as I stepped through the code I noticed that trying to compare two objects with == return false, while converting those same objects to JSON and comparing them with == returns true I believe I'm using the class as intended and will put snippets below.

Steps To Reproduce I can't share exact code but I'll try to re-create structure. These steps also include full bloc_test steps but you may be able to create 2 Bloc/Cubit States with freezed and compare to reproduce.

  1. Download dependencies
    
    environment:
    sdk: ">=2.15.1 <3.0.0"

dependencies: flutter: sdk: flutter freezed_annotation: ^2.0.1 json_annotation: ^4.5.0 flutter_dotenv: ^5.0.2 bloc: ^8.0.3 flutter_bloc: ^8.0.1 bloc_test: ^9.0.3 mocktail: ^0.3.0 dev_dependencies: flutter_test: sdk: flutter

flutter_lints: ^1.0.4 build_runner: ^2.1.10 freezed: ^2.0.3 json_serializable: ^6.0.0 ffigen: ^6.0.0

2. Create abstract class that is used as general state in cubit with corresponding immutable subclasses generated with freezed

part of 'scanner_cubit.dart';

abstract class ScannerStates {} @freezed abstract class InitialScannerState extends ScannerStates with _$InitialScannerState { const factory InitialScannerState( {required final ScannerSelection selection, @Default([]) final List rows, @Default(0) final int currentLayer, @Default(0.0) final double screenWidth, @Default(0.0) final double screenHeight, @Default(0.0) final double devicePixelRatio, @Default(false) final bool showCursor}) = _InitialScannerState; ...

3. run the builder to generate freezed files/classes: `flutter packages pub run build_runner build`
4. Create cubit with basic functionality and state manipulation that emits new state (one of subclasses mentioned above)
5. Create blocTest and expect updated state with specified values that will be changed upon calling a function (can use `verify` and convert to strings to test equality as well. `expectedState can be replace with actual state or defined above in `verify`)

build... act.... (emit state) expect: () => [expectedState] // Throws errors/fails test verify: (cubit) => { ... print(cubit.state == expectedState); // return false and fails test print((cubit.state).toString() == expectedState.toString()); // Returns true and test succeeds

6. Run test and see error

**Expected Behavior**
2 states of the same type with same values to return `true` when compared with `==`

**Screenshots**
N/A

**Additional Context**
Additional logs:

testBloc.. package:bloc_test/src/bloc_test.dart:229 dart:async _completeOnAsyncError package:bloc_test/src/bloc_test.dart testBloc.. package:bloc_test/src/bloc_test.dart:1 ===== asynchronous gap =========================== dart:async _asyncThenWrapperHelper package:bloc_test/src/bloc_test.dart testBloc.. package:bloc_test/src/bloc_test.dart:1 dart:async runZonedGuarded testBloc. package:bloc_test/src/bloc_test.dart:192 testBloc. package:bloc_test/src/bloc_test.dart:191 dart:async runZoned BlocOverrides.runZoned package:bloc/src/bloc_overrides.dart:46 testBloc package:bloc_test/src/bloc_test.dart:190 blocTest. package:bloc_test/src/bloc_test.dart:156 blocTest. package:bloc_test/src/bloc_test.dart:155

rrousselGit commented 2 years ago

Freezed already overrides ==. So if == returns false, it's likely that your objects are different.

Try checking all the properties of your class individually, to see which one is different.