|  | > [!IMPORTANT] | 
|  | > This page was copied from https://github.com/dart-lang/sdk/wiki and needs review. | 
|  | > Please [contribute](../CONTRIBUTING.md) changes to bring it up-to-date - | 
|  | > removing this header - or send a CL to delete the file. | 
|  |  | 
|  | --- | 
|  |  | 
|  | Stability is important for a programming language used to implement applications | 
|  | that [manage billions of dollars](http://news.dartlang.org/2016/03/the-new-adwords-ui-uses-dart-we-asked.html). To that end, the Dart repository contains a | 
|  | comprehensive test suite to cover the various configurations, compilers, tools, | 
|  | and runtimes we maintain and support. | 
|  |  | 
|  | We have tens of thousands of tests and a single test may be run across a | 
|  | combinatorial explosion of configurations. Does the static analyzer report any | 
|  | errors on it? In strong mode? Does it run on the standalone VM? Can dart2js | 
|  | compile it? Does the resulting code run in Chrome? Firefox? IE? In checked mode? | 
|  | With minification on? You get the idea. | 
|  |  | 
|  | Many tests are only meaningful for certain combinations of configurations. A | 
|  | test that uses "dart:io" is, by design, not going to run in a browser which | 
|  | doesn't have access to the local file system. Some bleeding edge web features | 
|  | aren't fully supported across all browsers. As we ramp up new tools, parts of | 
|  | our own stack may not be passing all tests. | 
|  |  | 
|  | So, for all of these tests, we need to track not just the test itself, but it's | 
|  | *status* -- what the expected outcome of the test is on various configurations. | 
|  | This status information lives (mostly) outside of the tests in separate "status | 
|  | files" with a ".status" extension. | 
|  |  | 
|  | This document explains the format of those files and how the test runner | 
|  | interprets them. | 
|  |  | 
|  | ## Outcomes and expectations | 
|  |  | 
|  | The test runner's main job, as you'd imagine, is to run tests. This sometimes | 
|  | involves invoking a compiler, and then spawning another process to execute the | 
|  | test itself. That process then may or may not complete successfully. | 
|  |  | 
|  | The test runner monitors this and tracks the various ways it can go wrong. | 
|  | Each of these outcomes has a canonical name. Things like: | 
|  |  | 
|  | - **Pass** – The runtime exited with exit code zero. | 
|  | - **CompileTimeError** – The compiler exited with a non-zero exit code. | 
|  | - **RuntimeError** – The runtime exited with a non-zero exit code. | 
|  |  | 
|  | There are other, more exotic outcomes. For the full list of them, see the code: | 
|  |  | 
|  | [`pkg/status_file/lib/expectation.dart`](https://github.com/dart-lang/sdk/blob/main/pkg/status_file/lib/expectation.dart) | 
|  |  | 
|  | In a perfect world, every test would pass in every configuration and the test | 
|  | runner could simplify verify that every test's outcome was "Pass". Alas, life is | 
|  | complicated. The status files keep track of what the *expected* outcome of each | 
|  | test is, which is why these outcomes are usually referred to as "expectations". | 
|  |  | 
|  | A test that ends with a runtime error is a successful test if the status file | 
|  | says we *expect* to get a runtime error. The test fails if no runtime error | 
|  | occurred. | 
|  |  | 
|  | ## Status files | 
|  |  | 
|  | Status files define the expectations for the tests by combining three facets: | 
|  |  | 
|  | * What are the expected outcomes... | 
|  | * ...for which tests... | 
|  | * ...under which configurations. | 
|  |  | 
|  | It's a bit like [Clue][]'s "Miss Scarlett, in the library, with the revolver." | 
|  | The status file says something like "'math/low_test', when compiled using | 
|  | dart2js, should produce a CompileError". | 
|  |  | 
|  | [clue]: https://en.wikipedia.org/wiki/Cluedo | 
|  |  | 
|  | With miles of tests and piles of configurations, we need a compact notation for | 
|  | defining expectations. That's what status files aim to be. | 
|  |  | 
|  | A status file is a line-oriented (newlines are significant) plain text file. | 
|  | Comments start with `#` and continue to the end of the line. Blank lines are | 
|  | ignored. | 
|  |  | 
|  | ### Sections | 
|  |  | 
|  | Each status file consists of a list of **sections**. Each section starts with a | 
|  | **header**, followed by one or more **entries**. (Entries at the top of the file | 
|  | above any header go into an implicit header-less section.) | 
|  |  | 
|  | Sections have no relation to each other and the order does not matter. | 
|  |  | 
|  | ### Headers | 
|  |  | 
|  | The header defines which configurations its entries apply to. It lets you | 
|  | specify the conditions under which a set of expectations come into play. The | 
|  | header contains an expression made up of accesses to various configuration | 
|  | variables. It's evaluated against the current configuration's values for those | 
|  | variables. If the expression evaluates to true, the section is applied and its | 
|  | entries are used. Otherwise, its entries are ignored. | 
|  |  | 
|  | If there are entries in the implicit first headerless section, the condition is | 
|  | always considered to be true and the entries are always applied. | 
|  |  | 
|  | Arbitrarily large expressions are supported, but the larger they are, the harder | 
|  | it is for your fellow teammates to understand what outcomes are expected for a | 
|  | given configuration. | 
|  |  | 
|  | Here's a complex example: | 
|  |  | 
|  | ```text | 
|  | [ $compiler == dart2js && ( $browser || $runtime == d8 ) ] | 
|  | ``` | 
|  |  | 
|  | The expression is contained in square brackets. Since we all love EBNF, the | 
|  | grammar for the expression inside is: | 
|  |  | 
|  | ```text | 
|  | expression := or | 
|  | or         := and ( "||" and )* | 
|  | and        := primary ( "&&" primary )* | 
|  | primary    := "$" identifier ( "==" | "!=" ) identifier | | 
|  | "!"? "$" identifier | | 
|  | "(" expression ")" | 
|  | identifier := regex "\w+" | 
|  | ``` | 
|  |  | 
|  | There are a few different expression forms: | 
|  |  | 
|  | *   **Variable** – This looks up the value of some configuration option like | 
|  | `$runtime` for which execution environment the test will be run in or | 
|  | `$strong` for whether the test is run in strong mode. Variables are always | 
|  | prefixed by `$`. | 
|  |  | 
|  | If the variable is a Boolean, you use it as a bare identifier like `$strong` | 
|  | or `$checked`. It may be prefixed with `!` to negate its value, so `! | 
|  | $checked` evaluates to true if the test is run in unchecked mode. | 
|  |  | 
|  | Non-Boolean variables accept one of an enumerated set of values. The set of | 
|  | values depends on the variable. For example, `$mode` can be `debug`, | 
|  | `release`, or `product`. To use one of these, it must be followed by `==` or | 
|  | `!=` and the value being tested. Examples: | 
|  |  | 
|  | ```text | 
|  | $runtime == vm | 
|  | $mode != debug | 
|  | ``` | 
|  |  | 
|  | Note that unlike variables, values are not prefixed with `$`. Note also | 
|  | that the equality operator and value is part of the variable expression | 
|  | itself. You can't do something like: `$mode == $runtime`. You always have | 
|  | to test against a literal value. | 
|  |  | 
|  | The set of variables that are available in status file expressions is baked | 
|  | into `test.dart`. You can see the full list of them here: | 
|  |  | 
|  | [`tools/testing/dart/environment.dart`](https://github.com/dart-lang/sdk/blob/main/pkg/test_runner/lib/src/environment.dart#L12) | 
|  |  | 
|  | For each variable, `test.dart` also knows all of the values that are allowed | 
|  | for it. It uses this to validate these expressions at parse time. If you | 
|  | misspell a variable, like `$compile` or test it against a value it can't | 
|  | have like `$runtime == dart2js` (dart2js is a compiler, not a runtime), it | 
|  | reports an error. | 
|  |  | 
|  | *   **Logical operators** - You can join two subexpressions using `||` or `&&`, | 
|  | with their usual meaning. `&&` has higher precedence than `||`. | 
|  |  | 
|  | *   **Parentheses** – If you want a `||` expression to be an operand to a `&&` | 
|  | expression, you can explicitly parenthesize. | 
|  |  | 
|  | Here are some examples: | 
|  |  | 
|  | ```text | 
|  | [ ! $checked ] | 
|  | ``` | 
|  |  | 
|  | This section applies only when not running the test in checked mode. | 
|  |  | 
|  | ```text | 
|  | [ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te ] | 
|  | ``` | 
|  |  | 
|  | This section applies only on various ARM simulator architectures. | 
|  |  | 
|  | ```text | 
|  | [ $checked && ($compiler == dartk || $compiler == dartkp) ] | 
|  | ``` | 
|  |  | 
|  | This section applies if the test is running in checked mode and using either of | 
|  | two Kernel compilers. | 
|  |  | 
|  | ```text | 
|  | [ $compiler != dart2js ] | 
|  | ``` | 
|  |  | 
|  | This section applies for any compiler except dart2js. | 
|  |  | 
|  | ### Entries | 
|  |  | 
|  | After the header, a section contains a list of entries. Each entry defines a | 
|  | glob-like path that matches a set of test files. Then it specifies the set of | 
|  | allowed outcomes for those tests. | 
|  |  | 
|  | For example: | 
|  |  | 
|  | ``` | 
|  | typed_data/int64_list_load_store_test: RuntimeError # Issue 10275 | 
|  | ``` | 
|  |  | 
|  | The syntax is a path, followed by `:`, followed by a comma-separated list of | 
|  | expectation names. It's a good idea to have a comment explaining why the test(s) | 
|  | have this expectation. If the expectation is because the test should be passing | 
|  | but isn't, the comment usually mentions the relevant issue number. | 
|  |  | 
|  | Here, it says the "int64_list_load_store_test" is failing at runtime because of | 
|  | some bug we should fix. | 
|  |  | 
|  | The path string is relative to the directory containing the status file. Note | 
|  | that paths do not have ".dart" extensions, even when they only match a single | 
|  | file (which is the normal case). You can also use `*` like a glob to match part | 
|  | of a path component as in: | 
|  |  | 
|  | ```text | 
|  | async/*deferred*: Pass,RuntimeError # Issue 17458 | 
|  | ``` | 
|  |  | 
|  | This matches any test inside the "async" directory whose name contains | 
|  | "deferred". If you want an entry that matches every single test in the directory | 
|  | containing the status file, use: | 
|  |  | 
|  | ```text | 
|  | *: Skip # Issue 28649 | 
|  | ``` | 
|  |  | 
|  | ## Applying status files | 
|  |  | 
|  | The trickiest part of status files is that the same test may be matched by | 
|  | multiple entries in different sections, potentially spread across different | 
|  | status files. These entries may apply and overlap in some configurations but not | 
|  | in others. For example, the status file for the corelib tests has five sections | 
|  | with entries that all match "async/multiple_timer_test" (I removed other | 
|  | unrelated entries here): | 
|  |  | 
|  | ```text | 
|  | [ $compiler == dart2js && $runtime == jsshell ] | 
|  | async/multiple_timer_test: RuntimeError,OK # Needs Timer to run. | 
|  |  | 
|  | [ $runtime == vm && $system == fuchsia ] | 
|  | async/multiple_timer_test: RuntimeError | 
|  |  | 
|  | [ $compiler == none && ($runtime == drt || $runtime == dartium) ] | 
|  | async/multiple_timer_test: Fail, Pass # Issue 15487 | 
|  |  | 
|  | [ $compiler == none && $runtime == drt && $system == windows ] | 
|  | async/multiple_timer_test: Fail, Pass # See Issue 10982 | 
|  |  | 
|  | [ $hot_reload || $hot_reload_rollback ] | 
|  | async/multiple_timer_test: Pass, Fail # Timing related | 
|  | ``` | 
|  |  | 
|  | Many of these sections are disjoint so that if one applies, another won't, but | 
|  | not all of them are. For example, if you're running on Fuchsia on the VM with | 
|  | hot reload enabled, the second and last sections both apply. They have different | 
|  | expectations. So what does `test.dart` expect this test to do? | 
|  |  | 
|  | When there are multiple sets of expectations for the same file, `test.dart` | 
|  | unions all of the sets together. So, in this case, the resulting expectation is | 
|  | "RuntimeError, Pass, Fail". | 
|  |  | 
|  | A test succeeds if the outcome is *any* of the expectations. Here, that | 
|  | basically means the test is going to succeed no matter what as long as it | 
|  | doesn't crash or timeout or something. | 
|  |  | 
|  | If no entries match a given file, the default expectation is "Pass". That means | 
|  | you only need to mention a file in a status file if it doesn't pass in at least | 
|  | one configuration. | 
|  |  | 
|  | ## Special expectations | 
|  |  | 
|  | Some "expectations" don't line up with actual possible test outcomes. Instead, | 
|  | they affect how the test runner works or have another purpose. A couple of | 
|  | important ones are: | 
|  |  | 
|  | *   **Skip** and **SkipByDesign** – These tell `test.dart` to not run the test | 
|  | at all. The latter is OK, it means "this behavior isn't relevant for this | 
|  | configuration". For example, Dartium doesn't support "dart:io", so the | 
|  | status file says: | 
|  |  | 
|  | ```text | 
|  | [ $compiler == none && ($runtime == drt || $runtime == dartium) ] | 
|  | io/*: SkipByDesign # Don't run tests using dart:io in the browser | 
|  | ``` | 
|  |  | 
|  | The "Skip" expectation is older and should be avoided, since it doesn't | 
|  | convey *why* the test is being skipped. | 
|  |  | 
|  | *   **OK** isn't a real expectation. It's more like a comment for a reader of | 
|  | the status file to know the behavior is intentional and desired. For | 
|  | example: | 
|  |  | 
|  | ```text | 
|  | [ $compiler == dart2js && $runtime == jsshell ] | 
|  | async/timer_cancel_test: RuntimeError,OK # Needs Timer to run. | 
|  | ``` | 
|  |  | 
|  | jsshell doesn't support Times, so we never expect this test to pass. | 
|  |  | 
|  | There are some other special expectations, documented in the source here: | 
|  |  | 
|  | [`/pkg/status_file/lib/expectation.dart`](https://github.com/dart-lang/sdk/blob/main/pkg/status_file/lib/expectation.dart) |