Adds support for layout tests.

Review URL: https://chromiumcodereview.appspot.com//10683009

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@9207 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
sigmund@google.com 2012-06-28 17:05:10 +00:00
parent 7be8e8fc12
commit 25a24b69a5
8 changed files with 221 additions and 10 deletions

View file

@ -0,0 +1,28 @@
// 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.
/**
* Tests the layout test functionality of test.dart. There is a .png image with
* the same name as this file. The existence of the .png file indicates to the
* test framework that we want to compare the final state of this application
* against an image file.
*/
#library("layouttest");
#import('dart:html');
main() {
var div1Style = _style('blue', 20, 10, 40, 10);
var div2Style = _style('red', 25, 30, 40, 10);
var div1 = new Element.html('<div style="$div1Style"></div>');
var div2 = new Element.html('<div style="$div2Style"></div>');
document.body.elements.add(div1);
document.body.elements.add(div2);
}
_style(String color, int top, int left, int width, int height) {
return ('background-color:$color; position:absolute; '
'top:${top}px; left:${left}px; '
'width:${width}px; height:${height}px;');
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,28 @@
// 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.
/**
* Tests the layout test functionality of test.dart. There is a .txt image with
* the same name as this file. The existence of the .txt file indicates to the
* test framework that we want to compare the final state of this application
* against a text file (with a text representation of the DOM tree).
*/
#library("layouttest");
#import('dart:html');
main() {
var div1Style = _style('blue', 20, 10, 40, 10);
var div2Style = _style('red', 25, 30, 40, 10);
var div1 = new Element.html('<div style="$div1Style"></div>');
var div2 = new Element.html('<div style="$div2Style"></div>');
document.body.elements.add(div1);
document.body.elements.add(div2);
}
_style(String color, int top, int left, int width, int height) {
return ('background-color:$color; position:absolute; '
'top:${top}px; left:${left}px; '
'width:${width}px; height:${height}px;');
}

View file

@ -0,0 +1,11 @@
Content-Type: text/plain
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x8
RenderBlock {HTML} at (0,0) size 800x8
RenderBody {BODY} at (8,8) size 784x0
layer at (10,20) size 40x10
RenderBlock (positioned) {DIV} at (10,20) size 40x10 [bgcolor=#0000FF]
layer at (30,25) size 40x10
RenderBlock (positioned) {DIV} at (30,25) size 40x10 [bgcolor=#FF0000]
#EOF

View file

@ -12,9 +12,8 @@ markdown_test: Skip
[ $compiler == frog ]
dummy_compiler_test: Fail
[ $compiler == frog ]
utf8_test: Crash
*_layout_test: Skip
[ $compiler == dart2js ]
utf8_test: Fail # compiler cancelled: Unhandled non-BMP character: U+10412
@ -40,3 +39,6 @@ dummy_compiler_test: Fail # Issue 3529.
[ $compiler == frog && $runtime == none ]
*: Skip
[ $runtime == vm ]
*_layout_test: Skip

View file

@ -2,7 +2,7 @@
// 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.
String GetHtmlContents(String title,
String getHtmlContents(String title,
String controllerScript,
String scriptType,
String sourceScript) =>
@ -27,13 +27,29 @@ String GetHtmlContents(String title,
</html>
""";
String WrapDartTestInLibrary(Path test) =>
String getHtmlLayoutContents(String scriptType, String sourceScript) =>
"""
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body>
<script type="text/javascript">
if (navigator.webkitStartDart) navigator.webkitStartDart();
</script>
<script type="$scriptType" src="$sourceScript"></script>
</body>
</html>
""";
String wrapDartTestInLibrary(Path test) =>
"""
#library('libraryWrapper');
#source('$test');
""";
String DartTestWrapper(Path dartHome, Path library) =>
String dartTestWrapper(Path dartHome, Path library) =>
"""
#library('test');

View file

@ -543,14 +543,14 @@ class StandardTestSuite implements TestSuite {
dartLibraryFilename = new Path('test_as_library.dart');
File file = new File('$tempDir/$dartLibraryFilename');
RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
dartLibrary.writeStringSync(WrapDartTestInLibrary(filePath));
dartLibrary.writeStringSync(wrapDartTestInLibrary(filePath));
dartLibrary.closeSync();
}
File file = new File(dartWrapperFilename);
RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
dartWrapper.writeStringSync(
DartTestWrapper(dartDir, dartLibraryFilename));
dartTestWrapper(dartDir, dartLibraryFilename));
dartWrapper.closeSync();
} else {
dartWrapperFilename = filename;
@ -578,11 +578,26 @@ class StandardTestSuite implements TestSuite {
// with 'C:' adding 'file:///' solves the problem.
filePrefix = 'file:///';
}
htmlTest.writeStringSync(GetHtmlContents(
String content = null;
Path dir = filePath.directoryPath;
String nameNoExt = filePath.filenameWithoutExtension;
Path pngPath = dir.append('$nameNoExt.png');
Path txtPath = dir.append('$nameNoExt.txt');
Path expectedOutput = null;
if (new File.fromPath(pngPath).existsSync()) {
expectedOutput = pngPath;
content = getHtmlLayoutContents(scriptType, '$filePrefix$scriptPath');
} else if (new File.fromPath(txtPath).existsSync()) {
expectedOutput = txtPath;
content = getHtmlLayoutContents(scriptType, '$filePrefix$scriptPath');
} else {
content = getHtmlContents(
filename,
'$filePrefix${dartDir.append("lib/unittest/test_controller.js")}',
scriptType,
'$filePrefix$scriptPath'));
'$filePrefix$scriptPath');
}
htmlTest.writeStringSync(content);
htmlTest.closeSync();
// Construct the command(s) that compile all the inputs needed by the
@ -633,6 +648,9 @@ class StandardTestSuite implements TestSuite {
args.add('--dart-flags=${Strings.join(dartFlags, " ")}');
}
args.add(htmlPath);
if (expectedOutput != null) {
args.add('--out-expectation=$expectedOutput');
}
}
commands.add(new Command('python', args));
@ -829,6 +847,59 @@ class StandardTestSuite implements TestSuite {
return result;
}
/**
* Special options for individual tests are currently specified in various
* ways: with comments directly in test files, by using certain imports, or by
* creating additional files in the test directories.
*
* Here is a list of options that are used by 'test.dart' today:
* - Flags can be passed to the vm or dartium process that runs the test by
* adding a comment to the test file:
*
* // VMOptions=--flag1 --flag2
*
* - Flags can be passed to the dart script that contains the test also
* using comments, as follows:
*
* // DartOptions=--flag1 --flag2
*
* - For tests that depend on compiling other files with dart2js (e.g.
* isolate tests that use multiple source scripts), you can specify
* additional files to compile using a comment too, as follows:
*
* // OtherScripts=file1.dart file2.dart
*
* - You can indicate whether a test is treated as a web-only test by
* using an explicit import to the dart:html library:
*
* #import('dart:html');
*
* Most tests are not web tests, but can (and will be) wrapped within
* another script file to test them also on browser environments (e.g.
* language and corelib tests are run this way). We deduce that if this
* import is specified, the test was intended to be a web test and no
* wrapping is necessary.
*
* - You can convert DRT web-tests into layout-web-tests by specifying a
* test expectation file. An expectation file is located in the same
* location as the test, it has the same file name, except for the extension
* (which can be either .txt or .png).
*
* When there are no expectation files, 'test.dart' assumes tests fail if
* the process return a non-zero exit code (in the case of web tests, we
* check for PASS/FAIL indications in the test output).
*
* When there is an expectation file, tests are run differently: the test
* code is run to the end of the event loop and 'test.dart' takes a snapshot
* of what is rendered in the page at that moment. This snapshot is
* represented either in text form, if the expectation ends in .txt, or as
* an image, if the expectation ends in .png. 'test.dart' will compare the
* snapshot to the expectation file. When tests fail, 'test.dart' saves the
* new snapshot into a file so it can be visualized or copied over.
* Expectations can be recorded for the first time by creating an empty file
* with the right name (touch test_name_test.png), running the test, and
* executing the copy command printed by the test script.
*/
Map readOptionsFromFile(Path filePath) {
RegExp testOptionsRegExp = const RegExp(@"// VMOptions=(.*)");
RegExp dartOptionsRegExp = const RegExp(@"// DartOptions=(.*)");

View file

@ -13,6 +13,7 @@ import subprocess
import sys
DART_FLAGS_PREFIX = '--dart-flags='
OUT_EXPECTATION_PREFIX = '--out-expectation='
def main(argv):
drt_path = argv[1]
@ -21,18 +22,72 @@ def main(argv):
cmd = [drt_path]
env = None
test_file = None
out_expected_file = None
is_png = False
# parse arguments, filtering out flags, and selecting the input test file
for arg in command_line:
if arg.startswith(DART_FLAGS_PREFIX):
env = dict(os.environ.items())
env['DART_FLAGS'] = arg[len(DART_FLAGS_PREFIX):]
elif arg.startswith(OUT_EXPECTATION_PREFIX):
out_expected_file = arg[len(OUT_EXPECTATION_PREFIX):]
if out_expected_file.endswith('.png'):
cmd.append('--pixel-tests')
cmd.append('--notree')
is_png = True
elif not out_expected_file.endswith('.txt'):
raise Exception(
'Bad file expectation (%s), ' % out_expected_file
+ 'please specify either a .txt or a .png file')
elif arg.endswith('.html'):
test_file = arg
cmd.append(arg)
else:
cmd.append(arg)
p = subprocess.Popen(cmd, env=env)
p = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE)
p.wait()
if p.returncode != 0:
raise Exception('Failed to run command. return code=%s' % p.returncode)
if out_expected_file:
# Compare output to the given expectation file.
output = None
expectation = None
with p.stdout as res:
if is_png:
# DRT prints the image to STDOUT, but includes 5 header lines.
for i in range(4): res.readline()
output = res.read()
if os.path.exists(out_expected_file):
with open(out_expected_file, 'r') as f:
expectation = f.read()
else:
# Instructions on how to create the expectation will be printed below
# (outout != expectation)
print 'File %s was not found' % out_expected_file
expectation = None
# Report test status using the format test.dart expects to see from DRT.
print 'Content-Type: text/plain'
if expectation == output:
print 'PASS'
print 'Expectation matches'
else:
# Generate a temporary file in the same place as the .html file:
out_file = test_file[:test_file.rfind('.html')] + out_expected_file[-4:]
with open(out_file, 'w') as f:
f.write(output)
print 'FAIL'
print 'Expectation didn\'t match. Update expectations by running:\n'
print 'cp %s %s\n' % (out_file, out_expected_file)
print '#EOF'
else:
# Pipe through the output for non-layout tests.
sys.stdout.write(p.stdout.read())
if __name__ == '__main__':
try: