| // Copyright (c) 2016, 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. |
| // SharedOptions=--supermixin |
| |
| library front_end.test.memory_file_system_test; |
| |
| import 'dart:convert'; |
| import 'dart:io' as io; |
| import 'dart:typed_data'; |
| |
| import 'package:front_end/src/api_prototype/file_system.dart' |
| show FileSystemException; |
| import 'package:front_end/src/api_prototype/memory_file_system.dart'; |
| import 'package:path/path.dart' as pathos; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| void main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(MemoryFileSystemTestNative); |
| defineReflectiveTests(MemoryFileSystemTestPosix); |
| defineReflectiveTests(MemoryFileSystemTestWindows); |
| defineReflectiveTests(FileTest); |
| }); |
| } |
| |
| final Matcher _throwsFileSystemException = |
| throwsA(const TypeMatcher<FileSystemException>()); |
| |
| @reflectiveTest |
| class FileTest extends _BaseTestNative { |
| late String path; |
| late MemoryFileSystemEntity file; |
| |
| void setUp() { |
| _baseSetUp(); |
| path = join(tempPath, 'file.txt'); |
| file = entityForPath(path); |
| } |
| |
| Future<void> test_createDirectory_doesNotExist() async { |
| file.createDirectory(); |
| expect(await file.exists(), true); |
| } |
| |
| Future<void> test_createDirectory_exists_asDirectory() async { |
| file.createDirectory(); |
| file.createDirectory(); |
| expect(await file.exists(), true); |
| } |
| |
| Future<void> test_createDirectory_exists_asFile() async { |
| file.writeAsStringSync(''); |
| await expectLater(file.createDirectory, _throwsFileSystemException); |
| } |
| |
| void test_equals_differentPaths() { |
| expect(file == entityForPath(join(tempPath, 'file2.txt')), isFalse); |
| } |
| |
| void test_equals_samePath() { |
| expect(file == entityForPath(join(tempPath, 'file.txt')), isTrue); |
| } |
| |
| Future<void> test_exists_directory_exists() async { |
| file.createDirectory(); |
| expect(await file.exists(), true); |
| } |
| |
| Future<void> test_exists_doesNotExist() async { |
| expect(await file.exists(), false); |
| } |
| |
| Future<void> test_exists_file_exists() async { |
| file.writeAsStringSync('x'); |
| expect(await file.exists(), true); |
| } |
| |
| void test_hashCode_samePath() { |
| expect(file.hashCode, entityForPath(join(tempPath, 'file.txt')).hashCode); |
| } |
| |
| void test_path() { |
| expect(file.uri, context.toUri(path)); |
| } |
| |
| Future<void> test_readAsBytes_badUtf8() async { |
| // A file containing invalid UTF-8 can still be read as raw bytes. |
| List<int> bytes = [0xc0, 0x40]; // Invalid UTF-8 |
| file.writeAsBytesSync(bytes); |
| expect(await file.readAsBytes(), bytes); |
| } |
| |
| Future<void> test_readAsBytes_doesNotExist() async { |
| await expectLater(file.readAsBytes, _throwsFileSystemException); |
| } |
| |
| Future<void> test_readAsBytes_exists() async { |
| var s = 'contents'; |
| file.writeAsStringSync(s); |
| expect(await file.readAsBytes(), utf8.encode(s)); |
| } |
| |
| Future<void> test_readAsString_badUtf8() async { |
| file.writeAsBytesSync([0xc0, 0x40]); // Invalid UTF-8 |
| await expectLater(file.readAsString, _throwsFileSystemException); |
| } |
| |
| Future<void> test_readAsString_doesNotExist() async { |
| await expectLater(file.readAsString, _throwsFileSystemException); |
| } |
| |
| Future<void> test_readAsString_exists() async { |
| var s = 'contents'; |
| file.writeAsStringSync(s); |
| expect(await file.readAsString(), s); |
| } |
| |
| Future<void> test_readAsString_utf8() async { |
| file.writeAsBytesSync([0xe2, 0x82, 0xac]); // Unicode € symbol, in UTF-8 |
| expect(await file.readAsString(), '\u20ac'); |
| } |
| |
| Future<void> test_writeAsBytesSync_directory() async { |
| file.createDirectory(); |
| await expectLater( |
| () => file.writeAsBytesSync([0]), _throwsFileSystemException); |
| } |
| |
| Future<void> test_writeAsBytesSync_modifyAfterRead() async { |
| // For efficiency we do not make defensive copies. |
| file.writeAsBytesSync([1]); |
| (await file.readAsBytes())[0] = 2; |
| expect(await file.readAsBytes(), [2]); |
| } |
| |
| Future<void> test_writeAsBytesSync_modifyAfterWrite_Uint8List() async { |
| // For efficiency we do not make defensive copies. |
| var bytes = new Uint8List.fromList([1]); |
| file.writeAsBytesSync(bytes); |
| bytes[0] = 2; |
| expect(await file.readAsBytes(), [2]); |
| } |
| |
| Future<void> test_writeAsBytesSync_modifyAfterWrite() async { |
| // For efficiency we generally do not make defensive copies, but on the |
| // other hrand we keep everything as `Uint8List`s internally, so in this |
| // case a copy is actually made. |
| var bytes = [1]; |
| file.writeAsBytesSync(bytes); |
| bytes[0] = 2; |
| expect(await file.readAsBytes(), [1]); |
| } |
| |
| Future<void> test_writeAsBytesSync_overwrite() async { |
| file.writeAsBytesSync([1]); |
| file.writeAsBytesSync([2]); |
| expect(await file.readAsBytes(), [2]); |
| } |
| |
| Future<void> test_writeAsStringSync_directory() async { |
| file.createDirectory(); |
| await expectLater( |
| () => file.writeAsStringSync(''), _throwsFileSystemException); |
| } |
| |
| Future<void> test_writeAsStringSync_overwrite() async { |
| file.writeAsStringSync('first'); |
| file.writeAsStringSync('second'); |
| expect(await file.readAsString(), 'second'); |
| } |
| |
| Future<void> test_writeAsStringSync_utf8() async { |
| file.writeAsStringSync('\u20ac'); // Unicode € symbol |
| expect(await file.readAsBytes(), [0xe2, 0x82, 0xac]); |
| } |
| } |
| |
| mixin MemoryFileSystemTestMixin implements _BaseTest { |
| late Uri tempUri; |
| |
| void setUp() { |
| _baseSetUp(); |
| tempUri = context.toUri(tempPath); |
| } |
| |
| void test_currentDirectory_trailingSlash() { |
| // The currentDirectory should already end in a trailing slash. |
| expect(fileSystem.currentDirectory.path, endsWith('/')); |
| // A trailing slash should automatically be appended when creating a |
| // MemoryFileSystem. |
| var path = fileSystem.currentDirectory.path; |
| var currentDirectoryWithoutSlash = fileSystem.currentDirectory |
| .replace(path: path.substring(0, path.length - 1)); |
| expect(new MemoryFileSystem(currentDirectoryWithoutSlash).currentDirectory, |
| fileSystem.currentDirectory); |
| // If the currentDirectory supplied to the MemoryFileSystem constructor |
| // already has a trailing slash, no further trailing slash should be added. |
| expect(new MemoryFileSystem(fileSystem.currentDirectory).currentDirectory, |
| fileSystem.currentDirectory); |
| } |
| |
| void test_entityForPath_absolutize() { |
| expect(entityForPath('file.txt').uri, |
| fileSystem.currentDirectory.resolve('file.txt')); |
| } |
| |
| void test_entityForPath_normalize_dot() { |
| expect(entityForPath(join(tempPath, '.', 'file.txt')).uri, |
| Uri.parse('$tempUri/file.txt')); |
| } |
| |
| void test_entityForPath_normalize_dotDot() { |
| expect(entityForPath(join(tempPath, 'foo', '..', 'file.txt')).uri, |
| Uri.parse('$tempUri/file.txt')); |
| } |
| |
| void test_entityForUri() { |
| expect(fileSystem.entityForUri(Uri.parse('$tempUri/file.txt')).uri, |
| Uri.parse('$tempUri/file.txt')); |
| } |
| |
| Future<void> test_entityForUri_fileUri_relative() async { |
| // A weird quirk of the Uri class is that it doesn't seem possible to create |
| // a `file:` uri with a relative path, no matter how many slashes you use or |
| // if you populate the fields directly. But just to be certain, try to do |
| // so, and make that `file:` uris with relative paths are rejected. |
| for (var uri in <Uri>[ |
| new Uri(scheme: 'file', path: 'file.txt'), |
| Uri.parse('file:file.txt'), |
| Uri.parse('file:/file.txt'), |
| Uri.parse('file://file.txt'), |
| Uri.parse('file:///file.txt') |
| ]) { |
| if (!uri.path.startsWith('/')) { |
| await expectLater(() => fileSystem.entityForUri(uri), |
| throwsA(const TypeMatcher<Error>())); |
| } |
| } |
| } |
| |
| void test_entityForUri_nonFileUri() { |
| var uri = Uri.parse('package:foo/bar.dart'); |
| expect(fileSystem.entityForUri(uri).uri, uri); |
| } |
| |
| void test_entityForUri_normalize_dot() { |
| expect(fileSystem.entityForUri(Uri.parse('$tempUri/./file.txt')).uri, |
| Uri.parse('$tempUri/file.txt')); |
| } |
| |
| void test_entityForUri_normalize_dotDot() { |
| expect(fileSystem.entityForUri(Uri.parse('$tempUri/foo/../file.txt')).uri, |
| Uri.parse('$tempUri/file.txt')); |
| } |
| } |
| |
| @reflectiveTest |
| class MemoryFileSystemTestNative extends _BaseTestNative |
| with MemoryFileSystemTestMixin {} |
| |
| @reflectiveTest |
| class MemoryFileSystemTestPosix extends _BaseTestPosix |
| with MemoryFileSystemTestMixin {} |
| |
| @reflectiveTest |
| class MemoryFileSystemTestWindows extends _BaseTestWindows |
| with MemoryFileSystemTestMixin {} |
| |
| abstract class _BaseTest { |
| pathos.Context get context; |
| MemoryFileSystem get fileSystem; |
| |
| String get tempPath; |
| |
| MemoryFileSystemEntity entityForPath(String path) => |
| fileSystem.entityForUri(context.toUri(path)); |
| |
| String join(String path1, String path2, [String path3, String path4]); |
| |
| void _baseSetUp(); |
| } |
| |
| class _BaseTestNative extends _BaseTest { |
| @override |
| final pathos.Context context = pathos.context; |
| |
| @override |
| late MemoryFileSystem fileSystem; |
| |
| @override |
| late String tempPath; |
| |
| @override |
| String join(String path1, String path2, [String? path3, String? path4]) => |
| pathos.join(path1, path2, path3, path4); |
| |
| @override |
| void _baseSetUp() { |
| tempPath = pathos.join(io.Directory.systemTemp.path, 'test_file_system'); |
| fileSystem = new MemoryFileSystem(pathos.toUri(io.Directory.current.path)); |
| } |
| } |
| |
| class _BaseTestPosix extends _BaseTest { |
| @override |
| final pathos.Context context = pathos.posix; |
| |
| @override |
| late MemoryFileSystem fileSystem; |
| |
| @override |
| late String tempPath; |
| |
| @override |
| String join(String path1, String path2, [String? path3, String? path4]) => |
| pathos.posix.join(path1, path2, path3, path4); |
| |
| @override |
| void _baseSetUp() { |
| tempPath = '/test_file_system'; |
| fileSystem = new MemoryFileSystem(Uri.parse('file:///cwd')); |
| } |
| } |
| |
| class _BaseTestWindows extends _BaseTest { |
| @override |
| final pathos.Context context = pathos.windows; |
| |
| @override |
| late MemoryFileSystem fileSystem; |
| |
| @override |
| late String tempPath; |
| |
| @override |
| String join(String path1, String path2, [String? path3, String? path4]) => |
| pathos.windows.join(path1, path2, path3, path4); |
| |
| @override |
| void _baseSetUp() { |
| tempPath = r'c:\test_file_system'; |
| fileSystem = new MemoryFileSystem(Uri.parse('file:///c:/cwd')); |
| } |
| } |