Don't test for file differences in the polling watcher.

The non-polling forms don't do this, so this makes the polling
style behave the same. It also has two important benefits:

1. On Windows, this avoids opening the files being watched.
   Since opening a file prevents it from being deleted on
   Windows, this causes the watcher to interfere with the
   files and leads to some flaky tests and buggy user
   behavior.

2. It saves some time and memory since we don't need to store
   the SHA1 for every file being watched.

BUG=http://dartbug.com/13026, http://dartbug.com/15431
R=nweiz@google.com

Review URL: https://codereview.chromium.org//122573003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/watcher@31574 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/lib/src/directory_watcher/polling.dart b/lib/src/directory_watcher/polling.dart
index 684f7aa..12a3245 100644
--- a/lib/src/directory_watcher/polling.dart
+++ b/lib/src/directory_watcher/polling.dart
@@ -7,7 +7,6 @@
 import 'dart:async';
 import 'dart:io';
 
-import 'package:crypto/crypto.dart';
 import 'package:stack_trace/stack_trace.dart';
 
 import '../async_queue.dart';
@@ -46,10 +45,10 @@
   /// directory contents.
   final Duration _pollingDelay;
 
-  /// The previous status of the files in the directory.
+  /// The previous modification times of the files in the directory.
   ///
   /// Used to tell which files have been modified.
-  final _statuses = new Map<String, _FileStatus>();
+  final _lastModifieds = new Map<String, DateTime>();
 
   /// The subscription used while [directory] is being listed.
   ///
@@ -89,7 +88,7 @@
     // Don't process any remaining files.
     _filesToProcess.clear();
     _polledFiles.clear();
-    _statuses.clear();
+    _lastModifieds.clear();
   }
 
   /// Scans the contents of the directory once to see which files have been
@@ -135,32 +134,25 @@
     return getModificationTime(file).then((modified) {
       if (_events.isClosed) return null;
 
-      var lastStatus = _statuses[file];
+      var lastModified = _lastModifieds[file];
 
       // If its modification time hasn't changed, assume the file is unchanged.
-      if (lastStatus != null && lastStatus.modified == modified) {
+      if (lastModified != null && lastModified == modified) {
         // The file is still here.
         _polledFiles.add(file);
         return null;
       }
 
-      return _hashFile(file).then((hash) {
-        if (_events.isClosed) return;
+      if (_events.isClosed) return null;
 
-        var status = new _FileStatus(modified, hash);
-        _statuses[file] = status;
-        _polledFiles.add(file);
+      _lastModifieds[file] = modified;
+      _polledFiles.add(file);
 
-        // Only notify if we're ready to emit events.
-        if (!isReady) return;
+      // Only notify if we're ready to emit events.
+      if (!isReady) return null;
 
-        // And the file is different.
-        var changed = lastStatus == null || !_sameHash(lastStatus.hash, hash);
-        if (!changed) return;
-
-        var type = lastStatus == null ? ChangeType.ADD : ChangeType.MODIFY;
-        _events.add(new WatchEvent(type, file));
-      });
+      var type = lastModified == null ? ChangeType.ADD : ChangeType.MODIFY;
+      _events.add(new WatchEvent(type, file));
     });
   }
 
@@ -169,10 +161,10 @@
   Future _completePoll() {
     // Any files that were not seen in the last poll but that we have a
     // status for must have been removed.
-    var removedFiles = _statuses.keys.toSet().difference(_polledFiles);
+    var removedFiles = _lastModifieds.keys.toSet().difference(_polledFiles);
     for (var removed in removedFiles) {
       if (isReady) _events.add(new WatchEvent(ChangeType.REMOVE, removed));
-      _statuses.remove(removed);
+      _lastModifieds.remove(removed);
     }
 
     if (!isReady) _ready.complete();
@@ -183,37 +175,4 @@
       _poll();
     });
   }
-
-  /// Calculates the SHA-1 hash of the file at [path].
-  Future<List<int>> _hashFile(String path) {
-    return Chain.track(new File(path).readAsBytes()).then((bytes) {
-      var sha1 = new SHA1();
-      sha1.add(bytes);
-      return sha1.close();
-    });
-  }
-
-  /// Returns `true` if [a] and [b] are the same hash value, i.e. the same
-  /// series of byte values.
-  bool _sameHash(List<int> a, List<int> b) {
-    // Hashes should always be the same size.
-    assert(a.length == b.length);
-
-    for (var i = 0; i < a.length; i++) {
-      if (a[i] != b[i]) return false;
-    }
-
-    return true;
-  }
 }
-
-class _FileStatus {
-  /// The last time the file was modified.
-  DateTime modified;
-
-  /// The SHA-1 hash of the contents of the file.
-  List<int> hash;
-
-  _FileStatus(this.modified, this.hash);
-}
-
diff --git a/pubspec.yaml b/pubspec.yaml
index a967294..c77dddf 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,13 +1,11 @@
 name: watcher
-version: 0.9.2
+version: 0.9.3-dev
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://www.dartlang.org
 description: >
-  A file watcher. It monitors (currently by polling) for changes to contents
-  of directories and notifies you when files have been added, removed, or
-  modified.
+  A file watcher. It monitors for changes to contents of directories and
+  notifies you when files have been added, removed, or modified.
 dependencies:
-  crypto: ">=0.9.0 <0.10.0"
   path: ">=0.9.0 <2.0.0"
   stack_trace: ">=0.9.1 <0.10.0"
 dev_dependencies:
diff --git a/test/directory_watcher/linux_test.dart b/test/directory_watcher/linux_test.dart
index f53b272..c2d0176 100644
--- a/test/directory_watcher/linux_test.dart
+++ b/test/directory_watcher/linux_test.dart
@@ -23,16 +23,6 @@
         new isInstanceOf<LinuxDirectoryWatcher>());
   });
 
-  test('notifies even if the file contents are unchanged', () {
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "before");
-    startWatcher();
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "after");
-    expectModifyEvent("a.txt");
-    expectModifyEvent("b.txt");
-  });
-
   test('emits events for many nested files moved out then immediately back in',
       () {
     withPermutations((i, j, k) =>
diff --git a/test/directory_watcher/mac_os_test.dart b/test/directory_watcher/mac_os_test.dart
index 8fc2d3e..077787a 100644
--- a/test/directory_watcher/mac_os_test.dart
+++ b/test/directory_watcher/mac_os_test.dart
@@ -36,16 +36,6 @@
     expectAddEvent("dir/newer.txt");
   });
 
-  test('notifies even if the file contents are unchanged', () {
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "before");
-    startWatcher();
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "after");
-    expectModifyEvent("a.txt");
-    expectModifyEvent("b.txt");
-  });
-
   test('emits events for many nested files moved out then immediately back in',
       () {
     withPermutations((i, j, k) =>
diff --git a/test/directory_watcher/polling_test.dart b/test/directory_watcher/polling_test.dart
index 02ed5d2..da29207 100644
--- a/test/directory_watcher/polling_test.dart
+++ b/test/directory_watcher/polling_test.dart
@@ -19,15 +19,6 @@
 
   sharedTests();
 
-  test('does not notify if the file contents are unchanged', () {
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "before");
-    startWatcher();
-    writeFile("a.txt", contents: "same");
-    writeFile("b.txt", contents: "after");
-    expectModifyEvent("b.txt");
-  });
-
   test('does not notify if the modification time did not change', () {
     writeFile("a.txt", contents: "before");
     writeFile("b.txt", contents: "before");
diff --git a/test/directory_watcher/shared.dart b/test/directory_watcher/shared.dart
index fe76a03..f831196 100644
--- a/test/directory_watcher/shared.dart
+++ b/test/directory_watcher/shared.dart
@@ -51,6 +51,16 @@
     expectModifyEvent("file.txt");
   });
 
+  test('notifies even if the file contents are unchanged', () {
+    writeFile("a.txt", contents: "same");
+    writeFile("b.txt", contents: "before");
+    startWatcher();
+    writeFile("a.txt", contents: "same");
+    writeFile("b.txt", contents: "after");
+    expectModifyEvent("a.txt");
+    expectModifyEvent("b.txt");
+  });
+
   test('when the watched directory is deleted, removes all files', () {
     writeFile("dir/a.txt");
     writeFile("dir/b.txt");