-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix ChangeNotifier generic typing issue (#76)
Fix ChangeNotifier generic typing issue - ChangeRecord.ANY and ChangeRecord.None is not typesafe for any subclasses of ChangeNotifier that subclass the generic. Proposed solution is to output a `ChangeRecords extends List<ChangeRecord>` with additional metadata to indicate the change is ANY or NONE. Advantage of this change is that it is backwards compatible with existing code while fixing type exceptions for future code.
- Loading branch information
Showing
10 changed files
with
361 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:observable/observable.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import 'observable_test_utils.dart'; | ||
|
||
void main() { | ||
group(ChangeRecords, () { | ||
test('any changes', () { | ||
expectChanges(const ChangeRecords<A>.any(), const ChangeRecords<A>.any()); | ||
expectChanges(ChangeRecords<A>.any(), ChangeRecords<A>.any()); | ||
expectNotChanges(ChangeRecords<A>.any(), ChangeRecords<A>.wrap([])); | ||
expectNotChanges(ChangeRecords<A>.any(), ChangeRecords<B>.any()); | ||
expectNotChanges(ChangeRecords<B>.any(), ChangeRecords<C>.any()); | ||
}); | ||
|
||
test('some changes', () { | ||
expectChanges(ChangeRecords<A>.fromIterable([A()]), | ||
ChangeRecords<A>.fromIterable([A()])); | ||
expectChanges(ChangeRecords<A>.fromIterable([B(1), B(2)]), | ||
ChangeRecords<A>.fromIterable([B(1), B(2)])); | ||
expectNotChanges(ChangeRecords<A>.fromIterable([A()]), | ||
ChangeRecords<A>.fromIterable([A(), A()])); | ||
expectNotChanges(ChangeRecords<B>.fromIterable([B(1)]), | ||
ChangeRecords<A>.fromIterable([B(2)])); | ||
expectNotChanges(ChangeRecords<B>.fromIterable([B(1)]), | ||
ChangeRecords<A>.fromIterable([C()])); | ||
}); | ||
}); | ||
|
||
group(ChangeNotifier, () { | ||
Future<void> runTest<T extends ChangeRecord>( | ||
FutureOr<void> runFn(ChangeNotifier<T> cn), | ||
FutureOr<void> testFn(ChangeRecords<T> cr)) async { | ||
final cn = ChangeNotifier<T>(); | ||
|
||
cn.changes.listen((value) { | ||
expect(value, TypeMatcher<ChangeRecords<T>>()); | ||
testFn(value); | ||
}); | ||
|
||
await runFn(cn); | ||
|
||
return Future(() {}); | ||
} | ||
|
||
test( | ||
'delivers any record when no change notified', | ||
() => runTest<A>((cn) { | ||
cn.notifyChange(); | ||
}, (cr) { | ||
expectChanges(cr, ChangeRecords<A>.any()); | ||
})); | ||
|
||
test( | ||
'delivers expectChangesed changes', | ||
() => runTest<B>((cn) { | ||
cn..notifyChange(B(1))..notifyChange(B(2))..notifyChange(B(3)); | ||
}, (cr) { | ||
expectChanges(cr, ChangeRecords<B>.wrap([B(1), B(2), B(3)])); | ||
})); | ||
}); | ||
} | ||
|
||
class A extends ChangeRecord { | ||
@override | ||
bool operator ==(Object other) => | ||
identical(this, other) || other is A && runtimeType == other.runtimeType; | ||
|
||
@override | ||
int get hashCode => 0; | ||
} | ||
|
||
class B extends A { | ||
final int value; | ||
|
||
B(this.value); | ||
|
||
@override | ||
bool operator ==(Object other) => | ||
identical(this, other) || | ||
super == other && | ||
other is B && | ||
runtimeType == other.runtimeType && | ||
this.value == other.value; | ||
|
||
@override | ||
int get hashCode => value.hashCode; | ||
} | ||
|
||
class C extends A { | ||
@override | ||
bool operator ==(Object other) => | ||
identical(this, other) || | ||
super == other && other is C && runtimeType == other.runtimeType; | ||
|
||
@override | ||
int get hashCode => 2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.