Store data objects for File/Folder in MemoryResourceProvider.

And by storing the list of child names in a folder we can implement
Folder.getChildren() more efficiently.

Bug: https://github.com/dart-lang/sdk/issues/47220
Change-Id: I893dffd6ada4095b8580ec5d469142478f57f284
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213682
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2021-09-19 20:43:01 +00:00 committed by commit-bot@chromium.org
parent b1d878fc8f
commit 28738dfad0
9 changed files with 231 additions and 192 deletions

View file

@ -1,3 +1,8 @@
## 2.4.0-dev
* Deprecated `ResourceProvider.getModificationTimes()`.
* Deprecated `MemoryResourceProvider.newDummyLink()`.
* Deprecated `MemoryResourceProvider.updateFile()`.
## 2.3.0
* Enable `constructor-tearoffs` feature by default in `2.15`.
* Improvements in constructors tear-off implementation.

View file

@ -198,6 +198,7 @@ abstract class ResourceProvider {
///
/// If the file of a source is not managed by this provider, return `null`.
/// If the file a source does not exist, return `-1`.
@Deprecated('Not used by clients')
Future<List<int?>> getModificationTimes(List<Source> sources);
/// Return the [Resource] that corresponds to the given [path].

View file

@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:typed_data';
@ -16,13 +15,9 @@ import 'package:watcher/watcher.dart';
/// An in-memory implementation of [ResourceProvider].
/// Use `/` as a path separator.
class MemoryResourceProvider implements ResourceProvider {
final Map<String, _MemoryResource> _pathToResource =
HashMap<String, _MemoryResource>();
final Map<String, Uint8List> _pathToBytes = HashMap<String, Uint8List>();
final Map<String, int> _pathToTimestamp = HashMap<String, int>();
final Map<String, _ResourceData> _pathToData = {};
final Map<String, String> _pathToLinkedPath = {};
final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers =
HashMap<String, List<StreamController<WatchEvent>>>();
final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers = {};
int nextStamp = 0;
final pathos.Context _pathContext;
@ -55,19 +50,28 @@ class MemoryResourceProvider implements ResourceProvider {
/// Delete the file with the given path.
void deleteFile(String path) {
_checkFileAtPath(path);
_pathToResource.remove(path);
_pathToBytes.remove(path);
_pathToTimestamp.remove(path);
var data = _pathToData[path];
if (data is! _FileData) {
throw FileSystemException(path, 'Not a file.');
}
_pathToData.remove(path);
_removeFromParentFolderData(path);
_notifyWatchers(path, ChangeType.REMOVE);
}
/// Delete the folder with the given path
/// and recursively delete nested files and folders.
void deleteFolder(String path) {
_checkFolderAtPath(path);
var folder = _pathToResource[path] as _MemoryFolder;
for (Resource child in folder.getChildren()) {
var data = _pathToData[path];
if (data is! _FolderData) {
throw FileSystemException(path, 'Not a folder.');
}
for (var childName in data.childNames.toList()) {
var childPath = pathContext.join(path, childName);
var child = getResource(childPath);
if (child is File) {
deleteFile(child.path);
} else if (child is Folder) {
@ -76,9 +80,17 @@ class MemoryResourceProvider implements ResourceProvider {
throw 'failed to delete resource: $child';
}
}
_pathToResource.remove(path);
_pathToBytes.remove(path);
_pathToTimestamp.remove(path);
if (_pathToData[path] != data) {
throw StateError('Unexpected concurrent modification: $path');
}
if (data.childNames.isNotEmpty) {
throw StateError('Must be empty.');
}
_pathToData.remove(path);
_removeFromParentFolderData(path);
_notifyWatchers(path, ChangeType.REMOVE);
}
@ -94,18 +106,27 @@ class MemoryResourceProvider implements ResourceProvider {
return _MemoryFolder(this, path);
}
@Deprecated('Not used by clients')
@override
Future<List<int>> getModificationTimes(List<Source> sources) async {
return sources.map((source) {
String path = source.fullName;
return _pathToTimestamp[path] ?? -1;
var file = getFile(path);
try {
return file.modificationStamp;
} on FileSystemException {
return -1;
}
}).toList();
}
@override
Resource getResource(String path) {
_ensureAbsoluteAndNormalized(path);
return _pathToResource[path] ?? _MemoryFile(this, path);
var data = _pathToData[path];
return data is _FolderData
? _MemoryFolder(this, path)
: _MemoryFile(this, path);
}
@override
@ -115,66 +136,53 @@ class MemoryResourceProvider implements ResourceProvider {
}
void modifyFile(String path, String content) {
_checkFileAtPath(path);
_pathToBytes[path] = utf8.encode(content) as Uint8List;
_pathToTimestamp[path] = nextStamp++;
var data = _pathToData[path];
if (data is! _FileData) {
throw FileSystemException(path, 'Not a file.');
}
_pathToData[path] = _FileData(
bytes: utf8.encode(content) as Uint8List,
timeStamp: nextStamp++,
);
_notifyWatchers(path, ChangeType.MODIFY);
}
/// Create a resource representing a dummy link (that is, a File object which
/// appears in its parent directory, but whose `exists` property is false)
@Deprecated('Not used by clients')
File newDummyLink(String path) {
_ensureAbsoluteAndNormalized(path);
newFolder(pathContext.dirname(path));
_MemoryDummyLink link = _MemoryDummyLink(this, path);
_pathToResource[path] = link;
_pathToTimestamp[path] = nextStamp++;
_notifyWatchers(path, ChangeType.ADD);
return link;
}
File newFile(String path, String content, [int? stamp]) {
_ensureAbsoluteAndNormalized(path);
_MemoryFile file = _newFile(path);
_pathToBytes[path] = utf8.encode(content) as Uint8List;
_pathToTimestamp[path] = stamp ?? nextStamp++;
_notifyWatchers(path, ChangeType.ADD);
return file;
var bytes = utf8.encode(content);
return newFileWithBytes(path, bytes, stamp);
}
File newFileWithBytes(String path, List<int> bytes, [int? stamp]) {
_ensureAbsoluteAndNormalized(path);
_MemoryFile file = _newFile(path);
_pathToBytes[path] = Uint8List.fromList(bytes);
_pathToTimestamp[path] = stamp ?? nextStamp++;
var parentPath = pathContext.dirname(path);
var parentData = _newFolder(parentPath);
_addToParentFolderData(parentData, path);
_pathToData[path] = _FileData(
bytes: Uint8List.fromList(bytes),
timeStamp: stamp ?? nextStamp++,
);
_notifyWatchers(path, ChangeType.ADD);
return file;
return _MemoryFile(this, path);
}
Folder newFolder(String path) {
_ensureAbsoluteAndNormalized(path);
if (!pathContext.isAbsolute(path)) {
throw ArgumentError("Path must be absolute : $path");
}
var resource = _pathToResource[path];
if (resource == null) {
String parentPath = pathContext.dirname(path);
if (parentPath != path) {
newFolder(parentPath);
}
_MemoryFolder folder = _MemoryFolder(this, path);
_pathToResource[path] = folder;
_pathToTimestamp[path] = nextStamp++;
_notifyWatchers(path, ChangeType.ADD);
return folder;
} else if (resource is _MemoryFolder) {
_notifyWatchers(path, ChangeType.ADD);
return resource;
} else {
String message =
'Folder expected at ' "'$path'" 'but ${resource.runtimeType} found';
throw ArgumentError(message);
}
_newFolder(path);
return _MemoryFolder(this, path);
}
/// Create a link from the [path] to the [target].
@ -184,44 +192,29 @@ class MemoryResourceProvider implements ResourceProvider {
_pathToLinkedPath[path] = target;
}
@Deprecated('Not used by clients')
File updateFile(String path, String content, [int? stamp]) {
_ensureAbsoluteAndNormalized(path);
newFolder(pathContext.dirname(path));
_MemoryFile file = _MemoryFile(this, path);
_pathToResource[path] = file;
_pathToBytes[path] = utf8.encode(content) as Uint8List;
_pathToTimestamp[path] = stamp ?? nextStamp++;
_pathToData[path] = _FileData(
bytes: utf8.encode(content) as Uint8List,
timeStamp: stamp ?? nextStamp++,
);
_notifyWatchers(path, ChangeType.MODIFY);
return file;
return _MemoryFile(this, path);
}
/// Write a representation of the file system on the given [sink].
void writeOn(StringSink sink) {
List<String> paths = _pathToResource.keys.toList();
List<String> paths = _pathToData.keys.toList();
paths.sort();
paths.forEach(sink.writeln);
}
void _checkFileAtPath(String path) {
// TODO(brianwilkerson) Consider throwing a FileSystemException rather than
// an ArgumentError.
var resource = _pathToResource[path];
if (resource is! _MemoryFile) {
if (resource == null) {
throw ArgumentError('File expected at "$path" but does not exist');
}
throw ArgumentError(
'File expected at "$path" but ${resource.runtimeType} found');
}
}
void _checkFolderAtPath(String path) {
// TODO(brianwilkerson) Consider throwing a FileSystemException rather than
// an ArgumentError.
var resource = _pathToResource[path];
if (resource is! _MemoryFolder) {
throw ArgumentError(
'Folder expected at "$path" but ${resource.runtimeType} found');
void _addToParentFolderData(_FolderData parentData, String path) {
var childName = pathContext.basename(path);
if (!parentData.childNames.contains(childName)) {
parentData.childNames.add(childName);
}
}
@ -236,18 +229,25 @@ class MemoryResourceProvider implements ResourceProvider {
}
}
/// Create a new [_MemoryFile] without any content.
_MemoryFile _newFile(String path) {
String folderPath = pathContext.dirname(path);
var folder = _pathToResource[folderPath];
if (folder == null) {
newFolder(folderPath);
} else if (folder is! Folder) {
throw ArgumentError('Cannot create file ($path) as child of file');
_FolderData _newFolder(String path) {
_ensureAbsoluteAndNormalized(path);
var data = _pathToData[path];
if (data is _FolderData) {
return data;
} else if (data == null) {
var parentPath = pathContext.dirname(path);
if (parentPath != path) {
var parentData = _newFolder(parentPath);
_addToParentFolderData(parentData, path);
}
var data = _FolderData();
_pathToData[path] = data;
_notifyWatchers(path, ChangeType.ADD);
return data;
} else {
throw FileSystemException(path, 'Folder expected.');
}
_MemoryFile file = _MemoryFile(this, path);
_pathToResource[path] = file;
return file;
}
void _notifyWatchers(String path, ChangeType changeType) {
@ -262,36 +262,41 @@ class MemoryResourceProvider implements ResourceProvider {
});
}
_MemoryFile _renameFileSync(_MemoryFile file, String newPath) {
String path = file.path;
void _removeFromParentFolderData(String path) {
var parentPath = pathContext.dirname(path);
var parentData = _pathToData[parentPath] as _FolderData;
var childName = pathContext.basename(path);
parentData.childNames.remove(childName);
}
void _renameFileSync(String path, String newPath) {
var data = _pathToData[path];
if (data is! _FileData) {
throw FileSystemException(path, 'Not a file.');
}
if (newPath == path) {
return file;
}
var existingNewResource = _pathToResource[newPath];
if (existingNewResource is _MemoryFolder) {
throw FileSystemException(
path, 'Could not be renamed: $newPath is a folder.');
return;
}
_MemoryFile newFile = _newFile(newPath);
_pathToResource.remove(path);
var oldBytes = _pathToBytes.remove(path);
if (oldBytes != null) {
_pathToBytes[newPath] = oldBytes;
var existingNewData = _pathToData[newPath];
if (existingNewData == null) {
// Nothing to do.
} else if (existingNewData is _FileData) {
deleteFile(newPath);
} else {
throw FileSystemException(newPath, 'Not a file.');
}
var oldTimestamp = _pathToTimestamp.remove(path);
if (oldTimestamp != null) {
_pathToTimestamp[newPath] = oldTimestamp;
}
var parentPath = pathContext.dirname(path);
var parentData = _newFolder(parentPath);
_addToParentFolderData(parentData, path);
_pathToData.remove(path);
_pathToData[newPath] = data;
if (existingNewResource != null) {
_notifyWatchers(newPath, ChangeType.REMOVE);
}
_notifyWatchers(path, ChangeType.REMOVE);
_notifyWatchers(newPath, ChangeType.ADD);
return newFile;
}
String _resolveLinks(String path) {
@ -317,15 +322,34 @@ class MemoryResourceProvider implements ResourceProvider {
return result;
}
void _setFileContent(_MemoryFile file, List<int> bytes) {
String path = file.path;
_pathToResource[path] = file;
_pathToBytes[path] = Uint8List.fromList(bytes);
_pathToTimestamp[path] = nextStamp++;
void _setFileContent(String path, List<int> bytes) {
var parentPath = pathContext.dirname(path);
var parentData = _newFolder(parentPath);
_addToParentFolderData(parentData, path);
_pathToData[path] = _FileData(
bytes: Uint8List.fromList(bytes),
timeStamp: nextStamp++,
);
_notifyWatchers(path, ChangeType.MODIFY);
}
}
class _FileData extends _ResourceData {
final Uint8List bytes;
final int timeStamp;
_FileData({
required this.bytes,
required this.timeStamp,
});
}
class _FolderData extends _ResourceData {
/// Names (not paths) of direct children.
final List<String> childNames = [];
}
/// An in-memory implementation of [File] which acts like a symbolic link to a
/// non-existent file.
class _MemoryDummyLink extends _MemoryResource implements File {
@ -347,11 +371,7 @@ class _MemoryDummyLink extends _MemoryResource implements File {
@override
int get modificationStamp {
var stamp = provider._pathToTimestamp[path];
if (stamp == null) {
throw FileSystemException(path, "File does not exist");
}
return stamp;
throw FileSystemException(path, "File does not exist");
}
@override
@ -413,7 +433,7 @@ class _MemoryFile extends _MemoryResource implements File {
@override
bool get exists {
var canonicalPath = provider._resolveLinks(path);
return provider._pathToResource[canonicalPath] is _MemoryFile;
return provider._pathToData[canonicalPath] is _FileData;
}
@override
@ -424,11 +444,11 @@ class _MemoryFile extends _MemoryResource implements File {
@override
int get modificationStamp {
var canonicalPath = provider._resolveLinks(path);
var stamp = provider._pathToTimestamp[canonicalPath];
if (stamp == null) {
throw FileSystemException(path, 'File "$path" does not exist.');
var data = provider._pathToData[canonicalPath];
if (data is! _FileData) {
throw FileSystemException(path, 'File does not exist.');
}
return stamp;
return data.timeStamp;
}
@override
@ -458,26 +478,23 @@ class _MemoryFile extends _MemoryResource implements File {
@override
Uint8List readAsBytesSync() {
var canonicalPath = provider._resolveLinks(path);
var content = provider._pathToBytes[canonicalPath];
if (content == null) {
throw FileSystemException(path, 'File "$path" does not exist.');
var data = provider._pathToData[canonicalPath];
if (data is! _FileData) {
throw FileSystemException(path, 'File does not exist.');
}
return content;
return data.bytes;
}
@override
String readAsStringSync() {
var canonicalPath = provider._resolveLinks(path);
var content = provider._pathToBytes[canonicalPath];
if (content == null) {
throw FileSystemException(path, 'File "$path" does not exist.');
}
return utf8.decode(content);
var bytes = readAsBytesSync();
return utf8.decode(bytes);
}
@override
File renameSync(String newPath) {
return provider._renameFileSync(this, newPath);
provider._renameFileSync(path, newPath);
return provider.getFile(newPath);
}
@override
@ -486,7 +503,7 @@ class _MemoryFile extends _MemoryResource implements File {
var result = provider.getFile(canonicalPath);
if (!result.exists) {
throw FileSystemException(path, 'File "$path" does not exist.');
throw FileSystemException(path, 'File does not exist.');
}
return result;
@ -494,12 +511,13 @@ class _MemoryFile extends _MemoryResource implements File {
@override
void writeAsBytesSync(List<int> bytes) {
provider._setFileContent(this, bytes);
provider._setFileContent(path, bytes);
}
@override
void writeAsStringSync(String content) {
provider._setFileContent(this, utf8.encode(content));
var bytes = utf8.encode(content);
writeAsBytesSync(bytes);
}
}
@ -511,7 +529,7 @@ class _MemoryFolder extends _MemoryResource implements Folder {
@override
bool get exists {
var canonicalPath = provider._resolveLinks(path);
return provider._pathToResource[canonicalPath] is _MemoryFolder;
return provider._pathToData[canonicalPath] is _FolderData;
}
@override
@ -555,29 +573,20 @@ class _MemoryFolder extends _MemoryResource implements Folder {
@override
Resource getChild(String relPath) {
String childPath = canonicalizePath(relPath);
return provider._pathToResource[childPath] ??
_MemoryFile(provider, childPath);
var path = canonicalizePath(relPath);
return provider.getResource(path);
}
@override
_MemoryFile getChildAssumingFile(String relPath) {
String childPath = canonicalizePath(relPath);
var resource = provider._pathToResource[childPath];
if (resource is _MemoryFile) {
return resource;
}
return _MemoryFile(provider, childPath);
var path = canonicalizePath(relPath);
return _MemoryFile(provider, path);
}
@override
_MemoryFolder getChildAssumingFolder(String relPath) {
String childPath = canonicalizePath(relPath);
var resource = provider._pathToResource[childPath];
if (resource is _MemoryFolder) {
return resource;
}
return _MemoryFolder(provider, childPath);
var path = canonicalizePath(relPath);
return _MemoryFolder(provider, path);
}
@override
@ -596,17 +605,17 @@ class _MemoryFolder extends _MemoryResource implements Folder {
}).toList();
}
if (!exists) {
var data = provider._pathToData[path];
if (data is! _FolderData) {
throw FileSystemException(path, 'Folder does not exist.');
}
var children = <Resource>[];
provider._pathToResource.forEach((resourcePath, resource) {
if (provider.pathContext.dirname(resourcePath) == path) {
children.add(resource);
}
});
for (var childName in data.childNames) {
var childPath = provider.pathContext.join(path, childName);
var child = provider.getResource(childPath);
children.add(child);
}
provider._pathToLinkedPath.forEach((resourcePath, targetPath) {
if (provider.pathContext.dirname(resourcePath) == path) {
@ -640,7 +649,7 @@ class _MemoryFolder extends _MemoryResource implements Folder {
var result = provider.getFolder(canonicalPath);
if (!result.exists) {
throw FileSystemException(path, 'Folder "$path" does not exist.');
throw FileSystemException(path, 'Folder does not exist.');
}
return result;
@ -712,3 +721,5 @@ abstract class _MemoryResource implements Resource {
@override
Uri toUri() => provider.pathContext.toUri(path);
}
class _ResourceData {}

View file

@ -40,6 +40,7 @@ class OverlayResourceProvider implements ResourceProvider {
Folder getFolder(String path) =>
_OverlayFolder(this, baseProvider.getFolder(path));
@Deprecated('Not used by clients')
@override
Future<List<int>> getModificationTimes(List<Source> sources) async {
return sources.map((source) {

View file

@ -78,6 +78,7 @@ class PhysicalResourceProvider implements ResourceProvider {
return _PhysicalFolder(io.Directory(path));
}
@Deprecated('Not used by clients')
@override
Future<List<int?>> getModificationTimes(List<Source> sources) async {
List<String> paths = sources.map((source) => source.fullName).toList();

View file

@ -1,5 +1,5 @@
name: analyzer
version: 2.3.0
version: 2.4.0-dev
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer

View file

@ -12,6 +12,8 @@ final isFile = TypeMatcher<File>();
final isFileSystemException = TypeMatcher<FileSystemException>();
final isFolder = TypeMatcher<Folder>();
final throwsFileSystemException = throwsA(isFileSystemException);
abstract class FileSystemTestSupport {
/// The content used for the file at the [defaultFilePath] if it is created
/// and no other content is provided.
@ -108,9 +110,11 @@ mixin FileTestMixin implements FileSystemTestSupport {
test_delete_existing() {
File file = getFile(exists: true);
expect(file.exists, isTrue);
expect(file.parent2.getChildren(), contains(file));
file.delete();
expect(file.exists, isFalse);
expect(file.parent2.getChildren(), isNot(contains(file)));
}
test_delete_notExisting();
@ -919,6 +923,7 @@ mixin ResourceProviderTestMixin implements FileSystemTestSupport {
expect(folder.exists, isFalse);
}
@Deprecated('Not used by clients')
test_getModificationTimes_existing() async {
Source source = getFile(exists: true).createSource();
@ -926,6 +931,7 @@ mixin ResourceProviderTestMixin implements FileSystemTestSupport {
expect(times, [source.modificationStamp]);
}
@Deprecated('Not used by clients')
test_getModificationTimes_notExisting() async {
Source source = getFile(exists: false).createSource();

View file

@ -241,7 +241,10 @@ class MemoryFileTest extends BaseTest with FileTestMixin {
File file = getFile(exists: false);
expect(file.exists, isFalse);
expect(() => file.delete(), throwsA(const TypeMatcher<ArgumentError>()));
expect(
() => file.delete(),
throwsFileSystemException,
);
}
@override
@ -304,14 +307,20 @@ class MemoryResourceProviderTest extends BaseTest
test_deleteFile_folder() {
Folder folder = getFolder(exists: true);
expect(() => provider.deleteFile(defaultFolderPath), throwsArgumentError);
expect(
() => provider.deleteFile(defaultFolderPath),
throwsFileSystemException,
);
expect(folder.exists, isTrue);
}
test_deleteFile_notExisting() {
File file = getFile(exists: false);
expect(() => provider.deleteFile(defaultFilePath), throwsArgumentError);
expect(
() => provider.deleteFile(defaultFilePath),
throwsFileSystemException,
);
expect(file.exists, isFalse);
}
@ -325,16 +334,20 @@ class MemoryResourceProviderTest extends BaseTest
test_modifyFile_existing_folder() {
getFolder(exists: true);
expect(() => provider.modifyFile(defaultFolderPath, 'contents'),
throwsArgumentError);
expect(
() => provider.modifyFile(defaultFolderPath, 'contents'),
throwsFileSystemException,
);
expect(provider.getResource(defaultFolderPath), isFolder);
}
test_modifyFile_notExisting() {
getFile(exists: false);
expect(() => provider.modifyFile(defaultFilePath, 'contents'),
throwsArgumentError);
expect(
() => provider.modifyFile(defaultFilePath, 'contents'),
throwsFileSystemException,
);
Resource file = provider.getResource(defaultFilePath);
expect(file, isFile);
expect(file.exists, isFalse);
@ -357,7 +370,10 @@ class MemoryResourceProviderTest extends BaseTest
test_newFolder_existing_file() {
getFile(exists: true);
expect(() => provider.newFolder(defaultFilePath), throwsArgumentError);
expect(
() => provider.newFolder(defaultFilePath),
throwsFileSystemException,
);
}
test_newFolder_existing_folder() {

View file

@ -272,25 +272,21 @@ class FileTest extends OverlayTestSupport {
test_renameSync_notExisting_withoutOverlay() {
String oldPath = '/foo/bar/file.txt';
String newPath = baseProvider.convertPath('/foo/bar/new-file.txt');
File oldFile = _file(exists: true, path: oldPath);
File newFile = oldFile.renameSync(newPath);
expect(oldFile.path, baseProvider.convertPath(oldPath));
expect(oldFile.exists, isFalse);
expect(newFile.path, newPath);
expect(newFile.exists, isTrue);
expect(newFile.readAsStringSync(), 'a');
File oldFile = _file(exists: false, path: oldPath);
expect(
() => oldFile.renameSync(newPath),
throwsFileSystemException,
);
}
test_renameSync_notExisting_withOverlay() {
String oldPath = '/foo/bar/file.txt';
String newPath = baseProvider.convertPath('/foo/bar/new-file.txt');
File oldFile = _file(exists: false, path: oldPath, withOverlay: true);
File newFile = oldFile.renameSync(newPath);
expect(oldFile.path, baseProvider.convertPath(oldPath));
expect(oldFile.exists, isFalse);
expect(newFile.path, newPath);
expect(newFile.exists, isTrue);
expect(newFile.readAsStringSync(), 'bbb');
expect(
() => oldFile.renameSync(newPath),
throwsFileSystemException,
);
}
@failingTest
@ -480,7 +476,7 @@ class FolderTest extends OverlayTestSupport {
test_delete_notExisting() {
Folder folder = _folder(exists: false);
expect(folder.exists, isFalse);
expect(() => folder.delete(), throwsA(TypeMatcher<ArgumentError>()));
expect(() => folder.delete(), throwsFileSystemException);
}
void test_exists_links_existing() {
@ -810,12 +806,14 @@ class OverlayResourceProviderTest extends OverlayTestSupport {
expect(folder.exists, isTrue);
}
@Deprecated('Not used by clients')
test_getModificationTimes_withoutOverlay() async {
Source source = _file(exists: true).createSource();
List<int> times = await provider.getModificationTimes([source]);
expect(times, [source.modificationStamp]);
}
@Deprecated('Not used by clients')
test_getModificationTimes_withOverlay() async {
Source source = _file(exists: true, withOverlay: true).createSource();
List<int> times = await provider.getModificationTimes([source]);