Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Unified Diff: utils/testrunner/dart_wrap_task.dart

Issue 10897016: Testrunner for 3rd parties. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « utils/testrunner/dart_task.dart ('k') | utils/testrunner/delete_task.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: utils/testrunner/dart_wrap_task.dart
===================================================================
--- utils/testrunner/dart_wrap_task.dart (revision 0)
+++ utils/testrunner/dart_wrap_task.dart (revision 0)
@@ -0,0 +1,443 @@
+// 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.
+
+/**
+ * The DartWrapTask generates a Dart wrapper for a test file, that has a
+ * test Configuration customized for the options specified by the user.
+ */
+class DartWrapTask extends PipelineTask {
+ final String _sourceFileTemplate;
+ final String _tempDartFileTemplate;
+
+ DartWrapTask(this._sourceFileTemplate, this._tempDartFileTemplate);
+
+ void execute(Path testfile, List stdout, List stderr, bool logging,
+ Function exitHandler) {
+ // Get the source test file and canonicalize the path.
+ var sourceName = makePathAbsolute(
+ expandMacros(_sourceFileTemplate, testfile));
+ // Get the destination file.
+ var destFile = expandMacros(_tempDartFileTemplate, testfile);
+
+ // Working buffer for the Dart wrapper.
+ StringBuffer sbuf = new StringBuffer();
+
+ // Add the common header stuff.
+ var p = new Path(sourceName);
+ sbuf.add(directives(p.filenameWithoutExtension,
+ config.unittestPath,
+ sourceName));
+
+ // Add the test configuration and determine the action function.
+ var action;
+ if (config.listTests) {
+ action = 'listTests';
+ sbuf.add(barebonesConfig());
+ sbuf.add(listTestsFunction);
+ sbuf.add(formatListMessageFunction(config.listFormat));
+ } else if (config.listGroups) {
+ sbuf.add(barebonesConfig());
+ sbuf.add(listGroupsFunction);
+ sbuf.add(formatListMessageFunction(config.listFormat));
+ action = 'listGroups';
+ } else {
+
+ if (config.runInBrowser) {
+ sbuf.add(browserTestPrintFunction);
+ sbuf.add(unblockDRTFunction);
+ } else {
+ sbuf.add(nonBrowserTestPrintFunction);
+ sbuf.add(stubUnblockDRTFunction);
+ }
+
+ if (config.runIsolated) {
+ sbuf.add(runIsolateTestsFunction);
+ action = 'runIsolateTests';
+ } else {
+ sbuf.add(runTestsFunction);
+ action = 'runTests';
+ }
+
+ sbuf.add(config.includeTime ? elapsedFunction : stubElapsedFunction);
+ sbuf.add(config.produceSummary ?
+ printSummaryFunction : stubPrintSummaryFunction);
+
+ if (config.immediateOutput) {
+ sbuf.add(printTestResultFunction);
+ sbuf.add(stubPrintAllTestResultsFunction);
+ } else {
+ sbuf.add(stubPrintTestResultFunction);
+ sbuf.add(printAllTestResultsFunction);
+ }
+
+ sbuf.add(dumpTestResultFunction);
+ sbuf.add(formatMessageFunction(config.passFormat,
+ config.failFormat,
+ config.errorFormat));
+ sbuf.add(testConfig());
+ }
+
+ // Add the filter, if applicable.
+ if (config.filtering) {
+ if (config.includeFilter.length > 0) {
+ sbuf.add(filterTestFunction(config.includeFilter, 'true'));
+ } else {
+ sbuf.add(filterTestFunction(config.excludeFilter, 'false'));
+ }
+ }
+
+ // Add the common trailer stuff.
+ sbuf.add(dartMain(sourceName, action, config.filtering));
+
+ // Save the Dart file.
+ createFile(destFile, sbuf.toString());
+ exitHandler(0);
+ }
+
+ void cleanup(Path testfile, List stdout, List stderr,
+ bool logging, bool keepFiles) {
+ deleteFiles([_tempDartFileTemplate], testfile, logging, keepFiles, stdout);
+ }
+
+ String directives(String library, String unittest, String sourceName) {
+ return """
+#library('$library');
+#import('dart:math');
+#import('dart:isolate');
+#import('$unittest', prefix:'unittest');
+#import('$sourceName', prefix: 'test');
+""";
+ }
+
+ // The core skeleton for a config. Most of the guts is in the
+ // parameter [body].
+ String configuration([String body = '']) {
+ return """
+class TestRunnerConfiguration extends unittest.Configuration {
+ get name => 'Test runner configuration';
+ get autoStart => false;
+ $body
+}
+""";
+ }
+
+ // A barebones config, used for listing tests, not running them.
+ String barebonesConfig() {
+ return configuration();
+ }
+
+ // A more complex config, used for running tests.
+ String testConfig() {
+ return configuration("""
+ void onTestResult(TestCase testCase) {
+ printResult('\$testFile ', testCase);
+ }
+
+ void onDone(int passed, int failed, int errors, List<TestCase> results,
+ String uncaughtError) {
+ var success = (passed > 0 && failed == 0 && errors == 0 &&
+ uncaughtError == null);
+ printResults(testFile, results);
+ printSummary(testFile, passed, failed, errors, uncaughtError);
+ unblockDRT();
+ }
+""");
+ }
+
+ // The main function, that creates the config, filters the tests if
+ // necessary, then performs the action (list/run/run-isolated).
+ String dartMain(String sourceName, String action, bool filter) {
+ return """
+var testFile = '$sourceName';
+main() {
+ unittest.groupSep = '###';
+ unittest.configure(new TestRunnerConfiguration());
+ unittest.group('', test.main);
+ ${filter ? 'unittest.filterTests(filterTest);' : ''}
+ $action();
+}
+""";
+ }
+
+ // For 'printing' when we are in the browser, we add text elements
+ // to a DOM element with id 'console'.
+ final String browserTestPrintFunction = """
+#import('dart:html');
+void tprint(msg) {
+var pre = query('#console');
+pre.elements.add(new Text('###\$msg\\n'));
+}
+""";
+
+ // For printing when not in the browser we can just use Dart's print().
+ final String nonBrowserTestPrintFunction = """
+void tprint(msg) {
+print('###\$msg');
+}
+""";
+
+ // A function to give us the elapsed time for a test.
+ final String elapsedFunction = """
+String elapsed(TestCase t) {
+ double duration = t.runningTime.inMilliseconds;
+ duration /= 1000;
+ return '\${duration.toStringAsFixed(3)}s ';
+}
+""";
+
+ // A dummy version of the elapsed function for when the user
+ // doesn't want test times included.
+ final String stubElapsedFunction = """
+String elapsed(TestCase t) {
+ return '';
+}
+""";
+
+ // A function to print the results of a test.
+ final String dumpTestResultFunction = """
+void dumpTestResult(source, TestCase t) {
+ var groupName = '', testName = '';
+ var idx = t.description.lastIndexOf('###');
+ if (idx >= 0) {
+ groupName = t.description.substring(0, idx).replaceAll('###', ' ');
+ testName = t.description.substring(idx+3);
+ } else {
+ testName = t.description;
+ }
+ var stack = (t.stackTrace == null) ? '' : '\${t.stackTrace} ';
+ var message = (t.message.length > 0) ? '\$t.message ' : '';
+ var duration = elapsed(t);
+ tprint(formatMessage(source, '\$groupName ', '\$testName ',
+ duration, t.result, message, stack));
+}
+""";
+
+ // A function to print the test summary.
+ final String printSummaryFunction = """
+void printSummary(String testFile, int passed, int failed, int errors,
+ String uncaughtError) {
+ tprint('');
+ if (passed == 0 && failed == 0 && errors == 0) {
+ tprint('\$testFile: No tests found.');
+ } else if (failed == 0 && errors == 0 && uncaughtError == null) {
+ tprint('\$testFile: All \$passed tests passed.');
+ } else {
+ if (uncaughtError != null) {
+ tprint('\$testFile: Top-level uncaught error: \$uncaughtError');
+ }
+ tprint('\$testFile: \$passed PASSED, \$failed FAILED, \$errors ERRORS');
+ }
+}
+""";
+
+ final String stubPrintSummaryFunction = """
+void printSummary(String testFile, int passed, int failed, int errors,
+ String uncaughtError) {
+}
+""";
+
+ // A function to print all test results.
+ final String printAllTestResultsFunction = """
+void printResults(testfile, List<TestCase> results) {
+ for (final testCase in results) {
+ dumpTestResult('\$testfile ', testCase);
+ }
+}
+""";
+
+ final String stubPrintAllTestResultsFunction = """
+void printResults(testfile, List<TestCase> results) {
+}
+""";
+
+ // A function to print a single test result.
+ final String printTestResultFunction = """
+void printResult(testfile, TestCase testCase) {
+ dumpTestResult('\$testfile ', testCase);
+}
+""";
+
+ final String stubPrintTestResultFunction = """
+void printResult(testfile, TestCase testCase) {
+}
+""";
+
+ final String unblockDRTFunction = """
+void unblockDRT() {
+ window.postMessage('done', '*');
+}
+ """;
+
+ final String stubUnblockDRTFunction = """
+void unblockDRT() {
+}
+""";
+
+ // A simple format function for listing tests.
+ String formatListMessageFunction(String format) {
+ return """
+String formatMessage(filename, groupname, [ testname = '']) {
+ return '${format}'.
+ replaceAll('${Macros.testfile}', filename).
+ replaceAll('${Macros.testGroup}', groupname).
+ replaceAll('${Macros.testDescription}', testname);
+}
+""";
+ }
+
+ // A richer format function for test results.
+ String formatMessageFunction(
+ String passFormat, String failFormat, String errorFormat) {
+ return """
+String formatMessage(filename, groupname,
+ [ testname = '', testTime = '', result = '',
+ message = '', stack = '' ]) {
+ var format = '$errorFormat';
+ if (result == 'pass') format = '$passFormat';
+ else if (result == 'fail') format = '$failFormat';
+ return format.
+ replaceAll('${Macros.testTime}', testTime).
+ replaceAll('${Macros.testfile}', filename).
+ replaceAll('${Macros.testGroup}', groupname).
+ replaceAll('${Macros.testDescription}', testname).
+ replaceAll('${Macros.testMessage}', message).
+ replaceAll('${Macros.testStacktrace}', stack);
+}
+""";
+ }
+
+ // A function to list the test groups.
+ final String listGroupsFunction = """
+listGroups() {
+ List tests = unittest.testCases;
+ Map groups = {};
+ for (var t in tests) {
+ var groupName, testName = '';
+ var idx = t.description.lastIndexOf('###');
+ if (idx >= 0) {
+ groupName = t.description.substring(0, idx).replaceAll('###', ' ');
+ if (!groups.containsKey(groupName)) {
+ groups[groupName] = '';
+ }
+ }
+ }
+ for (var g in groups.getKeys()) {
+ var msg = formatMessage('\$testfile ', '\$g ');
+ print('###\$msg');
+ }
+}
+""";
+
+ // A function to list the tests.
+ final String listTestsFunction = """
+listTests() {
+ List tests = unittest.testCases;
+ for (var t in tests) {
+ var groupName, testName = '';
+ var idx = t.description.lastIndexOf('###');
+ if (idx >= 0) {
+ groupName = t.description.substring(0, idx).replaceAll('###', ' ');
+ testName = t.description.substring(idx+3);
+ } else {
+ groupName = '';
+ testName = t.description;
+ }
+ var msg = formatMessage('\$testfile ', '\$groupName ', '\$testName ');
+ print('###\$msg');
+ }
+}
+""";
+
+ // A function to filter the tests.
+ String filterTestFunction(List filters, String filterReturnValue) {
+ StringBuffer sbuf = new StringBuffer();
+ sbuf.add('filterTest(t) {\n');
+ if (filters != null) {
+ sbuf.add(' var name = t.description.replaceAll("###", " ");\n');
+ for (var f in filters) {
+ sbuf.add(' if (name.indexOf("$f")>=0) return $filterReturnValue;\n');
+ }
+ sbuf.add(' return !$filterReturnValue;\n');
+ } else {
+ sbuf.add(' return true;\n');
+ }
+ sbuf.add('}\n');
+ return sbuf.toString();
+ }
+
+ // Code to support running single tests as master/slave in isolates.
+ final String runIsolateTestsFunction = """
+class TestRunnerSlaveConfiguration extends unittest.Configuration {
+ get name => 'Test runner slave configuration';
+ get autoStart => false;
+
+ void onDone(int passed, int failed, int errors, List<TestCase> results,
+ String uncaughtError) {
+ TestCase test = results[0];
+ masterPort.send([test.result, test.runningTime.inMilliseconds,
+ test.message, test.stackTrace]);
+ }
+}
+
+var masterPort;
+runSlaveTest() {
+ port.receive((testName, sendport) {
+ masterPort = sendport;
+ unittest.configure(new TestRunnerSlaveConfiguration());
+ unittest.groupSep = '###';
+ unittest.group('', test.main);
+ unittest.filterTests(testName);
+ unittest.runTests();
+ });
+}
+
+var testNum;
+var failed;
+var errors;
+var passed;
+
+runMasterTest() {
+ var tests = unittest.testCases;
+ tests[testNum].startTime = new Date.now();
+ SendPort slavePort = spawnFunction(runSlaveTest);
+ slavePort.call(tests[testNum].description).then((results) {
+ var result = results[0];
+ var duration = new Duration(milliseconds: results[1]);
+ var message = results[2];
+ var stack = results[3];
+ if (result == 'pass') {
+ tests[testNum].pass();
+ ++passed;
+ } else if (result == 'fail') {
+ tests[testNum].fail(message, stack);
+ ++failed;
+ } else {
+ tests[testNum].error(message, stack);
+ ++errors;
+ }
+ tests[testNum].runningTime = duration;
+ ++testNum;
+ if (testNum < tests.length) {
+ runMasterTest();
+ } else {
+ unittest.config.onDone(passed, failed, errors,
+ unittest.testCases, null);
+ }
+ });
+}
+
+runIsolateTests() {
+ testNum = 0;
+ passed = failed = errors = 0;
+ runMasterTest();
+}
+""";
+
+ // Code for running all tests in the normal (non-isolate) way.
+ final String runTestsFunction = """
+runTests() {
+ unittest.runTests();
+}
+""";
+}
« no previous file with comments | « utils/testrunner/dart_task.dart ('k') | utils/testrunner/delete_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698