Fix bug, tidy up. (#28)

* Fix bug, tidy up.

* Address feedback
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3a099e..8f04e16 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.20.3
+
+* Bug fix: Avoid emitting an empty list via `ObservableList.listChanges`
+
 ## 0.20.2
 
 * Bug fix: Avoid emitting a no-op `MapChangeRecord`
diff --git a/lib/src/collections/observable_list.dart b/lib/src/collections/observable_list.dart
index 8cd1a4b..515818d 100644
--- a/lib/src/collections/observable_list.dart
+++ b/lib/src/collections/observable_list.dart
@@ -216,9 +216,9 @@
   bool get hasListObservers => _listChanges.hasObservers;
 
   @override
-  Stream<List<ListChangeRecord<E>>> get listChanges {
-    return _listChanges.changes.map((r) => projectListSplices(this, r));
-  }
+  Stream<List<ListChangeRecord<E>>> get listChanges => _listChanges.changes
+      .map((r) => projectListSplices(this, r))
+      .where((c) => c.isNotEmpty);
 
   @override
   void notifyListChange(
diff --git a/lib/src/observable.dart b/lib/src/observable.dart
index 0990b96..de9c637 100644
--- a/lib/src/observable.dart
+++ b/lib/src/observable.dart
@@ -53,8 +53,6 @@
   ///
   /// Returns `true` if changes were emitted.
   @Deprecated('Use ChangeNotifier instead to have this method available')
-  // REMOVE IGNORE when https://github.com/dart-lang/observable/issues/10
-  // ignore: invalid_use_of_protected_member
   bool deliverChanges() => _delegate.deliverChanges();
 
   /// Notify that the [field] name of this object has been changed.
diff --git a/test/collections/observable_list_test.dart b/test/collections/observable_list_test.dart
index 2544677..67e2587 100644
--- a/test/collections/observable_list_test.dart
+++ b/test/collections/observable_list_test.dart
@@ -310,6 +310,61 @@
 
 // These are tests we will remove after deprecations occur.
 _runDeprecatedTests() {
+  group('listChanges stream', () {
+    Completer<List<ListChangeRecord>> completer;
+    ObservableList<String> list;
+    List<String> previousState;
+    StreamSubscription sub;
+
+    Future next() {
+      completer = new Completer<List<ListChangeRecord>>.sync();
+      return completer.future;
+    }
+
+    Future<Null> expectChanges(List<ListChangeRecord> changes) {
+      // Applying these change records in order should make the new list.
+      for (final change in changes) {
+        change.apply(previousState);
+      }
+      expect(list, previousState);
+
+      // If these fail, it might be safe to update if optimized/changed.
+      return next().then((actualChanges) {
+        expect(actualChanges, changes);
+      });
+    }
+
+    setUp(() {
+      previousState = ['a', 'b', 'c'];
+      list = new ObservableList<String>.from(previousState);
+      sub = list.listChanges.listen((c) {
+        if (completer?.isCompleted == false) {
+          completer.complete(c.toList());
+        }
+        previousState = list.toList();
+      });
+    });
+
+    tearDown(() => sub.cancel());
+
+    test('updates when an index changes', () async {
+      list[0] = 'd';
+      await expectChanges([
+        new ListChangeRecord.replace(list, 0, ['a']),
+      ]);
+    });
+
+    test('should not emit an empty list', () async {
+      // This is optimized into a no-op.
+      list[0] = 'd';
+      list[0] = 'a';
+      next().then((_) {
+        fail('Should not emit change records');
+      });
+      await new Future.value();
+    });
+  });
+
   group('length changes', () {
     Completer<List<ListChangeRecord>> completer;
     ObservableList<String> list;
diff --git a/tool/presubmit.sh b/tool/presubmit.sh
index f1c7a23..8446b90 100755
--- a/tool/presubmit.sh
+++ b/tool/presubmit.sh
@@ -26,13 +26,18 @@
 # Fail on anything that fails going forward.
 set -e
 
+# Allow running this script locally, otherwise it fails outside of travis.
+if [[ ${TEST_PLATFORM} == "" ]]
+then
+  TEST_PLATFORM="vm"
+fi
+
 THE_COMMAND="pub run test -p $TEST_PLATFORM"
-if [ $TEST_PLATFORM == 'firefox' ]; then
+if [[ ${TEST_PLATFORM} == "firefox" ]]
+then
   export DISPLAY=:99.0
   sh -e /etc/init.d/xvfb start
   t=0; until (xdpyinfo -display :99 &> /dev/null || test $t -gt 10); do sleep 1; let t=$t+1; done
 fi
 echo $THE_COMMAND
 exec $THE_COMMAND
-
-pub run test