Move path-manipulation code from io.dart into path.dart.

Review URL: https://codereview.chromium.org//11553005

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@16063 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
nweiz@google.com 2012-12-12 21:24:09 +00:00
parent 973a3f0993
commit 7a2155fd65
4 changed files with 339 additions and 132 deletions

View file

@ -30,45 +30,24 @@ final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?");
* platform-specific path separators. Parts can be [String], [Directory], or
* [File] objects.
*/
String join(part1, [part2, part3, part4]) {
part1 = _getPath(part1);
if (part2 != null) part2 = _getPath(part2);
if (part3 != null) part3 = _getPath(part3);
if (part4 != null) part4 = _getPath(part4);
String join(part1, [part2, part3, part4, part5, part6, part7, part8]) {
var parts = [part1, part2, part3, part4, part5, part6, part7, part8]
.map((part) => part == null ? null : _getPath(part));
// TODO(nweiz): Don't use "?part" in path.dart.
if (part4 != null) {
return path.join(part1, part2, part3, part4);
} else if (part3 != null) {
return path.join(part1, part2, part3);
} else if (part2 != null) {
return path.join(part1, part2);
} else {
return path.join(part1);
}
return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5],
parts[6], parts[7]);
}
/// Gets the basename, the file name without any leading directory path, for
/// [file], which can either be a [String], [File], or [Directory].
String basename(file) => path.basename(_getPath(file));
// TODO(nweiz): move this into path.dart.
/// Gets the the leading directory path for [file], which can either be a
/// [String], [File], or [Directory].
String dirname(file) {
file = _sanitizePath(file);
String dirname(file) => path.dirname(_getPath(file));
int lastSlash = file.lastIndexOf('/', file.length);
if (lastSlash == -1) {
return '.';
} else {
return file.substring(0, lastSlash);
}
}
// TODO(nweiz): move this into path.dart.
/// Splits [path] into its individual components.
List<String> splitPath(path) => _sanitizePath(path).split('/');
/// Splits [entry] into its individual components.
List<String> splitPath(entry) => path.split(_getPath(entry));
/// Returns whether or not [entry] is nested somewhere within [dir]. This just
/// performs a path comparison; it doesn't look at the actual filesystem.
@ -77,10 +56,8 @@ bool isBeneath(entry, dir) {
return !path.isAbsolute(relative) && splitPath(relative)[0] != '..';
}
// TODO(nweiz): move this into path.dart.
/// Returns the path to [target] from [base].
String relativeTo(target, base) =>
new path.Builder(root: base).relative(target);
String relativeTo(target, base) => path.relative(target, from: base);
/**
* Asynchronously determines if [path], which can be a [String] file path, a
@ -1067,40 +1044,6 @@ String _getPath(entry) {
throw 'Entry $entry is not a supported type.';
}
/// Gets the path string for [entry], normalizing backslashes to forward slashes
/// on Windows.
String _sanitizePath(entry) {
entry = _getPath(entry);
if (Platform.operatingSystem != 'windows') return entry;
var split = _splitAbsolute(entry);
if (split.first == null) return split.last.replaceAll('\\', '/');
// For absolute Windows paths, we don't want the prefix (either "\\" or e.g.
// "C:\") to look like a normal path component, so we ensure that it only
// contains backslashes.
return '${split.first.replaceAll('/', '\\')}'
'${split.last.replaceAll('\\', '/')}';
}
// TODO(nweiz): Add something like this to path.dart.
/// Splits [entry] into two components: the absolute path prefix and the
/// remaining path. Takes into account Windows' quirky absolute paths syntaxes.
Pair<String, String> _splitAbsolute(entry) {
var path = _getPath(entry);
if (Platform.operatingSystem != 'windows') {
return !path.startsWith('/') ? new Pair(null, path)
: new Pair('/', path.substring(1));
}
// An absolute path on Windows is either UNC (two leading backslashes),
// or a drive letter followed by a colon and a slash.
var match = new RegExp(r'^(\\\\|[a-zA-Z]:[/\\])').firstMatch(path);
return match == null ? new Pair(null, path)
: new Pair(match.group(0), path.substring(match.end));
}
/**
* Gets a [Directory] for [entry], which can either already be one, or be a
* [String].

View file

@ -37,6 +37,12 @@ String basename(String path) => _builder.basename(path);
String basenameWithoutExtension(String path) =>
_builder.basenameWithoutExtension(path);
/// Gets the part of [path] before the last separator.
///
/// path.dirname('path/to/foo.dart'); // -> 'path/to'
/// path.dirname('path/to'); // -> 'to'
String dirname(String path) => _builder.dirname(path);
/// Gets the file extension of [path]: the portion of [basename] from the last
/// `.` to the end (including the `.` itself).
///
@ -52,6 +58,19 @@ String basenameWithoutExtension(String path) =>
/// path.extension('~/.notes.txt'); // -> '.txt'
String extension(String path) => _builder.extension(path);
// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
/// Returns the root of [path], if it's absolute, or the empty string if it's
/// relative.
///
/// // Unix
/// path.rootPrefix('path/to/foo'); // -> ''
/// path.rootPrefix('/path/to/foo'); // -> '/'
///
/// // Windows
/// path.rootPrefix(r'path\to\foo'); // -> ''
/// path.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
String rootPrefix(String path) => _builder.rootPrefix(path);
/// Returns `true` if [path] is an absolute path and `false` if it is a
/// relative path. On POSIX systems, absolute paths start with a `/` (forward
/// slash). On Windows, an absolute path starts with `\\`, or a drive letter
@ -78,17 +97,24 @@ bool isRelative(String path) => _builder.isRelative(path);
///
/// path.join('path', '/to', 'foo'); // -> '/to/foo'
String join(String part1, [String part2, String part3, String part4,
String part5, String part6, String part7, String part8]) {
if (!?part2) return _builder.join(part1);
if (!?part3) return _builder.join(part1, part2);
if (!?part4) return _builder.join(part1, part2, part3);
if (!?part5) return _builder.join(part1, part2, part3, part4);
if (!?part6) return _builder.join(part1, part2, part3, part4, part5);
if (!?part7) return _builder.join(part1, part2, part3, part4, part5, part6);
if (!?part8) return _builder.join(part1, part2, part3, part4, part5, part6,
part7);
return _builder.join(part1, part2, part3, part4, part5, part6, part7, part8);
}
String part5, String part6, String part7, String part8]) =>
_builder.join(part1, part2, part3, part4, part5, part6, part7, part8);
// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
/// Splits [path] into its components using the current platform's [separator].
/// Example:
///
/// path.split('path/to/foo'); // -> ['path', 'to', 'foo']
///
/// If [path] is absolute, the root directory will be the first element in the
/// array. Example:
///
/// // Unix
/// path.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo']
///
/// // Windows
/// path.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
List<String> split(String path) => _builder.split(path);
/// Normalizes [path], simplifying it by handling `..`, and `.`, and
/// removing redundant path separators whenever possible.
@ -103,12 +129,19 @@ String normalize(String path) => _builder.normalize(path);
/// path.relative('/root/path/a/b.dart'); // -> 'a/b.dart'
/// path.relative('/root/other.dart'); // -> '../other.dart'
///
/// If the [from] argument is passed, [path] is made relative to that instead.
///
/// path.relative('/root/path/a/b.dart',
/// from: '/root/path'); // -> 'a/b.dart'
/// path.relative('/root/other.dart',
/// from: '/root/path'); // -> '../other.dart'
///
/// Since there is no relative path from one drive letter to another on Windows,
/// this will return an absolute path in that case.
///
/// // Given current directory is C:\home:
/// path.relative(r'D:\other'); // -> 'D:\other'
String relative(String path) => _builder.relative(path);
/// path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other'
String relative(String path, {String from}) =>
_builder.relative(path, from: from);
/// Removes a trailing extension from the last part of [path].
///
@ -163,6 +196,24 @@ class Builder {
String basenameWithoutExtension(String path) =>
_parse(path).basenameWithoutExtension;
/// Gets the part of [path] before the last separator.
///
/// builder.dirname('path/to/foo.dart'); // -> 'path/to'
/// builder.dirname('path/to'); // -> 'to'
String dirname(String path) {
var parsed = _parse(path);
if (parsed.parts.isEmpty) return parsed.root == null ? '.' : parsed.root;
if (!parsed.hasTrailingSeparator) {
if (parsed.parts.length == 1) {
return parsed.root == null ? '.' : parsed.root;
}
parsed.parts.removeLast();
parsed.separators.removeLast();
}
parsed.separators[parsed.separators.length - 1] = '';
return parsed.toString();
}
/// Gets the file extension of [path]: the portion of [basename] from the last
/// `.` to the end (including the `.` itself).
///
@ -178,6 +229,22 @@ class Builder {
/// builder.extension('~/.notes.txt'); // -> '.txt'
String extension(String path) => _parse(path).extension;
// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
/// Returns the root of [path], if it's absolute, or an empty string if it's
/// relative.
///
/// // Unix
/// builder.rootPrefix('path/to/foo'); // -> ''
/// builder.rootPrefix('/path/to/foo'); // -> '/'
///
/// // Windows
/// builder.rootPrefix(r'path\to\foo'); // -> ''
/// builder.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
String rootPrefix(String path) {
var root = _parse(path).root;
return root == null ? '' : root;
}
/// Returns `true` if [path] is an absolute path and `false` if it is a
/// relative path. On POSIX systems, absolute paths start with a `/` (forward
/// slash). On Windows, an absolute path starts with `\\`, or a drive letter
@ -208,8 +275,16 @@ class Builder {
var buffer = new StringBuffer();
var needsSeparator = false;
addPart(condition, part) {
if (!condition) return;
var parts = [part1, part2, part3, part4, part5, part6, part7, part8];
for (var i = 1; i < parts.length; i++) {
if (parts[i] != null && parts[i - 1] == null) {
throw new ArgumentError("join(): part ${i - 1} was null, but part $i "
"was not.");
}
}
for (var part in parts) {
if (part == null) continue;
if (this.isAbsolute(part)) {
// An absolute path discards everything before it.
@ -231,18 +306,31 @@ class Builder {
!style.separatorPattern.hasMatch(part[part.length - 1]);
}
addPart(true, part1);
addPart(?part2, part2);
addPart(?part3, part3);
addPart(?part4, part4);
addPart(?part5, part5);
addPart(?part6, part6);
addPart(?part7, part7);
addPart(?part8, part8);
return buffer.toString();
}
// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
/// Splits [path] into its components using the current platform's
/// [separator]. Example:
///
/// builder.split('path/to/foo'); // -> ['path', 'to', 'foo']
///
/// If [path] is absolute, the root directory will be the first element in the
/// array. Example:
///
/// // Unix
/// builder.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo']
///
/// // Windows
/// builder.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
List<String> split(String path) {
var parsed = _parse(path);
// Filter out empty parts that exist due to multiple separators in a row.
parsed.parts = parsed.parts.filter((part) => part != '');
if (parsed.root != null) parsed.parts.insertRange(0, 1, parsed.root);
return parsed.parts;
}
/// Normalizes [path], simplifying it by handling `..`, and `.`, and
/// removing redundant path separators whenever possible.
///
@ -278,23 +366,44 @@ class Builder {
/// builder.relative('/root/path/a/b.dart'); // -> 'a/b.dart'
/// builder.relative('/root/other.dart'); // -> '../other.dart'
///
/// If the [from] argument is passed, [path] is made relative to that instead.
///
/// builder.relative('/root/path/a/b.dart',
/// from: '/root/path'); // -> 'a/b.dart'
/// builder.relative('/root/other.dart',
/// from: '/root/path'); // -> '../other.dart'
///
/// Since there is no relative path from one drive letter to another on
/// Windows, this will return an absolute path in that case.
///
/// var builder = new Builder(root: r'C:\home');
/// builder.relative(r'D:\other'); // -> 'D:\other'
String relative(String path) {
/// builder.relative(r'D:\other', from: r'C:\other'); // -> 'D:\other'
///
/// This will also return an absolute path if an absolute [path] is passed to
/// a builder with a relative [root].
///
/// var builder = new Builder(r'some/relative/path');
/// builder.relative(r'/absolute/path'); // -> '/absolute/path'
String relative(String path, {String from}) {
if (path == '') return '.';
// If the base path is relative, resolve it relative to the current
// directory.
var base = root;
if (this.isRelative(base)) base = absolute(base);
from = from == null ? root : this.join(root, from);
// If the given path is relative, resolve it relative to the base.
if (this.isRelative(path)) return this.normalize(path);
// We can't determine the path from a relative path to an absolute path.
if (this.isRelative(from) && this.isAbsolute(path)) {
return this.normalize(path);
}
var baseParsed = _parse(base)..normalize();
// If the given path is relative, resolve it relative to the root of the
// builder.
if (this.isRelative(path)) path = this.resolve(path);
// If the path is still relative and `from` is absolute, we're unable to
// find a path from `from` to `path`.
if (this.isRelative(path) && this.isAbsolute(from)) {
throw new ArgumentError('Unable to find a path to "$path" from "$from".');
}
var fromParsed = _parse(from)..normalize();
var pathParsed = _parse(path)..normalize();
// If the root prefixes don't match (for example, different drive letters
@ -302,21 +411,21 @@ class Builder {
// one.
// TODO(rnystrom): Drive letters are case-insentive on Windows. Should
// handle "C:\" and "c:\" being the same root.
if (baseParsed.root != pathParsed.root) return pathParsed.toString();
if (fromParsed.root != pathParsed.root) return pathParsed.toString();
// Strip off their common prefix.
while (baseParsed.parts.length > 0 && pathParsed.parts.length > 0 &&
baseParsed.parts[0] == pathParsed.parts[0]) {
baseParsed.parts.removeAt(0);
baseParsed.separators.removeAt(0);
while (fromParsed.parts.length > 0 && pathParsed.parts.length > 0 &&
fromParsed.parts[0] == pathParsed.parts[0]) {
fromParsed.parts.removeAt(0);
fromParsed.separators.removeAt(0);
pathParsed.parts.removeAt(0);
pathParsed.separators.removeAt(0);
}
// If there are any directories left in the root path, we need to walk up
// out of them.
pathParsed.parts.insertRange(0, baseParsed.parts.length, '..');
pathParsed.separators.insertRange(0, baseParsed.parts.length,
pathParsed.parts.insertRange(0, fromParsed.parts.length, '..');
pathParsed.separators.insertRange(0, fromParsed.parts.length,
style.separator);
// Corner case: the paths completely collapsed.

View file

@ -33,6 +33,30 @@ main() {
expect(builder.extension(r'a.b\c'), r'.b\c');
});
test('rootPrefix', () {
expect(builder.rootPrefix(''), '');
expect(builder.rootPrefix('a'), '');
expect(builder.rootPrefix('a/b'), '');
expect(builder.rootPrefix('/a/c'), '/');
expect(builder.rootPrefix('/'), '/');
});
test('dirname', () {
expect(builder.dirname(''), '.');
expect(builder.dirname('a'), '.');
expect(builder.dirname('a/b'), 'a');
expect(builder.dirname('a/b/c'), 'a/b');
expect(builder.dirname('a/b.c'), 'a');
expect(builder.dirname('a/'), 'a');
expect(builder.dirname('a/.'), 'a');
expect(builder.dirname(r'a\b/c'), r'a\b');
expect(builder.dirname('/a'), '/');
expect(builder.dirname('/'), '/');
expect(builder.dirname('a/b/'), 'a/b');
expect(builder.dirname(r'a/b\c'), 'a');
expect(builder.dirname('a//'), 'a/');
});
test('basename', () {
expect(builder.basename(''), '');
expect(builder.basename('a'), 'a');
@ -41,7 +65,13 @@ main() {
expect(builder.basename('a/b.c'), 'b.c');
expect(builder.basename('a/'), '');
expect(builder.basename('a/.'), '.');
expect(builder.basename(r'a\b/c'), 'c');
expect(builder.basename('/a'), 'a');
// TODO(nweiz): this should actually return '/'
expect(builder.basename('/'), '');
expect(builder.basename('a/b/'), '');
expect(builder.basename(r'a/b\c'), r'b\c');
expect(builder.basename('a//'), '');
});
test('basenameWithoutExtension', () {
@ -104,10 +134,42 @@ main() {
});
test('ignores parts before an absolute path', () {
expect(builder.join('a', '/', 'b', 'c'), '/b/c');
expect(builder.join('a', '/b', '/c', 'd'), '/c/d');
expect(builder.join('a', r'c:\b', 'c', 'd'), r'a/c:\b/c/d');
expect(builder.join('a', r'\\b', 'c', 'd'), r'a/\\b/c/d');
});
test('ignores trailing nulls', () {
expect(builder.join('a', null), equals('a'));
expect(builder.join('a', 'b', 'c', null, null), equals('a/b/c'));
});
test('disallows intermediate nulls', () {
expect(() => builder.join('a', null, 'b'), throwsArgumentError);
expect(() => builder.join(null, 'a'), throwsArgumentError);
});
});
group('split', () {
test('simple cases', () {
expect(builder.split('foo'), equals(['foo']));
expect(builder.split('foo/bar'), equals(['foo', 'bar']));
expect(builder.split('foo/bar/baz'), equals(['foo', 'bar', 'baz']));
expect(builder.split('foo/../bar/./baz'),
equals(['foo', '..', 'bar', '.', 'baz']));
expect(builder.split('foo//bar///baz'), equals(['foo', 'bar', 'baz']));
expect(builder.split('foo/\\/baz'), equals(['foo', '\\', 'baz']));
expect(builder.split('.'), equals(['.']));
expect(builder.split(''), equals([]));
expect(builder.split('foo/'), equals(['foo']));
expect(builder.split('//'), equals(['/']));
});
test('includes the root for absolute paths', () {
expect(builder.split('/foo/bar/baz'), equals(['/', 'foo', 'bar', 'baz']));
expect(builder.split('/'), equals(['/']));
});
});
group('normalize', () {
@ -211,15 +273,10 @@ main() {
group('from relative root', () {
var r = new path.Builder(style: path.Style.posix, root: 'foo/bar');
// These tests rely on the current working directory, so don't do the
// right thing if you run them on the wrong platform.
if (io.Platform.operatingSystem != 'windows') {
test('given absolute path', () {
var b = new path.Builder(style: path.Style.posix);
expect(r.relative('/'), b.join(b.relative('/'), '../..'));
expect(r.relative('/a/b'), b.join(b.relative('/'), '../../a/b'));
});
}
test('given absolute path', () {
expect(r.relative('/'), equals('/'));
expect(r.relative('/a/b'), equals('/a/b'));
});
test('given relative path', () {
// The path is considered relative to the root, so it basically just
@ -238,6 +295,23 @@ main() {
var r = new path.Builder(style: path.Style.posix, root: '/dir.ext');
expect(r.relative('/dir.ext/file'), 'file');
});
test('with a root parameter', () {
expect(builder.relative('/foo/bar/baz', from: '/foo/bar'), equals('baz'));
expect(builder.relative('..', from: '/foo/bar'), equals('../../root'));
expect(builder.relative('/foo/bar/baz', from: 'foo/bar'),
equals('../../../../foo/bar/baz'));
expect(builder.relative('..', from: 'foo/bar'), equals('../../..'));
});
test('with a root parameter and a relative root', () {
var r = new path.Builder(style: path.Style.posix, root: 'relative/root');
expect(r.relative('/foo/bar/baz', from: '/foo/bar'), equals('baz'));
expect(() => r.relative('..', from: '/foo/bar'), throwsArgumentError);
expect(r.relative('/foo/bar/baz', from: 'foo/bar'),
equals('/foo/bar/baz'));
expect(r.relative('..', from: 'foo/bar'), equals('../../..'));
});
});
group('resolve', () {

View file

@ -35,6 +35,35 @@ main() {
expect(builder.extension(r'a.b/c'), r'');
});
test('rootPrefix', () {
expect(builder.rootPrefix(''), '');
expect(builder.rootPrefix('a'), '');
expect(builder.rootPrefix(r'a\b'), '');
expect(builder.rootPrefix(r'C:\a\c'), r'C:\');
expect(builder.rootPrefix('C:\\'), r'C:\');
expect(builder.rootPrefix('C:/'), 'C:/');
// TODO(nweiz): enable this once issue 7323 is fixed.
// expect(builder.rootPrefix(r'\\server\a\b'), r'\\server\');
});
test('dirname', () {
expect(builder.dirname(r''), '.');
expect(builder.dirname(r'a'), '.');
expect(builder.dirname(r'a\b'), 'a');
expect(builder.dirname(r'a\b\c'), r'a\b');
expect(builder.dirname(r'a\b.c'), 'a');
expect(builder.dirname(r'a\'), 'a');
expect(builder.dirname('a/'), 'a');
expect(builder.dirname(r'a\.'), 'a');
expect(builder.dirname(r'a\b/c'), r'a\b');
expect(builder.dirname(r'C:\a'), r'C:\');
expect(builder.dirname('C:\\'), r'C:\');
expect(builder.dirname(r'a\b\'), r'a\b');
expect(builder.dirname(r'a/b\c'), 'a/b');
expect(builder.dirname(r'a\\'), r'a\');
});
test('basename', () {
expect(builder.basename(r''), '');
expect(builder.basename(r'a'), 'a');
@ -45,6 +74,12 @@ main() {
expect(builder.basename(r'a/'), '');
expect(builder.basename(r'a\.'), '.');
expect(builder.basename(r'a\b/c'), r'c');
expect(builder.basename(r'C:\a'), 'a');
// TODO(nweiz): this should actually return 'C:\'
expect(builder.basename(r'C:\'), '');
expect(builder.basename(r'a\b\'), '');
expect(builder.basename(r'a/b\c'), 'c');
expect(builder.basename(r'a\\'), '');
});
test('basenameWithoutExtension', () {
@ -123,6 +158,43 @@ main() {
expect(builder.join('a', r'c:\b', 'c', 'd'), r'c:\b\c\d');
expect(builder.join('a', r'\\b', r'\\c', 'd'), r'\\c\d');
});
test('ignores trailing nulls', () {
expect(builder.join('a', null), equals('a'));
expect(builder.join('a', 'b', 'c', null, null), equals(r'a\b\c'));
});
test('disallows intermediate nulls', () {
expect(() => builder.join('a', null, 'b'), throwsArgumentError);
expect(() => builder.join(null, 'a'), throwsArgumentError);
});
});
group('split', () {
test('simple cases', () {
expect(builder.split('foo'), equals(['foo']));
expect(builder.split(r'foo\bar'), equals(['foo', 'bar']));
expect(builder.split(r'foo\bar\baz'), equals(['foo', 'bar', 'baz']));
expect(builder.split(r'foo\..\bar\.\baz'),
equals(['foo', '..', 'bar', '.', 'baz']));
expect(builder.split(r'foo\\bar\\\baz'), equals(['foo', 'bar', 'baz']));
expect(builder.split(r'foo\/\baz'), equals(['foo', 'baz']));
expect(builder.split('.'), equals(['.']));
expect(builder.split(''), equals([]));
expect(builder.split('foo/'), equals(['foo']));
expect(builder.split(r'C:\'), equals([r'C:\']));
});
test('includes the root for absolute paths', () {
expect(builder.split(r'C:\foo\bar\baz'),
equals([r'C:\', 'foo', 'bar', 'baz']));
expect(builder.split(r'C:\\'), equals([r'C:\']));
// TODO(nweiz): enable these once issue 7323 is fixed.
// expect(builder.split(r'\\server\foo\bar\baz'),
// equals([r'\\server\', 'foo', 'bar', 'baz']));
// expect(builder.split(r'\\server\'), equals([r'\\server\']));
});
});
group('normalize', () {
@ -225,21 +297,10 @@ main() {
group('from relative root', () {
var r = new path.Builder(style: path.Style.windows, root: r'foo\bar');
// These tests rely on the current working directory, so don't do the
// right thing if you run them on the wrong platform.
if (io.Platform.operatingSystem == 'windows') {
test('given absolute path', () {
var b = new path.Builder(style: path.Style.windows);
// TODO(rnystrom): Use a path method here to get the root prefix
// when one exists.
var drive = path.current.substring(0, 3);
expect(r.relative(drive), b.join(b.relative(drive), r'..\..'));
expect(r.relative(b.join(drive, r'a\b')),
b.join(b.relative(drive), r'..\..\a\b'));
// TODO(rnystrom): Test behavior when drive letters differ.
});
}
test('given absolute path', () {
expect(r.relative(r'C:\'), equals(r'C:\'));
expect(r.relative(r'C:\a\b'), equals(r'C:\a\b'));
});
test('given relative path', () {
// The path is considered relative to the root, so it basically just
@ -259,6 +320,26 @@ main() {
expect(r.relative(r'C:\dir.ext\file'), 'file');
});
test('with a root parameter', () {
expect(builder.relative(r'C:\foo\bar\baz', from: r'C:\foo\bar'),
equals('baz'));
expect(builder.relative('..', from: r'C:\foo\bar'),
equals(r'..\..\root'));
expect(builder.relative('..', from: r'D:\foo\bar'), equals(r'C:\root'));
expect(builder.relative(r'C:\foo\bar\baz', from: r'foo\bar'),
equals(r'..\..\..\..\foo\bar\baz'));
expect(builder.relative('..', from: r'foo\bar'), equals(r'..\..\..'));
});
test('with a root parameter and a relative root', () {
var r = new path.Builder(style: path.Style.windows, root: r'relative\root');
expect(r.relative(r'C:\foo\bar\baz', from: r'C:\foo\bar'), equals('baz'));
expect(() => r.relative('..', from: r'C:\foo\bar'), throwsArgumentError);
expect(r.relative(r'C:\foo\bar\baz', from: r'foo\bar'),
equals(r'C:\foo\bar\baz'));
expect(r.relative('..', from: r'foo\bar'), equals(r'..\..\..'));
});
test('given absolute with different root prefix', () {
expect(builder.relative(r'D:\a\b'), r'D:\a\b');
expect(builder.relative(r'\\a\b'), r'\\a\b');