Try to fix flaky timestamp tests (#153)

* Try to fix flaky timestamp tests

There seems to be an underlying Dart issue that causes access and
modification times to files to sometimes be 1 second before the
current time.

Adjust `package:file`'s access and modification time tests to
tolerate this.  Previously they verified that the access and
modification times always were within a 1 second interval, starting
from the current second and ending at the next second.  This change
adjusts the interval to start at the previous second and end at the
current time rounded up to the nearest second.  This means that the
interval will be 1 second if the current time happens to be an exact
second or will be up to 2 seconds otherwise.

With this change, I've run one of the modification time tests in a
continuous loop for 10s (>300K iterations) without failure.

Bonus: Make some additional changes related to time handling:

* Change `ceil()` to be a mathematical ceiling.  Previously if the
  current time happened to be an exact second, `ceil()` would return
  the next second, which is a bit misleading.

* Change `expect(before, isSameOrBefore(timestamp))` to
  `expect(timestamp, isSameOrAfter(before))` since we're verifying
  that the timestamp is correct, not that the `before` reference time
  is.  Otherwise output from a test failure mixes up the notion of
  "Actual" and "Expected" values.

* Update CHANGELOG.md
diff --git a/packages/file/CHANGELOG.md b/packages/file/CHANGELOG.md
index b2c3ae7..cc5c305 100644
--- a/packages/file/CHANGELOG.md
+++ b/packages/file/CHANGELOG.md
@@ -6,6 +6,11 @@
   in the file as the start of a new, empty line.
 * `RecordingFile.readAsLine()`/`readAsLinesSync()` now always record a final
   newline.
+* `MemoryFile.flush()` now returns `Future<void>` instead of `Future<dynamic>`.
+* Fixed incorrect formatting in `NoMatchingInvocationError.toString()`.
+* Fixed a lot of test flakiness.
+* Enabled more tests.
+* Internal cleanup.
 
 #### 5.2.0
 
diff --git a/packages/file/test/common_tests.dart b/packages/file/test/common_tests.dart
index b99f3aa..b5ad188 100644
--- a/packages/file/test/common_tests.dart
+++ b/packages/file/test/common_tests.dart
@@ -1567,12 +1567,12 @@
 
       group('lastAccessed', () {
         test('isNowForNewlyCreatedFile', () {
-          DateTime before = floor();
+          DateTime before = downstairs();
           File f = fs.file(ns('/foo'))..createSync();
           DateTime after = ceil();
           DateTime accessed = f.lastAccessedSync();
-          expect(before, isSameOrBefore(accessed));
-          expect(after, isSameOrAfter(accessed));
+          expect(accessed, isSameOrAfter(before));
+          expect(accessed, isSameOrBefore(after));
         });
 
         test('throwsIfDoesntExist', () {
@@ -1589,13 +1589,13 @@
         });
 
         test('succeedsIfExistsAsLinkToFile', () {
-          DateTime before = floor();
+          DateTime before = downstairs();
           fs.file(ns('/foo')).createSync();
           fs.link(ns('/bar')).createSync(ns('/foo'));
           DateTime after = ceil();
           DateTime accessed = fs.file(ns('/bar')).lastAccessedSync();
-          expect(before, isSameOrBefore(accessed));
-          expect(after, isSameOrAfter(accessed));
+          expect(accessed, isSameOrAfter(before));
+          expect(accessed, isSameOrBefore(after));
         });
       });
 
@@ -1631,12 +1631,12 @@
 
       group('lastModified', () {
         test('isNowForNewlyCreatedFile', () {
-          DateTime before = floor();
+          DateTime before = downstairs();
           File f = fs.file(ns('/foo'))..createSync();
           DateTime after = ceil();
           DateTime modified = f.lastModifiedSync();
-          expect(before, isSameOrBefore(modified));
-          expect(after, isSameOrAfter(modified));
+          expect(modified, isSameOrAfter(before));
+          expect(modified, isSameOrBefore(after));
         });
 
         test('throwsIfDoesntExist', () {
@@ -1653,13 +1653,13 @@
         });
 
         test('succeedsIfExistsAsLinkToFile', () {
-          DateTime before = floor();
+          DateTime before = downstairs();
           fs.file(ns('/foo')).createSync();
           fs.link(ns('/bar')).createSync(ns('/foo'));
           DateTime after = ceil();
           DateTime modified = fs.file(ns('/bar')).lastModifiedSync();
-          expect(before, isSameOrBefore(modified));
-          expect(after, isSameOrAfter(modified));
+          expect(modified, isSameOrAfter(before));
+          expect(modified, isSameOrBefore(after));
         });
       });
 
diff --git a/packages/file/test/utils.dart b/packages/file/test/utils.dart
index 2d7a6db..aebad3e 100644
--- a/packages/file/test/utils.dart
+++ b/packages/file/test/utils.dart
@@ -5,6 +5,8 @@
 import 'package:meta/meta.dart';
 import 'package:test/test.dart';
 
+const Duration _oneSecond = Duration(seconds: 1);
+
 /// Returns a [DateTime] with an exact second-precision by removing the
 /// milliseconds and microseconds from the specified [time].
 ///
@@ -17,17 +19,23 @@
   ));
 }
 
-/// Returns a [DateTime] with an exact second precision by adding just enough
-/// milliseconds and microseconds to the specified [time] to reach the next
-/// second.
+/// Returns a [DateTime] with an exact second precision, rounding up to the
+/// nearest second if necessary.
 ///
 /// If [time] is not specified, it will default to the current time.
 DateTime ceil([DateTime time]) {
   time ??= DateTime.now();
   int microseconds = (1000 * time.millisecond) + time.microsecond;
-  return time.add(Duration(microseconds: 1000000 - microseconds));
+  return (microseconds == 0)
+      ? time
+      // Add just enough milliseconds and microseconds to reach the next second.
+      : time.add(Duration(microseconds: 1000000 - microseconds));
 }
 
+/// Returns 1 second before the [floor] of the specified [DateTime].
+// TODO(jamesderlin): Remove this and use [floor], https://github.com/dart-lang/sdk/issues/42444
+DateTime downstairs([DateTime time]) => floor(time).subtract(_oneSecond);
+
 /// Successfully matches against a [DateTime] that is the same moment or before
 /// the specified [time].
 Matcher isSameOrBefore(DateTime time) => _IsSameOrBefore(time);
diff --git a/packages/file/test/utils_test.dart b/packages/file/test/utils_test.dart
index 2e45896..75293bf 100644
--- a/packages/file/test/utils_test.dart
+++ b/packages/file/test/utils_test.dart
@@ -27,9 +27,17 @@
 
   test('floorAndCeilWorkWithExactSecondDateTime', () {
     DateTime time = DateTime.parse('1999-12-31 23:59:59');
-    int lower = time.difference(floor(time)).inMicroseconds;
-    int upper = ceil(time).difference(time).inMicroseconds;
-    expect(lower, 0);
-    expect(upper, lessThanOrEqualTo(1000000));
+    DateTime lower = floor(time);
+    DateTime upper = ceil(time);
+    expect(lower, time);
+    expect(upper, time);
+  });
+
+  test('floorAndCeilWorkWithInexactSecondDateTime', () {
+    DateTime time = DateTime.parse('1999-12-31 23:59:59.500');
+    DateTime lower = floor(time);
+    DateTime upper = ceil(time);
+    Duration difference = upper.difference(lower);
+    expect(difference.inMicroseconds, 1000000);
   });
 }