| // 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 "dart:async"; |
| import "dart:io"; |
| |
| import "package:async_helper/async_helper.dart"; |
| import "package:expect/expect.dart"; |
| import "package:path/path.dart"; |
| |
| // Test the dart:io Link class. |
| |
| class FutureExpect { |
| static Future isTrue(Future<bool> result) => |
| result.then((value) => Expect.isTrue(value)); |
| static Future isFalse(Future<bool> result) => |
| result.then((value) => Expect.isFalse(value)); |
| static Future equals(expected, Future result) => |
| result.then((value) => Expect.equals(expected, value)); |
| static Future listEquals(expected, Future result) => |
| result.then((value) => Expect.listEquals(expected, value)); |
| static Future throws(Future result) => result.then((value) { |
| throw new ExpectException( |
| "FutureExpect.throws received $value instead of an exception"); |
| }, onError: (_) => null); |
| } |
| |
| Future testCreate() { |
| return Directory.systemTemp.createTemp('dart_link_async').then((baseDir) { |
| if (isRelative(baseDir.path)) { |
| Expect.fail( |
| 'Link tests expect absolute paths to system temporary directories. ' |
| 'A relative path in TMPDIR gives relative paths to them.'); |
| } |
| String base = baseDir.path; |
| String link = join(base, 'link'); |
| String target = join(base, 'target'); |
| return new Directory(target) |
| .create() |
| .then((_) => new Link(link).create(target)) |
| .then((_) => FutureExpect.equals( |
| FileSystemEntityType.directory, FileSystemEntity.type(link))) |
| .then((_) => FutureExpect.equals( |
| FileSystemEntityType.directory, FileSystemEntity.type(target))) |
| .then((_) => FutureExpect.equals(FileSystemEntityType.link, |
| FileSystemEntity.type(link, followLinks: false))) |
| .then((_) => FutureExpect.equals(FileSystemEntityType.directory, |
| FileSystemEntity.type(target, followLinks: false))) |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.isLink(link))) |
| .then((_) => FutureExpect.isFalse(FileSystemEntity.isLink(target))) |
| .then((_) => FutureExpect.isTrue(new Directory(link).exists())) |
| .then((_) => FutureExpect.isTrue(new Directory(target).exists())) |
| .then((_) => FutureExpect.isTrue(new Link(link).exists())) |
| .then((_) => FutureExpect.isFalse(new Link(target).exists())) |
| .then((_) => FutureExpect.equals(target, new Link(link).target())) |
| .then((_) => FutureExpect.throws(new Link(target).target())) |
| .then((_) { |
| String createdThroughLink = join(base, 'link', 'createdThroughLink'); |
| String createdDirectly = join(base, 'target', 'createdDirectly'); |
| String createdFile = join(base, 'link', 'createdFile'); |
| return new Directory(createdThroughLink) |
| .create() |
| .then((_) => new Directory(createdDirectly).create()) |
| .then((_) => new File(createdFile).create()) |
| .then((_) => |
| FutureExpect.isTrue(new Directory(createdThroughLink).exists())) |
| .then((_) => |
| FutureExpect.isTrue(new Directory(createdDirectly).exists())) |
| .then((_) => FutureExpect.isTrue( |
| new Directory(join(base, 'link', 'createdDirectly')).exists())) |
| .then((_) => FutureExpect.isTrue( |
| new Directory(join(base, 'target', 'createdThroughLink')) |
| .exists())) |
| .then((_) => FutureExpect.equals(FileSystemEntityType.directory, |
| FileSystemEntity.type(createdThroughLink, followLinks: false))) |
| .then((_) => FutureExpect.equals(FileSystemEntityType.directory, |
| FileSystemEntity.type(createdDirectly, followLinks: false))) |
| |
| // Test FileSystemEntity.identical on files, directories, and links, |
| // reached by different paths. |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.identical(createdDirectly, createdDirectly))) |
| .then((_) => FutureExpect.isFalse(FileSystemEntity.identical(createdDirectly, createdThroughLink))) |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.identical(createdDirectly, join(base, 'link', 'createdDirectly')))) |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.identical(createdThroughLink, join(base, 'target', 'createdThroughLink')))) |
| .then((_) => FutureExpect.isFalse(FileSystemEntity.identical(target, link))) |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.identical(link, link))) |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.identical(target, target))) |
| .then((_) => new Link(link).target()) |
| .then((linkTarget) => FutureExpect.isTrue(FileSystemEntity.identical(target, linkTarget))) |
| .then((_) => new File(".").resolveSymbolicLinks()) |
| .then((fullCurrentDir) => FutureExpect.isTrue(FileSystemEntity.identical(".", fullCurrentDir))) |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.identical(createdFile, createdFile))) |
| .then((_) => FutureExpect.isFalse(FileSystemEntity.identical(createdFile, createdDirectly))) |
| .then((_) => FutureExpect.isTrue(FileSystemEntity.identical(createdFile, join(base, 'link', 'createdFile')))) |
| .then((_) => FutureExpect.throws(FileSystemEntity.identical(createdFile, join(base, 'link', 'does_not_exist')))) |
| .then((_) => testDirectoryListing(base, baseDir)) |
| .then((_) => new Directory(target).delete(recursive: true)) |
| .then((_) { |
| var futures = <Future>[]; |
| 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); |
| futures.add(FutureExpect.isTrue(baseDir |
| .list(recursive: recursive, followLinks: followLinks) |
| .single |
| .then((element) => element is Link))); |
| } |
| } |
| return Future.wait(futures); |
| }).then((_) => baseDir.delete(recursive: true)); |
| }); |
| }); |
| } |
| |
| Future testCreateLoopingLink(_) { |
| return Directory.systemTemp |
| .createTemp('dart_link_async') |
| .then((dir) => dir.path) |
| .then((String base) => 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) |
| // This directory listing must terminate, even though it contains loops. |
| .then((_) => new Directory(join(base, 'a')) |
| .list(recursive: true, followLinks: true) |
| .last) |
| // This directory listing must terminate, even though it contains loops. |
| .then((_) => new Directory(join(base, 'a', 'b', 'c')) |
| .list(recursive: true, followLinks: true) |
| .last) |
| .then((_) => new Directory(base).delete(recursive: true)) |
| .then((_) => FutureExpect.isFalse(new Directory(base).exists()))); |
| } |
| |
| Future testRename(_) { |
| Future testRename(String base, String target) { |
| Link link1; |
| Link link2; |
| return new Link(join(base, 'c')).create(target).then((link) { |
| link1 = link; |
| Expect.isTrue(link1.existsSync()); |
| return link1.rename(join(base, 'd')); |
| }).then((link) { |
| link2 = link; |
| Expect.isFalse(link1.existsSync()); |
| Expect.isTrue(link2.existsSync()); |
| return link2.delete(); |
| }).then((_) => Expect.isFalse(link2.existsSync())); |
| } |
| |
| Future testUpdate(String base, String target1, String target2) { |
| Link link1; |
| return new Link(join(base, 'c')).create(target1).then((link) { |
| link1 = link; |
| Expect.isTrue(link1.existsSync()); |
| return link1.update(target2); |
| }).then((Link link) { |
| Expect.isTrue(link1.existsSync()); |
| Expect.isTrue(link.existsSync()); |
| return FutureExpect |
| .equals(target2, link.target()) |
| .then((_) => FutureExpect.equals(target2, link1.target())) |
| .then((_) => link.delete()); |
| }).then((_) => Expect.isFalse(link1.existsSync())); |
| } |
| |
| return Directory.systemTemp.createTemp('dart_link_async').then((baseDir) { |
| String base = baseDir.path; |
| var targetsFutures = <Future>[]; |
| targetsFutures.add(new Directory(join(base, 'a')).create()); |
| if (Platform.isWindows) { |
| // Currently only links to directories are supported on Windows. |
| targetsFutures.add(new Directory(join(base, 'b')).create()); |
| } else { |
| targetsFutures.add(new File(join(base, 'b')).create()); |
| } |
| return Future.wait(targetsFutures).then((targets) { |
| return testRename(base, targets[0].path) |
| .then((_) => testRename(base, targets[1].path)) |
| .then((_) => testUpdate(base, targets[0].path, targets[1].path)) |
| .then((_) => baseDir.delete(recursive: true)); |
| }); |
| }); |
| } |
| |
| Future testDirectoryListing(String base, Directory baseDir) { |
| 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); |
| futures.add(baseDir |
| .list(recursive: recursive, followLinks: followLinks) |
| .forEach((entity) => checkEntity(entity, expected)) |
| .then((_) { |
| for (var v in expected.values) { |
| Expect.equals('Found', v); |
| } |
| })); |
| } |
| } |
| return Future.wait(futures); |
| } |
| |
| Future checkExists(String filePath) => |
| new File(filePath).exists().then(Expect.isTrue); |
| |
| Future testRelativeLinks(_) { |
| return Directory.systemTemp |
| .createTemp('dart_link_async') |
| .then((tempDirectory) { |
| String temp = tempDirectory.path; |
| String oldWorkingDirectory = Directory.current.path; |
| // Make directories and files to test links. |
| return new Directory(join(temp, 'dir1', 'dir2')) |
| .create(recursive: true) |
| .then((_) => new File(join(temp, 'dir1', 'file1')).create()) |
| .then((_) => new File(join(temp, 'dir1', 'dir2', 'file2')).create()) |
| // Make links whose path and/or target is given by a relative path. |
| .then((_) => new Link(join(temp, 'dir1', 'link1_2')).create('dir2')) |
| .then((_) => Directory.current = temp) |
| .then((_) => new Link('link0_2').create(join('dir1', 'dir2'))) |
| .then((_) => new Link(join('dir1', 'link1_0')).create('..')) |
| .then((_) => Directory.current = 'dir1') |
| .then((_) => new Link(join('..', 'link0_1')).create('dir1')) |
| .then( |
| (_) => new Link(join('dir2', 'link2_1')).create(join(temp, 'dir1'))) |
| .then((_) => new Link(join(temp, 'dir1', 'dir2', 'link2_0')) |
| .create(join('..', '..'))) |
| // Test that the links go to the right targets. |
| .then((_) => checkExists(join('..', 'link0_1', 'file1'))) |
| .then((_) => checkExists(join('..', 'link0_2', 'file2'))) |
| .then((_) => checkExists(join('link1_0', 'dir1', 'file1'))) |
| .then((_) => checkExists(join('link1_2', 'file2'))) |
| .then((_) => checkExists(join('dir2', 'link2_0', 'dir1', 'file1'))) |
| .then((_) => checkExists(join('dir2', 'link2_1', 'file1'))) |
| // Clean up |
| .whenComplete(() => Directory.current = oldWorkingDirectory) |
| .whenComplete(() => tempDirectory.delete(recursive: true)); |
| }); |
| } |
| |
| main() { |
| asyncStart(); |
| testCreate() |
| .then(testCreateLoopingLink) |
| .then(testRename) |
| .then(testRelativeLinks) |
| .then((_) => asyncEnd()); |
| } |