Fix Uri handling in FileSystem methods (#57)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index e136c32..bba68b3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+#### 2.3.2
+
+* Fixed `FileSystem.directory(Uri)`, `FileSystem.file(Uri)`, and
+  `FileSystem.link(Uri)` to consult the file system's path context when
+  converting the URI to a file path rather than using `Uri.toFilePath()`.
+
 #### 2.3.1
 
 * Fixed `MemoryFileSystem` to make `File.writeAs...()` update the last modified
diff --git a/lib/src/backends/chroot/chroot_directory.dart b/lib/src/backends/chroot/chroot_directory.dart
index 3cfaa61..4d5a929 100644
--- a/lib/src/backends/chroot/chroot_directory.dart
+++ b/lib/src/backends/chroot/chroot_directory.dart
@@ -170,4 +170,7 @@
     }
     throw new FileSystemException('Unsupported type: $entity', entity.path);
   }
+
+  @override
+  String toString() => "ChrootDirectory: '$path'";
 }
diff --git a/lib/src/backends/chroot/chroot_file.dart b/lib/src/backends/chroot/chroot_file.dart
index 3e12c43..abf22be 100644
--- a/lib/src/backends/chroot/chroot_file.dart
+++ b/lib/src/backends/chroot/chroot_file.dart
@@ -333,4 +333,7 @@
         encoding: encoding,
         flush: flush,
       );
+
+  @override
+  String toString() => "ChrootFile: '$path'";
 }
diff --git a/lib/src/backends/chroot/chroot_file_system.dart b/lib/src/backends/chroot/chroot_file_system.dart
index ae5135d..963832a 100644
--- a/lib/src/backends/chroot/chroot_file_system.dart
+++ b/lib/src/backends/chroot/chroot_file_system.dart
@@ -61,13 +61,13 @@
 
   @override
   Directory directory(dynamic path) =>
-      new _ChrootDirectory(this, common.getPath(path));
+      new _ChrootDirectory(this, getPath(path));
 
   @override
-  File file(dynamic path) => new _ChrootFile(this, common.getPath(path));
+  File file(dynamic path) => new _ChrootFile(this, getPath(path));
 
   @override
-  Link link(dynamic path) => new _ChrootLink(this, common.getPath(path));
+  Link link(dynamic path) => new _ChrootLink(this, getPath(path));
 
   @override
   p.Context get path =>
diff --git a/lib/src/backends/chroot/chroot_link.dart b/lib/src/backends/chroot/chroot_link.dart
index e0ffa17..4fea186 100644
--- a/lib/src/backends/chroot/chroot_link.dart
+++ b/lib/src/backends/chroot/chroot_link.dart
@@ -41,4 +41,7 @@
 
   @override
   Link get absolute => new _ChrootLink(fileSystem, _absolutePath);
+
+  @override
+  String toString() => "ChrootLink: '$path'";
 }
diff --git a/lib/src/backends/local/local_file_system.dart b/lib/src/backends/local/local_file_system.dart
index 0751e79..cca5364 100644
--- a/lib/src/backends/local/local_file_system.dart
+++ b/lib/src/backends/local/local_file_system.dart
@@ -14,13 +14,13 @@
 
   @override
   Directory directory(dynamic path) =>
-      new _LocalDirectory(this, shim.newDirectory(path));
+      new _LocalDirectory(this, shim.newDirectory(getPath(path)));
 
   @override
-  File file(dynamic path) => new _LocalFile(this, shim.newFile(path));
+  File file(dynamic path) => new _LocalFile(this, shim.newFile(getPath(path)));
 
   @override
-  Link link(dynamic path) => new _LocalLink(this, shim.newLink(path));
+  Link link(dynamic path) => new _LocalLink(this, shim.newLink(getPath(path)));
 
   @override
   p.Context get path => new p.Context();
diff --git a/lib/src/backends/memory/memory_file_system.dart b/lib/src/backends/memory/memory_file_system.dart
index 4fa8578..74faaf6 100644
--- a/lib/src/backends/memory/memory_file_system.dart
+++ b/lib/src/backends/memory/memory_file_system.dart
@@ -61,13 +61,13 @@
 
   @override
   Directory directory(dynamic path) =>
-      new _MemoryDirectory(this, common.getPath(path));
+      new _MemoryDirectory(this, getPath(path));
 
   @override
-  File file(dynamic path) => new _MemoryFile(this, common.getPath(path));
+  File file(dynamic path) => new _MemoryFile(this, getPath(path));
 
   @override
-  Link link(dynamic path) => new _MemoryLink(this, common.getPath(path));
+  Link link(dynamic path) => new _MemoryLink(this, getPath(path));
 
   @override
   p.Context get path => new p.Context(style: p.Style.posix, current: _cwd);
diff --git a/lib/src/common.dart b/lib/src/common.dart
index 39b647f..eded17b 100644
--- a/lib/src/common.dart
+++ b/lib/src/common.dart
@@ -3,20 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'interface.dart';
-import 'io.dart' as io;
-
-/// Gets the string path represented by the specified generic [path].
-String getPath(dynamic path) {
-  if (path is io.FileSystemEntity) {
-    return path.path;
-  } else if (path is String) {
-    return path;
-  } else if (path is Uri) {
-    return path.toFilePath();
-  } else {
-    throw new ArgumentError('Invalid type for "path": ${path?.runtimeType}');
-  }
-}
 
 /// Returns a 'No such file or directory' [FileSystemException].
 FileSystemException noSuchFileOrDirectory(String path) {
diff --git a/lib/src/interface/file_system.dart b/lib/src/interface/file_system.dart
index 18f5a51..9e51256 100644
--- a/lib/src/interface/file_system.dart
+++ b/lib/src/interface/file_system.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 
+import 'package:meta/meta.dart';
 import 'package:path/path.dart' as p;
 
 import 'directory.dart';
@@ -144,4 +145,20 @@
   /// [io.FileSystemEntityType.LINK].
   bool isLinkSync(String path) =>
       typeSync(path) == io.FileSystemEntityType.LINK;
+
+  /// Gets the string path represented by the specified generic [path].
+  ///
+  /// [path] may be a [io.FileSystemEntity], a [String], or a [Uri].
+  @protected
+  String getPath(dynamic path) {
+    if (path is io.FileSystemEntity) {
+      return path.path;
+    } else if (path is String) {
+      return path;
+    } else if (path is Uri) {
+      return this.path.fromUri(path);
+    } else {
+      throw new ArgumentError('Invalid type for "path": ${path?.runtimeType}');
+    }
+  }
 }
diff --git a/lib/src/io/shim_dart_io.dart b/lib/src/io/shim_dart_io.dart
index 18744f0..0c1914a 100644
--- a/lib/src/io/shim_dart_io.dart
+++ b/lib/src/io/shim_dart_io.dart
@@ -3,20 +3,16 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
-
 import 'dart:io' as io;
 
-import 'package:file/src/common.dart' as common;
-
 /// Creates a new [io.Directory] with the specified [path].
-io.Directory newDirectory(dynamic path) =>
-    new io.Directory(common.getPath(path));
+io.Directory newDirectory(String path) => new io.Directory(path);
 
 /// Creates a new [io.File] with the specified [path].
-io.File newFile(dynamic path) => new io.File(common.getPath(path));
+io.File newFile(String path) => new io.File(path);
 
 /// Creates a new [io.Link] with the specified [path].
-io.Link newLink(dynamic path) => new io.Link(common.getPath(path));
+io.Link newLink(String path) => new io.Link(path);
 
 /// Wraps [io.Directory.systemTemp].
 io.Directory systemTemp() => io.Directory.systemTemp;
diff --git a/pubspec.yaml b/pubspec.yaml
index a63d8ed..49d686f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: file
-version: 2.3.1
+version: 2.3.2
 authors:
 - Matan Lurey <matanl@google.com>
 - Yegor Jbanov <yjbanov@google.com>
diff --git a/test/common_tests.dart b/test/common_tests.dart
index c87fd8a..a8082de 100644
--- a/test/common_tests.dart
+++ b/test/common_tests.dart
@@ -158,6 +158,12 @@
           expect(fs.directory(Uri.parse('file:///')), isDirectory);
         });
 
+        test('succeedsWithUriArgument', () {
+          fs.directory(ns('/foo')).createSync();
+          Uri uri = Uri.parse('file://${ns('/foo')}${fs.path.separator}');
+          expect(fs.directory(uri), exists);
+        });
+
         test('allowsDirectoryArgument', () {
           expect(fs.directory(new io.Directory(ns('/foo'))), isDirectory);
         });
@@ -176,6 +182,12 @@
           expect(fs.file(Uri.parse('file:///')), isFile);
         });
 
+        test('succeedsWithUriArgument', () {
+          fs.file(ns('/foo')).createSync();
+          Uri uri = Uri.parse('file://${ns('/foo')}');
+          expect(fs.file(uri), exists);
+        });
+
         test('allowsDirectoryArgument', () {
           expect(fs.file(new io.File(ns('/foo'))), isFile);
         });
@@ -194,6 +206,13 @@
           expect(fs.link(Uri.parse('file:///')), isLink);
         });
 
+        test('succeedsWithUriArgument', () {
+          fs.file(ns('/foo')).createSync();
+          fs.link(ns('/bar')).createSync(ns('/foo'));
+          Uri uri = Uri.parse('file://${ns('/bar')}');
+          expect(fs.link(uri), exists);
+        });
+
         test('allowsDirectoryArgument', () {
           expect(fs.link(new io.File(ns('/foo'))), isLink);
         });
diff --git a/test/local_test.dart b/test/local_test.dart
index b8b854c..3cfdf08 100644
--- a/test/local_test.dart
+++ b/test/local_test.dart
@@ -44,6 +44,9 @@
 
     Map<String, List<String>> skipOnPlatform = <String, List<String>>{
       'windows': <String>[
+        'FileSystem > directory > succeedsWithUriArgument',
+        'FileSystem > file > succeedsWithUriArgument',
+        'FileSystem > link > succeedsWithUriArgument',
         'FileSystem > currentDirectory > throwsIfHasNonExistentPathInComplexChain',
         'FileSystem > currentDirectory > staysAtRootIfSetToParentOfRoot',
         'FileSystem > currentDirectory > resolvesLinksIfEncountered',