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

Unified Diff: utils/testrunner/drt_task.dart

Issue 10914049: Added support for layout render tests. These use expected values for the text render output from Du… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 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_wrap_task.dart ('k') | utils/testrunner/html_wrap_task.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: utils/testrunner/drt_task.dart
===================================================================
--- utils/testrunner/drt_task.dart (revision 11963)
+++ utils/testrunner/drt_task.dart (working copy)
@@ -5,7 +5,216 @@
/** A pipeline task for running DumpRenderTree. */
class DrtTask extends RunProcessTask {
- DrtTask(String htmlFileTemplate) {
+ String _testFileTemplate;
+
+ DrtTask(this._testFileTemplate, String htmlFileTemplate) {
init(config.drtPath, ['--no-timeout', htmlFileTemplate], config.timeout);
}
+
+ // In order to extract the relevant parts of the DRT render text
+ // output we use a somewhat kludgy approach, but it should be robust.
+ // DRT formats output with indentation, and we know that the test title
+ // is on a line with 12 spaces indent followed by 'text run', while the
+ // IFrame body elements are all indented at least 18 spaces.
+ const TEST_LABEL_LINE_PREFIX = ' text run';
+ const BODY_LINE_PREFIX = ' ';
+
+ void execute(Path testfile, List stdout, List stderr, bool logging,
+ Function exitHandler) {
+
+ var testname = expandMacros(_testFileTemplate, testfile);
+ var isLayout = isLayoutRenderTest(testname) || config.generateRenders;
+
+ if (!isLayout) {
+ super.execute(testfile, stdout, stderr, logging, exitHandler);
+ } else {
+ var tmpLog = new List<String>();
+ super.execute(testfile, tmpLog, tmpLog, true,
+ (code) {
+ var layoutFile = layoutFileName(testname);
+ var layouts = getFileContents(layoutFile, false);
+ var i = 0;
+ StringBuffer sbuf = null;
+ if (config.generateRenders) {
+ sbuf = new StringBuffer();
+ }
+ while ( i < tmpLog.length) {
+ var line = tmpLog[i];
+ if (logging) {
+ stdout.add(line);
+ }
+ if (line.startsWith(TEST_LABEL_LINE_PREFIX)) {
+ var j = i+1;
+ var start = -1, end = -1;
+ // Walk forward to the next label or end of log.
+ while (j < tmpLog.length &&
+ !tmpLog[j].startsWith(TEST_LABEL_LINE_PREFIX)) {
+ // Is this a body render line?
+ if (tmpLog[j].startsWith(BODY_LINE_PREFIX)) {
+ if (start < 0) { // Is it the first?
+ start = j;
+ }
+ } else { // Not a render line.
+ if (start >= 0 && end < 0) {
+ // We were just in a set of render lines, so this
+ // line is the first non-member.
+ end = j;
+ }
+ }
+ j++;
+ }
+ if (start >= 0) { // We have some render lines.
+ if (end < 0) {
+ end = tmpLog.length; // Sanity.
+ }
+ var actualLayout = new List<String>();
+ while (start < end) {
+ actualLayout.add(
+ tmpLog[start++].substring(BODY_LINE_PREFIX.length));
+ }
+ var testName = checkTest(testfile, line, layouts,
+ actualLayout, stdout);
+ if (testName == null) {
+ code = -1;
+ } else if (config.generateRenders) {
+ sbuf.add(testName);
+ sbuf.add('\n');
+ for (var renderLine in actualLayout) {
+ sbuf.add(renderLine);
+ sbuf.add('\n');
+ }
+ }
+ }
+ i = j;
+ } else {
+ i++;
+ }
+ }
+ if (config.generateRenders) {
+ createFile(layoutFile, sbuf.toString());
+ }
+ exitHandler(code);
+ });
+ }
+ }
+
+ /**
+ * Verify whether a test passed - it must pass the code expectations,
+ * and have validated layout. Report success or failure in a test
+ * result message. Upon success the render section name is returned
+ * (useful for `config.generateRenders`); otherwise null is returned.
+ */
+ String checkTest(Path testfile, String label, List layouts,
+ List actual, List out) {
+ var testGroup = null;
+ var testName = null;
+
+ // The label line has the form:
+ // "result:duration:<test>//message"
+ // where <test> is a test name or series of one or more group names
+ // followed by a test name, separated by ###.
+
+ // First extract test state, duration, name and message. If the test
+ // passed we can ignore these and continue to layout verification, but
+ // if the test failed we want to know that so we can report failure.
+ //
+ // TODO(gram) - currently we lose the stack trace although the user
+ // will get it in the overall output if they used --verbose. We may
+ // want to fix this properly at some point.
+ var labelParser = const RegExp('\"\([a-z]*\):\([0-9]*\):\(.*\)//\(.*\)\"');
+ Match match = labelParser.firstMatch(label);
+ var result = match.group(1);
+ var duration = parseDouble(match.group(2)) / 1000;
+ var test = match.group(3);
+ var message = match.group(4);
+
+ // Split name up with group.
+ var idx = test.lastIndexOf('###');
+ if (idx >= 0) {
+ testGroup = test.substring(0, idx).replaceAll('###', ' ');
+ testName = test.substring(idx+3);
+ } else {
+ testGroup = '';
+ testName = test;
+ }
+ var section = '[${_pad(testGroup)}$testName]';
+
+ if (config.generateRenders) {
+ // Do nothing; fake a pass.
+ out.add(_formatMessage(config.passFormat,
+ testfile, testGroup, testName, duration, ''));
+ } else if (result != 'pass') {
+ // The test failed separately from layout; just report that
+ // failure.
+ out.add(_formatMessage(
+ (result == 'fail' ? config.failFormat : config.errorFormat),
+ testfile, testGroup, testName, duration, message));
+ return null;
+ } else {
+ // The test passed, at least the expectations. So check the layout.
+ var expected = _getLayout(layouts, section);
+ var failMessage = null;
+ var lineNum = 0;
+ if (expected != null) {
+ while (lineNum < expected.length) {
+ if (lineNum >= actual.length) {
+ failMessage = 'expected "${expected[lineNum]}" but got nothing';
+ break;
+ } else {
+ if (expected[lineNum] != actual[lineNum]) {
+ failMessage = 'expected "${expected[lineNum]}" '
+ 'but got "${actual[lineNum]}"';
+ break;
+ }
+ }
+ lineNum++;
+ }
+ if (failMessage == null && lineNum < actual.length) {
+ failMessage = 'expected nothing but got "${actual[lineNum]}"';
+ }
+ }
+ if (failMessage != null) {
+ out.add(_formatMessage(config.failFormat,
+ testfile, testGroup, testName, duration,
+ 'Layout content mismatch at line $lineNum: '
+ '$failMessage'));
+ return null;
+ } else {
+ out.add(_formatMessage(config.passFormat,
+ testfile, testGroup, testName, duration, ''));
+ }
+ }
+ return section;
+ }
+
+ /** Get the expected layout for a test. */
+ List _getLayout(List layouts, String section) {
+ List layout = new List();
+ for (var i = 0; i < layouts.length; i++) {
+ if (layouts[i] == section) {
+ ++i;
+ while (i < layouts.length && !layouts[i].startsWith('[')) {
+ layout.add(layouts[i++]);
+ }
+ break;
+ }
+ }
+ return layout;
+ }
+
+ /** Pad a string with a rightmost space unless it is empty. */
+ static String _pad(s) => (s.length > 0) ? '$s ' : s;
+
+ /** Format a test result message. */
+ String _formatMessage(String format,
+ Path testfile, String testGroup, String testName,
+ double duration, String message) {
+ String fname = makePathAbsolute(testfile.directoryPath.toString());
+ return "###${format.
+ replaceAll(Macros.testTime, '${duration.toStringAsFixed(3)}s ').
+ replaceAll(Macros.testfile, _pad(fname)).
+ replaceAll(Macros.testGroup, _pad(testGroup)).
+ replaceAll(Macros.testDescription, _pad(testName)).
+ replaceAll(Macros.testMessage, _pad(message))}";
+ }
}
« no previous file with comments | « utils/testrunner/dart_wrap_task.dart ('k') | utils/testrunner/html_wrap_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698