| // Copyright (c) 2013, 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. |
| |
| // @dart = 2.9 |
| |
| import "package:async_helper/async_helper.dart"; |
| import "package:expect/expect.dart"; |
| import "package:path/path.dart"; |
| import "dart:async"; |
| import "dart:io"; |
| |
| // Test the dart:io Link class. |
| |
| testCreateSync() { |
| asyncStart(); |
| String base = Directory.systemTemp.createTempSync('dart_link').path; |
| if (isRelative(base)) { |
| Expect.fail( |
| 'Link tests expect absolute paths to system temporary directories. ' |
| 'A relative path in TMPDIR gives relative paths to them.'); |
| } |
| String link = join(base, 'link'); |
| String target = join(base, 'target'); |
| new Directory(target).createSync(); |
| new Link(link).createSync(target); |
| Expect.equals( |
| FileSystemEntityType.directory, FileSystemEntity.typeSync(link)); |
| Expect.equals( |
| FileSystemEntityType.directory, FileSystemEntity.typeSync(target)); |
| Expect.equals(FileSystemEntityType.link, |
| FileSystemEntity.typeSync(link, followLinks: false)); |
| Expect.equals(FileSystemEntityType.directory, |
| FileSystemEntity.typeSync(target, followLinks: false)); |
| Expect.isTrue(FileSystemEntity.isLinkSync(link)); |
| Expect.isFalse(FileSystemEntity.isLinkSync(target)); |
| Expect.isTrue(new Directory(link).existsSync()); |
| Expect.isTrue(new Directory(target).existsSync()); |
| Expect.isTrue(new Link(link).existsSync()); |
| Expect.isFalse(new Link(target).existsSync()); |
| Expect.equals(target, new Link(link).targetSync()); |
| Expect.throws(() => new Link(target).targetSync()); |
| |
| String createdThroughLink = join(base, 'link', 'createdThroughLink'); |
| String createdDirectly = join(base, 'target', 'createdDirectly'); |
| new Directory(createdThroughLink).createSync(); |
| new Directory(createdDirectly).createSync(); |
| Expect.isTrue(new Directory(createdThroughLink).existsSync()); |
| Expect.isTrue(new Directory(createdDirectly).existsSync()); |
| Expect.isTrue( |
| new Directory(join(base, 'link', 'createdDirectly')).existsSync()); |
| Expect.isTrue( |
| new Directory(join(base, 'target', 'createdThroughLink')).existsSync()); |
| Expect.equals(FileSystemEntityType.directory, |
| FileSystemEntity.typeSync(createdThroughLink, followLinks: false)); |
| Expect.equals(FileSystemEntityType.directory, |
| FileSystemEntity.typeSync(createdDirectly, followLinks: false)); |
| |
| // Test FileSystemEntity.identical on files, directories, and links, |
| // reached by different paths. |
| Expect.isTrue( |
| FileSystemEntity.identicalSync(createdDirectly, createdDirectly)); |
| Expect.isFalse( |
| FileSystemEntity.identicalSync(createdDirectly, createdThroughLink)); |
| Expect.isTrue(FileSystemEntity.identicalSync( |
| createdDirectly, join(base, 'link', 'createdDirectly'))); |
| Expect.isTrue(FileSystemEntity.identicalSync( |
| createdThroughLink, join(base, 'target', 'createdThroughLink'))); |
| |
| Expect.isFalse(FileSystemEntity.identicalSync(target, link)); |
| Expect.isTrue(FileSystemEntity.identicalSync(link, link)); |
| Expect.isTrue(FileSystemEntity.identicalSync(target, target)); |
| Expect.isTrue( |
| FileSystemEntity.identicalSync(target, new Link(link).targetSync())); |
| String absolutePath = new File(".").resolveSymbolicLinksSync(); |
| Expect.isTrue(FileSystemEntity.identicalSync(".", absolutePath)); |
| |
| String createdFile = join(base, 'target', 'createdFile'); |
| new File(createdFile).createSync(); |
| Expect.isTrue(FileSystemEntity.identicalSync(createdFile, createdFile)); |
| Expect.isFalse(FileSystemEntity.identicalSync(createdFile, createdDirectly)); |
| Expect.isTrue(FileSystemEntity.identicalSync( |
| createdFile, join(base, 'link', 'createdFile'))); |
| Expect.throws(() => FileSystemEntity.identicalSync( |
| createdFile, join(base, 'link', 'does_not_exist'))); |
| |
| var baseDir = new Directory(base); |
| |
| Map makeExpected(bool recursive, bool followLinks) { |
| Map expected = new Map(); |
| expected['target'] = 'Directory'; |
| expected['link'] = followLinks ? 'Directory' : 'Link'; |
| if (recursive) { |
| expected[join('target', 'createdDirectly')] = 'Directory'; |
| expected[join('target', 'createdThroughLink')] = 'Directory'; |
| expected[join('target', 'createdFile')] = 'File'; |
| if (followLinks) { |
| expected[join('link', 'createdDirectly')] = 'Directory'; |
| expected[join('link', 'createdThroughLink')] = 'Directory'; |
| expected[join('link', 'createdFile')] = 'File'; |
| } |
| } |
| return expected; |
| } |
| |
| void checkEntity(FileSystemEntity x, Map expected) { |
| String ending = relative(x.path, from: base); |
| Expect.isNotNull(expected[ending]); |
| Expect.isTrue(x.toString().startsWith(expected[ending])); |
| expected[ending] = 'Found'; |
| } |
| |
| var futures = <Future>[]; |
| for (bool recursive in [true, false]) { |
| for (bool followLinks in [true, false]) { |
| Map expected = makeExpected(recursive, followLinks); |
| for (var x |
| in baseDir.listSync(recursive: recursive, followLinks: followLinks)) { |
| checkEntity(x, expected); |
| } |
| for (var v in expected.values) { |
| Expect.equals('Found', v); |
| } |
| expected = makeExpected(recursive, followLinks); |
| // We use Stream.reduce to run a function on each entry, and return |
| // a future that completes when done. |
| var f = new Completer(); |
| futures.add(f.future); |
| baseDir.list(recursive: recursive, followLinks: followLinks).listen( |
| (entity) { |
| checkEntity(entity, expected); |
| }, onDone: () { |
| for (var v in expected.values) { |
| Expect.equals('Found', v); |
| } |
| f.complete(null); |
| }); |
| } |
| } |
| Future.wait(futures).then((_) { |
| new Directory(target).deleteSync(recursive: true); |
| for (bool recursive in [true, false]) { |
| for (bool followLinks in [true, false]) { |
| var result = |
| baseDir.listSync(recursive: recursive, followLinks: followLinks); |
| Expect.equals(1, result.length); |
| Expect.isTrue(result[0] is Link); |
| } |
| } |
| baseDir.deleteSync(recursive: true); |
| asyncEnd(); |
| }); |
| } |
| |
| testCreateLoopingLink() { |
| asyncStart(); |
| String base = Directory.systemTemp.createTempSync('dart_link').path; |
| new Directory(join(base, 'a', 'b', 'c')) |
| .create(recursive: true) |
| .then((_) => |
| new Link(join(base, 'a', 'b', 'c', 'd')).create(join(base, 'a', 'b'))) |
| .then((_) => |
| new Link(join(base, 'a', 'b', 'c', 'e')).create(join(base, 'a'))) |
| .then((_) => new Directory(join(base, 'a')) |
| .list(recursive: true, followLinks: false) |
| .last) |
| .then((_) => |
| // This directory listing must terminate, even though it contains loops. |
| new Directory(join(base, 'a')) |
| .list(recursive: true, followLinks: true) |
| .last) |
| .then((_) => |
| // This directory listing must terminate, even though it contains loops. |
| new Directory(join(base, 'a', 'b', 'c')) |
| .list(recursive: true, followLinks: true) |
| .last) |
| .whenComplete(() { |
| new Directory(base).deleteSync(recursive: true); |
| asyncEnd(); |
| }); |
| } |
| |
| testRenameSync() { |
| testRename(String base, String target) { |
| Link link1 = new Link(join(base, 'c'))..createSync(target); |
| Expect.isTrue(link1.existsSync()); |
| Link link2 = link1.renameSync(join(base, 'd')); |
| Expect.isFalse(link1.existsSync()); |
| Expect.isTrue(link2.existsSync()); |
| link2.deleteSync(); |
| Expect.isFalse(link2.existsSync()); |
| } |
| |
| testRenameToLink(String base, String target) { |
| Link link1 = Link(join(base, '1'))..createSync(target); |
| Link link2 = Link(join(base, '2'))..createSync(target); |
| Expect.isTrue(link1.existsSync()); |
| Expect.isTrue(link2.existsSync()); |
| Link renamed = link1.renameSync(link2.path); |
| Expect.isFalse(link1.existsSync()); |
| Expect.isTrue(renamed.existsSync()); |
| renamed.deleteSync(); |
| Expect.isFalse(renamed.existsSync()); |
| } |
| |
| testRenameToTarget(String linkName, String target, bool isDirectory) { |
| Link link = Link(linkName)..createSync(target); |
| Expect.isTrue(link.existsSync()); |
| try { |
| Link renamed = link.renameSync(target); |
| if (isDirectory) { |
| Expect.fail('Renaming a link to the name of an existing directory ' + |
| 'should fail'); |
| } |
| Expect.isTrue(renamed.existsSync()); |
| renamed.deleteSync(); |
| } on FileSystemException catch (_) { |
| if (isDirectory) { |
| return; |
| } |
| Expect.fail('Renaming a link to the name of an existing file should ' + |
| 'not fail'); |
| } |
| } |
| |
| Directory baseDir = Directory.systemTemp.createTempSync('dart_link'); |
| String base = baseDir.path; |
| Directory dir = new Directory(join(base, 'a'))..createSync(); |
| File file = new File(join(base, 'b'))..createSync(); |
| |
| testRename(base, file.path); |
| testRename(base, dir.path); |
| |
| testRenameToLink(base, file.path); |
| |
| testRenameToTarget(join(base, 'fileLink'), file.path, false); |
| testRenameToTarget(join(base, 'dirLink'), dir.path, true); |
| |
| baseDir.deleteSync(recursive: true); |
| } |
| |
| void testLinkErrorSync() { |
| Expect.throws( |
| () => new Link('some-dir-that-doent exist/some link file/bla/fisk') |
| .createSync('bla bla bla/b lalal/blfir/sdfred/es'), |
| (e) => e is FileSystemException); |
| } |
| |
| checkExists(String filePath) => Expect.isTrue(new File(filePath).existsSync()); |
| |
| testRelativeLinksSync() { |
| Directory tempDirectory = Directory.systemTemp.createTempSync('dart_link'); |
| String temp = tempDirectory.path; |
| String oldWorkingDirectory = Directory.current.path; |
| // Make directories and files to test links. |
| new Directory(join(temp, 'dir1', 'dir2')).createSync(recursive: true); |
| new File(join(temp, 'dir1', 'file1')).createSync(); |
| new File(join(temp, 'dir1', 'dir2', 'file2')).createSync(); |
| // Make links whose path and/or target is given by a relative path. |
| new Link(join(temp, 'dir1', 'link1_2')).createSync('dir2'); |
| Directory.current = temp; |
| new Link('link0_2').createSync(join('dir1', 'dir2')); |
| new Link(join('dir1', 'link1_0')).createSync('..'); |
| Directory.current = 'dir1'; |
| new Link(join('..', 'link0_1')).createSync('dir1'); |
| new Link(join('dir2', 'link2_1')).createSync(join(temp, 'dir1')); |
| new Link(join(temp, 'dir1', 'dir2', 'link2_0')).createSync(join('..', '..')); |
| // Test that the links go to the right targets. |
| checkExists(join('..', 'link0_1', 'file1')); |
| checkExists(join('..', 'link0_2', 'file2')); |
| checkExists(join('link1_0', 'dir1', 'file1')); |
| checkExists(join('link1_2', 'file2')); |
| checkExists(join('dir2', 'link2_0', 'dir1', 'file1')); |
| checkExists(join('dir2', 'link2_1', 'file1')); |
| // Clean up |
| Directory.current = oldWorkingDirectory; |
| tempDirectory.deleteSync(recursive: true); |
| } |
| |
| testIsDir() async { |
| // Only run on Platforms that supports file watcher |
| if (!Platform.isWindows && !Platform.isLinux && !Platform.isMacOS) return; |
| Directory sandbox = Directory.systemTemp.createTempSync(); |
| Directory dir = new Directory(sandbox.path + Platform.pathSeparator + "dir"); |
| dir.createSync(); |
| File target = new File(sandbox.path + Platform.pathSeparator + "target"); |
| target.createSync(); |
| |
| var eventCompleter = new Completer<FileSystemEvent>(); |
| var subscription; |
| // Check for link pointing to file |
| subscription = dir.watch().listen((FileSystemEvent event) { |
| if (event.path.endsWith('link')) { |
| eventCompleter.complete(event); |
| subscription.cancel(); |
| } |
| }); |
| Link link = new Link(dir.path + Platform.pathSeparator + "link"); |
| link.createSync(target.path); |
| var event = await eventCompleter.future; |
| Expect.isFalse(event.isDirectory); |
| |
| // Check for link pointing to directory |
| eventCompleter = new Completer<FileSystemEvent>(); |
| subscription = dir.watch().listen((FileSystemEvent event) { |
| if (event.path.endsWith('link2')) { |
| eventCompleter.complete(event); |
| subscription.cancel(); |
| } |
| }); |
| link = new Link(dir.path + Platform.pathSeparator + "link2"); |
| link.createSync(dir.path); |
| event = await eventCompleter.future; |
| Expect.isFalse(event.isDirectory); |
| |
| sandbox.deleteSync(recursive: true); |
| } |
| |
| main() { |
| testCreateSync(); |
| testCreateLoopingLink(); |
| testRenameSync(); |
| testLinkErrorSync(); |
| testRelativeLinksSync(); |
| testIsDir(); |
| } |