From bf2ee2d111c48699dcf41290f08bdff94904ef13 Mon Sep 17 00:00:00 2001 From: Scott Carnett <798305+scarnett@users.noreply.github.com> Date: Tue, 20 Apr 2021 13:39:50 -0500 Subject: [PATCH 1/7] nullsafety migration --- lib/interval_tree.dart | 54 +++++++++++++++++++++--------------------- pubspec.yaml | 2 +- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/interval_tree.dart b/lib/interval_tree.dart index b66861e..2e9af40 100644 --- a/lib/interval_tree.dart +++ b/lib/interval_tree.dart @@ -150,7 +150,7 @@ class Interval extends Comparable { /// final b = Interval(3, 5); /// print(b.intersection(a)); // null /// - Interval intersection(Interval other) { + Interval? intersection(Interval other) { if (!intersects(other)) return null; return Interval(_max(start, other.start), _min(end, other.end)); } @@ -177,7 +177,7 @@ class Interval extends Comparable { /// print(a.difference(b)); // [[1, 2], [4, 5]] /// print(b.difference(a)); // null /// - Iterable difference(Interval other) { + Iterable? difference(Interval other) { if (other.contains(this)) return null; if (!other.intersects(this)) return [this]; if (other.start > start && other.end >= end) { @@ -308,7 +308,7 @@ class Interval extends Comparable { /// /// final interval = ivt.Interval(1, 2); /// -class IntervalTree with IterableMixin { +class IntervalTree with IterableMixin { /// Creates a tree, optionally with an [interval]. IntervalTree([dynamic interval]) { add(interval); @@ -324,16 +324,16 @@ class IntervalTree with IterableMixin { } /// Creates a tree from [intervals]. - factory IntervalTree.of(Iterable intervals) => + factory IntervalTree.of(Iterable intervals) => IntervalTree()..addAll(intervals); /// Adds an [interval] into this tree. void add(dynamic interval) { - Interval iv = _asInterval(interval); + Interval? iv = _asInterval(interval); if (iv == null) return; bool joined = false; - BidirectionalIterator it = _tree.fromIterator(iv); + BidirectionalIterator it = _tree.fromIterator(iv); while (it.movePrevious()) { final union = _tryJoin(it.current, iv); if (union == null) break; @@ -367,7 +367,7 @@ class IntervalTree with IterableMixin { final iv = _asInterval(interval); if (iv == null) return; - BidirectionalIterator it = _tree.fromIterator(iv); + BidirectionalIterator it = _tree.fromIterator(iv); while (it.movePrevious()) { final current = it.current; if (!_trySplit(it.current, iv)) break; @@ -408,13 +408,13 @@ class IntervalTree with IterableMixin { final result = IntervalTree(); if (isEmpty || other.isEmpty) result; for (final iv in other) { - BidirectionalIterator it = _tree.fromIterator(iv); - while (it.movePrevious() && iv.intersects(it.current)) { - result.add(iv.intersection(it.current)); + BidirectionalIterator it = _tree.fromIterator(iv); + while (it.movePrevious() && iv!.intersects(it.current!)) { + result.add(iv.intersection(it.current!)); } it = _tree.fromIterator(iv, inclusive: false); - while (it.moveNext() && iv.intersects(it.current)) { - result.add(iv.intersection(it.current)); + while (it.moveNext() && iv!.intersects(it.current!)) { + result.add(iv.intersection(it.current!)); } } return result; @@ -425,13 +425,13 @@ class IntervalTree with IterableMixin { final iv = _asInterval(interval); if (iv == null) return false; - BidirectionalIterator it = _tree.fromIterator(iv); - while (it.movePrevious() && iv.intersects(it.current)) { - if (it.current.contains(iv)) return true; + BidirectionalIterator it = _tree.fromIterator(iv); + while (it.movePrevious() && iv.intersects(it.current!)) { + if (it.current!.contains(iv)) return true; } it = _tree.fromIterator(iv, inclusive: false); - while (it.moveNext() && it.current.intersects(iv)) { - if (it.current.contains(iv)) return true; + while (it.moveNext() && it.current!.intersects(iv)) { + if (it.current!.contains(iv)) return true; } return false; } @@ -450,35 +450,35 @@ class IntervalTree with IterableMixin { /// Returns the first interval in tree, or `null` if this tree is empty. @override - Interval get first => _tree.first; + Interval? get first => _tree.first; /// Returns the first interval in tree, or `null` if this tree is empty. @override - Interval get last => _tree.last; + Interval? get last => _tree.last; /// Checks that this tree has only one interval, and returns that interval. @override - Interval get single => _tree.single; + Interval? get single => _tree.single; /// Returns a bidirectional iterator that allows iterating the intervals. @override - BidirectionalIterator get iterator => _tree.iterator; + BidirectionalIterator get iterator => _tree.iterator; /// Returns a string representation of the tree. @override String toString() => 'IntervalTree' + super.toString(); - Interval _asInterval(dynamic interval) { + Interval? _asInterval(dynamic interval) { if (interval is Iterable) { if (interval.length != 2 || interval.first is Iterable) { throw ArgumentError('$interval is not an interval'); } return Interval(interval.first, interval.last); } - return interval as Interval; + return interval as Interval?; } - Interval _tryJoin(Interval a, Interval b) { + Interval? _tryJoin(Interval? a, Interval? b) { if (a == null || b == null) return null; if (a.contains(b)) return a; if (!a.intersects(b)) return null; @@ -489,7 +489,7 @@ class IntervalTree with IterableMixin { return union; } - bool _trySplit(Interval a, Interval b) { + bool _trySplit(Interval? a, Interval b) { if (a == null || b == null) return false; if (!a.intersects(b)) return false; _tree.remove(a); @@ -497,6 +497,6 @@ class IntervalTree with IterableMixin { return true; } - final AvlTreeSet _tree = - AvlTreeSet(comparator: Comparable.compare); + final AvlTreeSet _tree = AvlTreeSet( + comparator: Comparable.compare as int Function(Interval?, Interval?)); } diff --git a/pubspec.yaml b/pubspec.yaml index 4eedc24..f9d3d6f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,7 @@ repository: https://github.com/jpnurmi/interval_tree issue_tracker: https://github.com/jpnurmi/interval_tree/issues environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: meta: ^1.1.8 quiver: ^2.0.5 From 45b0f25f2b9bd25a57f4169fa7f64ffb5e9c5cbc Mon Sep 17 00:00:00 2001 From: Scott Carnett <798305+scarnett@users.noreply.github.com> Date: Tue, 20 Apr 2021 15:18:48 -0500 Subject: [PATCH 2/7] updates --- lib/interval_tree.dart | 44 +++++++++++++++--------------------- pubspec.yaml | 2 +- test/interval_tree_test.dart | 4 ++-- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/lib/interval_tree.dart b/lib/interval_tree.dart index 2e9af40..24a744c 100644 --- a/lib/interval_tree.dart +++ b/lib/interval_tree.dart @@ -308,10 +308,10 @@ class Interval extends Comparable { /// /// final interval = ivt.Interval(1, 2); /// -class IntervalTree with IterableMixin { +class IntervalTree with IterableMixin { /// Creates a tree, optionally with an [interval]. IntervalTree([dynamic interval]) { - add(interval); + if (interval != null) add(interval); } /// Creates a tree from given iterable of [intervals]. @@ -329,9 +329,7 @@ class IntervalTree with IterableMixin { /// Adds an [interval] into this tree. void add(dynamic interval) { - Interval? iv = _asInterval(interval); - if (iv == null) return; - + Interval iv = _asInterval(interval); bool joined = false; BidirectionalIterator it = _tree.fromIterator(iv); while (it.movePrevious()) { @@ -356,7 +354,6 @@ class IntervalTree with IterableMixin { /// Adds all [intervals] into this tree. void addAll(Iterable intervals) { - if (intervals == null) return; for (final interval in intervals) { add(interval); } @@ -365,9 +362,8 @@ class IntervalTree with IterableMixin { /// Removes an [interval] from this tree. void remove(dynamic interval) { final iv = _asInterval(interval); - if (iv == null) return; - BidirectionalIterator it = _tree.fromIterator(iv); + BidirectionalIterator it = _tree.fromIterator(iv); while (it.movePrevious()) { final current = it.current; if (!_trySplit(it.current, iv)) break; @@ -384,7 +380,6 @@ class IntervalTree with IterableMixin { /// Removes all [intervals] from this tree. void removeAll(Iterable intervals) { - if (intervals == null) return; for (final interval in intervals) { remove(interval); } @@ -408,13 +403,13 @@ class IntervalTree with IterableMixin { final result = IntervalTree(); if (isEmpty || other.isEmpty) result; for (final iv in other) { - BidirectionalIterator it = _tree.fromIterator(iv); - while (it.movePrevious() && iv!.intersects(it.current!)) { - result.add(iv.intersection(it.current!)); + BidirectionalIterator it = _tree.fromIterator(iv); + while (it.movePrevious() && iv.intersects(it.current)) { + result.add(iv.intersection(it.current)); } it = _tree.fromIterator(iv, inclusive: false); - while (it.moveNext() && iv!.intersects(it.current!)) { - result.add(iv.intersection(it.current!)); + while (it.moveNext() && iv.intersects(it.current)) { + result.add(iv.intersection(it.current)); } } return result; @@ -423,8 +418,6 @@ class IntervalTree with IterableMixin { @override bool contains(dynamic interval) { final iv = _asInterval(interval); - if (iv == null) return false; - BidirectionalIterator it = _tree.fromIterator(iv); while (it.movePrevious() && iv.intersects(it.current!)) { if (it.current!.contains(iv)) return true; @@ -450,32 +443,32 @@ class IntervalTree with IterableMixin { /// Returns the first interval in tree, or `null` if this tree is empty. @override - Interval? get first => _tree.first; + Interval get first => _tree.first; /// Returns the first interval in tree, or `null` if this tree is empty. @override - Interval? get last => _tree.last; + Interval get last => _tree.last; /// Checks that this tree has only one interval, and returns that interval. @override - Interval? get single => _tree.single; + Interval get single => _tree.single; /// Returns a bidirectional iterator that allows iterating the intervals. @override - BidirectionalIterator get iterator => _tree.iterator; + BidirectionalIterator get iterator => _tree.iterator; /// Returns a string representation of the tree. @override String toString() => 'IntervalTree' + super.toString(); - Interval? _asInterval(dynamic interval) { + Interval _asInterval(dynamic interval) { if (interval is Iterable) { if (interval.length != 2 || interval.first is Iterable) { throw ArgumentError('$interval is not an interval'); } return Interval(interval.first, interval.last); } - return interval as Interval?; + return interval; } Interval? _tryJoin(Interval? a, Interval? b) { @@ -489,14 +482,13 @@ class IntervalTree with IterableMixin { return union; } - bool _trySplit(Interval? a, Interval b) { - if (a == null || b == null) return false; + bool _trySplit(Interval a, Interval b) { if (!a.intersects(b)) return false; _tree.remove(a); _tree.addAll([...?a.difference(b)]); return true; } - final AvlTreeSet _tree = AvlTreeSet( - comparator: Comparable.compare as int Function(Interval?, Interval?)); + final AvlTreeSet _tree = + AvlTreeSet(comparator: Comparable.compare); } diff --git a/pubspec.yaml b/pubspec.yaml index f9d3d6f..d47d850 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,7 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: meta: ^1.1.8 - quiver: ^2.0.5 + quiver: ^3.0.1 dev_dependencies: test: ^1.14.2 test_coverage: ^0.4.1 diff --git a/test/interval_tree_test.dart b/test/interval_tree_test.dart index 33d17e4..82c74e4 100644 --- a/test/interval_tree_test.dart +++ b/test/interval_tree_test.dart @@ -248,8 +248,8 @@ void main() { IntervalTree empty = IntervalTree(); expect(empty.isEmpty, isTrue); expect(empty.isNotEmpty, isFalse); - expect(empty.first, isNull); - expect(empty.last, isNull); + // expect(empty.first, isNull); + // expect(empty.last, isNull); expect(empty.length, 0); expect(() => empty.single, throwsStateError); From 3dfce1976828c457c3186bbe32f17ed5dd7e8a9d Mon Sep 17 00:00:00 2001 From: Scott Carnett <798305+scarnett@users.noreply.github.com> Date: Wed, 21 Apr 2021 18:51:07 -0500 Subject: [PATCH 3/7] nullsafe updates --- lib/interval_tree.dart | 18 ++++++++++-------- test/interval_tree_test.dart | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/interval_tree.dart b/lib/interval_tree.dart index 24a744c..31a64dd 100644 --- a/lib/interval_tree.dart +++ b/lib/interval_tree.dart @@ -311,7 +311,7 @@ class Interval extends Comparable { class IntervalTree with IterableMixin { /// Creates a tree, optionally with an [interval]. IntervalTree([dynamic interval]) { - if (interval != null) add(interval); + add(interval); } /// Creates a tree from given iterable of [intervals]. @@ -328,8 +328,10 @@ class IntervalTree with IterableMixin { IntervalTree()..addAll(intervals); /// Adds an [interval] into this tree. - void add(dynamic interval) { - Interval iv = _asInterval(interval); + void add(dynamic? interval) { + Interval? iv = _asInterval(interval); + if (iv == null) return; + bool joined = false; BidirectionalIterator it = _tree.fromIterator(iv); while (it.movePrevious()) { @@ -339,7 +341,7 @@ class IntervalTree with IterableMixin { joined = true; } - it = _tree.fromIterator(iv, inclusive: false); + it = _tree.fromIterator(iv!, inclusive: false); while (it.moveNext()) { final union = _tryJoin(it.current, iv); if (union == null) break; @@ -348,7 +350,7 @@ class IntervalTree with IterableMixin { } if (!joined) { - _tree.add(iv); + _tree.add(iv!); } } @@ -363,7 +365,7 @@ class IntervalTree with IterableMixin { void remove(dynamic interval) { final iv = _asInterval(interval); - BidirectionalIterator it = _tree.fromIterator(iv); + BidirectionalIterator it = _tree.fromIterator(iv!); while (it.movePrevious()) { final current = it.current; if (!_trySplit(it.current, iv)) break; @@ -418,7 +420,7 @@ class IntervalTree with IterableMixin { @override bool contains(dynamic interval) { final iv = _asInterval(interval); - BidirectionalIterator it = _tree.fromIterator(iv); + BidirectionalIterator it = _tree.fromIterator(iv!); while (it.movePrevious() && iv.intersects(it.current!)) { if (it.current!.contains(iv)) return true; } @@ -461,7 +463,7 @@ class IntervalTree with IterableMixin { @override String toString() => 'IntervalTree' + super.toString(); - Interval _asInterval(dynamic interval) { + Interval? _asInterval(dynamic? interval) { if (interval is Iterable) { if (interval.length != 2 || interval.first is Iterable) { throw ArgumentError('$interval is not an interval'); diff --git a/test/interval_tree_test.dart b/test/interval_tree_test.dart index 82c74e4..33d17e4 100644 --- a/test/interval_tree_test.dart +++ b/test/interval_tree_test.dart @@ -248,8 +248,8 @@ void main() { IntervalTree empty = IntervalTree(); expect(empty.isEmpty, isTrue); expect(empty.isNotEmpty, isFalse); - // expect(empty.first, isNull); - // expect(empty.last, isNull); + expect(empty.first, isNull); + expect(empty.last, isNull); expect(empty.length, 0); expect(() => empty.single, throwsStateError); From ad7ae023d2b336d4aa59a03f3bf9dfa879cfd2fb Mon Sep 17 00:00:00 2001 From: Scott Carnett <798305+scarnett@users.noreply.github.com> Date: Wed, 21 Apr 2021 18:51:58 -0500 Subject: [PATCH 4/7] remove 2 tests --- test/interval_tree_test.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/interval_tree_test.dart b/test/interval_tree_test.dart index 33d17e4..030f715 100644 --- a/test/interval_tree_test.dart +++ b/test/interval_tree_test.dart @@ -248,8 +248,6 @@ void main() { IntervalTree empty = IntervalTree(); expect(empty.isEmpty, isTrue); expect(empty.isNotEmpty, isFalse); - expect(empty.first, isNull); - expect(empty.last, isNull); expect(empty.length, 0); expect(() => empty.single, throwsStateError); From 0a4b7e44b0fedcd86a522cb36698dcb0210be83c Mon Sep 17 00:00:00 2001 From: Scott Carnett <798305+scarnett@users.noreply.github.com> Date: Wed, 21 Apr 2021 19:00:52 -0500 Subject: [PATCH 5/7] test for exception --- lib/interval_tree.dart | 4 ++-- test/interval_tree_test.dart | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/interval_tree.dart b/lib/interval_tree.dart index 31a64dd..b4d3716 100644 --- a/lib/interval_tree.dart +++ b/lib/interval_tree.dart @@ -443,11 +443,11 @@ class IntervalTree with IterableMixin { @override bool get isNotEmpty => _tree.isNotEmpty; - /// Returns the first interval in tree, or `null` if this tree is empty. + /// Returns the first interval in tree, otherwise throw StateError. @override Interval get first => _tree.first; - /// Returns the first interval in tree, or `null` if this tree is empty. + /// Returns the first interval in tree, otherwise throw StateError. @override Interval get last => _tree.last; diff --git a/test/interval_tree_test.dart b/test/interval_tree_test.dart index 030f715..8a564c9 100644 --- a/test/interval_tree_test.dart +++ b/test/interval_tree_test.dart @@ -248,6 +248,8 @@ void main() { IntervalTree empty = IntervalTree(); expect(empty.isEmpty, isTrue); expect(empty.isNotEmpty, isFalse); + expect(() => empty.first, throwsA(isA())); + expect(() => empty.last, throwsA(isA())); expect(empty.length, 0); expect(() => empty.single, throwsStateError); From de16edcdb217f12fcfa3b80ae240aba9767734a6 Mon Sep 17 00:00:00 2001 From: Scott Carnett <798305+scarnett@users.noreply.github.com> Date: Wed, 21 Apr 2021 19:24:03 -0500 Subject: [PATCH 6/7] switch to test_cov --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index d47d850..949c128 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,4 +15,4 @@ dependencies: quiver: ^3.0.1 dev_dependencies: test: ^1.14.2 - test_coverage: ^0.4.1 + test_cov: ^1.0.1 From 72ca1a356534b1b958c8d0be51eae6063993815d Mon Sep 17 00:00:00 2001 From: Scott Carnett <798305+scarnett@users.noreply.github.com> Date: Wed, 21 Apr 2021 19:27:21 -0500 Subject: [PATCH 7/7] update workflow --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a179b60..1ea9a34 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: - name: Run tests run: pub run test - name: Measure coverage - run: pub run test_coverage + run: pub run test_cov - name: Upload coverage uses: codecov/codecov-action@v1.0.6 with: