Skip to content

Decouple more tests from dart:io #255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 23, 2025
548 changes: 275 additions & 273 deletions pkgs/io_file/test/copy_file_test.dart

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pkgs/io_file/test/create_directory_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ void tests(FileUtils utils, FileSystem fs) {
late String cwd;

setUp(() {
tmp = createTemp('createDirectory');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's neat! I hadn't seen that package before.

I don't think that I can use it though because it depends on dart:io. The purpose of this TestUtils refactor is to (eventually) divorce the tests from dart:io completely so that you can verify fakes (where the file system objects will exist only in memory).

tmp = utils.createTestDirectory('createDirectory');
cwd = fs.currentDirectory;
fs.currentDirectory = tmp;
});

tearDown(() {
fs.currentDirectory = cwd;
deleteTemp(tmp);
utils.deleteDirectoryTree(tmp);
});

test('success', () {
Expand Down
347 changes: 175 additions & 172 deletions pkgs/io_file/test/create_temporary_directory_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,181 +13,184 @@ import 'package:test/test.dart';
import 'package:win32/win32.dart' as win32;

import 'errors.dart' as errors;
import 'file_system_file_utils.dart' hide fileUtils;
import 'test_utils.dart';

void main() {
group('createTemporaryDirectory', () {
late String tmp;
late String cwd;

setUp(() {
tmp = createTemp('createTemporaryDirectory');
cwd = fileSystem.currentDirectory;
fileSystem.currentDirectory = tmp;
});

tearDown(() {
fileSystem.currentDirectory = cwd;
deleteTemp(tmp);
});

test('no arguments', () {
final tmp1 = fileSystem.createTemporaryDirectory();
addTearDown(() => io.Directory(tmp1).deleteSync());
final tmp2 = fileSystem.createTemporaryDirectory();
addTearDown(() => io.Directory(tmp2).deleteSync());

expect(fileSystem.same(tmp1, tmp2), isFalse);
expect(io.Directory(tmp1).existsSync(), isTrue);
expect(io.Directory(tmp2).existsSync(), isTrue);
});

test('prefix', () {
final tmp1 = fileSystem.createTemporaryDirectory(prefix: 'myprefix');
addTearDown(() => io.Directory(tmp1).deleteSync());
final tmp2 = fileSystem.createTemporaryDirectory(prefix: 'myprefix');
addTearDown(() => io.Directory(tmp2).deleteSync());

expect(tmp1, contains('myprefix'));
expect(tmp2, contains('myprefix'));
expect(fileSystem.same(tmp1, tmp2), isFalse);
expect(io.Directory(tmp1).existsSync(), isTrue);
expect(io.Directory(tmp2).existsSync(), isTrue);
});

test('prefix is empty string', () {
final tmp1 = fileSystem.createTemporaryDirectory(prefix: '');
addTearDown(() => io.Directory(tmp1).deleteSync());
final tmp2 = fileSystem.createTemporaryDirectory(prefix: '');
addTearDown(() => io.Directory(tmp2).deleteSync());

expect(fileSystem.same(tmp1, tmp2), isFalse);
expect(io.Directory(tmp1).existsSync(), isTrue);
expect(io.Directory(tmp2).existsSync(), isTrue);
});

test('prefix contains XXXXXX', () {
final tmp1 = fileSystem.createTemporaryDirectory(
prefix: 'myprefix-XXXXXX',
);
addTearDown(() => io.Directory(tmp1).deleteSync());
final tmp2 = fileSystem.createTemporaryDirectory(
prefix: 'myprefix-XXXXXX',
);
addTearDown(() => io.Directory(tmp2).deleteSync());

expect(tmp1, contains('myprefix-'));
expect(tmp2, contains('myprefix-'));
expect(fileSystem.same(tmp1, tmp2), isFalse);
expect(io.Directory(tmp1).existsSync(), isTrue);
expect(io.Directory(tmp2).existsSync(), isTrue);
});

test('parent', () {
final tmp1 = fileSystem.createTemporaryDirectory(parent: tmp);
final tmp2 = fileSystem.createTemporaryDirectory(parent: tmp);

expect(tmp1, startsWith(tmp));
expect(tmp2, startsWith(tmp));
expect(fileSystem.same(tmp1, tmp2), isFalse);
expect(io.Directory(tmp1).existsSync(), isTrue);
expect(io.Directory(tmp2).existsSync(), isTrue);
});

test('parent has a long directory name', () {
// On Windows:
// When using an API to create a directory, the specified path cannot be
// so long that you cannot append an 8.3 file name (that is, the directory
// name cannot exceed MAX_PATH minus 12).
final dirname = 'd' * (io.Platform.isWindows ? win32.MAX_PATH - 12 : 255);
final parent = p.join(tmp, dirname);
io.Directory(parent).createSync();

final tmp1 = fileSystem.createTemporaryDirectory(parent: parent);
final tmp2 = fileSystem.createTemporaryDirectory(parent: parent);

expect(tmp1, startsWith(tmp));
expect(tmp2, startsWith(tmp));
expect(fileSystem.same(tmp1, tmp2), isFalse);
expect(io.Directory(tmp1).existsSync(), isTrue);
expect(io.Directory(tmp2).existsSync(), isTrue);
});

test('parent is empty string', () {
final tmp1 = fileSystem.createTemporaryDirectory(parent: '');
addTearDown(() => io.Directory(tmp1).deleteSync());
final tmp2 = fileSystem.createTemporaryDirectory(parent: '');
addTearDown(() => io.Directory(tmp2).deleteSync());

expect(p.isRelative(tmp1), isTrue);
expect(p.isRelative(tmp2), isTrue);
expect(fileSystem.same(tmp1, tmp2), isFalse);
expect(io.Directory(tmp1).existsSync(), isTrue);
expect(io.Directory(tmp2).existsSync(), isTrue);
});

test('parent does not exist', () {
expect(
() => fileSystem.createTemporaryDirectory(parent: '/foo/bar/baz'),
throwsA(
isA<PathNotFoundException>().having(
(e) => e.errorCode,
'errorCode',
io.Platform.isWindows ? win32.ERROR_PATH_NOT_FOUND : errors.enoent,
),
void tests(FileUtils utils, FileSystem fs) {
late String tmp;
late String cwd;

setUp(() {
tmp = utils.createTestDirectory('createTemporaryDirectory');
cwd = fs.currentDirectory;
fs.currentDirectory = tmp;
});

tearDown(() {
fs.currentDirectory = cwd;
utils.deleteDirectoryTree(tmp);
});

test('no arguments', () {
final tmp1 = fs.createTemporaryDirectory();
addTearDown(() => utils.deleteDirectory(tmp1));
final tmp2 = fs.createTemporaryDirectory();
addTearDown(() => utils.deleteDirectory(tmp2));

expect(fs.same(tmp1, tmp2), isFalse);
expect(utils.isDirectory(tmp1), isTrue);
expect(utils.isDirectory(tmp2), isTrue);
});

test('prefix', () {
final tmp1 = fs.createTemporaryDirectory(prefix: 'myprefix');
addTearDown(() => utils.deleteDirectory(tmp1));
final tmp2 = fs.createTemporaryDirectory(prefix: 'myprefix');
addTearDown(() => utils.deleteDirectory(tmp2));

expect(tmp1, contains('myprefix'));
expect(tmp2, contains('myprefix'));
expect(fs.same(tmp1, tmp2), isFalse);
expect(utils.isDirectory(tmp1), isTrue);
expect(utils.isDirectory(tmp2), isTrue);
});

test('prefix is empty string', () {
final tmp1 = fs.createTemporaryDirectory(prefix: '');
addTearDown(() => utils.deleteDirectory(tmp1));
final tmp2 = fs.createTemporaryDirectory(prefix: '');
addTearDown(() => utils.deleteDirectory(tmp2));

expect(fs.same(tmp1, tmp2), isFalse);
expect(utils.isDirectory(tmp1), isTrue);
expect(utils.isDirectory(tmp2), isTrue);
});

test('prefix contains XXXXXX', () {
final tmp1 = fs.createTemporaryDirectory(prefix: 'myprefix-XXXXXX');
addTearDown(() => utils.deleteDirectory(tmp1));
final tmp2 = fs.createTemporaryDirectory(prefix: 'myprefix-XXXXXX');
addTearDown(() => utils.deleteDirectory(tmp2));

expect(tmp1, contains('myprefix-'));
expect(tmp2, contains('myprefix-'));
expect(fs.same(tmp1, tmp2), isFalse);
expect(utils.isDirectory(tmp1), isTrue);
expect(utils.isDirectory(tmp2), isTrue);
});

test('parent', () {
final tmp1 = fs.createTemporaryDirectory(parent: tmp);
final tmp2 = fs.createTemporaryDirectory(parent: tmp);

expect(tmp1, startsWith(tmp));
expect(tmp2, startsWith(tmp));
expect(fs.same(tmp1, tmp2), isFalse);
expect(utils.isDirectory(tmp1), isTrue);
expect(utils.isDirectory(tmp2), isTrue);
});

test('parent has a long directory name', () {
// On Windows:
// When using an API to create a directory, the specified path cannot be
// so long that you cannot append an 8.3 file name (that is, the directory
// name cannot exceed MAX_PATH minus 12).
final dirname = 'd' * (io.Platform.isWindows ? win32.MAX_PATH - 12 : 255);
final parent = p.join(tmp, dirname);
utils.createDirectory(parent);

final tmp1 = fs.createTemporaryDirectory(parent: parent);
final tmp2 = fs.createTemporaryDirectory(parent: parent);

expect(tmp1, startsWith(tmp));
expect(tmp2, startsWith(tmp));
expect(fs.same(tmp1, tmp2), isFalse);
expect(utils.isDirectory(tmp1), isTrue);
expect(utils.isDirectory(tmp2), isTrue);
});

test('parent is empty string', () {
final tmp1 = fs.createTemporaryDirectory(parent: '');
addTearDown(() => utils.deleteDirectory(tmp1));
final tmp2 = fs.createTemporaryDirectory(parent: '');
addTearDown(() => utils.deleteDirectory(tmp2));

expect(p.isRelative(tmp1), isTrue);
expect(p.isRelative(tmp2), isTrue);
expect(fs.same(tmp1, tmp2), isFalse);
expect(utils.isDirectory(tmp1), isTrue);
expect(utils.isDirectory(tmp2), isTrue);
});

test('parent does not exist', () {
expect(
() => fs.createTemporaryDirectory(parent: '/foo/bar/baz'),
throwsA(
isA<PathNotFoundException>().having(
(e) => e.errorCode,
'errorCode',
io.Platform.isWindows ? win32.ERROR_PATH_NOT_FOUND : errors.enoent,
),
);
});

test('prefix is absolute path inside of parent', () {
final subdir1 = '$tmp/dir1';
io.Directory(subdir1).createSync();

final tmp1 = fileSystem.createTemporaryDirectory(
parent: subdir1,
prefix: '$subdir1/file',
);

expect(tmp1, startsWith(subdir1));
});

test('prefix is absolute path outside of parent', () {
final subdir1 = '$tmp/dir1';
final subdir2 = '$tmp/dir2';
io.Directory(subdir1).createSync();
io.Directory(subdir2).createSync();

final tmp1 = fileSystem.createTemporaryDirectory(
parent: subdir1,
prefix: '$subdir2/file',
);

expect(tmp1, startsWith(subdir2));
});

test('prefix is non-existant path inside temp directory', () {
expect(
() => fileSystem.createTemporaryDirectory(prefix: 'subdir/file'),
throwsA(
isA<PathNotFoundException>().having(
(e) => e.errorCode,
'errorCode',
io.Platform.isWindows ? win32.ERROR_PATH_NOT_FOUND : errors.enoent,
),
),
);
});

test('prefix is absolute path inside of parent', () {
final subdir1 = '$tmp/dir1';
utils.createDirectory(subdir1);

final tmp1 = fs.createTemporaryDirectory(
parent: subdir1,
prefix: '$subdir1/file',
);

expect(tmp1, startsWith(subdir1));
});

test('prefix is absolute path outside of parent', () {
final subdir1 = '$tmp/dir1';
final subdir2 = '$tmp/dir2';
utils
..createDirectory(subdir1)
..createDirectory(subdir2);

final tmp1 = fs.createTemporaryDirectory(
parent: subdir1,
prefix: '$subdir2/file',
);

expect(tmp1, startsWith(subdir2));
});

test('prefix is non-existant path inside temp directory', () {
expect(
() => fs.createTemporaryDirectory(prefix: 'subdir/file'),
throwsA(
isA<PathNotFoundException>().having(
(e) => e.errorCode,
'errorCode',
io.Platform.isWindows ? win32.ERROR_PATH_NOT_FOUND : errors.enoent,
),
);
});

test('prefix is existant path inside temp directory', () {
final subdir1 = '$tmp/dir1';
io.Directory(subdir1).createSync();

final tmp1 = fileSystem.createTemporaryDirectory(
parent: tmp,
prefix: 'dir1/file',
);
expect(p.canonicalize(tmp1), startsWith(p.canonicalize(subdir1)));
expect(io.Directory(tmp1).existsSync(), isTrue);
});
),
);
});

test('prefix is existant path inside temp directory', () {
final subdir1 = '$tmp/dir1';
utils.createDirectory(subdir1);

final tmp1 = fs.createTemporaryDirectory(parent: tmp, prefix: 'dir1/file');
expect(p.canonicalize(tmp1), startsWith(p.canonicalize(subdir1)));
expect(utils.isDirectory(tmp1), isTrue);
});
}

void main() {
group('createTemporaryDirectory', () {
group('dart:io verification', () => tests(fileUtils(), fileSystem));
group(
'self verification',
() => tests(FileSystemFileUtils(fileSystem), fileSystem),
);
});
}
Loading