[dart:io] Begins work on mocking support

Change-Id: I770ed9485a934af07e570fbad3f3fb84ebef973d
Reviewed-on: https://dart-review.googlesource.com/3302
Commit-Queue: Zach Anderson <zra@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Florian Loitsch <floitsch@google.com>
This commit is contained in:
Zachary Anderson 2017-10-10 17:39:12 +00:00 committed by commit-bot@chromium.org
parent c5ff5b4011
commit dcd275fa74
16 changed files with 1113 additions and 93 deletions

View file

@ -24,16 +24,18 @@
methods are now supported on iOS and OSX.
* Deprecated `SecurityContext.alpnSupported` as ALPN is now supported on all
platforms.
* Added 'timeout' parameter to 'Socket.connect', 'RawSocket.connect',
'SecureSocket.connect' and 'RawSecureSocket.connect. If a connection attempt
takes longer than the duration specified in 'timeout', a 'SocketException'
will be thrown. Note: if the duration specified in 'timeout' is greater than
the system level timeout duration, a timeout may occur sooner than specified
in 'timeout'.
* Added a `timeout` parameter to `Socket.connect`, `RawSocket.connect`,
`SecureSocket.connect` and `RawSecureSocket.connect`. If a connection attempt
takes longer than the duration specified in `timeout`, a `SocketException`
will be thrown. Note: if the duration specified in `timeout` is greater than
the OS level timeout, a timeout may occur sooner than specified in
`timeout`.
* Added `Platform.operatingSystemVersion` that gives a platform-specific
String describing the version of the operating system.
* Added `RawZLibFilter` for low-level access to compression and
decompression.
decompression routines.
* Added `IoOverrides` and `HttpOverrides` to aid in writing tests that wish to
mock varios `dart:io` objects.
* `dart:core`
* The `Uri` class now correctly handles paths while running on Node.js on

View file

@ -84,12 +84,12 @@ class FileStat {
@patch
class FileSystemEntity {
@patch
static _getType(_Namespace namespace, String path, bool followLinks) {
static _getTypeNative(_Namespace namespace, String path, bool followLinks) {
throw new UnsupportedError("FileSystemEntity._getType");
}
@patch
static _identical(_Namespace namespace, String path1, String path2) {
static _identicalNative(_Namespace namespace, String path1, String path2) {
throw new UnsupportedError("FileSystemEntity._identical");
}

View file

@ -13,10 +13,10 @@ class FileStat {
@patch
class FileSystemEntity {
@patch
static _getType(_Namespace namespace, String path, bool followLinks)
static _getTypeNative(_Namespace namespace, String path, bool followLinks)
native "File_GetType";
@patch
static _identical(_Namespace namespace, String path1, String path2)
static _identicalNative(_Namespace namespace, String path1, String path2)
native "File_AreIdentical";
@patch
static _resolveSymbolicLinks(_Namespace namespace, String path)

View file

@ -26,6 +26,7 @@ part 'http_headers.dart';
part 'http_impl.dart';
part 'http_parser.dart';
part 'http_session.dart';
part 'overrides.dart';
part 'websocket.dart';
part 'websocket_impl.dart';
@ -1363,7 +1364,13 @@ abstract class HttpClient {
*/
String userAgent;
factory HttpClient({SecurityContext context}) => new _HttpClient(context);
factory HttpClient({SecurityContext context}) {
HttpOverrides overrides = HttpOverrides.current;
if (overrides == null) {
return new _HttpClient(context);
}
return overrides.createHttpClient(context);
}
/**
* Opens a HTTP connection.
@ -1623,7 +1630,11 @@ abstract class HttpClient {
*/
static String findProxyFromEnvironment(Uri url,
{Map<String, String> environment}) {
return _HttpClient._findProxyFromEnvironment(url, environment);
HttpOverrides overrides = HttpOverrides.current;
if (overrides == null) {
return _HttpClient._findProxyFromEnvironment(url, environment);
}
return overrides.findProxyFromEnvironment(url, environment);
}
/**

View file

@ -12,6 +12,7 @@ http_sdk_sources = [
"http_impl.dart",
"http_parser.dart",
"http_session.dart",
"overrides.dart",
"websocket.dart",
"websocket_impl.dart",
]

View file

@ -0,0 +1,107 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._http;
final _httpOverridesToken = new Object();
const _asyncRunZoned = runZoned;
/// This class facilitates overriding [HttpClient] with a mock implementation.
/// It should be extended by another class in client code with overrides
/// that construct a mock implementation. The implementation in this base class
/// defaults to the actual [HttpClient] implementation. For example:
///
/// ```
/// class MyHttpClient implements HttpClient {
/// ...
/// // An implementation of the HttpClient interface
/// ...
/// }
///
/// main() {
/// HttpOverrides.runZoned(() {
/// ...
/// // Operations will use MyHttpClient instead of the real HttpClient
/// // implementation whenever HttpClient is used.
/// ...
/// }, createHttpClient: (SecurityContext c) => new MyHttpClient(c));
/// }
/// ```
abstract class HttpOverrides {
static HttpOverrides get current {
return Zone.current[_httpOverridesToken];
}
/// Runs [body] in a fresh [Zone] using the provided overrides.
static R runZoned<R>(R body(),
{HttpClient Function(SecurityContext) createHttpClient,
String Function(Uri uri, Map<String, String> environment)
findProxyFromEnvironment,
ZoneSpecification zoneSpecification,
Function onError}) {
HttpOverrides overrides =
new _HttpOverridesScope(createHttpClient, findProxyFromEnvironment);
return _asyncRunZoned<R>(body,
zoneValues: {_httpOverridesToken: overrides},
zoneSpecification: zoneSpecification,
onError: onError);
}
/// Runs [body] in a fresh [Zone] using the overrides found in [overrides].
///
/// Note that [overrides] should be an instance of a class that extends
/// [HttpOverrides].
static R runWithHttpOverrides<R>(R body(), HttpOverrides overrides,
{ZoneSpecification zoneSpecification, Function onError}) {
return _asyncRunZoned<R>(body,
zoneValues: {_httpOverridesToken: overrides},
zoneSpecification: zoneSpecification,
onError: onError);
}
/// Returns a new [HttpClient] using the given [context].
///
/// When this override is installed, this function overrides the behavior of
/// `new HttpClient`.
HttpClient createHttpClient(SecurityContext context) {
return new _HttpClient(context);
}
/// Resolves the proxy server to be used for HTTP connections.
///
/// When this override is installed, this function overrides the behavior of
/// `HttpClient.findProxyFromEnvironment`.
String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
return _HttpClient._findProxyFromEnvironment(url, environment);
}
}
class _HttpOverridesScope extends HttpOverrides {
final HttpOverrides _previous = HttpOverrides.current;
final HttpClient Function(SecurityContext) _createHttpClient;
final String Function(Uri uri, Map<String, String> environment)
_findProxyFromEnvironment;
_HttpOverridesScope(this._createHttpClient, this._findProxyFromEnvironment);
@override
HttpClient createHttpClient(SecurityContext context) {
if (_createHttpClient != null) return _createHttpClient(context);
if (_previous != null) return _previous.createHttpClient(context);
return super.createHttpClient(context);
}
@override
String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
if (_findProxyFromEnvironment != null) {
return _findProxyFromEnvironment(url, environment);
}
if (_previous != null) {
return _previous.findProxyFromEnvironment(url, environment);
}
return super.findProxyFromEnvironment(url, environment);
}
}

View file

@ -84,12 +84,12 @@ class FileStat {
@patch
class FileSystemEntity {
@patch
static _getType(_Namespace namespace, String path, bool followLinks) {
static _getTypeNative(_Namespace namespace, String path, bool followLinks) {
throw new UnsupportedError("FileSystemEntity._getType");
}
@patch
static _identical(_Namespace namespace, String path1, String path2) {
static _identicalNative(_Namespace namespace, String path1, String path2) {
throw new UnsupportedError("FileSystemEntity._identical");
}

View file

@ -126,7 +126,13 @@ abstract class Directory implements FileSystemEntity {
* If [path] is an absolute path, it will be immune to changes to the
* current working directory.
*/
factory Directory(String path) => new _Directory(path);
factory Directory(String path) {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return new _Directory(path);
}
return overrides.createDirectory(path);
}
/**
* Create a Directory object from a URI.
@ -139,7 +145,13 @@ abstract class Directory implements FileSystemEntity {
* Creates a directory object pointing to the current working
* directory.
*/
static Directory get current => _Directory.current;
static Directory get current {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _Directory.current;
}
return overrides.getCurrentDirectory();
}
/**
* Returns a [Uri] representing the directory's location.
@ -169,7 +181,12 @@ abstract class Directory implements FileSystemEntity {
* are working with the file system, can lead to unexpected results.
*/
static void set current(path) {
_Directory.current = path;
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
_Directory.current = path;
return;
}
overrides.setCurrentDirectory(path);
}
/**
@ -204,7 +221,13 @@ abstract class Directory implements FileSystemEntity {
* The location of the system temp directory is platform-dependent,
* and may be set by an environment variable.
*/
static Directory get systemTemp => _Directory.systemTemp;
static Directory get systemTemp {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _Directory.systemTemp;
}
return overrides.getSystemTempDirectory();
}
/**
* Creates a temporary directory in this directory. Additional random

View file

@ -219,7 +219,13 @@ abstract class File implements FileSystemEntity {
* If [path] is an absolute path, it will be immune to changes to the
* current working directory.
*/
factory File(String path) => new _File(path);
factory File(String path) {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return new _File(path);
}
return overrides.createFile(path);
}
/**
* Create a File object from a URI.

View file

@ -49,30 +49,40 @@ class FileStat {
/**
* The time of the last change to the data or metadata of the file system
* object. On Windows platforms, this is instead the file creation time.
* object.
*
* On Windows platforms, this is instead the file creation time.
*/
final DateTime changed;
/**
* The time of the last change to the data of the file system
* object.
* The time of the last change to the data of the file system object.
*/
final DateTime modified;
/**
* The time of the last access to the data of the file system
* object. On Windows platforms, this may have 1 day granularity, and be
* The time of the last access to the data of the file system object.
*
* On Windows platforms, this may have 1 day granularity, and be
* out of date by an hour.
*/
final DateTime accessed;
/**
* The type of the object (file, directory, or link). If the call to
* stat() fails, the type of the returned object is NOT_FOUND.
* The type of the object (file, directory, or link).
*
* If the call to stat() fails, the type of the returned object is NOT_FOUND.
*/
final FileSystemEntityType type;
/**
* The mode of the file system object. Permissions are encoded in the lower
* 16 bits of this number, and can be decoded using the [modeString] getter.
* The mode of the file system object.
*
* Permissions are encoded in the lower 16 bits of this number, and can be
* decoded using the [modeString] getter.
*/
final int mode;
/**
* The size of the file system object.
*/
@ -93,11 +103,20 @@ class FileStat {
/**
* Calls the operating system's stat() function on [path].
*
* Returns a [FileStat] object containing the data returned by stat().
* If the call fails, returns a [FileStat] object with .type set to
* FileSystemEntityType.NOT_FOUND and the other fields invalid.
*/
static FileStat statSync(String path) {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _statSyncInternal(path);
}
return overrides.statSync(path);
}
static FileStat _statSyncInternal(String path) {
// Trailing path is not supported on Windows.
if (Platform.isWindows) {
path = FileSystemEntity._trimTrailingPathSeparators(path);
@ -115,12 +134,21 @@ class FileStat {
/**
* Asynchronously calls the operating system's stat() function on [path].
*
* Returns a Future which completes with a [FileStat] object containing
* the data returned by stat().
* If the call fails, completes the future with a [FileStat] object with
* .type set to FileSystemEntityType.NOT_FOUND and the other fields invalid.
* the data returned by stat(). If the call fails, completes the future with a
* [FileStat] object with `.type` set to FileSystemEntityType.NOT_FOUND and
* the other fields invalid.
*/
static Future<FileStat> stat(String path) {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _stat(path);
}
return overrides.stat(path);
}
static Future<FileStat> _stat(String path) {
// Trailing path is not supported on Windows.
if (Platform.isWindows) {
path = FileSystemEntity._trimTrailingPathSeparators(path);
@ -151,11 +179,13 @@ FileStat: type $type
size $size""";
/**
* Returns the mode value as a human-readable string, in the format
* "rwxrwxrwx", reflecting the user, group, and world permissions to
* read, write, and execute the file system object, with "-" replacing the
* letter for missing permissions. Extra permission bits may be represented
* by prepending "(suid)", "(guid)", and/or "(sticky)" to the mode string.
* Returns the mode value as a human-readable string.
*
* The string is in the format "rwxrwxrwx", reflecting the user, group, and
* world permissions to read, write, and execute the file system object, with
* "-" replacing the letter for missing permissions. Extra permission bits
* may be represented by prepending "(suid)", "(guid)", and/or "(sticky)" to
* the mode string.
*/
String modeString() {
var permissions = mode & 0xFFF;
@ -255,9 +285,10 @@ abstract class FileSystemEntity {
bool existsSync();
/**
* Renames this file system entity. Returns a `Future<FileSystemEntity>`
* that completes with a [FileSystemEntity] instance for the renamed
* file system entity.
* Renames this file system entity.
*
* Returns a `Future<FileSystemEntity>` that completes with a
* [FileSystemEntity] instance for the renamed file system entity.
*
* If [newPath] identifies an existing entity of the same type, that entity
* is replaced. If [newPath] identifies an existing entity of a different
@ -266,8 +297,9 @@ abstract class FileSystemEntity {
Future<FileSystemEntity> rename(String newPath);
/**
* Synchronously renames this file system entity. Returns a [FileSystemEntity]
* instance for the renamed entity.
* Synchronously renames this file system entity.
*
* Returns a [FileSystemEntity] instance for the renamed entity.
*
* If [newPath] identifies an existing entity of the same type, that entity
* is replaced. If [newPath] identifies an existing entity of a different
@ -277,8 +309,10 @@ abstract class FileSystemEntity {
/**
* Resolves the path of a file system object relative to the
* current working directory, resolving all symbolic links on
* the path and resolving all `..` and `.` path segments.
* current working directory.
*
* Resolves all symbolic links on the path and resolves all `..` and `.` path
* segments.
*
* [resolveSymbolicLinks] uses the operating system's native
* file system API to resolve the path, using the `realpath` function
@ -316,8 +350,10 @@ abstract class FileSystemEntity {
/**
* Resolves the path of a file system object relative to the
* current working directory, resolving all symbolic links on
* the path and resolving all `..` and `.` path segments.
* current working directory.
*
* Resolves all symbolic links on the path and resolves all `..` and `.` path
* segments.
*
* [resolveSymbolicLinksSync] uses the operating system's native
* file system API to resolve the path, using the `realpath` function
@ -349,7 +385,9 @@ abstract class FileSystemEntity {
/**
* Calls the operating system's stat() function on the [path] of this
* [FileSystemEntity]. Identical to [:FileStat.stat(this.path):].
* [FileSystemEntity].
*
* Identical to [:FileStat.stat(this.path):].
*
* Returns a [:Future<FileStat>:] object containing the data returned by
* stat().
@ -363,6 +401,7 @@ abstract class FileSystemEntity {
/**
* Synchronously calls the operating system's stat() function on the
* [path] of this [FileSystemEntity].
*
* Identical to [:FileStat.statSync(this.path):].
*
* Returns a [FileStat] object containing the data returned by stat().
@ -443,16 +482,34 @@ abstract class FileSystemEntity {
* A move event may be reported as seperate delete and create events.
*/
Stream<FileSystemEvent> watch(
{int events: FileSystemEvent.ALL, bool recursive: false}) =>
_FileSystemWatcher._watch(
_trimTrailingPathSeparators(path), events, recursive);
{int events: FileSystemEvent.ALL, bool recursive: false}) {
final String trimmedPath = _trimTrailingPathSeparators(path);
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _FileSystemWatcher._watch(trimmedPath, events, recursive);
}
return overrides.fsWatch(trimmedPath, events, recursive);
}
Future<FileSystemEntity> _delete({bool recursive: false});
void _deleteSync({bool recursive: false});
static Future<bool> _identical(String path1, String path2) {
return _File._dispatchWithNamespace(
_FILE_IDENTICAL, [null, path1, path2]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
"Error in FileSystemEntity.identical($path1, $path2)", "");
}
return response;
});
}
/**
* Checks whether two paths refer to the same object in the
* file system. Returns a [:Future<bool>:] that completes with the result.
* file system.
*
* Returns a [:Future<bool>:] that completes with the result.
*
* Comparing a link to its target returns false, as does comparing two links
* that point to the same target. To check the target of a link, use
@ -463,14 +520,11 @@ abstract class FileSystemEntity {
* to an object that does not exist.
*/
static Future<bool> identical(String path1, String path2) {
return _File._dispatchWithNamespace(
_FILE_IDENTICAL, [null, path1, path2]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
"Error in FileSystemEntity.identical($path1, $path2)", "");
}
return response;
});
IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _identical(path1, path2);
}
return overrides.fseIdentical(path1, path2);
}
static final RegExp _absoluteWindowsPathPattern =
@ -493,6 +547,7 @@ abstract class FileSystemEntity {
/**
* Returns a [FileSystemEntity] whose path is the absolute path to [this].
*
* The type of the returned instance is the type of [this].
*
* The absolute path is computed by prefixing
@ -512,6 +567,12 @@ abstract class FileSystemEntity {
}
}
static bool _identicalSync(String path1, String path2) {
var result = _identicalNative(_Namespace._namespace, path1, path2);
_throwIfError(result, 'Error in FileSystemEntity.identicalSync');
return result;
}
/**
* Synchronously checks whether two paths refer to the same object in the
* file system.
@ -525,9 +586,11 @@ abstract class FileSystemEntity {
* exist.
*/
static bool identicalSync(String path1, String path2) {
var result = _identical(_Namespace._namespace, path1, path2);
_throwIfError(result, 'Error in FileSystemEntity.identicalSync');
return result;
IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _identicalSync(path1, path2);
}
return overrides.fseIdenticalSync(path1, path2);
}
/**
@ -535,11 +598,18 @@ abstract class FileSystemEntity {
*
* OS X 10.6 and below is not supported.
*/
static bool get isWatchSupported => _FileSystemWatcher.isSupported;
static bool get isWatchSupported {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _FileSystemWatcher.isSupported;
}
return overrides.fsWatchIsSupported();
}
/**
* Finds the type of file system object that a path points to. Returns
* a [:Future<FileSystemEntityType>:] that completes with the result.
* Finds the type of file system object that a path points to.
*
* Returns a [:Future<FileSystemEntityType>:] that completes with the result.
*
* [FileSystemEntityType] has the constant instances FILE, DIRECTORY,
* LINK, and NOT_FOUND. [type] will return LINK only if the optional
@ -550,11 +620,13 @@ abstract class FileSystemEntity {
* caused by passing the wrong type of arguments to the function.
*/
static Future<FileSystemEntityType> type(String path,
{bool followLinks: true}) =>
_getTypeAsync(path, followLinks).then(FileSystemEntityType._lookup);
{bool followLinks: true}) {
return _getType(path, followLinks);
}
/**
* Synchronously finds the type of file system object that a path points to.
*
* Returns a [FileSystemEntityType].
*
* [FileSystemEntityType] has the constant instances FILE, DIRECTORY,
@ -565,51 +637,53 @@ abstract class FileSystemEntity {
* error or exception that may be thrown is ArgumentError,
* caused by passing the wrong type of arguments to the function.
*/
static FileSystemEntityType typeSync(String path, {bool followLinks: true}) =>
FileSystemEntityType._lookup(_getTypeSync(path, followLinks));
static FileSystemEntityType typeSync(String path, {bool followLinks: true}) {
return _getTypeSync(path, followLinks);
}
/**
* Checks if type(path, followLinks: false) returns
* FileSystemEntityType.LINK.
* Checks if type(path, followLinks: false) returns FileSystemEntityType.LINK.
*/
static Future<bool> isLink(String path) => _getTypeAsync(path, false)
.then((type) => (type == FileSystemEntityType.LINK._type));
static Future<bool> isLink(String path) =>
_getType(path, false).then((type) => (type == FileSystemEntityType.LINK));
/**
* Checks if type(path) returns FileSystemEntityType.FILE.
*/
static Future<bool> isFile(String path) => _getTypeAsync(path, true)
.then((type) => (type == FileSystemEntityType.FILE._type));
static Future<bool> isFile(String path) =>
_getType(path, true).then((type) => (type == FileSystemEntityType.FILE));
/**
* Checks if type(path) returns FileSystemEntityType.DIRECTORY.
*/
static Future<bool> isDirectory(String path) => _getTypeAsync(path, true)
.then((type) => (type == FileSystemEntityType.DIRECTORY._type));
static Future<bool> isDirectory(String path) => _getType(path, true)
.then((type) => (type == FileSystemEntityType.DIRECTORY));
/**
* Synchronously checks if typeSync(path, followLinks: false) returns
* FileSystemEntityType.LINK.
*/
static bool isLinkSync(String path) =>
(_getTypeSync(path, false) == FileSystemEntityType.LINK._type);
(_getTypeSync(path, false) == FileSystemEntityType.LINK);
/**
* Synchronously checks if typeSync(path) returns
* FileSystemEntityType.FILE.
*/
static bool isFileSync(String path) =>
(_getTypeSync(path, true) == FileSystemEntityType.FILE._type);
(_getTypeSync(path, true) == FileSystemEntityType.FILE);
/**
* Synchronously checks if typeSync(path) returns
* FileSystemEntityType.DIRECTORY.
*/
static bool isDirectorySync(String path) =>
(_getTypeSync(path, true) == FileSystemEntityType.DIRECTORY._type);
(_getTypeSync(path, true) == FileSystemEntityType.DIRECTORY);
external static _getType(_Namespace namespace, String path, bool followLinks);
external static _identical(_Namespace namespace, String path1, String path2);
external static _getTypeNative(
_Namespace namespace, String path, bool followLinks);
external static _identicalNative(
_Namespace namespace, String path1, String path2);
external static _resolveSymbolicLinks(_Namespace namespace, String path);
// Finds the next-to-last component when dividing at path separators.
@ -619,9 +693,11 @@ abstract class FileSystemEntity {
/**
* Removes the final path component of a path, using the platform's
* path separator to split the path. Will not remove the root component
* of a Windows path, like "C:\\" or "\\\\server_name\\".
* Ignores trailing path separators, and leaves no trailing path separators.
* path separator to split the path.
*
* Will not remove the root component of a Windows path, like "C:\\" or
* "\\\\server_name\\". Ignores trailing path separators, and leaves no
* trailing path separators.
*/
static String parentOf(String path) {
int rootEnd = -1;
@ -653,22 +729,40 @@ abstract class FileSystemEntity {
*/
Directory get parent => new Directory(parentOf(path));
static int _getTypeSync(String path, bool followLinks) {
var result = _getType(_Namespace._namespace, path, followLinks);
static FileSystemEntityType _getTypeSyncHelper(
String path, bool followLinks) {
var result = _getTypeNative(_Namespace._namespace, path, followLinks);
_throwIfError(result, 'Error getting type of FileSystemEntity');
return result;
return FileSystemEntityType._lookup(result);
}
static Future<int> _getTypeAsync(String path, bool followLinks) {
static FileSystemEntityType _getTypeSync(String path, bool followLinks) {
IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _getTypeSyncHelper(path, followLinks);
}
return overrides.fseGetTypeSync(path, followLinks);
}
static Future<FileSystemEntityType> _getTypeRequest(
String path, bool followLinks) {
return _File._dispatchWithNamespace(
_FILE_TYPE, [null, path, followLinks]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "Error getting type", path);
}
return response;
return FileSystemEntityType._lookup(response);
});
}
static Future<FileSystemEntityType> _getType(String path, bool followLinks) {
IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return _getTypeRequest(path, followLinks);
}
return overrides.fseGetType(path, followLinks);
}
static _throwIfError(Object result, String msg, [String path]) {
if (result is OSError) {
throw new FileSystemException(msg, path, result);
@ -750,8 +844,10 @@ class FileSystemEvent {
final int type;
/**
* The path that triggered the event. Depending on the platform and the
* FileSystemEntity, the path may be relative.
* The path that triggered the event.
*
* Depending on the platform and the FileSystemEntity, the path may be
* relative.
*/
final String path;

View file

@ -220,6 +220,7 @@ part 'io_sink.dart';
part 'io_service.dart';
part 'link.dart';
part 'namespace_impl.dart';
part 'overrides.dart';
part 'platform.dart';
part 'platform_impl.dart';
part 'process.dart';

View file

@ -21,6 +21,7 @@ io_sdk_sources = [
"io_service.dart",
"link.dart",
"namespace_impl.dart",
"overrides.dart",
"platform.dart",
"platform_impl.dart",
"process.dart",

View file

@ -12,7 +12,13 @@ abstract class Link implements FileSystemEntity {
/**
* Creates a Link object.
*/
factory Link(String path) => new _Link(path);
factory Link(String path) {
final IoOverrides overrides = IoOverrides.current;
if (overrides == null) {
return new _Link(path);
}
return overrides.createLink(path);
}
/**
* Creates a [Link] object.

395
sdk/lib/io/overrides.dart Normal file
View file

@ -0,0 +1,395 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
final _ioOverridesToken = new Object();
const _asyncRunZoned = runZoned;
/// This class facilitates overriding various APIs of dart:io with mock
/// implementations.
///
/// This abstract base class should be extended with overrides for the
/// operations needed to construct mocks. The implementations in this base class
/// default to the actual dart:io implementation. For example:
///
/// ```
/// class MyDirectory implements Directory {
/// ...
/// // An implementation of the Directory interface
/// ...
/// }
///
/// main() {
/// IoOverrides.runZoned(() {
/// ...
/// // Operations will use MyDirectory instead of dart:io's Directory
/// // implementation whenever Directory is used.
/// ...
/// }, createDirectory: (String path) => new MyDirectory(path));
/// }
/// ```
abstract class IoOverrides {
static IoOverrides get current {
return Zone.current[_ioOverridesToken];
}
/// Runs [body] in a fresh [Zone] using the provided overrides.
///
/// See the documentation on the corresponding methods of IoOverrides for
/// information about what the optional arguments do.
static R runZoned<R>(R body(),
{
// Directory
Directory Function(String) createDirectory,
Directory Function() getCurrentDirectory,
void Function(String) setCurrentDirectory,
Directory Function() getSystemTempDirectory,
// File
File Function(String) createFile,
// FileStat
Future<FileStat> Function(String) stat,
FileStat Function(String) statSync,
// FileSystemEntity
Future<bool> Function(String, String) fseIdentical,
bool Function(String, String) fseIdenticalSync,
Future<FileSystemEntityType> Function(String, bool) fseGetType,
FileSystemEntityType Function(String, bool) fseGetTypeSync,
// _FileSystemWatcher
Stream<FileSystemEvent> Function(String, int, bool) fsWatch,
bool Function() fsWatchIsSupported,
// Link
Link Function(String) createLink,
// Optional Zone parameters
ZoneSpecification zoneSpecification,
Function onError}) {
IoOverrides overrides = new _IoOverridesScope(
// Directory
createDirectory,
getCurrentDirectory,
setCurrentDirectory,
getSystemTempDirectory,
// File
createFile,
// FileStat
stat,
statSync,
// FileSystemEntity
fseIdentical,
fseIdenticalSync,
fseGetType,
fseGetTypeSync,
// _FileSystemWatcher
fsWatch,
fsWatchIsSupported,
// Link
createLink,
);
return _asyncRunZoned<R>(body,
zoneValues: {_ioOverridesToken: overrides},
zoneSpecification: zoneSpecification,
onError: onError);
}
/// Runs [body] in a fresh [Zone] using the overrides found in [overrides].
///
/// Note that [overrides] should be an instance of a class that extends
/// [IoOverrides].
static R runWithIoOverrides<R>(R body(), IoOverrides overrides,
{ZoneSpecification zoneSpecification, Function onError}) {
return _asyncRunZoned<R>(body,
zoneValues: {_ioOverridesToken: overrides},
zoneSpecification: zoneSpecification,
onError: onError);
}
// Directory
/// Creates a new [Directory] object for the given [path].
///
/// When this override is installed, this function overrides the behavior of
/// `new Directory()` and `new Directory.fromUri()`.
Directory createDirectory(String path) => new _Directory(path);
/// Returns the current working directory.
///
/// When this override is installed, this function overrides the behavior of
/// the static getter `Directory.current`
Directory getCurrentDirectory() => _Directory.current;
/// Sets the current working directory to be [path].
///
/// When this override is installed, this function overrides the behavior of
/// the setter `Directory.current`.
void setCurrentDirectory(String path) {
_Directory.current = path;
}
/// Returns the system temporary directory.
///
/// When this override is installed, this function overrides the behavior of
/// `Directory.systemTemp`.
Directory getSystemTempDirectory() => _Directory.systemTemp;
// File
/// Creates a new [File] object for the given [path].
///
/// When this override is installed, this function overrides the behavior of
/// `new File()` and `new File.fromUri()`.
File createFile(String path) => new _File(path);
// FileStat
/// Asynchronously returns [FileStat] information for [path].
///
/// When this override is installed, this function overrides the behavior of
/// `FileStat.stat()`.
Future<FileStat> stat(String path) {
return FileStat._stat(path);
}
/// Returns [FileStat] information for [path].
///
/// When this override is installed, this function overrides the behavior of
/// `FileStat.statSync()`.
FileStat statSync(String path) {
return FileStat._statSyncInternal(path);
}
// FileSystemEntity
/// Asynchronously returns `true` if [path1] and [path2] are paths to the
/// same file system object.
///
/// When this override is installed, this function overrides the behavior of
/// `FileSystemEntity.identical`.
Future<bool> fseIdentical(String path1, String path2) {
return FileSystemEntity._identical(path1, path2);
}
/// Returns `true` if [path1] and [path2] are paths to the
/// same file system object.
///
/// When this override is installed, this function overrides the behavior of
/// `FileSystemEntity.identicalSync`.
bool fseIdenticalSync(String path1, String path2) {
return FileSystemEntity._identicalSync(path1, path2);
}
/// Asynchronously returns the [FileSystemEntityType] for [path].
///
/// When this override is installed, this function overrides the behavior of
/// `FileSystemEntity.type`.
Future<FileSystemEntityType> fseGetType(String path, bool followLinks) {
return FileSystemEntity._getTypeRequest(path, followLinks);
}
/// Returns the [FileSystemEntityType] for [path].
///
/// When this override is installed, this function overrides the behavior of
/// `FileSystemEntity.typeSync`.
FileSystemEntityType fseGetTypeSync(String path, bool followLinks) {
return FileSystemEntity._getTypeSyncHelper(path, followLinks);
}
// _FileSystemWatcher
/// Returns a [Stream] of [FileSystemEvent]s.
///
/// When this override is installed, this function overrides the behavior of
/// `FileSystemEntity.watch()`.
Stream<FileSystemEvent> fsWatch(String path, int events, bool recursive) {
return _FileSystemWatcher._watch(path, events, recursive);
}
/// Returns `true` when [FileSystemEntity.watch] is supported.
///
/// When this override is installed, this function overrides the behavior of
/// `FileSystemEntity.isWatchSupported`.
bool fsWatchIsSupported() => _FileSystemWatcher.isSupported;
// Link
/// Returns a new [Link] object for the given [path].
/// When this override is installed, this function overrides the behavior of
/// `new Link()` and `new Link.fromUri()`.
Link createLink(String path) => new _Link(path);
}
class _IoOverridesScope extends IoOverrides {
final IoOverrides _previous = IoOverrides.current;
// Directory
Directory Function(String) _createDirectory;
Directory Function() _getCurrentDirectory;
void Function(String) _setCurrentDirectory;
Directory Function() _getSystemTempDirectory;
// File
File Function(String) _createFile;
// FileStat
Future<FileStat> Function(String) _stat;
FileStat Function(String) _statSync;
// FileSystemEntity
Future<bool> Function(String, String) _fseIdentical;
bool Function(String, String) _fseIdenticalSync;
Future<FileSystemEntityType> Function(String, bool) _fseGetType;
FileSystemEntityType Function(String, bool) _fseGetTypeSync;
// _FileSystemWatcher
Stream<FileSystemEvent> Function(String, int, bool) _fsWatch;
bool Function() _fsWatchIsSupported;
// Link
Link Function(String) _createLink;
_IoOverridesScope(
// Directory
this._createDirectory,
this._getCurrentDirectory,
this._setCurrentDirectory,
this._getSystemTempDirectory,
// File
this._createFile,
// FileStat
this._stat,
this._statSync,
// FileSystemEntity
this._fseIdentical,
this._fseIdenticalSync,
this._fseGetType,
this._fseGetTypeSync,
// _FileSystemWatcher
this._fsWatch,
this._fsWatchIsSupported,
// Link
this._createLink,
);
// Directory
@override
Directory createDirectory(String path) {
if (_createDirectory != null) return _createDirectory(path);
if (_previous != null) return _previous.createDirectory(path);
return super.createDirectory(path);
}
@override
Directory getCurrentDirectory() {
if (_getCurrentDirectory != null) return _getCurrentDirectory();
if (_previous != null) return _previous.getCurrentDirectory();
return super.getCurrentDirectory();
}
@override
void setCurrentDirectory(String path) {
if (_setCurrentDirectory != null)
_setCurrentDirectory(path);
else if (_previous != null)
_previous.setCurrentDirectory(path);
else
super.setCurrentDirectory(path);
}
@override
Directory getSystemTempDirectory() {
if (_getSystemTempDirectory != null) return _getSystemTempDirectory();
if (_previous != null) return _previous.getSystemTempDirectory();
return super.getSystemTempDirectory();
}
// File
@override
File createFile(String path) {
if (_createFile != null) return _createFile(path);
if (_previous != null) return _previous.createFile(path);
return super.createFile(path);
}
// FileStat
@override
Future<FileStat> stat(String path) {
if (_stat != null) return _stat(path);
if (_previous != null) return _previous.stat(path);
return super.stat(path);
}
@override
FileStat statSync(String path) {
if (_stat != null) return _statSync(path);
if (_previous != null) return _previous.statSync(path);
return super.statSync(path);
}
// FileSystemEntity
@override
Future<bool> fseIdentical(String path1, String path2) {
if (_fseIdentical != null) return _fseIdentical(path1, path2);
if (_previous != null) return _previous.fseIdentical(path1, path2);
return super.fseIdentical(path1, path2);
}
@override
bool fseIdenticalSync(String path1, String path2) {
if (_fseIdenticalSync != null) return _fseIdenticalSync(path1, path2);
if (_previous != null) return _previous.fseIdenticalSync(path1, path2);
return super.fseIdenticalSync(path1, path2);
}
@override
Future<FileSystemEntityType> fseGetType(String path, bool followLinks) {
if (_fseGetType != null) return _fseGetType(path, followLinks);
if (_previous != null) return _previous.fseGetType(path, followLinks);
return super.fseGetType(path, followLinks);
}
@override
FileSystemEntityType fseGetTypeSync(String path, bool followLinks) {
if (_fseGetTypeSync != null) return _fseGetTypeSync(path, followLinks);
if (_previous != null) return _previous.fseGetTypeSync(path, followLinks);
return super.fseGetTypeSync(path, followLinks);
}
// _FileSystemWatcher
@override
Stream<FileSystemEvent> fsWatch(String path, int events, bool recursive) {
if (_fsWatch != null) return _fsWatch(path, events, recursive);
if (_previous != null) return _previous.fsWatch(path, events, recursive);
return super.fsWatch(path, events, recursive);
}
bool fsWatchIsSupported() {
if (_fsWatchIsSupported != null) return _fsWatchIsSupported();
if (_previous != null) return _previous.fsWatchIsSupported();
return super.fsWatchIsSupported();
}
// Link
@override
Link createLink(String path) {
if (_createLink != null) return _createLink(path);
if (_previous != null) return _previous.createLink(path);
return super.createLink(path);
}
}

View file

@ -0,0 +1,178 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import "package:expect/expect.dart";
class MyHttpClient1 implements HttpClient {
String userAgent = "MyHttpClient1";
MyHttpClient1(SecurityContext context);
Duration idleTimeout;
int maxConnectionsPerHost;
bool autoUncompress;
Future<HttpClientRequest> open(
String method, String host, int port, String path) =>
null;
Future<HttpClientRequest> openUrl(String method, Uri url) => null;
Future<HttpClientRequest> get(String host, int port, String path) => null;
Future<HttpClientRequest> getUrl(Uri url) => null;
Future<HttpClientRequest> post(String host, int port, String path) => null;
Future<HttpClientRequest> postUrl(Uri url) => null;
Future<HttpClientRequest> put(String host, int port, String path) => null;
Future<HttpClientRequest> putUrl(Uri url) => null;
Future<HttpClientRequest> delete(String host, int port, String path) => null;
Future<HttpClientRequest> deleteUrl(Uri url) => null;
Future<HttpClientRequest> patch(String host, int port, String path) => null;
Future<HttpClientRequest> patchUrl(Uri url) => null;
Future<HttpClientRequest> head(String host, int port, String path) => null;
Future<HttpClientRequest> headUrl(Uri url) => null;
set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {}
void addCredentials(
Uri url, String realm, HttpClientCredentials credentials) {}
set findProxy(String f(Uri url)) {}
set authenticateProxy(
Future<bool> f(String host, int port, String scheme, String realm)) {}
void addProxyCredentials(
String host, int port, String realm, HttpClientCredentials credentials) {}
set badCertificateCallback(
bool callback(X509Certificate cert, String host, int port)) {}
void close({bool force: false}) {}
}
class MyHttpClient2 implements HttpClient {
String userAgent = "MyHttpClient2";
MyHttpClient2(SecurityContext context);
Duration idleTimeout;
int maxConnectionsPerHost;
bool autoUncompress;
Future<HttpClientRequest> open(
String method, String host, int port, String path) =>
null;
Future<HttpClientRequest> openUrl(String method, Uri url) => null;
Future<HttpClientRequest> get(String host, int port, String path) => null;
Future<HttpClientRequest> getUrl(Uri url) => null;
Future<HttpClientRequest> post(String host, int port, String path) => null;
Future<HttpClientRequest> postUrl(Uri url) => null;
Future<HttpClientRequest> put(String host, int port, String path) => null;
Future<HttpClientRequest> putUrl(Uri url) => null;
Future<HttpClientRequest> delete(String host, int port, String path) => null;
Future<HttpClientRequest> deleteUrl(Uri url) => null;
Future<HttpClientRequest> patch(String host, int port, String path) => null;
Future<HttpClientRequest> patchUrl(Uri url) => null;
Future<HttpClientRequest> head(String host, int port, String path) => null;
Future<HttpClientRequest> headUrl(Uri url) => null;
set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {}
void addCredentials(
Uri url, String realm, HttpClientCredentials credentials) {}
set findProxy(String f(Uri url)) {}
set authenticateProxy(
Future<bool> f(String host, int port, String scheme, String realm)) {}
void addProxyCredentials(
String host, int port, String realm, HttpClientCredentials credentials) {}
set badCertificateCallback(
bool callback(X509Certificate cert, String host, int port)) {}
void close({bool force: false}) {}
}
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext context) {
return new MyHttpClient1(context);
}
}
HttpClient myCreateHttp1Client(SecurityContext context) {
return new MyHttpClient1(context);
}
HttpClient myCreateHttp2Client(SecurityContext context) {
return new MyHttpClient2(context);
}
String myFindProxyFromEnvironment(Uri url, Map<String, String> environment) {
return "proxy";
}
withHttpOverridesTest() {
HttpOverrides.runZoned(() {
var httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient1);
Expect.equals((new MyHttpClient1(null)).userAgent, httpClient.userAgent);
}, createHttpClient: myCreateHttp1Client);
var httpClient = new HttpClient();
Expect.isTrue(httpClient is HttpClient);
Expect.isTrue(httpClient is! MyHttpClient1);
}
nestedWithHttpOverridesTest() {
HttpOverrides.runZoned(() {
var httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient1);
Expect.equals((new MyHttpClient1(null)).userAgent, httpClient.userAgent);
HttpOverrides.runZoned(() {
var httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient2);
Expect.equals((new MyHttpClient2(null)).userAgent, httpClient.userAgent);
}, createHttpClient: myCreateHttp2Client);
httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient1);
Expect.equals((new MyHttpClient1(null)).userAgent, httpClient.userAgent);
}, createHttpClient: myCreateHttp1Client);
var httpClient = new HttpClient();
Expect.isTrue(httpClient is HttpClient);
Expect.isTrue(httpClient is! MyHttpClient1);
Expect.isTrue(httpClient is! MyHttpClient2);
}
nestedDifferentOverridesTest() {
HttpOverrides.runZoned(() {
var httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient1);
Expect.equals((new MyHttpClient1(null)).userAgent, httpClient.userAgent);
HttpOverrides.runZoned(() {
var httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient1);
Expect.equals((new MyHttpClient1(null)).userAgent, httpClient.userAgent);
Expect.equals(myFindProxyFromEnvironment(null, null),
HttpClient.findProxyFromEnvironment(null));
}, findProxyFromEnvironment: myFindProxyFromEnvironment);
httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient1);
Expect.equals((new MyHttpClient1(null)).userAgent, httpClient.userAgent);
}, createHttpClient: myCreateHttp1Client);
var httpClient = new HttpClient();
Expect.isTrue(httpClient is HttpClient);
Expect.isTrue(httpClient is! MyHttpClient1);
Expect.isTrue(httpClient is! MyHttpClient2);
}
zonedWithHttpOverridesTest() {
HttpOverrides.runWithHttpOverrides(() {
var httpClient = new HttpClient();
Expect.isNotNull(httpClient);
Expect.isTrue(httpClient is MyHttpClient1);
Expect.equals((new MyHttpClient1(null)).userAgent, httpClient.userAgent);
}, new MyHttpOverrides());
}
main() {
withHttpOverridesTest();
nestedWithHttpOverridesTest();
nestedDifferentOverridesTest();
zonedWithHttpOverridesTest();
}

View file

@ -0,0 +1,193 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import "package:expect/expect.dart";
class DirectoryMock extends FileSystemEntity implements Directory {
final String path = "/mockdir";
DirectoryMock(String path);
static DirectoryMock createDirectory(String path) => new DirectoryMock(path);
static DirectoryMock getCurrent() => new DirectoryMock(null);
static void setCurrent(String path) {}
static DirectoryMock getSystemTemp() => new DirectoryMock(null);
Uri get uri => null;
Future<Directory> create({bool recursive: false}) => null;
void createSync({bool recursive: false}) {}
Future<Directory> createTemp([String prefix]) => null;
Directory createTempSync([String prefix]) => null;
Future<String> resolveSymbolicLinks() => null;
String resolveSymbolicLinksSync() => null;
Future<Directory> rename(String newPath) => null;
Directory renameSync(String newPath) => null;
Directory get absolute => null;
Stream<FileSystemEntity> list(
{bool recursive: false, bool followLinks: true}) =>
null;
List<FileSystemEntity> listSync(
{bool recursive: false, bool followLinks: true}) =>
null;
}
class FileMock extends FileSystemEntity implements File {
String get path => "/mockfile";
FileMock(String path);
static FileMock createFile(String path) => new FileMock(path);
Future<File> create({bool recursive: false}) => null;
void createSync({bool recursive: false}) {}
Future<File> rename(String newPath) => null;
File renameSync(String newPath) => null;
Future<File> copy(String newPath) => null;
File copySync(String newPath) => null;
Future<int> length() => null;
int lengthSync() => null;
File get absolute => null;
Future<DateTime> lastAccessed() => null;
DateTime lastAccessedSync() => null;
Future setLastAccessed(DateTime time) => null;
void setLastAccessedSync(DateTime time) {}
Future<DateTime> lastModified() => null;
DateTime lastModifiedSync() => null;
Future setLastModified(DateTime time) => null;
void setLastModifiedSync(DateTime time) {}
Future<RandomAccessFile> open({FileMode mode: FileMode.READ}) => null;
RandomAccessFile openSync({FileMode mode: FileMode.READ}) => null;
Stream<List<int>> openRead([int start, int end]) => null;
IOSink openWrite({FileMode mode: FileMode.WRITE, Encoding encoding: UTF8}) =>
null;
Future<List<int>> readAsBytes() => null;
List<int> readAsBytesSync() => null;
Future<String> readAsString({Encoding encoding: UTF8}) => null;
String readAsStringSync({Encoding encoding: UTF8}) => null;
Future<List<String>> readAsLines({Encoding encoding: UTF8}) => null;
List<String> readAsLinesSync({Encoding encoding: UTF8}) => null;
Future<File> writeAsBytes(List<int> bytes,
{FileMode mode: FileMode.WRITE, bool flush: false}) =>
null;
void writeAsBytesSync(List<int> bytes,
{FileMode mode: FileMode.WRITE, bool flush: false}) {}
Future<File> writeAsString(String contents,
{FileMode mode: FileMode.WRITE,
Encoding encoding: UTF8,
bool flush: false}) =>
null;
void writeAsStringSync(String contents,
{FileMode mode: FileMode.WRITE,
Encoding encoding: UTF8,
bool flush: false}) {}
}
class FileStatMock implements FileStat {
final DateTime changed;
final DateTime modified;
final DateTime accessed;
final FileSystemEntityType type;
final int mode;
final int size;
FileStatMock();
static Future<FileStat> stat(String path) {
return new Future.value(new FileStatMock());
}
static FileStat statSync(String path) => new FileStatMock();
String modeString() => null;
}
class FileSystemEntityMock {
static Future<bool> identical(String path1, String path2) {
return new Future.value(false);
}
static bool identicalSync(String path1, String path2) => false;
static Future<FileSystemEntityType> getType(String path, bool followLinks) {
return new Future.value(FileSystemEntityType.FILE);
}
static FileSystemEntityType getTypeSync(String path, bool followLinks) {
return FileSystemEntityType.FILE;
}
}
class FileSystemWatcherMock {
static Stream<FileSystemEvent> watch(
String path, int events, bool recursive) {
return null;
}
static bool watchSupported() => false;
}
class LinkMock extends FileSystemEntity implements Link {
LinkMock(String path);
static createLink(String path) => new LinkMock(path);
Future<Link> create(String target, {bool recursive: false}) => null;
void createSync(String target, {bool recursive: false}) {}
void updateSync(String target) {}
Future<Link> update(String target) => null;
Future<String> resolveSymbolicLinks() => null;
String resolveSymbolicLinksSync() => null;
Future<Link> rename(String newPath) => null;
Link renameSync(String newPath) => null;
Link get absolute => null;
Future<String> target() => null;
String targetSync() => null;
}
Future<Null> ioOverridesRunTest() async {
Future<Null> f = IoOverrides.runZoned(
() async {
Expect.isTrue(new Directory("directory") is DirectoryMock);
Expect.isTrue(Directory.current is DirectoryMock);
Expect.isTrue(Directory.systemTemp is DirectoryMock);
Expect.isTrue(new File("file") is FileMock);
Expect.isTrue(await FileStat.stat("file") is FileStatMock);
Expect.isTrue(FileStat.statSync("file") is FileStatMock);
Expect.isFalse(await FileSystemEntity.identical("file", "file"));
Expect.isFalse(FileSystemEntity.identicalSync("file", "file"));
Expect.equals(
await FileSystemEntity.type("file"), FileSystemEntityType.FILE);
Expect.equals(
FileSystemEntity.typeSync("file"), FileSystemEntityType.FILE);
Expect.isFalse(FileSystemEntity.isWatchSupported);
Expect.isNull(new Directory("directory").watch());
Expect.isTrue(new Link("link") is LinkMock);
},
createDirectory: DirectoryMock.createDirectory,
getCurrentDirectory: DirectoryMock.getCurrent,
setCurrentDirectory: DirectoryMock.setCurrent,
getSystemTempDirectory: DirectoryMock.getSystemTemp,
createFile: FileMock.createFile,
stat: FileStatMock.stat,
statSync: FileStatMock.statSync,
fseIdentical: FileSystemEntityMock.identical,
fseIdenticalSync: FileSystemEntityMock.identicalSync,
fseGetType: FileSystemEntityMock.getType,
fseGetTypeSync: FileSystemEntityMock.getTypeSync,
fsWatch: FileSystemWatcherMock.watch,
fsWatchIsSupported: FileSystemWatcherMock.watchSupported,
createLink: LinkMock.createLink,
);
Expect.isFalse(new Directory("directory") is DirectoryMock);
Expect.isTrue(new Directory("directory") is Directory);
await f;
}
main() async {
await ioOverridesRunTest();
}