blob: 34dc801321da354fae35fd08cdf3ea84e39fc45d [file] [log] [blame]
// Copyright (c) 2014, 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 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/generated/engine.dart' show TimestampedData;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:watcher/watcher.dart';
import 'file_system_test_support.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(FileSystemExceptionTest);
defineReflectiveTests(MemoryFileSourceExistingTest);
defineReflectiveTests(MemoryFileSourceNotExistingTest);
defineReflectiveTests(MemoryFileTest);
defineReflectiveTests(MemoryFolderTest);
defineReflectiveTests(MemoryResourceProviderTest);
});
}
abstract class BaseTest extends FileSystemTestSupport {
/// The resource provider to be used by the tests. Tests should use [provider]
/// to access the resource provider.
MemoryResourceProvider? _provider;
/// The absolute path to the temporary directory in which all of the tests are
/// to work.
@override
late final String tempPath;
/// A path to a folder within the [tempPath] that can be used by tests.
@override
late final String defaultFolderPath;
/// A path to a file within the [defaultFolderPath] that can be used by tests.
@override
late final String defaultFilePath;
/// The content used for the file at the [defaultFilePath] if it is created
/// and no other content is provided.
@override
String get defaultFileContent => 'a';
@override
bool get hasSymbolicLinkSupport => true;
/// Return the resource provider to be used by the tests.
@override
MemoryResourceProvider get provider => _provider ??= createProvider();
@override
void createLink({required String path, required String target}) {
provider.newLink(path, target);
}
/// Create the resource provider to be used by the tests. Subclasses can
/// override this method to change the class of resource provider that is
/// used.
MemoryResourceProvider createProvider() => MemoryResourceProvider();
@override
File getFile({required bool exists, String? content, String? filePath}) {
if (filePath == null) {
filePath = defaultFilePath;
} else {
filePath = provider.convertPath(filePath);
}
if (exists) {
provider.newFile(filePath, content ?? defaultFileContent);
}
return provider.getFile(filePath);
}
@override
Folder getFolder({required bool exists, String? folderPath}) {
if (folderPath == null) {
folderPath = defaultFolderPath;
} else {
folderPath = provider.convertPath(folderPath);
}
if (exists) {
provider.newFolder(folderPath);
}
return provider.getFolder(folderPath);
}
setUp() {
tempPath = provider.convertPath('/temp');
defaultFolderPath = join(tempPath, 'bar');
defaultFilePath = join(tempPath, 'bar', 'test.dart');
}
}
@reflectiveTest
class FileSystemExceptionTest {
test_constructor() {
var exception = FileSystemException('/my/path', 'my message');
expect(exception.path, '/my/path');
expect(exception.message, 'my message');
expect(exception.toString(),
'FileSystemException(path=/my/path; message=my message)');
}
}
@reflectiveTest
class MemoryFileSourceExistingTest extends BaseTest {
late final String sourcePath;
late final Source source;
@override
setUp() {
super.setUp();
File file = getFile(exists: true);
sourcePath = file.path;
source = file.createSource();
}
test_contents() {
TimestampedData<String> contents = source.contents;
expect(contents.data, defaultFileContent);
}
test_equals_false_differentFile() {
File fileA = getFile(exists: false, filePath: join(tempPath, 'a.dart'));
File fileB = getFile(exists: false, filePath: join(tempPath, 'b.dart'));
Source sourceA = fileA.createSource();
Source sourceB = fileB.createSource();
expect(sourceA == sourceB, isFalse);
}
test_equals_false_notMemorySource() {
expect(source == Object(), isFalse);
}
test_equals_true_sameFile() {
Source sourceA = getFile(exists: false).createSource();
Source sourceB = getFile(exists: false).createSource();
expect(sourceA == sourceB, isTrue);
}
test_equals_true_self() {
expect(source == source, isTrue);
}
test_exists() {
expect(source.exists(), isTrue);
}
test_fullName() {
expect(source.fullName, sourcePath);
}
test_hashCode() {
expect(source.hashCode, isNotNull);
}
test_resolveRelative() {
Uri relative = resolveRelativeUri(
source.uri,
provider.pathContext
.toUri(provider.pathContext.join('bar', 'baz.dart')));
expect(
relative,
provider.pathContext
.toUri(provider.convertPath('/temp/bar/bar/baz.dart')));
}
test_resolveRelative_dart() {
File file = getFile(
exists: false,
filePath: provider.convertPath('/sdk/lib/core/core.dart'));
Source source = file.createSource(Uri.parse('dart:core'));
Uri resolved = resolveRelativeUri(source.uri, Uri.parse('int.dart'));
expect(resolved.toString(), 'dart:core/int.dart');
}
test_shortName() {
expect(source.shortName, 'test.dart');
}
}
@reflectiveTest
class MemoryFileSourceNotExistingTest extends BaseTest {
late final String sourcePath;
late final Source source;
@override
setUp() {
super.setUp();
File file = getFile(exists: false);
sourcePath = file.path;
source = file.createSource();
}
test_contents() {
expect(() => source.contents, throwsA(isFileSystemException));
}
test_exists() {
expect(source.exists(), isFalse);
}
test_fullName() {
expect(source.fullName, sourcePath);
}
test_modificationStamp() {
expect(source.modificationStamp, -1);
}
test_resolveRelative() {
Uri relative = resolveRelativeUri(
source.uri,
provider.pathContext
.toUri(provider.pathContext.join('bar', 'baz.dart')));
expect(
relative,
provider.pathContext
.toUri(provider.convertPath('/temp/bar/bar/baz.dart')));
}
test_shortName() {
expect(source.shortName, 'test.dart');
}
}
@reflectiveTest
class MemoryFileTest extends BaseTest with FileTestMixin {
@override
test_delete_notExisting() {
File file = getFile(exists: false);
expect(file.exists, isFalse);
expect(() => file.delete(), throwsA(const TypeMatcher<ArgumentError>()));
}
@override
test_renameSync_notExisting() {
String oldPath = join(tempPath, 'file.txt');
String newPath = join(tempPath, 'new-file.txt');
File oldFile = getFile(exists: true, filePath: oldPath);
File newFile = oldFile.renameSync(newPath);
expect(oldFile.path, oldPath);
expect(oldFile.exists, isFalse);
expect(newFile.path, newPath);
expect(newFile.exists, isTrue);
expect(newFile.readAsStringSync(), defaultFileContent);
}
@override
test_writeAsBytesSync_notExisting() {
File file = getFile(exists: false);
file.writeAsBytesSync(<int>[99, 99]);
expect(file.exists, true);
expect(file.readAsBytesSync(), <int>[99, 99]);
}
@override
test_writeAsStringSync_notExisting() {
File file = getFile(exists: false);
file.writeAsStringSync('cc');
expect(file.exists, true);
expect(file.readAsStringSync(), 'cc');
}
}
@reflectiveTest
class MemoryFolderTest extends BaseTest with FolderTestMixin {
test_isRoot_false() {
var path = provider.convertPath('/foo');
expect(provider.getFolder(path).isRoot, isFalse);
}
test_isRoot_true() {
var path = provider.convertPath('/');
expect(provider.getFolder(path).isRoot, isTrue);
}
}
@reflectiveTest
class MemoryResourceProviderTest extends BaseTest
with ResourceProviderTestMixin {
test_deleteFile_existing() {
File file = getFile(exists: true);
expect(file.exists, isTrue);
provider.deleteFile(defaultFilePath);
expect(file.exists, isFalse);
}
test_deleteFile_folder() {
Folder folder = getFolder(exists: true);
expect(() => provider.deleteFile(defaultFolderPath), throwsArgumentError);
expect(folder.exists, isTrue);
}
test_deleteFile_notExisting() {
File file = getFile(exists: false);
expect(() => provider.deleteFile(defaultFilePath), throwsArgumentError);
expect(file.exists, isFalse);
}
test_modifyFile_existing_file() {
File file = getFile(exists: true);
provider.modifyFile(file.path, 'contents 2');
expect(file.readAsStringSync(), 'contents 2');
}
test_modifyFile_existing_folder() {
getFolder(exists: true);
expect(() => provider.modifyFile(defaultFolderPath, 'contents'),
throwsArgumentError);
expect(provider.getResource(defaultFolderPath), isFolder);
}
test_modifyFile_notExisting() {
getFile(exists: false);
expect(() => provider.modifyFile(defaultFilePath, 'contents'),
throwsArgumentError);
Resource file = provider.getResource(defaultFilePath);
expect(file, isFile);
expect(file.exists, isFalse);
}
test_newFileWithBytes() {
List<int> bytes = <int>[1, 2, 3, 4, 5];
provider.newFileWithBytes(defaultFilePath, bytes);
Resource file = provider.getResource(defaultFilePath);
expect(file, isFile);
expect(file.exists, isTrue);
expect((file as File).readAsBytesSync(), bytes);
}
test_newFolder_emptyPath() {
expect(() => provider.newFolder(''), throwsArgumentError);
}
test_newFolder_existing_file() {
getFile(exists: true);
expect(() => provider.newFolder(defaultFilePath), throwsArgumentError);
}
test_newFolder_existing_folder() {
Folder folder = getFolder(exists: true);
Folder newFolder = provider.newFolder(folder.path);
expect(newFolder, folder);
}
test_newFolder_notAbsolute() {
expect(() => provider.newFolder('not/absolute'), throwsArgumentError);
}
test_newLink_folder() {
provider.newLink(
provider.convertPath('/test/lib/foo'),
provider.convertPath('/test/lib'),
);
provider.newFile(
provider.convertPath('/test/lib/a.dart'),
'aaa',
);
{
var path = '/test/lib/foo/a.dart';
var convertedPath = provider.convertPath(path);
var file = provider.getFile(convertedPath);
expect(file.exists, true);
expect(file.modificationStamp, isNonNegative);
expect(file.readAsStringSync(), 'aaa');
}
{
var path = '/test/lib/foo/foo/a.dart';
var convertedPath = provider.convertPath(path);
var file = provider.getFile(convertedPath);
expect(file.exists, true);
expect(file.modificationStamp, isNonNegative);
expect(file.readAsStringSync(), 'aaa');
}
}
@override
test_pathContext() {
if (path.style == path.Style.windows) {
// On Windows the path context is replaced by one whose current directory
// is the root of the 'C' drive.
path.Context context = provider.pathContext;
expect(context.style, path.Style.windows);
expect(context.current, 'C:\\');
} else {
super.test_pathContext();
}
}
test_watch_createFile() {
String rootPath = provider.convertPath('/my/path');
provider.newFolder(rootPath);
return _watchingFolder(rootPath, (changesReceived) {
expect(changesReceived, hasLength(0));
String path = provider.pathContext.join(rootPath, 'foo');
provider.newFile(path, 'contents');
return _delayed(() {
expect(changesReceived, hasLength(1));
expect(changesReceived[0].type, equals(ChangeType.ADD));
expect(changesReceived[0].path, equals(path));
});
});
}
test_watch_deleteFile() {
String rootPath = provider.convertPath('/my/path');
provider.newFolder(rootPath);
String path = provider.pathContext.join(rootPath, 'foo');
provider.newFile(path, 'contents 1');
return _watchingFolder(rootPath, (changesReceived) {
expect(changesReceived, hasLength(0));
provider.deleteFile(path);
return _delayed(() {
expect(changesReceived, hasLength(1));
expect(changesReceived[0].type, equals(ChangeType.REMOVE));
expect(changesReceived[0].path, equals(path));
});
});
}
test_watch_modifyFile() {
String rootPath = provider.convertPath('/my/path');
provider.newFolder(rootPath);
String path = provider.pathContext.join(rootPath, 'foo');
provider.newFile(path, 'contents 1');
return _watchingFolder(rootPath, (changesReceived) {
expect(changesReceived, hasLength(0));
provider.modifyFile(path, 'contents 2');
return _delayed(() {
expect(changesReceived, hasLength(1));
expect(changesReceived[0].type, equals(ChangeType.MODIFY));
expect(changesReceived[0].path, equals(path));
});
});
}
test_watch_modifyFile_inSubDir() {
String rootPath = provider.convertPath('/my/path');
provider.newFolder(rootPath);
String subdirPath = provider.pathContext.join(rootPath, 'foo');
provider.newFolder(subdirPath);
String path = provider.pathContext.join(rootPath, 'bar');
provider.newFile(path, 'contents 1');
return _watchingFolder(rootPath, (changesReceived) {
expect(changesReceived, hasLength(0));
provider.modifyFile(path, 'contents 2');
return _delayed(() {
expect(changesReceived, hasLength(1));
expect(changesReceived[0].type, equals(ChangeType.MODIFY));
expect(changesReceived[0].path, equals(path));
});
});
}
Future _delayed(Function() computation) {
return Future.delayed(Duration.zero, computation);
}
_watchingFolder(
String path, Function(List<WatchEvent> changesReceived) test) {
var folder = provider.getResource(path) as Folder;
var changesReceived = <WatchEvent>[];
folder.changes.listen(changesReceived.add);
return test(changesReceived);
}
}