blob: 2c9161cbf0df4fd2db1a1443d59265cc6e41aecf [file] [log] [blame]
// Copyright 2014 The Flutter Authors. 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:io' as io;
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/signals.dart';
import 'package:mockito/mockito.dart';
import '../../src/common.dart';
import '../../src/context.dart';
void main() {
group('fsUtils', () {
MemoryFileSystem fs;
FileSystemUtils fsUtils;
setUp(() {
fs = MemoryFileSystem.test();
fsUtils = FileSystemUtils(
fileSystem: fs,
platform: FakePlatform(),
);
});
testWithoutContext('ensureDirectoryExists recursively creates a directory if it does not exist', () async {
fsUtils.ensureDirectoryExists('foo/bar/baz.flx');
expect(fs.isDirectorySync('foo/bar'), true);
});
testWithoutContext('ensureDirectoryExists throws tool exit on failure to create', () async {
fs.file('foo').createSync();
expect(() => fsUtils.ensureDirectoryExists('foo/bar.flx'), throwsToolExit());
});
testWithoutContext('getUniqueFile creates a unique file name', () async {
final File fileA = fsUtils.getUniqueFile(fs.currentDirectory, 'foo', 'json')
..createSync();
final File fileB = fsUtils.getUniqueFile(fs.currentDirectory, 'foo', 'json');
expect(fileA.path, '/foo_01.json');
expect(fileB.path, '/foo_02.json');
});
testWithoutContext('getUniqueDirectory creates a unique directory name', () async {
final Directory directoryA = fsUtils.getUniqueDirectory(fs.currentDirectory, 'foo')
..createSync();
final Directory directoryB = fsUtils.getUniqueDirectory(fs.currentDirectory, 'foo');
expect(directoryA.path, '/foo_01');
expect(directoryB.path, '/foo_02');
});
});
group('copyDirectorySync', () {
/// Test file_systems.copyDirectorySync() using MemoryFileSystem.
/// Copies between 2 instances of file systems which is also supported by copyDirectorySync().
testWithoutContext('test directory copy', () async {
final MemoryFileSystem sourceMemoryFs = MemoryFileSystem.test();
const String sourcePath = '/some/origin';
final Directory sourceDirectory = await sourceMemoryFs.directory(sourcePath).create(recursive: true);
sourceMemoryFs.currentDirectory = sourcePath;
final File sourceFile1 = sourceMemoryFs.file('some_file.txt')..writeAsStringSync('bleh');
final DateTime writeTime = sourceFile1.lastModifiedSync();
sourceMemoryFs.file('sub_dir/another_file.txt').createSync(recursive: true);
sourceMemoryFs.directory('empty_directory').createSync();
// Copy to another memory file system instance.
final MemoryFileSystem targetMemoryFs = MemoryFileSystem.test();
const String targetPath = '/some/non-existent/target';
final Directory targetDirectory = targetMemoryFs.directory(targetPath);
final FileSystemUtils fsUtils = FileSystemUtils(
fileSystem: sourceMemoryFs,
platform: FakePlatform(),
);
fsUtils.copyDirectorySync(sourceDirectory, targetDirectory);
expect(targetDirectory.existsSync(), true);
targetMemoryFs.currentDirectory = targetPath;
expect(targetMemoryFs.directory('empty_directory').existsSync(), true);
expect(targetMemoryFs.file('sub_dir/another_file.txt').existsSync(), true);
expect(targetMemoryFs.file('some_file.txt').readAsStringSync(), 'bleh');
// Assert that the copy operation hasn't modified the original file in some way.
expect(sourceMemoryFs.file('some_file.txt').lastModifiedSync(), writeTime);
// There's still 3 things in the original directory as there were initially.
expect(sourceMemoryFs.directory(sourcePath).listSync().length, 3);
});
testWithoutContext('Skip files if shouldCopyFile returns false', () {
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FileSystemUtils fsUtils = FileSystemUtils(
fileSystem: fileSystem,
platform: FakePlatform(),
);
final Directory origin = fileSystem.directory('/origin');
origin.createSync();
fileSystem.file(fileSystem.path.join('origin', 'a.txt')).writeAsStringSync('irrelevant');
fileSystem.directory('/origin/nested').createSync();
fileSystem.file(fileSystem.path.join('origin', 'nested', 'a.txt')).writeAsStringSync('irrelevant');
fileSystem.file(fileSystem.path.join('origin', 'nested', 'b.txt')).writeAsStringSync('irrelevant');
final Directory destination = fileSystem.directory('/destination');
fsUtils.copyDirectorySync(origin, destination, shouldCopyFile: (File origin, File dest) {
return origin.basename == 'b.txt';
});
expect(destination.existsSync(), isTrue);
expect(destination.childDirectory('nested').existsSync(), isTrue);
expect(destination.childDirectory('nested').childFile('b.txt').existsSync(), isTrue);
expect(destination.childFile('a.txt').existsSync(), isFalse);
expect(destination.childDirectory('nested').childFile('a.txt').existsSync(), isFalse);
});
});
group('escapePath', () {
testWithoutContext('on Windows', () {
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FileSystemUtils fsUtils = FileSystemUtils(
fileSystem: fileSystem,
platform: FakePlatform(operatingSystem: 'windows'),
);
expect(fsUtils.escapePath(r'C:\foo\bar\cool.dart'), r'C:\\foo\\bar\\cool.dart');
expect(fsUtils.escapePath(r'foo\bar\cool.dart'), r'foo\\bar\\cool.dart');
expect(fsUtils.escapePath('C:/foo/bar/cool.dart'), 'C:/foo/bar/cool.dart');
});
testWithoutContext('on Linux', () {
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FileSystemUtils fsUtils = FileSystemUtils(
fileSystem: fileSystem,
platform: FakePlatform(operatingSystem: 'linux'),
);
expect(fsUtils.escapePath('/foo/bar/cool.dart'), '/foo/bar/cool.dart');
expect(fsUtils.escapePath('foo/bar/cool.dart'), 'foo/bar/cool.dart');
expect(fsUtils.escapePath(r'foo\cool.dart'), r'foo\cool.dart');
});
});
group('LocalFileSystem', () {
MockIoProcessSignal mockSignal;
ProcessSignal signalUnderTest;
StreamController<io.ProcessSignal> controller;
setUp(() {
mockSignal = MockIoProcessSignal();
signalUnderTest = ProcessSignal(mockSignal);
controller = StreamController<io.ProcessSignal>();
when(mockSignal.watch()).thenAnswer((Invocation invocation) => controller.stream);
});
testUsingContext('deletes system temp entry on a fatal signal', () async {
final Completer<void> completer = Completer<void>();
final Signals signals = Signals.test();
final LocalFileSystem localFileSystem = LocalFileSystem.test(
signals: signals,
fatalSignals: <ProcessSignal>[signalUnderTest],
);
final Directory temp = localFileSystem.systemTempDirectory;
signals.addHandler(signalUnderTest, (ProcessSignal s) {
completer.complete();
});
expect(temp.existsSync(), isTrue);
controller.add(mockSignal);
await completer.future;
expect(temp.existsSync(), isFalse);
});
});
}
class MockIoProcessSignal extends Mock implements io.ProcessSignal {}
class MockFile extends Mock implements File {}