| // 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. | 
 |  | 
 | import "package:expect/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-does-not exist/some link file/bla/fisk', | 
 |     ).createSync('bla bla bla/b lalal/blfir/sdfred/es'), | 
 |     (e) => e is PathNotFoundException, | 
 |   ); | 
 | } | 
 |  | 
 | 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); | 
 | } | 
 |  | 
 | void testRelativeLinkToDirectoryNotRelativeToCurrentWorkingDirectory() { | 
 |   final tempDirectory = Directory.systemTemp.createTempSync('dart_link'); | 
 |   final dir2 = Directory(join(tempDirectory.path, 'dir1', 'dir2')) | 
 |     ..createSync(recursive: true); | 
 |  | 
 |   final link = Link(join(tempDirectory.path, 'link')) | 
 |     ..createSync(join('dir1', 'dir2')); | 
 |  | 
 |   String resolvedDir2Path = link.resolveSymbolicLinksSync(); | 
 |   Expect.isTrue(FileSystemEntity.identicalSync(dir2.path, resolvedDir2Path)); | 
 |  | 
 |   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); | 
 | } | 
 |  | 
 | testBrokenLinkTypeSync() { | 
 |   String base = Directory.systemTemp.createTempSync('dart_link').path; | 
 |   String link = join(base, 'link'); | 
 |   Link(link).createSync('does not exist'); | 
 |  | 
 |   Expect.equals( | 
 |     FileSystemEntityType.link, | 
 |     FileSystemEntity.typeSync(link, followLinks: false), | 
 |   ); | 
 |  | 
 |   Expect.equals( | 
 |     FileSystemEntityType.notFound, | 
 |     FileSystemEntity.typeSync(link, followLinks: true), | 
 |   ); | 
 | } | 
 |  | 
 | void testTopLevelLinkSync() { | 
 |   if (!Platform.isWindows) return; | 
 |   try { | 
 |     Link(r"C:\").createSync('the target does not matter'); | 
 |     Expect.fail("expected FileSystemException"); | 
 |   } on FileSystemException catch (e) { | 
 |     Expect.equals(5, e.osError!.errorCode); // ERROR_ACCESS_DENIED | 
 |   } | 
 | } | 
 |  | 
 | main() { | 
 |   testCreateSync(); | 
 |   testCreateLoopingLink(); | 
 |   testRenameSync(); | 
 |   testLinkErrorSync(); | 
 |   testRelativeLinksSync(); | 
 |   testRelativeLinkToDirectoryNotRelativeToCurrentWorkingDirectory(); | 
 |   testIsDir(); | 
 |   testBrokenLinkTypeSync(); | 
 |   testTopLevelLinkSync(); | 
 | } |