Merge the null_safety branch into master (#143)
Migrates the package to null safety
diff --git a/.travis.yml b/.travis.yml
index 96ba17a..5801d68 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,27 +1,43 @@
language: dart
dart:
-- 2.3.0
- dev
-dart_task:
-- test
-
-matrix:
+jobs:
include:
- # Only validate formatting using the dev release
- - dart: dev
- dart_task: dartfmt
- - dart: dev
- dart_task:
- dartanalyzer: --fatal-infos --fatal-warnings .
- - dart: 2.3.0
- dart_task:
- dartanalyzer: --fatal-warnings .
+ - stage: analyze_and_format
+ name: "Analyze lib/"
+ dart: dev
+ os: linux
+ script: dartanalyzer --fatal-warnings --fatal-infos lib/
+ - stage: analyze_and_format
+ name: "Analyze test/"
+ dart: dev
+ os: linux
+ script: dartanalyzer --enable-experiment=non-nullable --fatal-warnings --fatal-infos test/
+ - stage: analyze_and_format
+ name: "Format"
+ dart: dev
+ os: linux
+ script: dartfmt -n --set-exit-if-changed .
+ - stage: test
+ name: "Vm Tests"
+ dart: dev
+ os: linux
+ script: pub run --enable-experiment=non-nullable test -p vm
+ - stage: test
+ name: "Web Tests"
+ dart: dev
+ os: linux
+ script: pub run --enable-experiment=non-nullable test -p chrome
+
+stages:
+ - analyze_and_format
+ - test
# Only building master means that we don't run two builds for each pull request.
branches:
- only: [master]
+ only: [master, null_safety]
# Incremental pub cache and builds.
cache:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19e4773..3a47241 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 1.15.0-nnbd
+
+Pre-release for the null safety migration of this package.
+
+Note that `1.15.0` may not be the final stable null safety release version,
+we reserve the right to release it as a `2.0.0` breaking change.
+
+This release will be pinned to only allow pre-release sdk versions starting
+from `2.9.0-dev.18.0`, which is the first version where this package will
+appear in the null safety allow list.
+
## 1.14.13
* Deprecate `mapMap`. The Map interface has a `map` call and map literals can
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 05bafc1..5adddb1 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -5,6 +5,9 @@
unused_import: error
unused_local_variable: error
dead_code: error
+ enable-experiment:
+ - non-nullable
+
linter:
rules:
# Errors
diff --git a/lib/src/algorithms.dart b/lib/src/algorithms.dart
index cb6a03f..616be85 100644
--- a/lib/src/algorithms.dart
+++ b/lib/src/algorithms.dart
@@ -16,7 +16,8 @@
/// (`CastError` on some SDK versions).
///
/// Returns -1 if [value] is not in the list by default.
-int binarySearch<T>(List<T> sortedList, T value, {int Function(T, T) compare}) {
+int binarySearch<T>(List<T> sortedList, T value,
+ {int Function(T, T)? compare}) {
compare ??= defaultCompare<T>();
var min = 0;
var max = sortedList.length;
@@ -46,7 +47,7 @@
///
/// Returns [sortedList.length] if all the items in [sortedList] compare less
/// than [value].
-int lowerBound<T>(List<T> sortedList, T value, {int Function(T, T) compare}) {
+int lowerBound<T>(List<T> sortedList, T value, {int Function(T, T)? compare}) {
compare ??= defaultCompare<T>();
var min = 0;
var max = sortedList.length;
@@ -66,7 +67,7 @@
/// Shuffles a list randomly.
///
/// A sub-range of a list can be shuffled by providing [start] and [end].
-void shuffle(List list, [int start = 0, int end]) {
+void shuffle(List list, [int start = 0, int? end]) {
var random = math.Random();
end ??= list.length;
var length = end - start;
@@ -80,7 +81,7 @@
}
/// Reverses a list, or a part of a list, in-place.
-void reverse(List list, [int start = 0, int end]) {
+void reverse(List list, [int start = 0, int? end]) {
end ??= list.length;
_reverse(list, start, end);
}
@@ -111,7 +112,7 @@
/// This insertion sort is stable: Equal elements end up in the same order
/// as they started in.
void insertionSort<T>(List<T> list,
- {int Function(T, T) compare, int start = 0, int end}) {
+ {int Function(T, T)? compare, int start = 0, int? end}) {
// If the same method could have both positional and named optional
// parameters, this should be (list, [start, end], {compare}).
compare ??= defaultCompare<T>();
@@ -155,8 +156,8 @@
/// This merge sort is stable: Equal elements end up in the same order
/// as they started in.
void mergeSort<T>(List<T> list,
- {int start = 0, int end, int Function(T, T) compare}) {
- end ??= list.length;
+ {int start = 0, int? end, int Function(T, T)? compare}) {
+ end = RangeError.checkValidRange(start, end, list.length);
compare ??= defaultCompare<T>();
var length = end - start;
@@ -175,12 +176,12 @@
var firstLength = middle - start;
var secondLength = end - middle;
// secondLength is always the same as firstLength, or one greater.
- var scratchSpace = List<T>(secondLength);
- _mergeSort(list, compare, middle, end, scratchSpace, 0);
+ var scratchSpace = List<T>.filled(secondLength, list[start]);
+ _mergeSort<T>(list, compare, middle, end, scratchSpace, 0);
var firstTarget = end - firstLength;
- _mergeSort(list, compare, start, middle, list, firstTarget);
- _merge(compare, list, firstTarget, end, scratchSpace, 0, secondLength, list,
- start);
+ _mergeSort<T>(list, compare, start, middle, list, firstTarget);
+ _merge<T>(compare, list, firstTarget, end, scratchSpace, 0, secondLength,
+ list, start);
}
/// Performs an insertion sort into a potentially different list than the
@@ -198,7 +199,7 @@
var max = targetOffset + i;
while (min < max) {
var mid = min + ((max - min) >> 1);
- if (compare(element, target[mid]) < 0) {
+ if (compare(element, target[mid]!) < 0) {
max = mid;
} else {
min = mid + 1;
@@ -220,7 +221,7 @@
List<T> target, int targetOffset) {
var length = end - start;
if (length < _MERGE_SORT_LIMIT) {
- _movingInsertionSort(list, compare, start, end, target, targetOffset);
+ _movingInsertionSort<T>(list, compare, start, end, target, targetOffset);
return;
}
var middle = start + (length >> 1);
@@ -229,11 +230,11 @@
// Here secondLength >= firstLength (differs by at most one).
var targetMiddle = targetOffset + firstLength;
// Sort the second half into the end of the target area.
- _mergeSort(list, compare, middle, end, target, targetMiddle);
+ _mergeSort<T>(list, compare, middle, end, target, targetMiddle);
// Sort the first half into the end of the source area.
- _mergeSort(list, compare, start, middle, list, middle);
+ _mergeSort<T>(list, compare, start, middle, list, middle);
// Merge the two parts into the target area.
- _merge(compare, list, middle, middle + firstLength, target, targetMiddle,
+ _merge<T>(compare, list, middle, middle + firstLength, target, targetMiddle,
targetMiddle + secondLength, target, targetOffset);
}
@@ -261,7 +262,7 @@
var cursor1 = firstStart;
var cursor2 = secondStart;
var firstElement = firstList[cursor1++];
- var secondElement = secondList[cursor2++];
+ var secondElement = secondList[cursor2++]!;
while (true) {
if (compare(firstElement, secondElement) <= 0) {
target[targetOffset++] = firstElement;
@@ -270,7 +271,7 @@
} else {
target[targetOffset++] = secondElement;
if (cursor2 != secondEnd) {
- secondElement = secondList[cursor2++];
+ secondElement = secondList[cursor2++]!;
continue;
}
// Second list empties first. Flushing first list here.
diff --git a/lib/src/canonicalized_map.dart b/lib/src/canonicalized_map.dart
index 16e55e4..280050c 100644
--- a/lib/src/canonicalized_map.dart
+++ b/lib/src/canonicalized_map.dart
@@ -12,13 +12,10 @@
/// more efficient than a [LinkedHashMap] with a custom equality operator
/// because it only canonicalizes each key once, rather than doing so for each
/// comparison.
-///
-/// By default, `null` is allowed as a key. It can be forbidden via the
-/// `isValidKey` parameter.
class CanonicalizedMap<C, K, V> implements Map<K, V> {
final C Function(K) _canonicalize;
- final bool Function(Object) _isValidKeyFn;
+ final bool Function(K)? _isValidKeyFn;
final _base = <C, Pair<K, V>>{};
@@ -31,7 +28,7 @@
/// methods that take arbitrary objects. It can be used to filter out keys
/// that can't be canonicalized.
CanonicalizedMap(C Function(K key) canonicalize,
- {bool Function(Object key) isValidKey})
+ {bool Function(K key)? isValidKey})
: _canonicalize = canonicalize,
_isValidKeyFn = isValidKey;
@@ -45,14 +42,14 @@
/// methods that take arbitrary objects. It can be used to filter out keys
/// that can't be canonicalized.
CanonicalizedMap.from(Map<K, V> other, C Function(K key) canonicalize,
- {bool Function(Object key) isValidKey})
+ {bool Function(K key)? isValidKey})
: _canonicalize = canonicalize,
_isValidKeyFn = isValidKey {
addAll(other);
}
@override
- V operator [](Object key) {
+ V? operator [](Object? key) {
if (!_isValidKey(key)) return null;
var pair = _base[_canonicalize(key as K)];
return pair == null ? null : pair.last;
@@ -82,13 +79,13 @@
}
@override
- bool containsKey(Object key) {
+ bool containsKey(Object? key) {
if (!_isValidKey(key)) return false;
return _base.containsKey(_canonicalize(key as K));
}
@override
- bool containsValue(Object value) =>
+ bool containsValue(Object? value) =>
_base.values.any((pair) => pair.last == value);
@override
@@ -124,7 +121,7 @@
}
@override
- V remove(Object key) {
+ V? remove(Object? key) {
if (!_isValidKey(key)) return null;
var pair = _base.remove(_canonicalize(key as K));
return pair == null ? null : pair.last;
@@ -138,7 +135,7 @@
Map<K2, V2> retype<K2, V2>() => cast<K2, V2>();
@override
- V update(K key, V Function(V) update, {V Function() ifAbsent}) => _base
+ V update(K key, V Function(V) update, {V Function()? ifAbsent}) => _base
.update(_canonicalize(key), (pair) => Pair(key, update(pair.last)),
ifAbsent: ifAbsent == null ? null : () => Pair(key, ifAbsent()))
.last;
@@ -178,9 +175,8 @@
return result.toString();
}
- bool _isValidKey(Object key) =>
- (key == null || key is K) &&
- (_isValidKeyFn == null || _isValidKeyFn(key));
+ bool _isValidKey(Object? key) =>
+ (key is K) && (_isValidKeyFn == null || _isValidKeyFn!(key));
}
/// A collection used to identify cyclic maps during toString() calls.
diff --git a/lib/src/combined_wrappers/combined_iterable.dart b/lib/src/combined_wrappers/combined_iterable.dart
index ce19c20..8c5f091 100644
--- a/lib/src/combined_wrappers/combined_iterable.dart
+++ b/lib/src/combined_wrappers/combined_iterable.dart
@@ -26,7 +26,7 @@
// efficient implementation instead of running through the entire iterator.
@override
- bool contains(Object element) => _iterables.any((i) => i.contains(element));
+ bool contains(Object? element) => _iterables.any((i) => i.contains(element));
@override
bool get isEmpty => _iterables.every((i) => i.isEmpty);
@@ -45,17 +45,30 @@
/// avoid instantiating unnecessary iterators.
final Iterator<Iterator<T>> _iterators;
- _CombinedIterator(this._iterators);
+ /// The current iterator in [_iterators], or `null` if done iterating.
+ Iterator<T>? _currentItr;
+
+ _CombinedIterator(this._iterators) {
+ _advance();
+ }
@override
- T get current => _iterators.current?.current;
+ T get current => _iterators.current.current;
@override
bool moveNext() {
- var current = _iterators.current;
- if (current != null && current.moveNext()) {
+ if (_currentItr == null) return false;
+ if (_currentItr!.moveNext()) {
return true;
+ } else {
+ _advance();
}
- return _iterators.moveNext() && moveNext();
+ return moveNext();
+ }
+
+ /// Advances [_currentItr] or sets it to `null` if there are no more entries
+ /// in [_iterators].
+ void _advance() {
+ _currentItr = _iterators.moveNext() ? _iterators.current : null;
}
}
diff --git a/lib/src/combined_wrappers/combined_list.dart b/lib/src/combined_wrappers/combined_list.dart
index 961ea42..e341be4 100644
--- a/lib/src/combined_wrappers/combined_list.dart
+++ b/lib/src/combined_wrappers/combined_list.dart
@@ -15,7 +15,7 @@
/// both `O(lists)` rather than `O(1)`. A [CombinedListView] is unmodifiable.
class CombinedListView<T> extends ListBase<T>
implements UnmodifiableListView<T> {
- static void _throw() {
+ static Never _throw() {
throw UnsupportedError('Cannot modify an unmodifiable List');
}
@@ -57,9 +57,8 @@
}
@override
- bool remove(Object element) {
+ bool remove(Object? element) {
_throw();
- return null;
}
@override
diff --git a/lib/src/combined_wrappers/combined_map.dart b/lib/src/combined_wrappers/combined_map.dart
index 8e2f729..ae72006 100644
--- a/lib/src/combined_wrappers/combined_map.dart
+++ b/lib/src/combined_wrappers/combined_map.dart
@@ -29,7 +29,7 @@
CombinedMapView(this._maps);
@override
- V operator [](Object key) {
+ V? operator [](Object? key) {
for (var map in _maps) {
// Avoid two hash lookups on a positive hit.
var value = map[key];
@@ -75,7 +75,7 @@
// duplicates.
@override
- bool contains(Object element) => _iterable.contains(element);
+ bool contains(Object? element) => _iterable.contains(element);
@override
bool get isEmpty => _iterable.isEmpty;
diff --git a/lib/src/empty_unmodifiable_set.dart b/lib/src/empty_unmodifiable_set.dart
index 86cbbb4..6d7f03c 100644
--- a/lib/src/empty_unmodifiable_set.dart
+++ b/lib/src/empty_unmodifiable_set.dart
@@ -25,18 +25,18 @@
@override
EmptyUnmodifiableSet<T> cast<T>() => EmptyUnmodifiableSet<T>();
@override
- bool contains(Object element) => false;
+ bool contains(Object? element) => false;
@override
- bool containsAll(Iterable<Object> other) => other.isEmpty;
+ bool containsAll(Iterable<Object?> other) => other.isEmpty;
@override
Iterable<E> followedBy(Iterable<E> other) => Set.from(other);
@override
- E lookup(Object element) => null;
+ E? lookup(Object? element) => null;
@deprecated
@override
EmptyUnmodifiableSet<T> retype<T>() => EmptyUnmodifiableSet<T>();
@override
- E singleWhere(bool Function(E) test, {E Function() orElse}) =>
+ E singleWhere(bool Function(E) test, {E Function()? orElse}) =>
super.singleWhere(test);
@override
Iterable<T> whereType<T>() => EmptyUnmodifiableSet<T>();
@@ -45,9 +45,9 @@
@override
Set<E> union(Set<E> other) => Set.from(other);
@override
- Set<E> intersection(Set<Object> other) => {};
+ Set<E> intersection(Set<Object?> other) => {};
@override
- Set<E> difference(Set<Object> other) => {};
+ Set<E> difference(Set<Object?> other) => {};
@override
bool add(E value) => _throw();
@@ -56,13 +56,13 @@
@override
void clear() => _throw();
@override
- bool remove(Object element) => _throw();
+ bool remove(Object? element) => _throw();
@override
- void removeAll(Iterable<Object> elements) => _throw();
+ void removeAll(Iterable<Object?> elements) => _throw();
@override
void removeWhere(bool Function(E) test) => _throw();
@override
void retainWhere(bool Function(E) test) => _throw();
@override
- void retainAll(Iterable<Object> elements) => _throw();
+ void retainAll(Iterable<Object?> elements) => _throw();
}
diff --git a/lib/src/equality.dart b/lib/src/equality.dart
index b003a06..eba3841 100644
--- a/lib/src/equality.dart
+++ b/lib/src/equality.dart
@@ -27,7 +27,7 @@
///
/// Some implementations may be restricted to only work on specific types
/// of objects.
- bool isValidKey(Object o);
+ bool isValidKey(Object? o);
}
/// Equality of objects based on derived values.
@@ -52,7 +52,7 @@
final Equality<F> _inner;
EqualityBy(F Function(E) comparisonKey,
- [Equality<F> inner = const DefaultEquality()])
+ [Equality<F> inner = const DefaultEquality<Never>()])
: _comparisonKey = comparisonKey,
_inner = inner;
@@ -64,7 +64,7 @@
int hash(E e) => _inner.hash(_comparisonKey(e));
@override
- bool isValidKey(Object o) {
+ bool isValidKey(Object? o) {
if (o is E) {
final value = _comparisonKey(o);
return value is F && _inner.isValidKey(value);
@@ -84,11 +84,11 @@
class DefaultEquality<E> implements Equality<E> {
const DefaultEquality();
@override
- bool equals(Object e1, Object e2) => e1 == e2;
+ bool equals(Object? e1, Object? e2) => e1 == e2;
@override
- int hash(Object e) => e.hashCode;
+ int hash(Object? e) => e.hashCode;
@override
- bool isValidKey(Object o) => true;
+ bool isValidKey(Object? o) => true;
}
/// Equality of objects that compares only the identity of the objects.
@@ -99,7 +99,7 @@
@override
int hash(E e) => identityHashCode(e);
@override
- bool isValidKey(Object o) => true;
+ bool isValidKey(Object? o) => true;
}
/// Equality on iterables.
@@ -110,13 +110,13 @@
/// even if the [isValidKey] returns `false` for `null`.
/// The [hash] of `null` is `null.hashCode`.
class IterableEquality<E> implements Equality<Iterable<E>> {
- final Equality<E> _elementEquality;
+ final Equality<E?> _elementEquality;
const IterableEquality(
- [Equality<E> elementEquality = const DefaultEquality()])
+ [Equality<E> elementEquality = const DefaultEquality<Never>()])
: _elementEquality = elementEquality;
@override
- bool equals(Iterable<E> elements1, Iterable<E> elements2) {
+ bool equals(Iterable<E>? elements1, Iterable<E>? elements2) {
if (identical(elements1, elements2)) return true;
if (elements1 == null || elements2 == null) return false;
var it1 = elements1.iterator;
@@ -130,7 +130,7 @@
}
@override
- int hash(Iterable<E> elements) {
+ int hash(Iterable<E>? elements) {
if (elements == null) return null.hashCode;
// Jenkins's one-at-a-time hash function.
var hash = 0;
@@ -147,7 +147,7 @@
}
@override
- bool isValidKey(Object o) => o is Iterable<E>;
+ bool isValidKey(Object? o) => o is Iterable<E>;
}
/// Equality on lists.
@@ -163,11 +163,12 @@
/// The [hash] of `null` is `null.hashCode`.
class ListEquality<E> implements Equality<List<E>> {
final Equality<E> _elementEquality;
- const ListEquality([Equality<E> elementEquality = const DefaultEquality()])
+ const ListEquality(
+ [Equality<E> elementEquality = const DefaultEquality<Never>()])
: _elementEquality = elementEquality;
@override
- bool equals(List<E> list1, List<E> list2) {
+ bool equals(List<E>? list1, List<E>? list2) {
if (identical(list1, list2)) return true;
if (list1 == null || list2 == null) return false;
var length = list1.length;
@@ -179,7 +180,7 @@
}
@override
- int hash(List<E> list) {
+ int hash(List<E>? list) {
if (list == null) return null.hashCode;
// Jenkins's one-at-a-time hash function.
// This code is almost identical to the one in IterableEquality, except
@@ -198,10 +199,10 @@
}
@override
- bool isValidKey(Object o) => o is List<E>;
+ bool isValidKey(Object? o) => o is List<E>;
}
-abstract class _UnorderedEquality<E, T extends Iterable<E>>
+abstract class _UnorderedEquality<E, T extends Iterable<E>?>
implements Equality<T> {
final Equality<E> _elementEquality;
@@ -250,13 +251,13 @@
/// Two iterables are considered equal if they have the same number of elements,
/// and the elements of one set can be paired with the elements
/// of the other iterable, so that each pair are equal.
-class UnorderedIterableEquality<E> extends _UnorderedEquality<E, Iterable<E>> {
+class UnorderedIterableEquality<E> extends _UnorderedEquality<E, Iterable<E>?> {
const UnorderedIterableEquality(
- [Equality<E> elementEquality = const DefaultEquality()])
+ [Equality<E> elementEquality = const DefaultEquality<Never>()])
: super(elementEquality);
@override
- bool isValidKey(Object o) => o is Iterable<E>;
+ bool isValidKey(Object? o) => o is Iterable<E>;
}
/// Equality of sets.
@@ -271,12 +272,13 @@
/// The [equals] and [hash] methods accepts `null` values,
/// even if the [isValidKey] returns `false` for `null`.
/// The [hash] of `null` is `null.hashCode`.
-class SetEquality<E> extends _UnorderedEquality<E, Set<E>> {
- const SetEquality([Equality<E> elementEquality = const DefaultEquality()])
+class SetEquality<E> extends _UnorderedEquality<E, Set<E>?> {
+ const SetEquality(
+ [Equality<E> elementEquality = const DefaultEquality<Never>()])
: super(elementEquality);
@override
- bool isValidKey(Object o) => o is Set<E>;
+ bool isValidKey(Object? o) => o is Set<E>;
}
/// Internal class used by [MapEquality].
@@ -314,13 +316,13 @@
final Equality<K> _keyEquality;
final Equality<V> _valueEquality;
const MapEquality(
- {Equality<K> keys = const DefaultEquality(),
- Equality<V> values = const DefaultEquality()})
+ {Equality<K> keys = const DefaultEquality<Never>(),
+ Equality<V> values = const DefaultEquality<Never>()})
: _keyEquality = keys,
_valueEquality = values;
@override
- bool equals(Map<K, V> map1, Map<K, V> map2) {
+ bool equals(Map<K, V>? map1, Map<K, V>? map2) {
if (identical(map1, map2)) return true;
if (map1 == null || map2 == null) return false;
var length = map1.length;
@@ -341,12 +343,12 @@
}
@override
- int hash(Map<K, V> map) {
+ int hash(Map<K, V>? map) {
if (map == null) return null.hashCode;
var hash = 0;
for (var key in map.keys) {
var keyHash = _keyEquality.hash(key);
- var valueHash = _valueEquality.hash(map[key]);
+ var valueHash = _valueEquality.hash(map[key] as V);
hash = (hash + 3 * keyHash + 7 * valueHash) & _HASH_MASK;
}
hash = (hash + (hash << 3)) & _HASH_MASK;
@@ -356,7 +358,7 @@
}
@override
- bool isValidKey(Object o) => o is Map<K, V>;
+ bool isValidKey(Object? o) => o is Map<K, V>;
}
/// Combines several equalities into a single equality.
@@ -396,7 +398,7 @@
}
@override
- bool isValidKey(Object o) {
+ bool isValidKey(Object? o) {
for (var eq in _equalities) {
if (eq.isValidKey(o)) return true;
}
@@ -422,7 +424,7 @@
class DeepCollectionEquality implements Equality {
final Equality _base;
final bool _unordered;
- const DeepCollectionEquality([Equality base = const DefaultEquality()])
+ const DeepCollectionEquality([Equality base = const DefaultEquality<Never>()])
: _base = base,
_unordered = false;
@@ -430,7 +432,7 @@
/// iterables are not considered important. That is, lists and iterables are
/// treated as unordered iterables.
const DeepCollectionEquality.unordered(
- [Equality base = const DefaultEquality()])
+ [Equality base = const DefaultEquality<Never>()])
: _base = base,
_unordered = true;
@@ -457,7 +459,7 @@
}
@override
- int hash(Object o) {
+ int hash(Object? o) {
if (o is Set) return SetEquality(this).hash(o);
if (o is Map) return MapEquality(keys: this, values: this).hash(o);
if (!_unordered) {
@@ -470,7 +472,8 @@
}
@override
- bool isValidKey(Object o) => o is Iterable || o is Map || _base.isValidKey(o);
+ bool isValidKey(Object? o) =>
+ o is Iterable || o is Map || _base.isValidKey(o);
}
/// String equality that's insensitive to differences in ASCII case.
@@ -487,5 +490,5 @@
int hash(String string) => hashIgnoreAsciiCase(string);
@override
- bool isValidKey(Object object) => object is String;
+ bool isValidKey(Object? object) => object is String;
}
diff --git a/lib/src/functions.dart b/lib/src/functions.dart
index 5fbef30..8f401d4 100644
--- a/lib/src/functions.dart
+++ b/lib/src/functions.dart
@@ -13,13 +13,13 @@
/// [value] are used as the values for the new map.
@Deprecated('Use Map.map or a for loop in a Map literal.')
Map<K2, V2> mapMap<K1, V1, K2, V2>(Map<K1, V1> map,
- {K2 Function(K1, V1) key, V2 Function(K1, V1) value}) {
- key ??= (mapKey, _) => mapKey as K2;
- value ??= (_, mapValue) => mapValue as V2;
+ {K2 Function(K1, V1)? key, V2 Function(K1, V1)? value}) {
+ var keyFn = key ?? (mapKey, _) => mapKey as K2;
+ var valueFn = value ?? (_, mapValue) => mapValue as V2;
var result = <K2, V2>{};
map.forEach((mapKey, mapValue) {
- result[key(mapKey, mapValue)] = value(mapKey, mapValue);
+ result[keyFn(mapKey, mapValue)] = valueFn(mapKey, mapValue);
});
return result;
}
@@ -30,13 +30,13 @@
/// select the value that goes into the resulting map based on the two original
/// values. If [value] is omitted, the value from [map2] is used.
Map<K, V> mergeMaps<K, V>(Map<K, V> map1, Map<K, V> map2,
- {V Function(V, V) value}) {
+ {V Function(V, V)? value}) {
var result = Map<K, V>.from(map1);
if (value == null) return result..addAll(map2);
map2.forEach((key, mapValue) {
result[key] =
- result.containsKey(key) ? value(result[key], mapValue) : mapValue;
+ result.containsKey(key) ? value(result[key] as V, mapValue) : mapValue;
});
return result;
}
@@ -60,12 +60,14 @@
/// The values returned by [orderBy] are compared using the [compare] function.
/// If [compare] is omitted, values must implement [Comparable<T>] and they are
/// compared using their [Comparable.compareTo].
-S minBy<S, T>(Iterable<S> values, T Function(S) orderBy,
- {int Function(T, T) compare}) {
+///
+/// Returns `null` if [values] is empty.
+S? minBy<S, T>(Iterable<S> values, T Function(S) orderBy,
+ {int Function(T, T)? compare}) {
compare ??= defaultCompare<T>();
- S minValue;
- T minOrderBy;
+ S? minValue;
+ T? minOrderBy;
for (var element in values) {
var elementOrderBy = orderBy(element);
if (minOrderBy == null || compare(elementOrderBy, minOrderBy) < 0) {
@@ -82,15 +84,17 @@
/// The values returned by [orderBy] are compared using the [compare] function.
/// If [compare] is omitted, values must implement [Comparable<T>] and they are
/// compared using their [Comparable.compareTo].
-S maxBy<S, T>(Iterable<S> values, T Function(S) orderBy,
- {int Function(T, T) compare}) {
+///
+/// Returns `null` if [values] is empty.
+S? maxBy<S, T>(Iterable<S> values, T Function(S?) orderBy,
+ {int? Function(T, T)? compare}) {
compare ??= defaultCompare<T>();
- S maxValue;
- T maxOrderBy;
+ S? maxValue;
+ T? maxOrderBy;
for (var element in values) {
var elementOrderBy = orderBy(element);
- if (maxOrderBy == null || compare(elementOrderBy, maxOrderBy) > 0) {
+ if (maxOrderBy == null || compare(elementOrderBy, maxOrderBy)! > 0) {
maxValue = element;
maxOrderBy = elementOrderBy;
}
@@ -125,9 +129,9 @@
for (var vertex1 in keys) {
for (var vertex2 in keys) {
for (var vertex3 in keys) {
- if (result[vertex2].contains(vertex1) &&
- result[vertex1].contains(vertex3)) {
- result[vertex2].add(vertex3);
+ if (result[vertex2]!.contains(vertex1) &&
+ result[vertex1]!.contains(vertex3)) {
+ result[vertex2]!.add(vertex3);
}
}
}
@@ -153,7 +157,7 @@
//
// [Tarjan's algorithm]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
var index = 0;
- var stack = <T>[];
+ var stack = <T?>[];
var result = <Set<T>>[];
// The order of these doesn't matter, so we use un-linked implementations to
@@ -170,22 +174,22 @@
stack.add(vertex);
onStack.add(vertex);
- for (var successor in graph[vertex]) {
+ for (var successor in graph[vertex]!) {
if (!indices.containsKey(successor)) {
strongConnect(successor);
- lowLinks[vertex] = math.min(lowLinks[vertex], lowLinks[successor]);
+ lowLinks[vertex] = math.min(lowLinks[vertex]!, lowLinks[successor]!);
} else if (onStack.contains(successor)) {
- lowLinks[vertex] = math.min(lowLinks[vertex], lowLinks[successor]);
+ lowLinks[vertex] = math.min(lowLinks[vertex]!, lowLinks[successor]!);
}
}
if (lowLinks[vertex] == indices[vertex]) {
var component = <T>{};
- T neighbor;
+ T? neighbor;
do {
neighbor = stack.removeLast();
onStack.remove(neighbor);
- component.add(neighbor);
+ component.add(neighbor as T);
} while (neighbor != vertex);
result.add(component);
}
diff --git a/lib/src/iterable_zip.dart b/lib/src/iterable_zip.dart
index db38253..940b5e7 100644
--- a/lib/src/iterable_zip.dart
+++ b/lib/src/iterable_zip.dart
@@ -30,7 +30,7 @@
class _IteratorZip<T> implements Iterator<List<T>> {
final List<Iterator<T>> _iterators;
- List<T> _current;
+ List<T>? _current;
_IteratorZip(List<Iterator<T>> iterators) : _iterators = iterators;
@@ -43,13 +43,11 @@
return false;
}
}
- _current = List(_iterators.length);
- for (var i = 0; i < _iterators.length; i++) {
- _current[i] = _iterators[i].current;
- }
+ _current = List.generate(_iterators.length, (i) => _iterators[i].current,
+ growable: false);
return true;
}
@override
- List<T> get current => _current;
+ List<T> get current => _current!;
}
diff --git a/lib/src/priority_queue.dart b/lib/src/priority_queue.dart
index 31ff828..d4355b0 100644
--- a/lib/src/priority_queue.dart
+++ b/lib/src/priority_queue.dart
@@ -21,7 +21,8 @@
/// If [comparison] is omitted, it defaults to [Comparable.compare]. If this
/// is the case, `E` must implement [Comparable], and this is checked at
/// runtime for every comparison.
- factory PriorityQueue([int Function(E, E) comparison]) = HeapPriorityQueue<E>;
+ factory PriorityQueue([int Function(E, E)? comparison]) =
+ HeapPriorityQueue<E>;
/// Number of elements in the queue.
int get length;
@@ -128,7 +129,7 @@
final Comparator<E> comparison;
/// List implementation of a heap.
- List<E> _queue = List<E>(_INITIAL_CAPACITY);
+ List<E?> _queue = List<E?>.filled(_INITIAL_CAPACITY, null);
/// Number of elements in queue.
///
@@ -144,7 +145,7 @@
/// If [comparison] is omitted, it defaults to [Comparable.compare]. If this
/// is the case, `E` must implement [Comparable], and this is checked at
/// runtime for every comparison.
- HeapPriorityQueue([int Function(E, E) comparison])
+ HeapPriorityQueue([int Function(E, E)? comparison])
: comparison = comparison ?? defaultCompare<E>();
@override
@@ -173,7 +174,7 @@
@override
E get first {
if (_length == 0) throw StateError('No such element');
- return _queue[0];
+ return _queue[0]!;
}
@override
@@ -207,13 +208,13 @@
var length = _length;
_queue = const [];
_length = 0;
- return result.take(length);
+ return result.take(length).cast();
}
@override
E removeFirst() {
if (_length == 0) throw StateError('No such element');
- var result = _queue[0];
+ var result = _queue[0]!;
var last = _removeLast();
if (_length > 0) {
_bubbleDown(last, 0);
@@ -222,19 +223,14 @@
}
@override
- List<E> toList() {
- var list = <E>[]
- ..length = _length
- ..setRange(0, _length, _queue)
- ..sort(comparison);
- return list;
- }
+ List<E> toList() =>
+ List<E>.generate(_length, (i) => _queue[i]!)..sort(comparison);
@override
Set<E> toSet() {
- Set<E> set = SplayTreeSet<E>(comparison);
+ var set = SplayTreeSet<E>(comparison);
for (var i = 0; i < _length; i++) {
- set.add(_queue[i]);
+ set.add(_queue[i]!);
}
return set;
}
@@ -271,7 +267,7 @@
// in the heap will also have lower priority.
do {
var index = position - 1;
- var element = _queue[index];
+ var element = _queue[index]!;
var comp = comparison(element, object);
if (comp == 0) return index;
if (comp < 0) {
@@ -298,7 +294,7 @@
E _removeLast() {
var newLength = _length - 1;
- var last = _queue[newLength];
+ var last = _queue[newLength]!;
_queue[newLength] = null;
_length = newLength;
return last;
@@ -312,7 +308,7 @@
void _bubbleUp(E element, int index) {
while (index > 0) {
var parentIndex = (index - 1) ~/ 2;
- var parent = _queue[parentIndex];
+ var parent = _queue[parentIndex]!;
if (comparison(element, parent) > 0) break;
_queue[index] = parent;
index = parentIndex;
@@ -329,10 +325,10 @@
var rightChildIndex = index * 2 + 2;
while (rightChildIndex < _length) {
var leftChildIndex = rightChildIndex - 1;
- var leftChild = _queue[leftChildIndex];
- var rightChild = _queue[rightChildIndex];
+ var leftChild = _queue[leftChildIndex]!;
+ var rightChild = _queue[rightChildIndex]!;
var comp = comparison(leftChild, rightChild);
- var minChildIndex;
+ int minChildIndex;
E minChild;
if (comp < 0) {
minChild = leftChild;
@@ -352,7 +348,7 @@
}
var leftChildIndex = rightChildIndex - 1;
if (leftChildIndex < _length) {
- var child = _queue[leftChildIndex];
+ var child = _queue[leftChildIndex]!;
var comp = comparison(element, child);
if (comp > 0) {
_queue[index] = child;
@@ -368,7 +364,7 @@
void _grow() {
var newCapacity = _queue.length * 2 + 1;
if (newCapacity < _INITIAL_CAPACITY) newCapacity = _INITIAL_CAPACITY;
- var newQueue = List<E>(newCapacity);
+ var newQueue = List<E?>.filled(newCapacity, null);
newQueue.setRange(0, _length, _queue);
_queue = newQueue;
}
diff --git a/lib/src/queue_list.dart b/lib/src/queue_list.dart
index eb80cbe..2bda02b 100644
--- a/lib/src/queue_list.dart
+++ b/lib/src/queue_list.dart
@@ -26,7 +26,7 @@
}
static const int _INITIAL_CAPACITY = 8;
- List<E> _table;
+ late List<E?> _table;
int _head;
int _tail;
@@ -34,7 +34,7 @@
///
/// If [initialCapacity] is given, prepare the queue for at least that many
/// elements.
- QueueList([int initialCapacity])
+ QueueList([int? initialCapacity])
: _head = 0,
_tail = 0 {
if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) {
@@ -43,11 +43,11 @@
initialCapacity = _nextPowerOf2(initialCapacity);
}
assert(_isPowerOf2(initialCapacity));
- _table = List<E>(initialCapacity);
+ _table = List<E?>.filled(initialCapacity, null);
}
- // An internal constructor for use by _CastQueueList.
- QueueList._();
+ /// An internal constructor for use by [_CastQueueList].
+ QueueList._(this._head, this._tail, this._table);
/// Create a queue initially containing the elements of [source].
factory QueueList.from(Iterable<E> source) {
@@ -127,7 +127,7 @@
@override
E removeFirst() {
if (_head == _tail) throw StateError('No element');
- var result = _table[_head];
+ var result = _table[_head] as E;
_table[_head] = null;
_head = (_head + 1) & (_table.length - 1);
return result;
@@ -137,7 +137,7 @@
E removeLast() {
if (_head == _tail) throw StateError('No element');
_tail = (_tail - 1) & (_table.length - 1);
- var result = _table[_tail];
+ var result = _table[_tail]!;
_table[_tail] = null;
return result;
}
@@ -150,6 +150,15 @@
@override
set length(int value) {
if (value < 0) throw RangeError('Length $value may not be negative.');
+ if (value > length) {
+ try {
+ null as E;
+ } on TypeError {
+ throw UnsupportedError(
+ 'The length can only be increased when the element type is '
+ 'nullable, but the current element type is `$E`.');
+ }
+ }
var delta = value - length;
if (delta >= 0) {
@@ -177,7 +186,7 @@
throw RangeError('Index $index must be in the range [0..$length).');
}
- return _table[(_head + index) & (_table.length - 1)];
+ return _table[(_head + index) & (_table.length - 1)] as E;
}
@override
@@ -220,7 +229,7 @@
/// Grow the table when full.
void _grow() {
- var newTable = List<E>(_table.length * 2);
+ var newTable = List<E?>.filled(_table.length * 2, null);
var split = _table.length - _head;
newTable.setRange(0, split, _table, _head);
newTable.setRange(split, split + _head, _table, 0);
@@ -229,7 +238,7 @@
_table = newTable;
}
- int _writeToList(List<E> target) {
+ int _writeToList(List<E?> target) {
assert(target.length >= length);
if (_head <= _tail) {
var length = _tail - _head;
@@ -251,7 +260,7 @@
// expansion.
newElementCount += newElementCount >> 1;
var newCapacity = _nextPowerOf2(newElementCount);
- var newTable = List<E>(newCapacity);
+ var newTable = List<E?>.filled(newCapacity, null);
_tail = _writeToList(newTable);
_table = newTable;
_head = 0;
@@ -261,9 +270,9 @@
class _CastQueueList<S, T> extends QueueList<T> {
final QueueList<S> _delegate;
- _CastQueueList(this._delegate) : super._() {
- _table = _delegate._table.cast<T>();
- }
+ // Assigns invalid values for head/tail because it uses the delegate to hold
+ // the real values, but they are non-null fields.
+ _CastQueueList(this._delegate) : super._(-1, -1, _delegate._table.cast<T>());
@override
int get _head => _delegate._head;
diff --git a/lib/src/union_set.dart b/lib/src/union_set.dart
index 1b76645..208a2a5 100644
--- a/lib/src/union_set.dart
+++ b/lib/src/union_set.dart
@@ -62,15 +62,15 @@
}
@override
- bool contains(Object element) => _sets.any((set) => set.contains(element));
+ bool contains(Object? element) => _sets.any((set) => set.contains(element));
@override
- E lookup(Object element) {
+ E? lookup(Object? element) {
if (element == null) return null;
-
- return _sets
- .map((set) => set.lookup(element))
- .firstWhere((result) => result != null, orElse: () => null);
+ for (var set in _sets) {
+ var result = set.lookup(element);
+ if (result != null) return result;
+ }
}
@override
diff --git a/lib/src/union_set_controller.dart b/lib/src/union_set_controller.dart
index 6c04cef..ef9bb8d 100644
--- a/lib/src/union_set_controller.dart
+++ b/lib/src/union_set_controller.dart
@@ -23,8 +23,7 @@
/// ```
class UnionSetController<E> {
/// The [UnionSet] that provides a view of the union of sets in [this].
- UnionSet<E> get set => _set;
- UnionSet<E> _set;
+ late final UnionSet<E> set;
/// The sets whose union is exposed through [set].
final _sets = <Set<E>>{};
@@ -35,7 +34,7 @@
/// disjoint—that is, that they contain no elements in common. This makes
/// many operations including [length] more efficient.
UnionSetController({bool disjoint = false}) {
- _set = UnionSet<E>(_sets, disjoint: disjoint);
+ set = UnionSet<E>(_sets, disjoint: disjoint);
}
/// Adds the contents of [component] to [set].
diff --git a/lib/src/unmodifiable_wrappers.dart b/lib/src/unmodifiable_wrappers.dart
index 7a7898e..96551e8 100644
--- a/lib/src/unmodifiable_wrappers.dart
+++ b/lib/src/unmodifiable_wrappers.dart
@@ -58,7 +58,7 @@
/// Throws an [UnsupportedError];
/// operations that change the length of the list are disallowed.
@override
- bool remove(Object value) => _throw();
+ bool remove(Object? value) => _throw();
/// Throws an [UnsupportedError];
/// operations that change the length of the list are disallowed.
@@ -134,7 +134,7 @@
/// Throws an [UnsupportedError];
/// operations that change the set are disallowed.
@override
- bool remove(Object value) => _throw();
+ bool remove(Object? value) => _throw();
/// Throws an [UnsupportedError];
/// operations that change the set are disallowed.
@@ -187,7 +187,7 @@
/// Throws an [UnsupportedError];
/// operations that change the map are disallowed.
@override
- V remove(Object key) => _throw();
+ V remove(Object? key) => _throw();
/// Throws an [UnsupportedError];
/// operations that change the map are disallowed.
diff --git a/lib/src/wrappers.dart b/lib/src/wrappers.dart
index 7734073..14e2d8c 100644
--- a/lib/src/wrappers.dart
+++ b/lib/src/wrappers.dart
@@ -23,7 +23,7 @@
Iterable<T> cast<T>() => _base.cast<T>();
@override
- bool contains(Object element) => _base.contains(element);
+ bool contains(Object? element) => _base.contains(element);
@override
E elementAt(int index) => _base.elementAt(index);
@@ -38,7 +38,7 @@
E get first => _base.first;
@override
- E firstWhere(bool Function(E) test, {E Function() orElse}) =>
+ E firstWhere(bool Function(E) test, {E Function()? orElse}) =>
_base.firstWhere(test, orElse: orElse);
@override
@@ -67,7 +67,7 @@
E get last => _base.last;
@override
- E lastWhere(bool Function(E) test, {E Function() orElse}) =>
+ E lastWhere(bool Function(E) test, {E Function()? orElse}) =>
_base.lastWhere(test, orElse: orElse);
@override
@@ -86,7 +86,7 @@
E get single => _base.single;
@override
- E singleWhere(bool Function(E) test, {E Function() orElse}) {
+ E singleWhere(bool Function(E) test, {E Function()? orElse}) {
return _base.singleWhere(test, orElse: orElse);
}
@@ -165,7 +165,7 @@
@Deprecated('Use list.cast<E> instead.')
static List<E> typed<E>(List base) => base.cast<E>();
- List<E> get _listBase => _base;
+ List<E> get _listBase => _base as List<E>;
@override
E operator [](int index) => _listBase[index];
@@ -200,7 +200,7 @@
}
@override
- void fillRange(int start, int end, [E fillValue]) {
+ void fillRange(int start, int end, [E? fillValue]) {
_listBase.fillRange(start, end, fillValue);
}
@@ -237,11 +237,11 @@
}
@override
- int lastIndexOf(E element, [int start]) =>
+ int lastIndexOf(E element, [int? start]) =>
_listBase.lastIndexOf(element, start);
@override
- int lastIndexWhere(bool Function(E) test, [int start]) =>
+ int lastIndexWhere(bool Function(E) test, [int? start]) =>
_listBase.lastIndexWhere(test, start);
@override
@@ -250,7 +250,7 @@
}
@override
- bool remove(Object value) => _listBase.remove(value);
+ bool remove(Object? value) => _listBase.remove(value);
@override
E removeAt(int index) => _listBase.removeAt(index);
@@ -296,17 +296,17 @@
}
@override
- void shuffle([math.Random random]) {
+ void shuffle([math.Random? random]) {
_listBase.shuffle(random);
}
@override
- void sort([int Function(E, E) compare]) {
+ void sort([int Function(E, E)? compare]) {
_listBase.sort(compare);
}
@override
- List<E> sublist(int start, [int end]) => _listBase.sublist(start, end);
+ List<E> sublist(int start, [int? end]) => _listBase.sublist(start, end);
}
/// A [Set] that delegates all operations to a base set.
@@ -330,7 +330,7 @@
@Deprecated('Use set.cast<E> instead.')
static Set<E> typed<E>(Set base) => base.cast<E>();
- Set<E> get _setBase => _base;
+ Set<E> get _setBase => _base as Set<E>;
@override
bool add(E value) => _setBase.add(value);
@@ -349,22 +349,22 @@
}
@override
- bool containsAll(Iterable<Object> other) => _setBase.containsAll(other);
+ bool containsAll(Iterable<Object?> other) => _setBase.containsAll(other);
@override
- Set<E> difference(Set<Object> other) => _setBase.difference(other);
+ Set<E> difference(Set<Object?> other) => _setBase.difference(other);
@override
- Set<E> intersection(Set<Object> other) => _setBase.intersection(other);
+ Set<E> intersection(Set<Object?> other) => _setBase.intersection(other);
@override
- E lookup(Object element) => _setBase.lookup(element);
+ E? lookup(Object? element) => _setBase.lookup(element);
@override
- bool remove(Object value) => _setBase.remove(value);
+ bool remove(Object? value) => _setBase.remove(value);
@override
- void removeAll(Iterable<Object> elements) {
+ void removeAll(Iterable<Object?> elements) {
_setBase.removeAll(elements);
}
@@ -374,7 +374,7 @@
}
@override
- void retainAll(Iterable<Object> elements) {
+ void retainAll(Iterable<Object?> elements) {
_setBase.retainAll(elements);
}
@@ -416,7 +416,7 @@
@Deprecated('Use queue.cast<E> instead.')
static Queue<E> typed<E>(Queue base) => base.cast<E>();
- Queue<E> get _baseQueue => _base;
+ Queue<E> get _baseQueue => _base as Queue<E>;
@override
void add(E value) {
@@ -447,7 +447,7 @@
}
@override
- bool remove(Object object) => _baseQueue.remove(object);
+ bool remove(Object? object) => _baseQueue.remove(object);
@override
void removeWhere(bool Function(E) test) {
@@ -495,7 +495,7 @@
static Map<K, V> typed<K, V>(Map base) => base.cast<K, V>();
@override
- V operator [](Object key) => _base[key];
+ V? operator [](Object? key) => _base[key];
@override
void operator []=(K key, V value) {
@@ -521,10 +521,10 @@
Map<K2, V2> cast<K2, V2>() => _base.cast<K2, V2>();
@override
- bool containsKey(Object key) => _base.containsKey(key);
+ bool containsKey(Object? key) => _base.containsKey(key);
@override
- bool containsValue(Object value) => _base.containsValue(value);
+ bool containsValue(Object? value) => _base.containsValue(value);
@override
Iterable<MapEntry<K, V>> get entries => _base.entries;
@@ -555,7 +555,7 @@
_base.putIfAbsent(key, ifAbsent);
@override
- V remove(Object key) => _base.remove(key);
+ V? remove(Object? key) => _base.remove(key);
@override
void removeWhere(bool Function(K, V) test) => _base.removeWhere(test);
@@ -570,7 +570,7 @@
String toString() => _base.toString();
@override
- V update(K key, V Function(V) update, {V Function() ifAbsent}) =>
+ V update(K key, V Function(V) update, {V Function()? ifAbsent}) =>
_base.update(key, update, ifAbsent: ifAbsent);
@override
@@ -590,7 +590,7 @@
with UnmodifiableSetMixin<E> {
final Map<E, dynamic> _baseMap;
- MapKeySet(Map<E, dynamic> base) : _baseMap = base;
+ MapKeySet(this._baseMap);
@override
Iterable<E> get _base => _baseMap.keys;
@@ -604,7 +604,7 @@
}
@override
- bool contains(Object element) => _baseMap.containsKey(element);
+ bool contains(Object? element) => _baseMap.containsKey(element);
@override
bool get isEmpty => _baseMap.isEmpty;
@@ -619,7 +619,7 @@
String toString() => "{${_base.join(', ')}}";
@override
- bool containsAll(Iterable<Object> other) => other.every(contains);
+ bool containsAll(Iterable<Object?> other) => other.every(contains);
/// Returns a new set with the the elements of [this] that are not in [other].
///
@@ -629,7 +629,7 @@
/// Note that the returned set will use the default equality operation, which
/// may be different than the equality operation [this] uses.
@override
- Set<E> difference(Set<Object> other) =>
+ Set<E> difference(Set<Object?> other) =>
where((element) => !other.contains(element)).toSet();
/// Returns a new set which is the intersection between [this] and [other].
@@ -640,12 +640,12 @@
/// Note that the returned set will use the default equality operation, which
/// may be different than the equality operation [this] uses.
@override
- Set<E> intersection(Set<Object> other) => where(other.contains).toSet();
+ Set<E> intersection(Set<Object?> other) => where(other.contains).toSet();
/// Throws an [UnsupportedError] since there's no corresponding method for
/// [Map]s.
@override
- E lookup(Object element) =>
+ E lookup(Object? element) =>
throw UnsupportedError("MapKeySet doesn't support lookup().");
@deprecated
@@ -688,14 +688,12 @@
final Map<K, V> _baseMap;
final K Function(V) _keyForValue;
- /// Creates a new [MapValueSet] based on [base].
+ /// Creates a new [MapValueSet] based on [_baseMap].
///
- /// [keyForValue] returns the key in the map that should be associated with
+ /// [_keyForValue] returns the key in the map that should be associated with
/// the given value. The set's notion of equality is identical to the equality
- /// of the return values of [keyForValue].
- MapValueSet(Map<K, V> base, K Function(V) keyForValue)
- : _baseMap = base,
- _keyForValue = keyForValue;
+ /// of the return values of [_keyForValue].
+ MapValueSet(this._baseMap, this._keyForValue);
@override
Iterable<V> get _base => _baseMap.values;
@@ -709,9 +707,9 @@
}
@override
- bool contains(Object element) {
- if (element != null && element is! V) return false;
- var key = _keyForValue(element as V);
+ bool contains(Object? element) {
+ if (element is! V) return false;
+ var key = _keyForValue(element);
return _baseMap.containsKey(key);
}
@@ -746,7 +744,7 @@
void clear() => _baseMap.clear();
@override
- bool containsAll(Iterable<Object> other) => other.every(contains);
+ bool containsAll(Iterable<Object?> other) => other.every(contains);
/// Returns a new set with the the elements of [this] that are not in [other].
///
@@ -756,7 +754,7 @@
/// Note that the returned set will use the default equality operation, which
/// may be different than the equality operation [this] uses.
@override
- Set<V> difference(Set<Object> other) =>
+ Set<V> difference(Set<Object?> other) =>
where((element) => !other.contains(element)).toSet();
/// Returns a new set which is the intersection between [this] and [other].
@@ -767,20 +765,20 @@
/// Note that the returned set will use the default equality operation, which
/// may be different than the equality operation [this] uses.
@override
- Set<V> intersection(Set<Object> other) => where(other.contains).toSet();
+ Set<V> intersection(Set<Object?> other) => where(other.contains).toSet();
@override
- V lookup(Object element) {
- if (element != null && element is! V) return null;
- var key = _keyForValue(element as V);
+ V? lookup(Object? element) {
+ if (element is! V) return null;
+ var key = _keyForValue(element);
return _baseMap[key];
}
@override
- bool remove(Object element) {
- if (element != null && element is! V) return false;
- var key = _keyForValue(element as V);
+ bool remove(Object? element) {
+ if (element is! V) return false;
+ var key = _keyForValue(element);
if (!_baseMap.containsKey(key)) return false;
_baseMap.remove(key);
@@ -788,7 +786,7 @@
}
@override
- void removeAll(Iterable<Object> elements) => elements.forEach(remove);
+ void removeAll(Iterable<Object?> elements) => elements.forEach(remove);
@override
void removeWhere(bool Function(V) test) {
@@ -800,14 +798,14 @@
}
@override
- void retainAll(Iterable<Object> elements) {
+ void retainAll(Iterable<Object?> elements) {
var valuesToRetain = Set<V>.identity();
for (var element in elements) {
- if (element != null && element is! V) continue;
- var key = _keyForValue(element as V);
+ if (element is! V) continue;
+ var key = _keyForValue(element);
if (!_baseMap.containsKey(key)) continue;
- valuesToRetain.add(_baseMap[key]);
+ valuesToRetain.add(_baseMap[key]!);
}
var keysToRemove = [];
diff --git a/pubspec.yaml b/pubspec.yaml
index 8949dd9..638740b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,12 +1,94 @@
name: collection
-version: 1.14.13
+version: 1.15.0-nnbd
description: Collections and utilities functions and classes related to collections.
homepage: https://www.github.com/dart-lang/collection
environment:
- sdk: '>=2.3.0 <3.0.0'
+ sdk: '>=2.9.0-18.0 <2.9.0'
dev_dependencies:
pedantic: ^1.0.0
test: ^1.0.0
+
+dependency_overrides:
+ async:
+ git:
+ url: git://github.com/dart-lang/async.git
+ ref: null_safety
+ boolean_selector:
+ git:
+ url: git://github.com/dart-lang/boolean_selector.git
+ ref: null_safety
+ charcode:
+ git:
+ url: git://github.com/dart-lang/charcode.git
+ ref: null_safety
+ js:
+ git:
+ url: git://github.com/dart-lang/sdk.git
+ path: pkg/js
+ matcher:
+ git:
+ url: git://github.com/dart-lang/matcher.git
+ ref: null_safety
+ meta:
+ git:
+ url: git://github.com/dart-lang/sdk.git
+ ref: null_safety-pkgs
+ path: pkg/meta
+ path:
+ git:
+ url: git://github.com/dart-lang/path.git
+ ref: null_safety
+ pedantic:
+ git:
+ url: git://github.com/dart-lang/pedantic.git
+ ref: null_safety
+ pool:
+ git:
+ url: git://github.com/dart-lang/pool.git
+ ref: null_safety
+ source_maps:
+ git:
+ url: git://github.com/dart-lang/source_maps.git
+ ref: null_safety
+ source_map_stack_trace:
+ git:
+ url: git://github.com/dart-lang/source_map_stack_trace.git
+ ref: null_safety
+ source_span:
+ git:
+ url: git://github.com/dart-lang/source_span.git
+ ref: null_safety
+ stack_trace:
+ git:
+ url: git://github.com/dart-lang/stack_trace.git
+ ref: null_safety
+ stream_channel:
+ git:
+ url: git://github.com/dart-lang/stream_channel.git
+ ref: null_safety
+ string_scanner:
+ git:
+ url: git://github.com/dart-lang/string_scanner.git
+ ref: null_safety
+ term_glyph:
+ git:
+ url: git://github.com/dart-lang/term_glyph.git
+ ref: null_safety
+ test_api:
+ git:
+ url: git://github.com/dart-lang/test.git
+ ref: null_safety
+ path: pkgs/test_api
+ test_core:
+ git:
+ url: git://github.com/dart-lang/test.git
+ ref: null_safety
+ path: pkgs/test_core
+ test:
+ git:
+ url: git://github.com/dart-lang/test.git
+ ref: null_safety
+ path: pkgs/test
diff --git a/test/algorithms_test.dart b/test/algorithms_test.dart
index 0d0d414..7ab096f 100644
--- a/test/algorithms_test.dart
+++ b/test/algorithms_test.dart
@@ -157,10 +157,10 @@
test('insertionSortRandom', () {
var random = Random();
for (var i = 0; i < 25; i++) {
- var list = List(i);
- for (var j = 0; j < i; j++) {
- list[j] = random.nextInt(25); // Expect some equal elements.
- }
+ var list = [
+ for (var j = 0; j < i; j++)
+ random.nextInt(25) // Expect some equal elements.
+ ];
insertionSort(list);
for (var j = 1; j < i; j++) {
expect(list[j - 1], lessThanOrEqualTo(list[j]));
@@ -195,10 +195,10 @@
test('MergeSortRandom', () {
var random = Random();
for (var i = 0; i < 250; i += 1) {
- var list = List(i);
- for (var j = 0; j < i; j++) {
- list[j] = random.nextInt(i); // Expect some equal elements.
- }
+ var list = [
+ for (var j = 0; j < i; j++)
+ random.nextInt(i) // Expect some equal elements.
+ ];
mergeSort(list);
for (var j = 1; j < i; j++) {
expect(list[j - 1], lessThanOrEqualTo(list[j]));
@@ -212,14 +212,13 @@
// larger case where the internal moving insertion sort is used
// larger cases with multiple splittings, numbers just around a power of 2.
for (var size in [8, 50, 511, 512, 513]) {
- var list = List<OC>(size);
// Class OC compares using id.
// With size elements with id's in the range 0..size/4, a number of
// collisions are guaranteed. These should be sorted so that the 'order'
// part of the objects are still in order.
- for (var i = 0; i < size; i++) {
- list[i] = OC(random.nextInt(size >> 2), i);
- }
+ var list = [
+ for (var i = 0; i < size; i++) OC(random.nextInt(size >> 2), i)
+ ];
mergeSort(list);
var prev = list[0];
for (var i = 1; i < size; i++) {
@@ -255,10 +254,7 @@
test('MergeSortSpecialCases', () {
for (var size in [511, 512, 513]) {
// All equal.
- var list = List(size);
- for (var i = 0; i < size; i++) {
- list[i] = OC(0, i);
- }
+ var list = [for (var i = 0; i < size; i++) OC(0, i)];
mergeSort(list);
for (var i = 0; i < size; i++) {
expect(list[i].order, equals(i));
diff --git a/test/canonicalized_map_test.dart b/test/canonicalized_map_test.dart
index 2d42b09..e5bd34e 100644
--- a/test/canonicalized_map_test.dart
+++ b/test/canonicalized_map_test.dart
@@ -7,11 +7,10 @@
void main() {
group('with an empty canonicalized map', () {
- CanonicalizedMap<int, String, String> map;
+ late CanonicalizedMap<int, String, String> map;
setUp(() {
- map = CanonicalizedMap(int.parse,
- isValidKey: (s) => RegExp(r'^\d+$').hasMatch(s as String));
+ map = CanonicalizedMap(int.parse, isValidKey: RegExp(r'^\d+$').hasMatch);
});
test('canonicalizes keys on set and get', () {
@@ -164,7 +163,7 @@
var map;
setUp(() {
map = CanonicalizedMap<int, String, dynamic>(int.parse,
- isValidKey: (s) => RegExp(r'^\d+$').hasMatch(s as String));
+ isValidKey: RegExp(r'^\d+$').hasMatch);
});
test('for an empty map', () {
diff --git a/test/comparators_test.dart b/test/comparators_test.dart
index b8dcb3e..ab48711 100644
--- a/test/comparators_test.dart
+++ b/test/comparators_test.dart
@@ -57,7 +57,7 @@
'~'
];
- List<String> sortedBy(int Function(String, String) compare) =>
+ List<String> sortedBy(int Function(String, String)? compare) =>
strings.toList()
..shuffle()
..sort(compare);
@@ -65,6 +65,7 @@
test('String.compareTo', () {
expect(sortedBy(null), strings);
});
+
test('compareAsciiLowerCase', () {
expect(sortedBy(compareAsciiLowerCase), sortedBy((a, b) {
var delta = a.toLowerCase().compareTo(b.toLowerCase());
@@ -73,6 +74,7 @@
return a.compareTo(b);
}));
});
+
test('compareAsciiUpperCase', () {
expect(sortedBy(compareAsciiUpperCase), sortedBy((a, b) {
var delta = a.toUpperCase().compareTo(b.toUpperCase());
@@ -88,7 +90,7 @@
// compared to non-digits.
String replaceNumbers(String string) =>
string.replaceAllMapped(RegExp(r'\d+'), (m) {
- var digits = m[0];
+ var digits = m[0]!;
return String.fromCharCodes([0x30, int.parse(digits), digits.length]);
});
diff --git a/test/functions_test.dart b/test/functions_test.dart
index a659c94..e37b978 100644
--- a/test/functions_test.dart
+++ b/test/functions_test.dart
@@ -29,14 +29,18 @@
});
test("maps the map's keys", () {
- // ignore: deprecated_member_use_from_same_package
- expect(mapMap({'foo': 1, 'bar': 2}, key: (key, value) => key[value]),
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ mapMap({'foo': 1, 'bar': 2},
+ key: (dynamic key, dynamic value) => key[value]),
equals({'o': 1, 'r': 2}));
});
test("maps the map's values", () {
- // ignore: deprecated_member_use_from_same_package
- expect(mapMap({'foo': 1, 'bar': 2}, value: (key, value) => key[value]),
+ expect(
+ // ignore: deprecated_member_use_from_same_package
+ mapMap({'foo': 1, 'bar': 2},
+ value: (dynamic key, dynamic value) => key[value]),
equals({'foo': 'o', 'bar': 'r'}));
});
@@ -44,15 +48,17 @@
expect(
// ignore: deprecated_member_use_from_same_package
mapMap({'foo': 1, 'bar': 2},
- key: (key, value) => '$key$value',
- value: (key, value) => key[value]),
+ key: (dynamic key, dynamic value) => '$key$value',
+ value: (dynamic key, dynamic value) => key[value]),
equals({'foo1': 'o', 'bar2': 'r'}));
});
});
group('mergeMaps()', () {
test('with empty maps returns an empty map', () {
- expect(mergeMaps({}, {}, value: expectAsync2((_, __) {}, count: 0)),
+ expect(
+ mergeMaps({}, {},
+ value: expectAsync2((dynamic _, dynamic __) {}, count: 0)),
isEmpty);
});
@@ -69,19 +75,20 @@
test('uses the callback to merge values', () {
expect(
mergeMaps({'foo': 1, 'bar': 2}, {'bar': 3, 'baz': 4},
- value: (value1, value2) => value1 + value2),
+ value: (dynamic value1, dynamic value2) => value1 + value2),
equals({'foo': 1, 'bar': 5, 'baz': 4}));
});
});
group('groupBy()', () {
test('returns an empty map for an empty iterable', () {
- expect(groupBy([], expectAsync1((_) {}, count: 0)), isEmpty);
+ expect(groupBy([], expectAsync1((dynamic _) {}, count: 0)), isEmpty);
});
test("groups elements by the function's return value", () {
expect(
- groupBy(['foo', 'bar', 'baz', 'bop', 'qux'], (string) => string[1]),
+ groupBy(['foo', 'bar', 'baz', 'bop', 'qux'],
+ (dynamic string) => string[1]),
equals({
'o': ['foo', 'bop'],
'a': ['bar', 'baz'],
@@ -93,8 +100,8 @@
group('minBy()', () {
test('returns null for an empty iterable', () {
expect(
- minBy([], expectAsync1((_) {}, count: 0),
- compare: expectAsync2((_, __) => null, count: 0)),
+ minBy([], expectAsync1((dynamic _) {}, count: 0),
+ compare: expectAsync2((dynamic _, dynamic __) => -1, count: 0)),
isNull);
});
@@ -108,7 +115,7 @@
{'foo': 4},
{'foo': 1},
{'foo': 2}
- ], (map) => map['foo']),
+ ], (dynamic map) => map['foo']),
equals({'foo': 1}));
});
@@ -121,7 +128,7 @@
{'foo': 1},
{'foo': 2}
], (map) => map,
- compare: (map1, map2) => map1['foo'].compareTo(map2['foo'])),
+ compare: (map1, map2) => map1['foo']!.compareTo(map2['foo']!)),
equals({'foo': 1}));
});
});
@@ -129,8 +136,8 @@
group('maxBy()', () {
test('returns null for an empty iterable', () {
expect(
- maxBy([], expectAsync1((_) {}, count: 0),
- compare: expectAsync2((_, __) => null, count: 0)),
+ maxBy([], expectAsync1((dynamic _) {}, count: 0),
+ compare: expectAsync2((dynamic _, dynamic __) => null, count: 0)),
isNull);
});
@@ -144,7 +151,7 @@
{'foo': 4},
{'foo': 1},
{'foo': 2}
- ], (map) => map['foo']),
+ ], (dynamic map) => map['foo']),
equals({'foo': 5}));
});
@@ -156,8 +163,8 @@
{'foo': 4},
{'foo': 1},
{'foo': 2}
- ], (map) => map,
- compare: (map1, map2) => map1['foo'].compareTo(map2['foo'])),
+ ], (map) => map!,
+ compare: (map1, map2) => map1['foo']!.compareTo(map2['foo']!)),
equals({'foo': 5}));
});
});
diff --git a/test/priority_queue_test.dart b/test/priority_queue_test.dart
index 928de6c..b38b3aa 100644
--- a/test/priority_queue_test.dart
+++ b/test/priority_queue_test.dart
@@ -29,7 +29,7 @@
}
void testCustom(
- PriorityQueue<C> Function(int Function(C, C) comparator) create) {
+ PriorityQueue<C> Function(int Function(C, C)? comparator) create) {
for (var count in [1, 5, 127, 128]) {
testQueue('Custom:$count/null', () => create(null),
List<C>.generate(count, (x) => C(x)), C(count));
@@ -48,7 +48,8 @@
test(name, () => testQueueBody(create, elements, notElement));
}
-void testQueueBody(PriorityQueue Function() create, List elements, notElement) {
+void testQueueBody<T>(
+ PriorityQueue<T> Function() create, List<T> elements, notElement) {
var q = create();
expect(q.isEmpty, isTrue);
expect(q, hasLength(0));
diff --git a/test/queue_list_test.dart b/test/queue_list_test.dart
index 4814550..21b6056 100644
--- a/test/queue_list_test.dart
+++ b/test/queue_list_test.dart
@@ -134,7 +134,7 @@
});
test('grows a smaller queue', () {
- var queue = QueueList.from([1, 2, 3]);
+ var queue = QueueList<int?>.from([1, 2, 3]);
queue.length = 5;
expect(queue, equals([1, 2, 3, null, null]));
});
@@ -142,6 +142,10 @@
test('throws a RangeError if length is less than 0', () {
expect(() => QueueList().length = -1, throwsRangeError);
});
+
+ test('throws an UnsupportedError if element type is non-nullable', () {
+ expect(() => QueueList<int>().length = 1, throwsUnsupportedError);
+ });
});
group('[]', () {
diff --git a/test/union_set_controller_test.dart b/test/union_set_controller_test.dart
index 8f5ad83..3604d62 100644
--- a/test/union_set_controller_test.dart
+++ b/test/union_set_controller_test.dart
@@ -7,8 +7,8 @@
import 'package:collection/collection.dart';
void main() {
- UnionSetController<int> controller;
- Set<int> innerSet;
+ late UnionSetController<int> controller;
+ late Set<int> innerSet;
setUp(() {
innerSet = {1, 2, 3};
controller = UnionSetController()..add(innerSet);
diff --git a/test/union_set_test.dart b/test/union_set_test.dart
index 795cf2b..e5da546 100644
--- a/test/union_set_test.dart
+++ b/test/union_set_test.dart
@@ -35,7 +35,7 @@
});
test("map() doesn't run on any elements", () {
- expect(set.map(expectAsync1((_) {}, count: 0)), isEmpty);
+ expect(set.map(expectAsync1((dynamic _) {}, count: 0)), isEmpty);
});
});
diff --git a/test/unmodifiable_collection_test.dart b/test/unmodifiable_collection_test.dart
index a7abd89..ea93e31 100644
--- a/test/unmodifiable_collection_test.dart
+++ b/test/unmodifiable_collection_test.dart
@@ -117,8 +117,8 @@
});
test('$name - fold', () {
- expect(wrapped.fold(0, (x, y) => x + y),
- equals(original.fold(0, (x, y) => x + y)));
+ expect(wrapped.fold(0, (dynamic x, y) => x + y),
+ equals(original.fold(0, (dynamic x, y) => x + y)));
});
test('$name - forEach', () {
diff --git a/test/wrapper_test.dart b/test/wrapper_test.dart
index 43ff4c2..2612867 100644
--- a/test/wrapper_test.dart
+++ b/test/wrapper_test.dart
@@ -4,7 +4,9 @@
/// Tests wrapper utilities.
+@TestOn('vm')
import 'dart:collection';
+import 'dart:mirrors';
import 'package:collection/collection.dart';
import 'package:test/test.dart';
@@ -35,10 +37,12 @@
// the *same* invocation on the wrapped object.
dynamic equals;
+ InstanceMirror get mirror;
+
@override
- dynamic noSuchMethod(Invocation i) {
- equals = wrappedChecker(i);
- return null;
+ dynamic noSuchMethod(Invocation actual) {
+ equals = wrappedChecker(actual);
+ return mirror.delegate(actual);
}
@override
@@ -54,11 +58,14 @@
// member invocation.
class InvocationChecker {
final Invocation _expected;
- InvocationChecker(this._expected);
+ final InstanceMirror _instanceMirror;
+
+ InvocationChecker(this._expected, this._instanceMirror);
+
@override
dynamic noSuchMethod(Invocation actual) {
testInvocations(_expected, actual);
- return null;
+ return _instanceMirror.delegate(actual);
}
@override
@@ -77,122 +84,147 @@
// argument to DelegatingIterable/Set/List/Queue.
class IterableInvocationChecker<T> extends InvocationChecker
implements Iterable<T> {
- IterableInvocationChecker(Invocation expected) : super(expected);
+ IterableInvocationChecker(Invocation expected, InstanceMirror mirror)
+ : super(expected, mirror);
}
class ListInvocationChecker<T> extends InvocationChecker implements List<T> {
- ListInvocationChecker(Invocation expected) : super(expected);
+ ListInvocationChecker(Invocation expected, InstanceMirror mirror)
+ : super(expected, mirror);
}
class SetInvocationChecker<T> extends InvocationChecker implements Set<T> {
- SetInvocationChecker(Invocation expected) : super(expected);
+ SetInvocationChecker(Invocation expected, InstanceMirror mirror)
+ : super(expected, mirror);
}
class QueueInvocationChecker<T> extends InvocationChecker implements Queue<T> {
- QueueInvocationChecker(Invocation expected) : super(expected);
+ QueueInvocationChecker(Invocation expected, InstanceMirror mirror)
+ : super(expected, mirror);
}
class MapInvocationChecker<K, V> extends InvocationChecker
implements Map<K, V> {
- MapInvocationChecker(Invocation expected) : super(expected);
+ MapInvocationChecker(Invocation expected, InstanceMirror mirror)
+ : super(expected, mirror);
}
// Expector that wraps in DelegatingIterable.
class IterableExpector<T> extends Expector implements Iterable<T> {
@override
+ final InstanceMirror mirror;
+
+ IterableExpector(Iterable<T> realInstance) : mirror = reflect(realInstance);
+
+ @override
dynamic wrappedChecker(Invocation i) =>
- DelegatingIterable<T>(IterableInvocationChecker<T>(i));
+ DelegatingIterable<T>(IterableInvocationChecker<T>(i, mirror));
}
// Expector that wraps in DelegatingList.
-class ListExpector<T> extends Expector implements List<T> {
+class ListExpector<T> extends IterableExpector<T> implements List<T> {
+ ListExpector(List<T> realInstance) : super(realInstance);
+
@override
dynamic wrappedChecker(Invocation i) =>
- DelegatingList<T>(ListInvocationChecker<T>(i));
+ DelegatingList<T>(ListInvocationChecker<T>(i, mirror));
}
// Expector that wraps in DelegatingSet.
-class SetExpector<T> extends Expector implements Set<T> {
+class SetExpector<T> extends IterableExpector<T> implements Set<T> {
+ SetExpector(Set<T> realInstance) : super(realInstance);
+
@override
dynamic wrappedChecker(Invocation i) =>
- DelegatingSet<T>(SetInvocationChecker<T>(i));
+ DelegatingSet<T>(SetInvocationChecker<T>(i, mirror));
}
// Expector that wraps in DelegatingSet.
-class QueueExpector<T> extends Expector implements Queue<T> {
+class QueueExpector<T> extends IterableExpector<T> implements Queue<T> {
+ QueueExpector(Queue<T> realInstance) : super(realInstance);
+
@override
dynamic wrappedChecker(Invocation i) =>
- DelegatingQueue<T>(QueueInvocationChecker<T>(i));
+ DelegatingQueue<T>(QueueInvocationChecker<T>(i, mirror));
}
// Expector that wraps in DelegatingMap.
class MapExpector<K, V> extends Expector implements Map<K, V> {
@override
+ final InstanceMirror mirror;
+
+ MapExpector(Map<K, V> realInstance) : mirror = reflect(realInstance);
+
+ @override
dynamic wrappedChecker(Invocation i) =>
- DelegatingMap<K, V>(MapInvocationChecker<K, V>(i));
+ DelegatingMap<K, V>(MapInvocationChecker<K, V>(i, mirror));
}
// Utility values to use as arguments in calls.
Null func0() => null;
-Null func1(Object x) => null;
-Null func2(Object x, Object y) => null;
-var val = Object();
+dynamic func1(dynamic x) => null;
+dynamic func2(dynamic x, dynamic y) => null;
+bool boolFunc(dynamic x) => true;
+Iterable<dynamic> expandFunc(dynamic x) => [x];
+dynamic foldFunc(dynamic previous, dynamic next) => previous;
+int compareFunc(dynamic x, dynamic y) => 0;
+var val = 10;
void main() {
- void testIterable(var expect) {
- (expect..any(func1)).equals.any(func1);
+ void testIterable(IterableExpector expect) {
+ (expect..any(boolFunc)).equals.any(boolFunc);
(expect..contains(val)).equals.contains(val);
(expect..elementAt(0)).equals.elementAt(0);
- (expect..every(func1)).equals.every(func1);
- (expect..expand(func1)).equals.expand(func1);
+ (expect..every(boolFunc)).equals.every(boolFunc);
+ (expect..expand(expandFunc)).equals.expand(expandFunc);
(expect..first).equals.first;
// Default values of the Iterable interface will be added in the
// second call to firstWhere, so we must record them in our
// expectation (which doesn't have the interface implemented or
// its default values).
- (expect..firstWhere(func1, orElse: null)).equals.firstWhere(func1);
- (expect..firstWhere(func1, orElse: func0))
+ (expect..firstWhere(boolFunc, orElse: null)).equals.firstWhere(boolFunc);
+ (expect..firstWhere(boolFunc, orElse: func0))
.equals
- .firstWhere(func1, orElse: func0);
- (expect..fold(null, func2)).equals.fold(null, func2);
- (expect..forEach(func1)).equals.forEach(func1);
+ .firstWhere(boolFunc, orElse: func0);
+ (expect..fold(null, foldFunc)).equals.fold(null, foldFunc);
+ (expect..forEach(boolFunc)).equals.forEach(boolFunc);
(expect..isEmpty).equals.isEmpty;
(expect..isNotEmpty).equals.isNotEmpty;
(expect..iterator).equals.iterator;
(expect..join('')).equals.join();
(expect..join('X')).equals.join('X');
(expect..last).equals.last;
- (expect..lastWhere(func1, orElse: null)).equals.lastWhere(func1);
- (expect..lastWhere(func1, orElse: func0))
+ (expect..lastWhere(boolFunc, orElse: null)).equals.lastWhere(boolFunc);
+ (expect..lastWhere(boolFunc, orElse: func0))
.equals
- .lastWhere(func1, orElse: func0);
+ .lastWhere(boolFunc, orElse: func0);
(expect..length).equals.length;
(expect..map(func1)).equals.map(func1);
(expect..reduce(func2)).equals.reduce(func2);
(expect..single).equals.single;
- (expect..singleWhere(func1, orElse: null)).equals.singleWhere(func1);
+ (expect..singleWhere(boolFunc, orElse: null)).equals.singleWhere(boolFunc);
(expect..skip(5)).equals.skip(5);
- (expect..skipWhile(func1)).equals.skipWhile(func1);
+ (expect..skipWhile(boolFunc)).equals.skipWhile(boolFunc);
(expect..take(5)).equals.take(5);
- (expect..takeWhile(func1)).equals.takeWhile(func1);
+ (expect..takeWhile(boolFunc)).equals.takeWhile(boolFunc);
(expect..toList(growable: true)).equals.toList();
(expect..toList(growable: true)).equals.toList(growable: true);
(expect..toList(growable: false)).equals.toList(growable: false);
(expect..toSet()).equals.toSet();
(expect..toString()).equals.toString();
- (expect..where(func1)).equals.where(func1);
+ (expect..where(boolFunc)).equals.where(boolFunc);
}
- void testList(var expect) {
+ void testList(ListExpector expect) {
testIterable(expect);
+ // Later expects require at least 5 items
+ (expect..add(val)).equals.add(val);
+ (expect..addAll([val, val, val, val])).equals.addAll([val, val, val, val]);
(expect..[4]).equals[4];
(expect..[4] = 5).equals[4] = 5;
- (expect..add(val)).equals.add(val);
- (expect..addAll([val])).equals.addAll([val]);
(expect..asMap()).equals.asMap();
- (expect..clear()).equals.clear();
(expect..fillRange(4, 5, null)).equals.fillRange(4, 5);
(expect..fillRange(4, 5, val)).equals.fillRange(4, 5, val);
(expect..getRange(4, 5)).equals.getRange(4, 5);
@@ -202,25 +234,30 @@
(expect..insertAll(4, [val])).equals.insertAll(4, [val]);
(expect..lastIndexOf(val, null)).equals.lastIndexOf(val);
(expect..lastIndexOf(val, 4)).equals.lastIndexOf(val, 4);
- (expect..length = 4).equals.length = 4;
- (expect..remove(val)).equals.remove(val);
- (expect..removeAt(4)).equals.removeAt(4);
- (expect..removeLast()).equals.removeLast();
- (expect..removeRange(4, 5)).equals.removeRange(4, 5);
- (expect..removeWhere(func1)).equals.removeWhere(func1);
(expect..replaceRange(4, 5, [val])).equals.replaceRange(4, 5, [val]);
- (expect..retainWhere(func1)).equals.retainWhere(func1);
+ (expect..retainWhere(boolFunc)).equals.retainWhere(boolFunc);
(expect..reversed).equals.reversed;
(expect..setAll(4, [val])).equals.setAll(4, [val]);
(expect..setRange(4, 5, [val], 0)).equals.setRange(4, 5, [val]);
- (expect..setRange(4, 5, [val], 3)).equals.setRange(4, 5, [val], 3);
- (expect..sort(null)).equals.sort();
- (expect..sort(func2)).equals.sort(func2);
+ (expect..setRange(4, 5, [val, val], 1))
+ .equals
+ .setRange(4, 5, [val, val], 1);
+ (expect..sort()).equals.sort();
+ (expect..sort(compareFunc)).equals.sort(compareFunc);
(expect..sublist(4, null)).equals.sublist(4);
(expect..sublist(4, 5)).equals.sublist(4, 5);
+
+ // Do destructive apis last so other ones can work properly
+ (expect..removeAt(4)).equals.removeAt(4);
+ (expect..remove(val)).equals.remove(val);
+ (expect..removeLast()).equals.removeLast();
+ (expect..removeRange(4, 5)).equals.removeRange(4, 5);
+ (expect..removeWhere(boolFunc)).equals.removeWhere(boolFunc);
+ (expect..length = 5).equals.length = 5;
+ (expect..clear()).equals.clear();
}
- void testSet(var expect) {
+ void testSet(SetExpector expect) {
testIterable(expect);
var set = <dynamic>{};
(expect..add(val)).equals.add(val);
@@ -231,25 +268,25 @@
(expect..intersection(set)).equals.intersection(set);
(expect..remove(val)).equals.remove(val);
(expect..removeAll([val])).equals.removeAll([val]);
- (expect..removeWhere(func1)).equals.removeWhere(func1);
+ (expect..removeWhere(boolFunc)).equals.removeWhere(boolFunc);
(expect..retainAll([val])).equals.retainAll([val]);
- (expect..retainWhere(func1)).equals.retainWhere(func1);
+ (expect..retainWhere(boolFunc)).equals.retainWhere(boolFunc);
(expect..union(set)).equals.union(set);
}
- void testQueue(var expect) {
+ void testQueue(QueueExpector expect) {
testIterable(expect);
(expect..add(val)).equals.add(val);
(expect..addAll([val])).equals.addAll([val]);
(expect..addFirst(val)).equals.addFirst(val);
(expect..addLast(val)).equals.addLast(val);
- (expect..clear()).equals.clear();
(expect..remove(val)).equals.remove(val);
(expect..removeFirst()).equals.removeFirst();
(expect..removeLast()).equals.removeLast();
+ (expect..clear()).equals.clear();
}
- void testMap(var expect) {
+ void testMap(MapExpector expect) {
var map = {};
(expect..[val]).equals[val];
(expect..[val] = val).equals[val] = val;
@@ -273,7 +310,7 @@
// [setUpSet] should return a set with two elements: "foo" and "bar".
void testTwoElementSet(Set<String> Function() setUpSet) {
group('with two elements', () {
- Set<String> set;
+ late Set<String> set;
setUp(() => set = setUpSet());
test('.any', () {
@@ -313,7 +350,9 @@
});
test('.fold', () {
- expect(set.fold('start', (previous, element) => previous + element),
+ expect(
+ set.fold(
+ 'start', (dynamic previous, element) => previous + element),
equals('startfoobar'));
});
@@ -434,28 +473,28 @@
}
test('Iterable', () {
- testIterable(IterableExpector());
+ testIterable(IterableExpector([1]));
});
test('List', () {
- testList(ListExpector());
+ testList(ListExpector([1]));
});
test('Set', () {
- testSet(SetExpector());
+ testSet(SetExpector({1}));
});
test('Queue', () {
- testQueue(QueueExpector());
+ testQueue(QueueExpector(Queue.of([1])));
});
test('Map', () {
- testMap(MapExpector());
+ testMap(MapExpector({'a': 'b'}));
});
group('MapKeySet', () {
- Map<String, dynamic> map;
- Set<String> set;
+ late Map<String, dynamic> map;
+ late Set<String> set;
setUp(() {
map = <String, int>{};
@@ -522,8 +561,8 @@
});
group('MapValueSet', () {
- Map<String, String> map;
- Set<String> set;
+ late Map<String, String> map;
+ late Set<String> set;
setUp(() {
map = <String, String>{};