Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 Layout Engine Visual Tests (reftest)
2 L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
3 July 19, 2006
5 This code is designed to run tests of Mozilla's layout engine. These
6 tests consist of an HTML (or other format) file along with a reference
7 in the same format. The tests are run based on a manifest file, and for
8 each test, PASS or FAIL is reported, and UNEXPECTED is reported if the
9 result (PASS or FAIL) was not the expected result noted in the manifest.
11 Images of the display of both tests are captured, and most test types
12 involve comparing these images (e.g., test types == or !=) to determine
13 whether the test passed. The captures of the tests are taken in a
14 viewport that is 800 pixels wide and 1000 pixels tall, so any content
15 outside that area will be ignored (except for any scrollbars that are
16 displayed). Ideally, however, tests should be written so that they fit
17 within 600x600, since we may in the future want to switch to 600x600 to
18 match http://lists.w3.org/Archives/Public/www-style/2012Sep/0562.html .
20 Why this way?
21 =============
23 Writing HTML tests where the reference rendering is also in HTML is
24 harder than simply writing bits of HTML that can be regression-tested by
25 comparing the rendering of an older build to that of a newer build
26 (perhaps using stored reference images from the older build). However,
27 comparing across time has major disadvantages:
29 * Comparisons across time either require two runs for every test, or
30 they require stored reference images appropriate for the platform and
31 configuration (often limiting testing to a very specific
32 configuration).
34 * Comparisons across time may fail due to expected changes, for
35 example, changes in the default style sheet for HTML, changes in the
36 appearance of form controls, or changes in default preferences like
37 default font size or default colors.
39 Using tests for which the pass criteria were explicitly chosen allows
40 running tests at any time to see whether they still pass.
42 Manifest Format
43 ===============
45 The test manifest format is a plain text file. A line starting with a
46 "#" is a comment. Lines may be commented using whitespace followed by
47 a "#" and the comment. Each non-blank line (after removal of comments)
48 must be one of the following:
50 1. Inclusion of another manifest
52 <failure-type>* include <relative_path>
54 <failure-type> is the same as listed below for a test item. As for
55 test items, multiple failure types listed on the same line are
56 combined by using the last matching failure type listed. However,
57 the failure type on a manifest is combined with the failure type on
58 the test (or on a nested manifest) with the rule that the last in the
59 following list wins: fails, random, skip. (In other words, skip
60 always wins, and random beats fails.)
62 2. A test item
64 [ <failure-type> | <preference> ]* [<http>] <type> <url> <url_ref>
66 where
68 a. <failure-type> (optional) is one of the following:
70 fails The test passes if the images of the two renderings DO NOT
71 meet the conditions specified in the <type>.
73 fails-if(condition) If the condition is met, the test passes if the
74 images of the two renderings DO NOT meet the
75 conditions of <type>. If the condition is not met,
76 the test passes if the conditions of <type> are met.
78 needs-focus The test fails or times out if the reftest window is not
79 focused.
81 random The results of the test are random and therefore not to be
82 considered in the output.
84 random-if(condition) The results of the test are random if a given
85 condition is met.
87 silentfail This test may fail silently, and if that happens it should
88 count as if the test passed. This is useful for cases where
89 silent failure is the intended behavior (for example, in
90 an out of memory situation in JavaScript, we stop running
91 the script silently and immediately, in hopes of reclaiming
92 enough memory to keep the browser functioning).
94 silentfail-if(condition) This test may fail silently if the condition
95 is met.
97 skip This test should not be run. This is useful when a test fails in a
98 catastrophic way, such as crashing or hanging the browser. Using
99 'skip' is preferred to simply commenting out the test because we
100 want to report the test failure at the end of the test run.
102 skip-if(condition) If the condition is met, the test is not run. This is
103 useful if, for example, the test crashes only on a
104 particular platform (i.e. it allows us to get test
105 coverage on the other platforms).
107 slow The test may take a long time to run, so run it if slow tests are
108 either enabled or not disabled (test manifest interpreters may
109 choose whether or not to run such tests by default).
111 slow-if(condition) If the condition is met, the test is treated as if
112 'slow' had been specified. This is useful for tests
113 which are slow only on particular platforms (e.g. a
114 test which exercised out-of-memory behavior might be
115 fast on a 32-bit system but inordinately slow on a
116 64-bit system).
118 fuzzy(maxDiff, diffCount)
119 This allows a test to pass if the pixel value differences are <=
120 maxDiff and the total number of different pixels is <= diffCount.
121 It can also be used with '!=' to ensure that the difference is
122 greater than maxDiff.
124 fuzzy-if(condition, maxDiff, diffCount)
125 If the condition is met, the test is treated as if 'fuzzy' had been
126 specified. This is useful if there are differences on particular
127 platforms.
129 require-or(cond1&&cond2&&...,fallback)
130 Require some particular setup be performed or environmental
131 condition(s) made true (eg setting debug mode) before the test
132 is run. If any condition is unknown, unimplemented, or fails,
133 revert to the fallback failure-type.
134 Example: require-or(debugMode,skip)
136 asserts(count)
137 Loading the test and reference is known to assert exactly
138 count times.
139 NOTE: An asserts() notation with a non-zero count or maxCount
140 suppresses use of a cached canvas for the test with the
141 annotation. However, if later occurrences of the same test
142 are not annotated, they will use the cached canvas
143 (potentially from the load that asserted). This allows
144 repeated use of the same test or reference to be annotated
145 correctly (which may be particularly useful when the uses are
146 in different subdirectories that can be tested independently),
147 but does not force them to be, nor does it force suppression
148 of caching for a common reference when it is the test that
149 asserts.
151 asserts(minCount-maxCount)
152 Loading the test and reference is known to assert between
153 minCount and maxCount times, inclusive.
154 NOTE: See above regarding canvas caching.
156 asserts-if(condition,count)
157 asserts-if(condition,minCount-maxCount)
158 Same as above, but only if condition is true.
160 Conditions are JavaScript expressions *without spaces* in them.
161 They are evaluated in a sandbox in which a limited set of
162 variables are defined. See the BuildConditionSandbox function in
163 layout/tools/reftest.js for details.
165 Examples of using conditions:
166 fails-if(winWidget) == test reference
167 asserts-if(cocoaWidget,2) load crashtest
169 b. <preference> (optional) is a string of the form
171 pref(<name>,<value>)
172 test-pref(<name>,<value>)
173 ref-pref(<name>,<value>)
175 where <name> is the name of a preference setting, as seen in
176 about:config, and <value> is the value to which this preference should
177 be set. <value> may be a boolean (true/false), an integer, or a
178 quoted string *without spaces*, according to the type of the preference.
180 The preference will be set to the specified value prior to
181 rendering the test and/or reference canvases (pref() applies to
182 both, test-pref() only to the test, and ref-pref() only to the
183 reference), and will be restored afterwards so that following
184 tests are not affected. Note that this feature is only useful for
185 "live" preferences that take effect immediately, without requiring
186 a browser restart.
188 c. <http>, if present, is one of the strings (sans quotes) "HTTP" or
189 "HTTP(..)" or "HTTP(../..)" or "HTTP(../../..)", etc. , indicating that
190 the test should be run over an HTTP server because it requires certain
191 HTTP headers or a particular HTTP status. (Don't use this if your test
192 doesn't require this functionality, because it unnecessarily slows down
193 the test.)
195 With "HTTP", HTTP tests have the restriction that any resource an HTTP
196 test accesses must be accessed using a relative URL, and the test and
197 the resource must be within the directory containing the reftest
198 manifest that describes the test (or within a descendant directory).
199 The variants "HTTP(..)", etc., can be used to relax this restriction by
200 allowing resources in the parent directory, etc.
202 To modify the HTTP status or headers of a resource named FOO, create a
203 sibling file named FOO^headers^ with the following contents:
205 [<http-status>]
206 <http-header>*
208 <http-status> A line of the form "HTTP ###[ <description>]", where
209 ### indicates the desired HTTP status and <description>
210 indicates a desired HTTP status description, if any.
211 If this line is omitted, the default is "HTTP 200 OK".
212 <http-header> A line in standard HTTP header line format, i.e.
213 "Field-Name: field-value". You may not repeat the use
214 of a Field-Name and must coalesce such headers together,
215 and each header must be specified on a single line, but
216 otherwise the format exactly matches that from HTTP
217 itself.
219 HTTP tests may also incorporate SJS files. SJS files provide similar
220 functionality to CGI scripts, in that the response they produce can be
221 dependent on properties of the incoming request. Currently these
222 properties are restricted to method type and headers, but eventually
223 it should be possible to examine data in the body of the request as
224 well when computing the generated response. An SJS file is a JavaScript
225 file with a .sjs extension which defines a global |handleRequest|
226 function (called every time that file is loaded during reftests) in this
227 format:
229 function handleRequest(request, response)
230 {
231 response.setStatusLine(request.httpVersion, 200, "OK");
233 // You *probably* want this, or else you'll get bitten if you run
234 // reftest multiple times with the same profile.
235 response.setHeader("Cache-Control", "no-cache");
237 response.write("any ASCII data you want");
239 var outputStream = response.bodyOutputStream;
240 // ...anything else you want to do, synchronously...
241 }
243 For more details on exactly which functions and properties are available
244 on request/response in handleRequest, see the nsIHttpRe(quest|sponse)
245 definitions in <netwerk/test/httpserver/nsIHttpServer.idl>.
247 d. <type> is one of the following:
249 == The test passes if the images of the two renderings are the
250 SAME.
251 != The test passes if the images of the two renderings are
252 DIFFERENT.
253 load The test passes unconditionally if the page loads. url_ref
254 must be omitted, and the test cannot be marked as fails or
255 random. (Used to test for crashes, hangs, assertions, and
256 leaks.)
257 script The loaded page records the test's pass or failure status
258 in a JavaScript data structure accessible through the following
259 API.
261 getTestCases() returns an array of test result objects
262 representing the results of the tests performed by the page.
264 Each test result object has two methods:
266 testPassed() returns true if the test result object passed,
267 otherwise it returns false.
269 testDescription() returns a string describing the test
270 result.
272 url_ref must be omitted. The test may be marked as fails or
273 random. (Used to test the JavaScript Engine.)
275 e. <url> is either a relative file path or an absolute URL for the
276 test page
278 f. <url_ref> is either a relative file path or an absolute URL for
279 the reference page
281 The only difference between <url> and <url_ref> is that results of
282 the test are reported using <url> only.
284 3. Specification of a url prefix
286 url-prefix <string>
288 <string> will be prepended to relative <url> and <url_ref> for all following
289 test items in the manifest.
291 <string> will not be prepended to the relative path when including another
292 manifest, e.g. include <relative_path>.
294 <string> will not be prepended to any <url> or <url_ref> matching the pattern
295 /^\w+:/. This will prevent the prefix from being applied to any absolute url
296 containing a protocol such as data:, about:, or http:.
298 While the typical use of url-prefix is expected to be as the first line of
299 a manifest, it is legal to use it anywhere in a manifest. Subsequent uses
300 of url-prefix overwrite any existing values.
302 4. Specification of default preferences
304 default-preferences <preference>*
306 where <preference> is defined above.
308 The <preference> settings will be used for all following test items in the
309 manifest.
311 If a test item includes its own preference settings, then they will override
312 any settings for preferences of the same names that are set using
313 default-preferences, just as later items within a line override earlier ones.
315 A default-preferences line with no <preference> settings following it will
316 reset the set of default preferences to be empty.
318 As with url-prefix, default-preferences will often be used at the start of a
319 manifest file so that it applies to all test items, but it is legal for
320 default-preferences to appear anywhere in the manifest. A subsequent
321 default-preferences will reset any previous default preference values and
322 overwrite them with the specified <preference> values.
324 This test manifest format could be used by other harnesses, such as ones
325 that do not depend on XUL, or even ones testing other layout engines.
327 Running Tests
328 =============
330 (If you're not using a DEBUG build, first set browser.dom.window.dump.enabled
331 to true (in about:config, in the profile you'll be using to run the tests).
332 Create the option as a new boolean if it doesn't exist already. If you skip
333 this step you won't get any output in the terminal.)
335 At some point in the future there will hopefully be a cleaner way to do
336 this. For now, go to your object directory, and run (perhaps using
337 MOZ_NO_REMOTE=1 or the -profile <directory> option)
339 ./firefox -reftest /path/to/srcdir/mozilla/layout/reftests/reftest.list > reftest.out
341 and then search/grep reftest.out for "UNEXPECTED".
343 There are two scripts provided to convert the reftest.out to HTML.
344 clean-reftest-output.pl converts reftest.out into simple HTML, stripping
345 lines from the log that aren't relevant. reftest-to-html.pl converts
346 the output into html that makes it easier to visually check for
347 failures.
349 Testable Areas
350 ==============
352 This framework is capable of testing many areas of the layout engine.
353 It is particularly well-suited to testing dynamic change handling (by
354 comparison to the static end-result as a reference) and incremental
355 layout (comparison of a script-interrupted layout to one that was not).
356 However, it is also possible to write tests for many other things that
357 can be described in terms of equivalence, for example:
359 * CSS cascading could be tested by comparing the result of a
360 complicated set of style rules that makes a word green to <span
361 style="color:green">word</span>.
363 * <canvas> compositing operators could be tested by comparing the
364 result of drawing using canvas to a block-level element with the
365 desired color as a CSS background-color.
367 * CSS counters could be tested by comparing the text output by counters
368 with a page containing the text written out
370 * complex margin collapsing could be tested by comparing the complex
371 case to a case where the margin is written out, or where the margin
372 space is created by an element with 'height' and transparent
373 background
375 When it is not possible to test by equivalence, it may be possible to
376 test by non-equivalence. For example, testing justification in cases
377 with more than two words, or more than three different words, is
378 difficult. However, it is simple to test that justified text is at
379 least displayed differently from left-, center-, or right-aligned text.
381 Writing Tests
382 =============
384 When writing tests for this framework, it is important for the test to
385 depend only on behaviors that are known to be correct and permanent.
386 For example, tests should not depend on default font sizes, default
387 margins of the body element, the default style sheet used for HTML, the
388 default appearance of form controls, or anything else that can be
389 avoided.
391 In general, the best way to achieve this is to make the test and the
392 reference identical in as many aspects as possible. For example:
394 Good test markup:
395 <div style="color:green"><table><tr><td><span>green
396 </span></td></tr></table></div>
398 Good reference markup:
399 <div><table><tr><td><span style="color:green">green
400 </span></td></tr></table></div>
402 BAD reference markup:
403 <!-- 3px matches the default cellspacing and cellpadding -->
404 <div style="color:green; padding: 3px">green
405 </div>
407 BAD test markup:
408 <!-- span doesn't change the positioning, so skip it -->
409 <div style="color:green"><table><tr><td>green
410 </td></tr></table></div>
412 Asynchronous Tests: class="reftest-wait"
413 ========================================
415 Normally reftest takes a snapshot of the given markup's rendering right
416 after the load event fires for content. If your test needs to postpone
417 the moment the snapshot is taken, it should make sure a class
418 'reftest-wait' is on the root element by the moment the load event
419 fires. The easiest way to do this is to put it in the markup, e.g.:
420 <html class="reftest-wait">
422 When your test is ready, you should remove this class from the root
423 element, for example using this code:
424 document.documentElement.className = "";
427 Note that in layout tests it is often enough to trigger layout using
428 document.body.offsetWidth // HTML example
430 When possible, you should use this technique instead of making your
431 test async.
433 Invalidation Tests: MozReftestInvalidate Event
434 ==============================================
436 When a test (or reference) uses reftest-wait, reftest tracks invalidation
437 via MozAfterPaint and updates the test image in the same way that
438 a regular window would be repainted. Therefore it is possible to test
439 invalidation-related bugs by setting up initial content and then
440 dynamically modifying it before removing reftest-wait. However, it is
441 important to get the timing of these dynamic modifications right so that
442 the test doesn't accidentally pass because a full repaint of the window
443 was already pending. To help with this, reftest fires one MozReftestInvalidate
444 event at the document root element for a reftest-wait test when it is safe to
445 make changes that should test invalidation. The event bubbles up to the
446 document and window so you can set listeners there too. For example,
448 function doTest() {
449 document.body.style.border = "";
450 document.documentElement.removeAttribute('class');
451 }
452 document.addEventListener("MozReftestInvalidate", doTest, false);
454 Painting Tests: class="reftest-no-paint"
455 ========================================
457 If an element shouldn't be painted, set the class "reftest-no-paint" on it
458 when doing an invalidation test. Causing a repaint in your
459 MozReftestInvalidate handler (for example, by changing the body's background
460 colour) will accurately test whether the element is painted.
462 Snapshot The Whole Window: class="reftest-snapshot-all"
463 =======================================================
465 In a reftest-wait test, to disable testing of invalidation and force the final
466 snapshot to be taken of the whole window, set the "reftest-snapshot-all"
467 class on the root element.
469 Zoom Tests: reftest-zoom="<float>"
470 ==================================
472 When the root element of a test has a "reftest-zoom" attribute, that zoom
473 factor is applied when rendering the test. The reftest document will be
474 800 device pixels wide by 1000 device pixels high. The reftest harness assumes
475 that the CSS pixel dimensions are 800/zoom and 1000/zoom. For best results
476 therefore, choose zoom factors that do not require rounding when we calculate
477 the number of appunits per device pixel; i.e. the zoom factor should divide 60,
478 so 60/zoom is an integer.
480 Setting Viewport Size: reftest-viewport-w/h="<int>"
481 ===================================================
483 If either of the "reftest-viewport-w" and "reftest-viewport-h" attributes on
484 the root element are non-zero, sets the CSS viewport to the given size in
485 CSS pixels. This does not affect the size of the snapshot that is taken.
487 Setting Async Scroll Mode: reftest-async-scroll attribute
488 =========================================================
490 If the "reftest-async-scroll" attribute is set on the root element, we try to
491 enable async scrolling for the document. This is unsupported in many
492 configurations.
494 Setting Displayport Dimensions: reftest-displayport-x/y/w/h="<int>"
495 ===================================================================
497 If any of the "reftest-displayport-x", "reftest-displayport-y",
498 "reftest-displayport-w" and "reftest-displayport-h" attributes on the root
499 element are nonzero, sets the displayport dimensions to the given bounds in
500 CSS pixels. This does not affect the size of the snapshot that is taken.
502 When the "reftest-async-scroll" attribute is set on the root element, *all*
503 elements in the document are checked for "reftest-displayport-x/y/w/h" and have
504 displayports set on them when those attributes are present.
506 Testing Async Scrolling: reftest-async-scroll-x/y="<int>"
507 =========================================================
509 When the "reftest-async-scroll" attribute is set on the root element, for any
510 element where either the "reftest-async-scroll-x" or "reftest-async-scroll-y
511 attributes are nonzero, at the end of the test take the snapshot with the given
512 offset (in CSS pixels) added to the async scroll offset.
514 Printing Tests: class="reftest-print"
515 =====================================
517 Now that the patch for bug 374050 has landed
518 (https://bugzilla.mozilla.org/show_bug.cgi?id=374050), it is possible to
519 create reftests that run in a paginated context.
521 The page size used is 5in wide and 3in tall (with the default half-inch
522 margins). This is to allow tests to have less text and to make the
523 entire test fit on the screen.
525 There is a layout/reftests/printing directory for printing reftests; however,
526 there is nothing special about this directory. You can put printing reftests
527 anywhere that is appropriate.
529 The suggested first lines for any printing test is
530 <!DOCTYPE html><html class="reftest-print">
531 <style>html{font-size:12pt}</style>
533 The reftest-print class on the root element triggers the reftest to
534 switch into page mode. Fixing the font size is suggested, although not
535 required, because the pages are a fixed size in inches. The switch to page mode
536 happens on load if the reftest-wait class is not present; otherwise it happens
537 immediately after firing the MozReftestInvalidate event.
539 The underlying layout support for this mode isn't really complete; it
540 doesn't use exactly the same codepath as real print preview/print. In
541 particular, scripting and frames are likely to cause problems; it is untested,
542 though. That said, it should be sufficient for testing layout issues related
543 to pagination.
545 Plugin and IPC Process Crash Tests: class="reftest-expect-process-crash"
546 ========================================================================
548 If you are running a test that causes an out-of-process plugin or IPC process
549 under Electrolysis to crash as part of a reftest, this will cause process
550 crash minidump files to be left in the profile directory. The test
551 infrastructure that runs the reftests will notice these minidump files and
552 dump out information from them, and these additional error messages in the logs
553 can end up erroneously being associated with other errors from the reftest run.
554 They are also confusing, since the appearance of "PROCESS-CRASH" messages in
555 the test run output can seem like a real problem, when in fact it is the
556 expected behavior.
558 To indicate to the reftest framework that a test is expecting a plugin or
559 IPC process crash, have the test include "reftest-expect-process-crash" as
560 one of the root element's classes by the time the test has finished. This will
561 cause any minidump files that are generated while running the test to be removed
562 and they won't cause any error messages in the test run output.
564 Skip Forcing A Content Process Layer-Tree Update: reftest-no-sync-layers attribute
565 ==================================================================================
567 Normally when an multi-process reftest test ends, we force the content process
568 to push a layer-tree update to the compositor before taking the snapshot.
569 Setting the "reftest-no-sync-layers" attribute on the root element skips this
570 step, enabling testing that layer-tree updates are being correctly generated.
571 However the test must manually wait for a MozAfterPaint event before ending.