mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 12:48:10 +00:00
Create generated tests inside the build directory
Patch Set 1 is a revert of r18295. Review URL: https://codereview.chromium.org//12223074 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@18802 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
9a6210c6e6
commit
d2c575c0b0
|
@ -21,7 +21,7 @@ var url = '';
|
|||
|
||||
main() {
|
||||
useHtmlConfiguration();
|
||||
url = "http://localhost:${window.location.port}/pkg/intl/lib/src/data/dates/";
|
||||
url = "http://localhost:${window.location.port}/root_dart/pkg/intl/lib/src/data/dates/";
|
||||
// Initialize one locale just so we know what the list is.
|
||||
test('Run everything', () {
|
||||
initializeDateFormatting("en_US", url).then(expectAsync1(runEverything));});
|
||||
|
|
|
@ -4,8 +4,8 @@ dom-modify-html.html and others in the dromaeo tests directory. -->
|
|||
<html>
|
||||
<head>
|
||||
<script type="application/dart" src="dromaeo_noop/dromaeo_smoke.dart"></script>
|
||||
<script src='../../pkg/browser/lib/dart.js'></script>
|
||||
<script src='../../samples/third_party/dromaeo/htmlrunner.js'></script>
|
||||
<script src='/root_dart/pkg/browser/lib/dart.js'></script>
|
||||
<script src='/root_dart/samples/third_party/dromaeo/htmlrunner.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
|
|
@ -24,7 +24,7 @@ void main() {
|
|||
useHtmlConfiguration();
|
||||
|
||||
var scriptSrc = new ScriptElement();
|
||||
scriptSrc.src = '../../../../pkg/browser/lib/dart.js';
|
||||
scriptSrc.src = '/root_dart/pkg/browser/lib/dart.js';
|
||||
document.head.children.add(scriptSrc);
|
||||
document.body.innerHtml = '''${document.body.innerHtml}
|
||||
<div id="main">
|
||||
|
|
|
@ -30,7 +30,8 @@ main() {
|
|||
var port = crossOriginPort;
|
||||
|
||||
test('XHR Cross-domain', () {
|
||||
var url = "http://localhost:$port/tests/html/xhr_cross_origin_data.txt";
|
||||
var url = "http://localhost:$port/"
|
||||
"root_dart/tests/html/xhr_cross_origin_data.txt";
|
||||
var xhr = new HttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
var validate = expectAsync1((data) {
|
||||
|
@ -49,7 +50,8 @@ main() {
|
|||
});
|
||||
|
||||
test('XHR.get Cross-domain', () {
|
||||
var url = "http://localhost:$port/tests/html/xhr_cross_origin_data.txt";
|
||||
var url = "http://localhost:$port/"
|
||||
"root_dart/tests/html/xhr_cross_origin_data.txt";
|
||||
HttpRequest.request(url).then(expectAsync1((xhr) {
|
||||
var data = json.parse(xhr.response);
|
||||
expect(data, contains('feed'));
|
||||
|
@ -59,7 +61,8 @@ main() {
|
|||
});
|
||||
|
||||
test('XHR.getWithCredentials Cross-domain', () {
|
||||
var url = "http://localhost:$port/tests/html/xhr_cross_origin_data.txt";
|
||||
var url = "http://localhost:$port/"
|
||||
"root_dart/tests/html/xhr_cross_origin_data.txt";
|
||||
HttpRequest.request(url, withCredentials: true).then(expectAsync1((xhr) {
|
||||
var data = json.parse(xhr.response);
|
||||
expect(data, contains('feed'));
|
||||
|
|
|
@ -17,7 +17,7 @@ void fail(message) {
|
|||
|
||||
main() {
|
||||
useHtmlIndividualConfiguration();
|
||||
var url = "/tests/html/xhr_cross_origin_data.txt";
|
||||
var url = "/root_dart/tests/html/xhr_cross_origin_data.txt";
|
||||
|
||||
void validate200Response(xhr) {
|
||||
expect(xhr.status, equals(200));
|
||||
|
|
|
@ -73,6 +73,8 @@ main() {
|
|||
}
|
||||
|
||||
var testSuites = new List<TestSuite>();
|
||||
TestingServerRunner.setBuildDir(firstConf);
|
||||
TestingServerRunner.setPackageRootDir(firstConf);
|
||||
for (var conf in configurations) {
|
||||
if (selectors.containsKey('co19')) {
|
||||
testSuites.add(new Co19TestSuite(conf));
|
||||
|
|
|
@ -126,6 +126,10 @@ main() {
|
|||
}
|
||||
|
||||
var testSuites = new List<TestSuite>();
|
||||
// FIXME(kustermann,ricow): This is broken and should be fixed ASAP.
|
||||
// Issue: 8366
|
||||
TestingServerRunner.setBuildDir(firstConf);
|
||||
TestingServerRunner.setPackageRootDir(firstConf);
|
||||
var maxBrowserProcesses = maxProcesses;
|
||||
for (var conf in configurations) {
|
||||
// There should not be more than one InternetExplorerDriver instance
|
||||
|
@ -134,7 +138,6 @@ main() {
|
|||
if (conf['runtime'].startsWith('ie')) {
|
||||
maxBrowserProcesses = 1;
|
||||
}
|
||||
TestingServerRunner.setPackageRootDir(conf);
|
||||
for (String key in selectors.keys) {
|
||||
if (key == 'co19') {
|
||||
testSuites.add(new Co19TestSuite(conf));
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
part of test_suite;
|
||||
|
||||
String getHtmlContents(String title,
|
||||
Path controllerScript,
|
||||
Path dartJsScript,
|
||||
String scriptType,
|
||||
Path sourceScript) =>
|
||||
"""
|
||||
|
@ -24,10 +22,13 @@ String getHtmlContents(String title,
|
|||
</head>
|
||||
<body>
|
||||
<h1> Running $title </h1>
|
||||
<script type="text/javascript" src="$controllerScript"></script>
|
||||
<script type="text/javascript"
|
||||
src="/root_dart/pkg/unittest/lib/test_controller.js">
|
||||
</script>
|
||||
<script type="$scriptType" src="$sourceScript" onerror="externalError(null)">
|
||||
</script>
|
||||
<script type="text/javascript" src="$dartJsScript"></script>
|
||||
<script type="text/javascript"
|
||||
src="/root_dart/pkg/browser/lib/dart.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
@ -48,37 +49,27 @@ String getHtmlLayoutContents(String scriptType, String sourceScript) =>
|
|||
</html>
|
||||
""";
|
||||
|
||||
String wrapDartTestInLibrary(Path test, String testPath) =>
|
||||
String wrapDartTestInLibrary(Path testRelativeToDart) =>
|
||||
"""
|
||||
library libraryWrapper;
|
||||
part '${pathLib.relative(test.toNativePath(),
|
||||
from: pathLib.dirname(testPath)).replaceAll('\\', '\\\\')}';
|
||||
part '/$testRelativeToDart';
|
||||
""";
|
||||
|
||||
String dartTestWrapper(Path dartHome, String testPath, Path library) {
|
||||
var testPathDir = pathLib.dirname(testPath);
|
||||
var dartHomePath = dartHome.toNativePath();
|
||||
// TODO(efortuna): Unify path libraries used in test.dart.
|
||||
var unitTest = pathLib.relative(pathLib.join(dartHomePath,
|
||||
'pkg/unittest/lib'), from: testPathDir).replaceAll('\\', '\\\\');
|
||||
|
||||
var libString = library.toNativePath();
|
||||
if (!pathLib.isAbsolute(libString)) {
|
||||
libString = pathLib.join(dartHome.toNativePath(), libString);
|
||||
}
|
||||
String dartTestWrapper(bool usePackageImport, String libraryPathComponent) {
|
||||
// Tests inside "pkg" import unittest using "package:". All others use a
|
||||
// relative path. The imports need to agree, so use a matching form here.
|
||||
if (pathLib.split(pathLib.relative(libString,
|
||||
from: dartHome.toNativePath())).contains("pkg")) {
|
||||
var unitTest;
|
||||
if (usePackageImport) {
|
||||
unitTest = 'package:unittest';
|
||||
} else {
|
||||
unitTest = '/root_dart/pkg/unittest/lib';
|
||||
}
|
||||
return """
|
||||
library test;
|
||||
|
||||
import '$unitTest/unittest.dart' as unittest;
|
||||
import '$unitTest/html_config.dart' as config;
|
||||
import '${pathLib.relative(libString, from: testPathDir).replaceAll(
|
||||
'\\', '\\\\')}' as Test;
|
||||
import '$libraryPathComponent' as Test;
|
||||
|
||||
main() {
|
||||
config.useHtmlConfiguration();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
library http_server;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:uri';
|
||||
|
@ -12,6 +13,30 @@ import 'test_suite.dart'; // For TestUtils.
|
|||
// expected number of arguments, so test.dart doesn't rely on the args library?
|
||||
// See discussion on https://codereview.chromium.org/11931025/.
|
||||
import 'vendored_pkg/args/args.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
|
||||
/// Interface of the HTTP server:
|
||||
///
|
||||
/// /echo: This will stream the data received in the request stream back
|
||||
/// to the client.
|
||||
/// /root_dart/X: This will serve the corresponding file from the dart
|
||||
/// directory (i.e. '$DartDirectory/X').
|
||||
/// /root_build/X: This will serve the corresponding file from the build
|
||||
/// directory (i.e. '$BuildDirectory/X').
|
||||
/// /FOO/packages/BAR: This will serve the corresponding file from the packages
|
||||
/// directory (i.e. '$BuildDirectory/packages/BAR')
|
||||
///
|
||||
/// In case a path does not refer to a file but rather to a directory, a
|
||||
/// directory listing will be displayed.
|
||||
|
||||
const PREFIX_BUILDDIR = 'root_build';
|
||||
const PREFIX_DARTDIR = 'root_dart';
|
||||
|
||||
// TODO(kustermann,ricow): We could change this to the following scheme:
|
||||
// http://host:port/root_packages/X -> $BuildDir/packages/X
|
||||
// Issue: 8368
|
||||
|
||||
|
||||
main() {
|
||||
/** Convenience method for local testing. */
|
||||
|
@ -43,7 +68,11 @@ main() {
|
|||
.join(new Path('../../test.dart'))
|
||||
.canonicalize()
|
||||
.toNativePath();
|
||||
// Note: args['package-root'] is always the build directory. We have the
|
||||
// implicit assumption that it contains the 'packages' subdirectory.
|
||||
// TODO: We should probably rename 'package-root' to 'build-directory'.
|
||||
TestingServerRunner._packageRootDir = new Path(args['package-root']);
|
||||
TestingServerRunner._buildDirectory = new Path(args['package-root']);
|
||||
var network = args['network'];
|
||||
TestingServerRunner.startHttpServer(network,
|
||||
port: int.parse(args['port']));
|
||||
|
@ -63,98 +92,129 @@ main() {
|
|||
class TestingServerRunner {
|
||||
static List serverList = [];
|
||||
static Path _packageRootDir = null;
|
||||
static Path _buildDirectory = null;
|
||||
|
||||
// Added as a getter so that the function will be called again each time the
|
||||
// default request handler closure is executed.
|
||||
static Path get packageRootDir => _packageRootDir;
|
||||
static Path get buildDirectory => _buildDirectory;
|
||||
|
||||
static setPackageRootDir(Map configuration) {
|
||||
_packageRootDir = TestUtils.currentWorkingDirectory.join(
|
||||
_packageRootDir = TestUtils.absolutePath(
|
||||
new Path(TestUtils.buildDir(configuration)));
|
||||
}
|
||||
|
||||
static setBuildDir(Map configuration) {
|
||||
_buildDirectory = TestUtils.absolutePath(
|
||||
new Path(TestUtils.buildDir(configuration)));
|
||||
}
|
||||
|
||||
static startHttpServer(String host, {int allowedPort:-1, int port: 0}) {
|
||||
var basePath = TestUtils.dartDir();
|
||||
var httpServer = new HttpServer();
|
||||
var packagesDirName = 'packages';
|
||||
httpServer.onError = (e) {
|
||||
// TODO(ricow): Once we have a debug log we should write this out there.
|
||||
print('Test http server error: $e');
|
||||
DebugLogger.error('HttpServer: an error occured: $e');
|
||||
};
|
||||
httpServer.defaultRequestHandler = (request, resp) {
|
||||
var requestPath = new Path(request.path.substring(1)).canonicalize();
|
||||
var path = basePath.join(requestPath);
|
||||
var file = new File(path.toNativePath());
|
||||
|
||||
if (requestPath.segments().contains(packagesDirName)) {
|
||||
// Essentially implement the packages path rewriting, so we don't have
|
||||
// to pass environment variables to the browsers.
|
||||
var requestPathStr = requestPath.toNativePath().substring(
|
||||
requestPath.toNativePath().indexOf(packagesDirName));
|
||||
path = packageRootDir.append(requestPathStr);
|
||||
file = new File(path.toNativePath());
|
||||
}
|
||||
file.exists().then((exists) {
|
||||
if (exists) {
|
||||
if (allowedPort != -1) {
|
||||
if (request.headers.value('Origin') != null) {
|
||||
var origin = new Uri(request.headers.value('Origin'));
|
||||
// Allow loading from http://*:$allowedPort in browsers.
|
||||
var allowedOrigin =
|
||||
'${origin.scheme}://${origin.domain}:${allowedPort}';
|
||||
resp.headers.set("Access-Control-Allow-Origin", allowedOrigin);
|
||||
resp.headers.set('Access-Control-Allow-Credentials', 'true');
|
||||
}
|
||||
} else {
|
||||
// No allowedPort specified. Allow from anywhere (but cross-origin
|
||||
// requests *with credentials* will fail because you can't use "*").
|
||||
resp.headers.set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
if (path.toNativePath().endsWith('.html')) {
|
||||
resp.headers.set('Content-Type', 'text/html');
|
||||
} else if (path.toNativePath().endsWith('.js')) {
|
||||
resp.headers.set('Content-Type', 'application/javascript');
|
||||
} else if (path.toNativePath().endsWith('.dart')) {
|
||||
resp.headers.set('Content-Type', 'application/dart');
|
||||
}
|
||||
file.openInputStream().pipe(resp.outputStream);
|
||||
} else {
|
||||
var directory = new Directory.fromPath(path);
|
||||
directory.exists().then((exists) {
|
||||
if (!exists) {
|
||||
sendNotFound(resp);
|
||||
} else {
|
||||
sendDirectoryListing(directory, request, resp);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
httpServer.defaultRequestHandler = (request, response) {
|
||||
handleFileOrDirectoryRequest(request, response, allowedPort);
|
||||
};
|
||||
|
||||
// Echos back the contents of the request as the response data.
|
||||
httpServer.addRequestHandler((req) => req.path == "/echo", (request, resp) {
|
||||
resp.headers.set("Access-Control-Allow-Origin", "*");
|
||||
|
||||
request.inputStream.pipe(resp.outputStream);
|
||||
});
|
||||
httpServer.addRequestHandler(
|
||||
(req) => req.path == "/echo", handleEchoRequest);
|
||||
|
||||
httpServer.listen(host, port);
|
||||
serverList.add(httpServer);
|
||||
}
|
||||
|
||||
static void sendNotFound(HttpResponse response) {
|
||||
response.statusCode = HttpStatus.NOT_FOUND;
|
||||
try {
|
||||
response.outputStream.close();
|
||||
} catch (e) {
|
||||
if (e is StreamException) {
|
||||
print('Test http_server error closing the response stream: $e');
|
||||
|
||||
static void handleFileOrDirectoryRequest(HttpRequest request,
|
||||
HttpResponse response,
|
||||
int allowedPort) {
|
||||
var path = getFilePathFromRequestPath(request.path);
|
||||
if (path != null) {
|
||||
var file = new File.fromPath(path);
|
||||
file.exists().then((exists) {
|
||||
if (exists) {
|
||||
sendFileContent(request, response, allowedPort, path, file);
|
||||
} else {
|
||||
var directory = new Directory.fromPath(path);
|
||||
directory.exists().then((exists) {
|
||||
if (exists) {
|
||||
listDirectory(directory).then((entries) {
|
||||
sendDirectoryListing(entries, request, response);
|
||||
});
|
||||
} else {
|
||||
sendNotFound(request, response);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (request.path == '/') {
|
||||
var entries = [new _Entry('root_dart', 'root_dart/'),
|
||||
new _Entry('root_build', 'root_build/'),
|
||||
new _Entry('echo', 'echo')];
|
||||
sendDirectoryListing(entries, request, response);
|
||||
} else {
|
||||
throw e;
|
||||
sendNotFound(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handleEchoRequest(HttpRequest request, HttpResponse response) {
|
||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
||||
request.inputStream.pipe(response.outputStream);
|
||||
}
|
||||
|
||||
static Path getFilePathFromRequestPath(String urlRequestPath) {
|
||||
// Go to the top of the file to see an explanation of the URL path scheme.
|
||||
var requestPath = new Path(urlRequestPath.substring(1)).canonicalize();
|
||||
var pathSegments = requestPath.segments();
|
||||
if (pathSegments.length > 0) {
|
||||
var basePath;
|
||||
var relativePath;
|
||||
if (pathSegments[0] == PREFIX_BUILDDIR) {
|
||||
basePath = _buildDirectory;
|
||||
relativePath = new Path(
|
||||
pathSegments.getRange(1, pathSegments.length - 1).join('/'));
|
||||
} else if (pathSegments[0] == PREFIX_DARTDIR) {
|
||||
basePath = TestUtils.dartDir();
|
||||
relativePath = new Path(
|
||||
pathSegments.getRange(1, pathSegments.length - 1).join('/'));
|
||||
}
|
||||
var packagesDirName = 'packages';
|
||||
var packagesIndex = pathSegments.indexOf(packagesDirName);
|
||||
if (packagesIndex != -1) {
|
||||
var start = packagesIndex + 1;
|
||||
var length = pathSegments.length - start;
|
||||
basePath = _packageRootDir.append(packagesDirName);
|
||||
relativePath = new Path(
|
||||
pathSegments.getRange(start, length).join('/'));
|
||||
}
|
||||
if (basePath != null && relativePath != null) {
|
||||
return basePath.join(relativePath);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<List<_Entry>> listDirectory(Directory directory) {
|
||||
var completer = new Completer();
|
||||
var entries = [];
|
||||
|
||||
directory.list()
|
||||
..onFile = (filepath) {
|
||||
var filename = new Path(filepath).filename;
|
||||
entries.add(new _Entry(filename, filename));
|
||||
}
|
||||
..onDir = (dirpath) {
|
||||
var filename = new Path(dirpath).filename;
|
||||
entries.add(new _Entry(filename, '$filename/'));
|
||||
}
|
||||
..onDone = (_) {
|
||||
completer.complete(entries);
|
||||
};
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a simple listing of all the files and sub-directories within
|
||||
* directory.
|
||||
|
@ -162,8 +222,9 @@ class TestingServerRunner {
|
|||
* This is intended to make it easier to browse tests when manually running
|
||||
* tests against this test server.
|
||||
*/
|
||||
static void sendDirectoryListing(Directory directory, HttpRequest request,
|
||||
HttpResponse response) {
|
||||
static void sendDirectoryListing(entries,
|
||||
HttpRequest request,
|
||||
HttpResponse response) {
|
||||
response.headers.set('Content-Type', 'text/html');
|
||||
var header = '''<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -181,30 +242,62 @@ class TestingServerRunner {
|
|||
</body>
|
||||
</html>''';
|
||||
|
||||
var entries = [];
|
||||
|
||||
directory.list()
|
||||
..onFile = (filepath) {
|
||||
var filename = new Path(filepath).filename;
|
||||
entries.add(new _Entry(filename, filename));
|
||||
}
|
||||
..onDir = (dirpath) {
|
||||
var filename = new Path(dirpath).filename;
|
||||
entries.add(new _Entry(filename, '$filename/'));
|
||||
}
|
||||
..onDone = (_) {
|
||||
var requestPath = new Path.raw(request.path);
|
||||
entries.sort();
|
||||
entries.sort();
|
||||
response.outputStream.writeString(header);
|
||||
for (var entry in entries) {
|
||||
response.outputStream.writeString(
|
||||
'<li><a href="${new Path(request.path).append(entry.name)}">'
|
||||
'${entry.displayName}</a></li>');
|
||||
}
|
||||
response.outputStream.writeString(footer);
|
||||
response.outputStream.close();
|
||||
}
|
||||
|
||||
response.outputStream.writeString(header);
|
||||
for (var entry in entries) {
|
||||
response.outputStream.writeString(
|
||||
'<li><a href="${requestPath.append(entry.name)}">'
|
||||
'${entry.displayName}</a></li>');
|
||||
}
|
||||
response.outputStream.writeString(footer);
|
||||
response.outputStream.close();
|
||||
};
|
||||
static void sendFileContent(HttpRequest request,
|
||||
HttpResponse response,
|
||||
int allowedPort,
|
||||
Path path,
|
||||
File file) {
|
||||
if (allowedPort != -1) {
|
||||
var origin = new Uri(request.headers.value('Origin'));
|
||||
// Allow loading from http://*:$allowedPort in browsers.
|
||||
var allowedOrigin =
|
||||
'${origin.scheme}://${origin.domain}:${allowedPort}';
|
||||
response.headers.set("Access-Control-Allow-Origin", allowedOrigin);
|
||||
response.headers.set('Access-Control-Allow-Credentials', 'true');
|
||||
} else {
|
||||
// No allowedPort specified. Allow from anywhere (but cross-origin
|
||||
// requests *with credentials* will fail because you can't use "*").
|
||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
if (path.filename.endsWith('.html')) {
|
||||
response.headers.set('Content-Type', 'text/html');
|
||||
} else if (path.filename.endsWith('.js')) {
|
||||
response.headers.set('Content-Type', 'application/javascript');
|
||||
} else if (path.filename.endsWith('.dart')) {
|
||||
response.headers.set('Content-Type', 'application/dart');
|
||||
}
|
||||
file.openInputStream().pipe(response.outputStream);
|
||||
}
|
||||
|
||||
static void sendNotFound(HttpRequest request, HttpResponse response) {
|
||||
// NOTE: Since some tests deliberately try to access non-existent files.
|
||||
// We might want to remove this warning (otherwise it will show
|
||||
// up in the debug.log every time).
|
||||
DebugLogger.warning('HttpServer: could not find file for request path: '
|
||||
'"${request.path}"');
|
||||
response.statusCode = HttpStatus.NOT_FOUND;
|
||||
try {
|
||||
response.outputStream.close();
|
||||
} catch (e) {
|
||||
if (e is StreamException) {
|
||||
DebugLogger.warning('HttpServer: error while closing the response '
|
||||
'stream: $e');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static terminateHttpServers() {
|
||||
|
|
|
@ -23,9 +23,7 @@ import "multitest.dart";
|
|||
import "status_file_parser.dart";
|
||||
import "test_runner.dart";
|
||||
import "utils.dart";
|
||||
|
||||
// TODO(efortuna,whess): Remove this import.
|
||||
import 'vendored_pkg/path/path.dart' as pathLib;
|
||||
import "http_server.dart" show PREFIX_BUILDDIR, PREFIX_DARTDIR;
|
||||
|
||||
part "browser_test.dart";
|
||||
|
||||
|
@ -812,7 +810,77 @@ class StandardTestSuite extends TestSuite {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* _createUrlPathFromFile takes a [file], which is either located in the dart
|
||||
* or in the build directory, and will return a String representing
|
||||
* the relative path to either the dart or the build directory.
|
||||
* Thus, the returned [String] will be the path component of the URL
|
||||
* corresponding to [file] (the http server serves files relative to the
|
||||
* dart/build directories).
|
||||
*/
|
||||
String _createUrlPathFromFile(Path file) {
|
||||
file = TestUtils.absolutePath(file);
|
||||
|
||||
var relativeBuildDir = new Path(TestUtils.buildDir(configuration));
|
||||
var buildDir = TestUtils.absolutePath(relativeBuildDir);
|
||||
var dartDir = TestUtils.absolutePath(TestUtils.dartDir());
|
||||
|
||||
var fileString = file.toString();
|
||||
if (fileString.startsWith(buildDir.toString())) {
|
||||
var fileRelativeToBuildDir = file.relativeTo(buildDir);
|
||||
return "/$PREFIX_BUILDDIR/$fileRelativeToBuildDir";
|
||||
} else if (fileString.startsWith(dartDir.toString())) {
|
||||
var fileRelativeToDartDir = file.relativeTo(dartDir);
|
||||
return "/$PREFIX_DARTDIR/$fileRelativeToDartDir";
|
||||
}
|
||||
// Unreachable
|
||||
Except.fail('This should be unreachable.');
|
||||
}
|
||||
|
||||
void _getUriForBrowserTest(TestInformation info,
|
||||
String pathComponent,
|
||||
subtestNames,
|
||||
subtestIndex) {
|
||||
// Note: If we run test.py with the "--list" option, no http servers
|
||||
// will be started. Therefore serverList is an empty list in this
|
||||
// case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
|
||||
var serverPort = "PORT";
|
||||
var crossOriginPort = "CROSS_ORIGIN_PORT";
|
||||
if (!configuration['list']) {
|
||||
serverPort = serverList[0].port.toString();
|
||||
crossOriginPort = serverList[1].port.toString();
|
||||
}
|
||||
|
||||
var url= 'http://127.0.0.1:$serverPort$pathComponent'
|
||||
'?crossOriginPort=$crossOriginPort';
|
||||
if (info.optionsFromFile['isMultiHtmlTest'] && subtestNames.length > 0) {
|
||||
url= '${url}&group=${subtestNames[subtestIndex]}';
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
void _createWrapperFile(String dartWrapperFilename, dartLibraryFilename) {
|
||||
File file = new File(dartWrapperFilename);
|
||||
RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
|
||||
|
||||
var usePackageImport = dartLibraryFilename.segments().contains("pkg");
|
||||
var libraryPathComponent = _createUrlPathFromFile(dartLibraryFilename);
|
||||
dartWrapper.writeStringSync(dartTestWrapper(usePackageImport,
|
||||
libraryPathComponent));
|
||||
dartWrapper.closeSync();
|
||||
}
|
||||
|
||||
void _createLibraryWrapperFile(Path dartLibraryFilename, filePath) {
|
||||
File file = new File(dartLibraryFilename.toNativePath());
|
||||
RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
|
||||
var requestPath = new Path(PREFIX_DARTDIR)
|
||||
.join(filePath.relativeTo(TestUtils.dartDir()));
|
||||
dartLibrary.writeStringSync(wrapDartTestInLibrary(requestPath));
|
||||
dartLibrary.closeSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* The [StandardTestSuite] has support for tests that
|
||||
* compile a test from Dart to JavaScript, and then run the resulting
|
||||
* JavaScript. This function creates a working directory to hold the
|
||||
|
@ -867,18 +935,9 @@ class StandardTestSuite extends TestSuite {
|
|||
if (!isLibraryDefinition) {
|
||||
dartLibraryFilename = new Path(tempDir).append(
|
||||
'test_as_library.dart');
|
||||
File file = new File(dartLibraryFilename.toNativePath());
|
||||
RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
|
||||
dartLibrary.writeStringSync(
|
||||
wrapDartTestInLibrary(filePath, file.name));
|
||||
dartLibrary.closeSync();
|
||||
_createLibraryWrapperFile(dartLibraryFilename, filePath);
|
||||
}
|
||||
|
||||
File file = new File(dartWrapperFilename);
|
||||
RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
|
||||
dartWrapper.writeStringSync(
|
||||
dartTestWrapper(dartDir, file.name, dartLibraryFilename));
|
||||
dartWrapper.closeSync();
|
||||
_createWrapperFile(dartWrapperFilename, dartLibraryFilename);
|
||||
} else {
|
||||
dartWrapperFilename = filename;
|
||||
// TODO(whesse): Once test.py is retired, adjust the relative path in
|
||||
|
@ -895,8 +954,10 @@ class StandardTestSuite extends TestSuite {
|
|||
}
|
||||
htmlPath = '$tempDir/../$htmlFilename';
|
||||
}
|
||||
final String scriptPath = (compiler == 'none') ?
|
||||
String scriptPath = (compiler == 'none') ?
|
||||
dartWrapperFilename : compiledDartWrapperFilename;
|
||||
scriptPath = _createUrlPathFromFile(new Path(scriptPath));
|
||||
|
||||
// Create the HTML file for the test.
|
||||
RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE);
|
||||
String content = null;
|
||||
|
@ -907,22 +968,13 @@ class StandardTestSuite extends TestSuite {
|
|||
Path expectedOutput = null;
|
||||
if (new File.fromPath(pngPath).existsSync()) {
|
||||
expectedOutput = pngPath;
|
||||
// TODO(efortuna): Unify path libraries in test.dart.
|
||||
content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
|
||||
from: pathLib.dirname(htmlPath)));
|
||||
content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
|
||||
} else if (new File.fromPath(txtPath).existsSync()) {
|
||||
expectedOutput = txtPath;
|
||||
content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
|
||||
from: pathLib.dirname(htmlPath)));
|
||||
content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
|
||||
} else {
|
||||
final htmlLocation = new Path(htmlPath);
|
||||
content = getHtmlContents(
|
||||
filename,
|
||||
dartDir.append('pkg/unittest/lib/test_controller.js')
|
||||
.relativeTo(htmlLocation),
|
||||
dartDir.append('pkg/browser/lib/dart.js').relativeTo(htmlLocation),
|
||||
scriptType,
|
||||
new Path(scriptPath).relativeTo(htmlLocation));
|
||||
content = getHtmlContents(filename, scriptType,
|
||||
new Path("$scriptPath"));
|
||||
}
|
||||
htmlTest.writeStringSync(content);
|
||||
htmlTest.closeSync();
|
||||
|
@ -962,35 +1014,11 @@ class StandardTestSuite extends TestSuite {
|
|||
commandSet = [];
|
||||
}
|
||||
|
||||
List<String> args = <String>[];
|
||||
var basePath = TestUtils.dartDir().toString();
|
||||
if (!htmlPath.startsWith('/') && !htmlPath.startsWith('http')) {
|
||||
htmlPath = '/$htmlPath';
|
||||
}
|
||||
htmlPath = htmlPath.startsWith(basePath) ?
|
||||
htmlPath.substring(basePath.length) : htmlPath;
|
||||
String fullHtmlPath = htmlPath;
|
||||
var searchStr = '?';
|
||||
if (!htmlPath.startsWith('http')) {
|
||||
// Note: If we run test.py with the "--list" option, no http servers
|
||||
// will be started. Therefore serverList is an empty list in this
|
||||
// case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
|
||||
var serverPort = "PORT";
|
||||
var crossOriginPort = "CROSS_ORIGIN_PORT";
|
||||
if (!configuration['list']) {
|
||||
serverPort = serverList[0].port.toString();
|
||||
crossOriginPort = serverList[1].port.toString();
|
||||
}
|
||||
fullHtmlPath = 'http://127.0.0.1:$serverPort$htmlPath${searchStr}'
|
||||
'crossOriginPort=$crossOriginPort';
|
||||
searchStr = '&';
|
||||
}
|
||||
if (info.optionsFromFile['isMultiHtmlTest']
|
||||
&& subtestNames.length > 0) {
|
||||
fullHtmlPath = '${fullHtmlPath}${searchStr}group='
|
||||
'${subtestNames[subtestIndex]}';
|
||||
}
|
||||
var htmlPath_subtest = _createUrlPathFromFile(new Path(htmlPath));
|
||||
var fullHtmlPath = _getUriForBrowserTest(info, htmlPath_subtest,
|
||||
subtestNames, subtestIndex);
|
||||
|
||||
List<String> args = <String>[];
|
||||
if (TestUtils.usesWebDriver(runtime)) {
|
||||
args = [
|
||||
dartDir.append('tools/testing/run_selenium.py').toNativePath(),
|
||||
|
@ -1125,8 +1153,7 @@ class StandardTestSuite extends TestSuite {
|
|||
var minified = configuration['minified'] ? '-minified' : '';
|
||||
var dirName = "${configuration['compiler']}-${configuration['runtime']}"
|
||||
"$checked$minified";
|
||||
Path generatedTestPath = new Path(dartDir.toNativePath())
|
||||
.append(buildDir)
|
||||
Path generatedTestPath = new Path(buildDir)
|
||||
.append('generated_tests')
|
||||
.append(dirName)
|
||||
.append(testUniqueName);
|
||||
|
@ -1816,6 +1843,10 @@ class TestUtils {
|
|||
const ['d8', 'jsshell'].contains(runtime);
|
||||
|
||||
static String buildDir(Map configuration) {
|
||||
// FIXME(kustermann,ricow): Our code assumes that the returned 'buildDir'
|
||||
// is relative to the current working directory.
|
||||
// Thus, if we pass in an absolute path (e.g. '--build-directory=/tmp/out')
|
||||
// we get into trouble.
|
||||
if (configuration['build_directory'] != '') {
|
||||
return configuration['build_directory'];
|
||||
}
|
||||
|
|
|
@ -1,689 +0,0 @@
|
|||
// Copyright (c) 2012, 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.
|
||||
|
||||
/// A comprehensive, cross-platform path manipulation library.
|
||||
library path;
|
||||
|
||||
import 'dart:io' as io;
|
||||
|
||||
/// An internal builder for the current OS so we can provide a straight
|
||||
/// functional interface and not require users to create one.
|
||||
final _builder = new Builder();
|
||||
|
||||
/// Gets the path to the current working directory.
|
||||
String get current => new io.Directory.current().path;
|
||||
|
||||
/// Gets the path separator for the current platform. On Mac and Linux, this
|
||||
/// is `/`. On Windows, it's `\`.
|
||||
String get separator => _builder.separator;
|
||||
|
||||
/// Converts [path] to an absolute path by resolving it relative to the current
|
||||
/// working directory. If [path] is already an absolute path, just returns it.
|
||||
///
|
||||
/// path.absolute('foo/bar.txt'); // -> /your/current/dir/foo/bar.txt
|
||||
String absolute(String path) => join(current, path);
|
||||
|
||||
/// Gets the part of [path] after the last separator.
|
||||
///
|
||||
/// path.basename('path/to/foo.dart'); // -> 'foo.dart'
|
||||
/// path.basename('path/to'); // -> 'to'
|
||||
///
|
||||
/// Trailing separators are ignored.
|
||||
///
|
||||
/// builder.dirname('path/to/'); // -> 'to'
|
||||
String basename(String path) => _builder.basename(path);
|
||||
|
||||
/// Gets the part of [path] after the last separator, and without any trailing
|
||||
/// file extension.
|
||||
///
|
||||
/// path.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo'
|
||||
///
|
||||
/// Trailing separators are ignored.
|
||||
///
|
||||
/// builder.dirname('path/to/foo.dart/'); // -> 'foo'
|
||||
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'
|
||||
///
|
||||
/// Trailing separators are ignored.
|
||||
///
|
||||
/// builder.dirname('path/to/'); // -> 'path'
|
||||
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).
|
||||
///
|
||||
/// path.extension('path/to/foo.dart'); // -> '.dart'
|
||||
/// path.extension('path/to/foo'); // -> ''
|
||||
/// path.extension('path.to/foo'); // -> ''
|
||||
/// path.extension('path/to/foo.dart.js'); // -> '.js'
|
||||
///
|
||||
/// If the file name starts with a `.`, then that is not considered the
|
||||
/// extension:
|
||||
///
|
||||
/// path.extension('~/.bashrc'); // -> ''
|
||||
/// 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
|
||||
/// followed by `:/` or `:\`.
|
||||
bool isAbsolute(String path) => _builder.isAbsolute(path);
|
||||
|
||||
/// Returns `true` if [path] is a relative path and `false` if it is absolute.
|
||||
/// On POSIX systems, absolute paths start with a `/` (forward slash). On
|
||||
/// Windows, an absolute path starts with `\\`, or a drive letter followed by
|
||||
/// `:/` or `:\`.
|
||||
bool isRelative(String path) => _builder.isRelative(path);
|
||||
|
||||
/// Joins the given path parts into a single path using the current platform's
|
||||
/// [separator]. Example:
|
||||
///
|
||||
/// path.join('path', 'to', 'foo'); // -> 'path/to/foo'
|
||||
///
|
||||
/// If any part ends in a path separator, then a redundant separator will not
|
||||
/// be added:
|
||||
///
|
||||
/// path.join('path/', 'to', 'foo'); // -> 'path/to/foo
|
||||
///
|
||||
/// If a part is an absolute path, then anything before that will be ignored:
|
||||
///
|
||||
/// 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]) =>
|
||||
_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].
|
||||
///
|
||||
/// path.split('path/to/foo'); // -> ['path', 'to', 'foo']
|
||||
///
|
||||
/// The path will *not* be normalized before splitting.
|
||||
///
|
||||
/// path.split('path/../foo'); // -> ['path', '..', '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.
|
||||
///
|
||||
/// path.normalize('path/./to/..//file.text'); // -> 'path/file.txt'
|
||||
String normalize(String path) => _builder.normalize(path);
|
||||
|
||||
/// Attempts to convert [path] to an equivalent relative path from the current
|
||||
/// directory.
|
||||
///
|
||||
/// // Given current directory is /root/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.
|
||||
///
|
||||
/// 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].
|
||||
///
|
||||
/// withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
|
||||
String withoutExtension(String path) => _builder.withoutExtension(path);
|
||||
|
||||
/// An instantiable class for manipulating paths. Unlike the top-level
|
||||
/// functions, this lets you explicitly select what platform the paths will use.
|
||||
class Builder {
|
||||
/// Creates a new path builder for the given style and root directory.
|
||||
///
|
||||
/// If [style] is omitted, it uses the host operating system's path style. If
|
||||
/// [root] is omitted, it defaults to the current working directory. If [root]
|
||||
/// is relative, it is considered relative to the current working directory.
|
||||
factory Builder({Style style, String root}) {
|
||||
if (style == null) {
|
||||
if (io.Platform.operatingSystem == 'windows') {
|
||||
style = Style.windows;
|
||||
} else {
|
||||
style = Style.posix;
|
||||
}
|
||||
}
|
||||
|
||||
if (root == null) root = current;
|
||||
|
||||
return new Builder._(style, root);
|
||||
}
|
||||
|
||||
Builder._(this.style, this.root);
|
||||
|
||||
/// The style of path that this builder works with.
|
||||
final Style style;
|
||||
|
||||
/// The root directory that relative paths will be relative to.
|
||||
final String root;
|
||||
|
||||
/// Gets the path separator for the builder's [style]. On Mac and Linux,
|
||||
/// this is `/`. On Windows, it's `\`.
|
||||
String get separator => style.separator;
|
||||
|
||||
/// Gets the part of [path] after the last separator on the builder's
|
||||
/// platform.
|
||||
///
|
||||
/// builder.basename('path/to/foo.dart'); // -> 'foo.dart'
|
||||
/// builder.basename('path/to'); // -> 'to'
|
||||
///
|
||||
/// Trailing separators are ignored.
|
||||
///
|
||||
/// builder.dirname('path/to/'); // -> 'to'
|
||||
String basename(String path) => _parse(path).basename;
|
||||
|
||||
/// Gets the part of [path] after the last separator on the builder's
|
||||
/// platform, and without any trailing file extension.
|
||||
///
|
||||
/// builder.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo'
|
||||
///
|
||||
/// Trailing separators are ignored.
|
||||
///
|
||||
/// builder.dirname('path/to/foo.dart/'); // -> 'foo'
|
||||
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'); // -> 'path'
|
||||
///
|
||||
/// Trailing separators are ignored.
|
||||
///
|
||||
/// builder.dirname('path/to/'); // -> 'path'
|
||||
String dirname(String path) {
|
||||
var parsed = _parse(path);
|
||||
parsed.removeTrailingSeparators();
|
||||
if (parsed.parts.isEmpty) return parsed.root == null ? '.' : parsed.root;
|
||||
if (parsed.parts.length == 1) {
|
||||
return parsed.root == null ? '.' : parsed.root;
|
||||
}
|
||||
parsed.parts.removeLast();
|
||||
parsed.separators.removeLast();
|
||||
parsed.removeTrailingSeparators();
|
||||
return parsed.toString();
|
||||
}
|
||||
|
||||
/// Gets the file extension of [path]: the portion of [basename] from the last
|
||||
/// `.` to the end (including the `.` itself).
|
||||
///
|
||||
/// builder.extension('path/to/foo.dart'); // -> '.dart'
|
||||
/// builder.extension('path/to/foo'); // -> ''
|
||||
/// builder.extension('path.to/foo'); // -> ''
|
||||
/// builder.extension('path/to/foo.dart.js'); // -> '.js'
|
||||
///
|
||||
/// If the file name starts with a `.`, then it is not considered an
|
||||
/// extension:
|
||||
///
|
||||
/// builder.extension('~/.bashrc'); // -> ''
|
||||
/// 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
|
||||
/// followed by `:/` or `:\`.
|
||||
bool isAbsolute(String path) => _parse(path).isAbsolute;
|
||||
|
||||
/// Returns `true` if [path] is a relative path and `false` if it is absolute.
|
||||
/// On POSIX systems, absolute paths start with a `/` (forward slash). On
|
||||
/// Windows, an absolute path starts with `\\`, or a drive letter followed by
|
||||
/// `:/` or `:\`.
|
||||
bool isRelative(String path) => !isAbsolute(path);
|
||||
|
||||
/// Joins the given path parts into a single path. Example:
|
||||
///
|
||||
/// builder.join('path', 'to', 'foo'); // -> 'path/to/foo'
|
||||
///
|
||||
/// If any part ends in a path separator, then a redundant separator will not
|
||||
/// be added:
|
||||
///
|
||||
/// builder.join('path/', 'to', 'foo'); // -> 'path/to/foo
|
||||
///
|
||||
/// If a part is an absolute path, then anything before that will be ignored:
|
||||
///
|
||||
/// builder.join('path', '/to', 'foo'); // -> '/to/foo'
|
||||
///
|
||||
String join(String part1, [String part2, String part3, String part4,
|
||||
String part5, String part6, String part7, String part8]) {
|
||||
var buffer = new StringBuffer();
|
||||
var needsSeparator = false;
|
||||
|
||||
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.
|
||||
buffer.clear();
|
||||
buffer.add(part);
|
||||
} else {
|
||||
if (part.length > 0 && part[0].contains(style.separatorPattern)) {
|
||||
// The part starts with a separator, so we don't need to add one.
|
||||
} else if (needsSeparator) {
|
||||
buffer.add(separator);
|
||||
}
|
||||
|
||||
buffer.add(part);
|
||||
}
|
||||
|
||||
// Unless this part ends with a separator, we'll need to add one before
|
||||
// the next part.
|
||||
needsSeparator = part.length > 0 &&
|
||||
!part[part.length - 1].contains(style.separatorPattern);
|
||||
}
|
||||
|
||||
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']
|
||||
///
|
||||
/// The path will *not* be normalized before splitting.
|
||||
///
|
||||
/// builder.split('path/../foo'); // -> ['path', '..', '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.where((part) => !part.isEmpty).toList();
|
||||
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.
|
||||
///
|
||||
/// builder.normalize('path/./to/..//file.text'); // -> 'path/file.txt'
|
||||
String normalize(String path) {
|
||||
if (path == '') return path;
|
||||
|
||||
var parsed = _parse(path);
|
||||
parsed.normalize();
|
||||
return parsed.toString();
|
||||
}
|
||||
|
||||
/// Creates a new path by appending the given path parts to the [root].
|
||||
/// Equivalent to [join()] with [root] as the first argument. Example:
|
||||
///
|
||||
/// var builder = new Builder(root: 'root');
|
||||
/// builder.resolve('path', 'to', 'foo'); // -> 'root/path/to/foo'
|
||||
String resolve(String part1, [String part2, String part3, String part4,
|
||||
String part5, String part6, String part7]) {
|
||||
if (!?part2) return join(root, part1);
|
||||
if (!?part3) return join(root, part1, part2);
|
||||
if (!?part4) return join(root, part1, part2, part3);
|
||||
if (!?part5) return join(root, part1, part2, part3, part4);
|
||||
if (!?part6) return join(root, part1, part2, part3, part4, part5);
|
||||
if (!?part7) return join(root, part1, part2, part3, part4, part5, part6);
|
||||
return join(root, part1, part2, part3, part4, part5, part6, part7);
|
||||
}
|
||||
|
||||
/// Attempts to convert [path] to an equivalent relative path relative to
|
||||
/// [root].
|
||||
///
|
||||
/// var builder = new Builder(root: '/root/path');
|
||||
/// 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.
|
||||
///
|
||||
/// 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 '.';
|
||||
|
||||
from = from == null ? root : this.join(root, from);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
// on Windows), then there is no relative path, so just return the absolute
|
||||
// one. In Windows, drive letters are case-insenstive and we allow
|
||||
// calculation of relative paths, even if a path has not been normalized.
|
||||
if (fromParsed.root != pathParsed.root &&
|
||||
((fromParsed.root == null || pathParsed.root == null) ||
|
||||
fromParsed.root.toLowerCase().replaceAll('/', '\\') !=
|
||||
pathParsed.root.toLowerCase().replaceAll('/', '\\'))) {
|
||||
return pathParsed.toString();
|
||||
}
|
||||
|
||||
// Strip off their common prefix.
|
||||
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, fromParsed.parts.length, '..');
|
||||
pathParsed.separators.insertRange(0, fromParsed.parts.length,
|
||||
style.separator);
|
||||
|
||||
// Corner case: the paths completely collapsed.
|
||||
if (pathParsed.parts.length == 0) return '.';
|
||||
|
||||
// Make it relative.
|
||||
pathParsed.root = '';
|
||||
pathParsed.removeTrailingSeparators();
|
||||
|
||||
return pathParsed.toString();
|
||||
}
|
||||
|
||||
/// Removes a trailing extension from the last part of [path].
|
||||
///
|
||||
/// builder.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
|
||||
String withoutExtension(String path) {
|
||||
var parsed = _parse(path);
|
||||
|
||||
for (var i = parsed.parts.length - 1; i >= 0; i--) {
|
||||
if (!parsed.parts[i].isEmpty) {
|
||||
parsed.parts[i] = parsed.basenameWithoutExtension;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed.toString();
|
||||
}
|
||||
|
||||
_ParsedPath _parse(String path) {
|
||||
var before = path;
|
||||
|
||||
// Remove the root prefix, if any.
|
||||
var root = style.getRoot(path);
|
||||
if (root != null) path = path.substring(root.length);
|
||||
|
||||
// Split the parts on path separators.
|
||||
var parts = [];
|
||||
var separators = [];
|
||||
var start = 0;
|
||||
for (var match in style.separatorPattern.allMatches(path)) {
|
||||
parts.add(path.substring(start, match.start));
|
||||
separators.add(match[0]);
|
||||
start = match.end;
|
||||
}
|
||||
|
||||
// Add the final part, if any.
|
||||
if (start < path.length) {
|
||||
parts.add(path.substring(start));
|
||||
separators.add('');
|
||||
}
|
||||
|
||||
return new _ParsedPath(style, root, parts, separators);
|
||||
}
|
||||
}
|
||||
|
||||
/// An enum type describing a "flavor" of path.
|
||||
class Style {
|
||||
/// POSIX-style paths use "/" (forward slash) as separators. Absolute paths
|
||||
/// start with "/". Used by UNIX, Linux, Mac OS X, and others.
|
||||
static final posix = new Style._('posix', '/', '/', '/');
|
||||
|
||||
/// Windows paths use "\" (backslash) as separators. Absolute paths start with
|
||||
/// a drive letter followed by a colon (example, "C:") or two backslashes
|
||||
/// ("\\") for UNC paths.
|
||||
// TODO(rnystrom): The UNC root prefix should include the drive name too, not
|
||||
// just the "\\".
|
||||
static final windows = new Style._('windows', '\\', r'[/\\]',
|
||||
r'\\\\|[a-zA-Z]:[/\\]');
|
||||
|
||||
Style._(this.name, this.separator, String separatorPattern,
|
||||
String rootPattern)
|
||||
: separatorPattern = new RegExp(separatorPattern),
|
||||
_rootPattern = new RegExp('^$rootPattern');
|
||||
|
||||
/// The name of this path style. Will be "posix" or "windows".
|
||||
final String name;
|
||||
|
||||
/// The path separator for this style. On POSIX, this is `/`. On Windows,
|
||||
/// it's `\`.
|
||||
final String separator;
|
||||
|
||||
/// The [Pattern] that can be used to match a separator for a path in this
|
||||
/// style. Windows allows both "/" and "\" as path separators even though
|
||||
/// "\" is the canonical one.
|
||||
final Pattern separatorPattern;
|
||||
|
||||
// TODO(nweiz): make this a Pattern when issue 7080 is fixed.
|
||||
/// The [RegExp] that can be used to match the root prefix of an absolute
|
||||
/// path in this style.
|
||||
final RegExp _rootPattern;
|
||||
|
||||
/// Gets the root prefix of [path] if path is absolute. If [path] is relative,
|
||||
/// returns `null`.
|
||||
String getRoot(String path) {
|
||||
var match = _rootPattern.firstMatch(path);
|
||||
if (match == null) return null;
|
||||
return match[0];
|
||||
}
|
||||
|
||||
String toString() => name;
|
||||
}
|
||||
|
||||
// TODO(rnystrom): Make this public?
|
||||
class _ParsedPath {
|
||||
/// The [Style] that was used to parse this path.
|
||||
Style style;
|
||||
|
||||
/// The absolute root portion of the path, or `null` if the path is relative.
|
||||
/// On POSIX systems, this will be `null` or "/". On Windows, it can be
|
||||
/// `null`, "//" for a UNC path, or something like "C:\" for paths with drive
|
||||
/// letters.
|
||||
String root;
|
||||
|
||||
/// The path-separated parts of the path. All but the last will be
|
||||
/// directories.
|
||||
List<String> parts;
|
||||
|
||||
/// The path separators following each part. The last one will be an empty
|
||||
/// string unless the path ends with a trailing separator.
|
||||
List<String> separators;
|
||||
|
||||
/// The file extension of the last part, or "" if it doesn't have one.
|
||||
String get extension => _splitExtension()[1];
|
||||
|
||||
/// `true` if this is an absolute path.
|
||||
bool get isAbsolute => root != null;
|
||||
|
||||
_ParsedPath(this.style, this.root, this.parts, this.separators);
|
||||
|
||||
String get basename {
|
||||
var copy = this.clone();
|
||||
copy.removeTrailingSeparators();
|
||||
if (copy.parts.isEmpty) return root == null ? '' : root;
|
||||
return copy.parts.last;
|
||||
}
|
||||
|
||||
String get basenameWithoutExtension {
|
||||
var copy = this.clone();
|
||||
copy.removeTrailingSeparators();
|
||||
if (copy.parts.isEmpty) return root == null ? '' : root;
|
||||
return copy._splitExtension()[0];
|
||||
}
|
||||
|
||||
void removeTrailingSeparators() {
|
||||
while (!parts.isEmpty && parts.last == '') {
|
||||
parts.removeLast();
|
||||
separators.removeLast();
|
||||
}
|
||||
if (separators.length > 0) separators[separators.length - 1] = '';
|
||||
}
|
||||
|
||||
void normalize() {
|
||||
// Handle '.', '..', and empty parts.
|
||||
var leadingDoubles = 0;
|
||||
var newParts = [];
|
||||
for (var part in parts) {
|
||||
if (part == '.' || part == '') {
|
||||
// Do nothing. Ignore it.
|
||||
} else if (part == '..') {
|
||||
// Pop the last part off.
|
||||
if (newParts.length > 0) {
|
||||
newParts.removeLast();
|
||||
} else {
|
||||
// Backed out past the beginning, so preserve the "..".
|
||||
leadingDoubles++;
|
||||
}
|
||||
} else {
|
||||
newParts.add(part);
|
||||
}
|
||||
}
|
||||
|
||||
// A relative path can back out from the start directory.
|
||||
if (!isAbsolute) {
|
||||
newParts.insertRange(0, leadingDoubles, '..');
|
||||
}
|
||||
|
||||
// If we collapsed down to nothing, do ".".
|
||||
if (newParts.length == 0 && !isAbsolute) {
|
||||
newParts.add('.');
|
||||
}
|
||||
|
||||
// Canonicalize separators.
|
||||
var newSeparators = [];
|
||||
newSeparators.insertRange(0, newParts.length, style.separator);
|
||||
|
||||
parts = newParts;
|
||||
separators = newSeparators;
|
||||
|
||||
// Normalize the Windows root if needed.
|
||||
if (root != null && style == Style.windows) {
|
||||
root = root.replaceAll('/', '\\');
|
||||
}
|
||||
removeTrailingSeparators();
|
||||
}
|
||||
|
||||
String toString() {
|
||||
var builder = new StringBuffer();
|
||||
if (root != null) builder.add(root);
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
builder.add(parts[i]);
|
||||
builder.add(separators[i]);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/// Splits the last part of the path into a two-element list. The first is
|
||||
/// the name of the file without any extension. The second is the extension
|
||||
/// or "" if it has none.
|
||||
List<String> _splitExtension() {
|
||||
if (parts.isEmpty) return ['', ''];
|
||||
|
||||
var file = parts.last;
|
||||
if (file == '..') return ['..', ''];
|
||||
|
||||
var lastDot = file.lastIndexOf('.');
|
||||
|
||||
// If there is no dot, or it's the first character, like '.bashrc', it
|
||||
// doesn't count.
|
||||
if (lastDot <= 0) return [file, ''];
|
||||
|
||||
return [file.substring(0, lastDot), file.substring(lastDot)];
|
||||
}
|
||||
|
||||
_ParsedPath clone() => new _ParsedPath(
|
||||
style, root, new List.from(parts), new List.from(separators));
|
||||
}
|
Loading…
Reference in a new issue