|  | // 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 test program for testing FileSystemEntity.resolveSymbolicLinks | 
|  |  | 
|  | import "package:expect/expect.dart"; | 
|  | import "package:path/path.dart"; | 
|  | import "package:expect/async_helper.dart"; | 
|  | import 'dart:async'; | 
|  | import 'dart:io'; | 
|  |  | 
|  | main() { | 
|  | String testsDir = Directory.current.uri.resolve('tests').toFilePath(); | 
|  |  | 
|  | // All of these tests test that resolveSymbolicLinks gives a path | 
|  | // that points to the same place as the original, and that it removes | 
|  | // all links, .., and . segments, and that it produces an absolute path. | 
|  | asyncTest( | 
|  | () => testFile( | 
|  | join(testsDir, 'standalone', 'io', 'resolve_symbolic_links_test.dart'), | 
|  | ), | 
|  | ); | 
|  | asyncTest( | 
|  | () => testFile( | 
|  | join( | 
|  | testsDir, | 
|  | 'standalone', | 
|  | 'io', | 
|  | '..', | 
|  | 'io', | 
|  | 'resolve_symbolic_links_test.dart', | 
|  | ), | 
|  | ), | 
|  | ); | 
|  |  | 
|  | asyncTest(() => testDir(join(testsDir, 'standalone', 'io'))); | 
|  | asyncTest(() => testDir(join(testsDir, 'lib', '..', 'standalone', 'io'))); | 
|  | // Test a relative path. | 
|  | if (Platform.isWindows) { | 
|  | asyncTest( | 
|  | () => testFile( | 
|  | join( | 
|  | '\\\\?\\$testsDir', | 
|  | 'standalone', | 
|  | 'io', | 
|  | 'resolve_symbolic_links_test.dart', | 
|  | ), | 
|  | ), | 
|  | ); | 
|  | asyncTest(() => testDir('\\\\?\\$testsDir')); | 
|  | } | 
|  | asyncTest( | 
|  | () => Directory.systemTemp.createTemp('dart_resolve_symbolic_links').then(( | 
|  | tempDir, | 
|  | ) { | 
|  | String temp = tempDir.path; | 
|  | return makeEntities(temp) | 
|  | .then( | 
|  | (_) => Future.wait([ | 
|  | testFile(join(temp, 'dir1', 'file1')), | 
|  | testFile(join(temp, 'link1', 'file2')), | 
|  | testDir(join(temp, 'dir1', 'dir2', '..', '.', '..', 'dir1')), | 
|  | testDir(join(temp, 'dir1', 'dir2', '..', '.', '..', 'dir1')), | 
|  | testLink(join(temp, 'link1')), | 
|  | testDir('.'), | 
|  | ]), | 
|  | ) | 
|  | .then((_) { | 
|  | if (Platform.isWindows) { | 
|  | // Windows applies '..' to a link without resolving the link first. | 
|  | return Future.wait([ | 
|  | testFile( | 
|  | join( | 
|  | temp, | 
|  | 'dir1', | 
|  | '..', | 
|  | 'link1', | 
|  | '..', | 
|  | 'dir1', | 
|  | 'dir2', | 
|  | 'file2', | 
|  | ), | 
|  | ), | 
|  | testDir(join(temp, 'dir1', '..', 'link1', '..', 'dir1')), | 
|  | testLink(join(temp, 'link1', '..', 'link1')), | 
|  | ]); | 
|  | } else { | 
|  | // Non-Windows platforms resolve the link before adding the '..'. | 
|  | return Future.wait([ | 
|  | testFile( | 
|  | join(temp, 'dir1', '..', 'link1', '..', 'dir2', 'file2'), | 
|  | ), | 
|  | testDir(join(temp, 'dir1', '..', 'link1', '..', 'dir2')), | 
|  | testLink(join(temp, 'link1', '..', '..', 'link1')), | 
|  | ]); | 
|  | } | 
|  | }) | 
|  | .then((_) { | 
|  | Directory.current = temp; | 
|  | return Future.wait([ | 
|  | testFile( | 
|  | 'dir1/dir2/file2', | 
|  | ), // Test forward slashes on Windows too. | 
|  | testFile('link1/file2'), | 
|  | testFile(join('dir1', '..', 'dir1', '.', 'file1')), | 
|  | testDir('.'), | 
|  | testLink('link1'), | 
|  | ]); | 
|  | }) | 
|  | .then((_) { | 
|  | Directory.current = 'link1'; | 
|  | if (Platform.isWindows) { | 
|  | return Future.wait([ | 
|  | testFile('file2'), | 
|  | // Windows applies '..' to a link without resolving the link first. | 
|  | testFile('..\\dir1\\file1'), | 
|  | testLink('.'), | 
|  | testDir('..'), | 
|  | testLink('..\\link1'), | 
|  | ]); | 
|  | } else { | 
|  | return Future.wait([ | 
|  | testFile('file2'), | 
|  | // On non-Windows the link is changed to dir1/dir2 before .. happens. | 
|  | testFile('../dir2/file2'), | 
|  | testDir('.'), | 
|  | testDir('..'), | 
|  | testLink('../../link1'), | 
|  | ]); | 
|  | } | 
|  | }) | 
|  | .whenComplete(() { | 
|  | Directory.current = testsDir; | 
|  | tempDir.delete(recursive: true); | 
|  | }); | 
|  | }), | 
|  | ); | 
|  |  | 
|  | asyncTest(testNonExistantPath); | 
|  | asyncTest(testLinkTargetTypeChangedAfterCreation); | 
|  | } | 
|  |  | 
|  | Future makeEntities(String temp) { | 
|  | return new Directory(join(temp, 'dir1', 'dir2')) | 
|  | .create(recursive: true) | 
|  | .then((_) => new File(join(temp, 'dir1', 'dir2', 'file2')).create()) | 
|  | .then((_) => new File(join(temp, 'dir1', 'file1')).create()) | 
|  | .then( | 
|  | (_) => new Link(join(temp, 'link1')).create(join(temp, 'dir1', 'dir2')), | 
|  | ); | 
|  | } | 
|  |  | 
|  | Future testFile(String name) { | 
|  | // We test that f.resolveSymbolicLinks points to the same place | 
|  | // as f, because the actual resolved path is not easily predictable. | 
|  | // The location of the temp directory varies from system to system, | 
|  | // and its path includes symbolic links on some systems. | 
|  | //Expect.isTrue(FileSystemEntity.identicalSync(name, | 
|  | //   new File(name).resolveSymbolicLinksSync())); | 
|  | return new File(name).resolveSymbolicLinks().then((String resolved) { | 
|  | //Expect.isTrue(FileSystemEntity.identicalSync(name, resolved)); | 
|  | Expect.isTrue(isAbsolute(resolved)); | 
|  | // Test that resolveSymbolicLinks removes all links, .., and . segments. | 
|  | Expect.isFalse(resolved.contains('..')); | 
|  | Expect.isFalse(resolved.contains('./')); | 
|  | Expect.isFalse(resolved.contains('link1')); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future testDir(String name) { | 
|  | Expect.isTrue( | 
|  | FileSystemEntity.identicalSync( | 
|  | name, | 
|  | new Directory(name).resolveSymbolicLinksSync(), | 
|  | ), | 
|  | ); | 
|  | return new Directory(name).resolveSymbolicLinks().then((String resolved) { | 
|  | Expect.isTrue(FileSystemEntity.identicalSync(name, resolved)); | 
|  | Expect.isTrue(isAbsolute(resolved)); | 
|  | // Test that resolveSymbolicLinks removes all links, .., and . segments. | 
|  | Expect.isFalse(resolved.contains('..')); | 
|  | Expect.isFalse(resolved.contains('./')); | 
|  | Expect.isFalse(resolved.contains('link1')); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future testLink(String name) { | 
|  | Expect.isFalse( | 
|  | FileSystemEntity.identicalSync( | 
|  | name, | 
|  | new Link(name).resolveSymbolicLinksSync(), | 
|  | ), | 
|  | ); | 
|  | Expect.isTrue( | 
|  | FileSystemEntity.identicalSync( | 
|  | new Link(name).targetSync(), | 
|  | new Link(name).resolveSymbolicLinksSync(), | 
|  | ), | 
|  | ); | 
|  | return new Link(name).resolveSymbolicLinks().then((String resolved) { | 
|  | Expect.isFalse(FileSystemEntity.identicalSync(name, resolved)); | 
|  | Expect.isTrue(isAbsolute(resolved)); | 
|  | // Test that resolveSymbolicLinks removes all links, .., and . segments. | 
|  | Expect.isFalse(resolved.contains('..')); | 
|  | Expect.isFalse(resolved.contains('./')); | 
|  | Expect.isFalse(resolved.contains('link1')); | 
|  | return new Link(name) | 
|  | .target() | 
|  | .then((targetName) => FileSystemEntity.identical(targetName, resolved)) | 
|  | .then((identical) => Expect.isTrue(identical)); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future testNonExistantPath() async { | 
|  | try { | 
|  | await File('/tmp/foo/doesnotexist').resolveSymbolicLinks(); | 
|  | Expect.fail("expected FileSystemException"); | 
|  | } on FileSystemException {} | 
|  | } | 
|  |  | 
|  | Future testLinkTargetTypeChangedAfterCreation() async { | 
|  | // Test the following scenario: | 
|  | // 1. create a file | 
|  | // 2. create a link to that file | 
|  | // 3. replace the file with a directory | 
|  | // 4. attempt to resolve the link | 
|  | final tmp = await Directory.systemTemp.createTemp( | 
|  | 'dart_resolve_symbolic_links', | 
|  | ); | 
|  | final tmpPath = tmp.absolute.path; | 
|  | final filePath = join(tmpPath, "file"); | 
|  | final linkPath = join(tmpPath, "link"); | 
|  | await File(filePath).create(); | 
|  | await Link(linkPath).create(filePath); | 
|  |  | 
|  | Expect.isTrue( | 
|  | FileSystemEntity.identicalSync( | 
|  | filePath, | 
|  | await Directory(linkPath).resolveSymbolicLinks(), | 
|  | ), | 
|  | ); | 
|  |  | 
|  | await File(filePath).delete(); | 
|  | await Directory(filePath).create(); | 
|  |  | 
|  | if (Platform.isWindows) { | 
|  | await asyncExpectThrows<PathAccessException>( | 
|  | Directory(linkPath).resolveSymbolicLinks(), | 
|  | ); | 
|  | } else { | 
|  | Expect.isTrue( | 
|  | await FileSystemEntity.identical( | 
|  | filePath, | 
|  | await Directory(linkPath).resolveSymbolicLinks(), | 
|  | ), | 
|  | ); | 
|  | } | 
|  | } |