Flutter Engine
The Flutter Engine
|
List of tests on this form:
``` TEST_NAME ==> a_test_file.dart <== ... source code for a_test_file.dart ... ==> another_test_file.dart.patch <== ... source code for another_test_file.dart ... ```
Filenames ending with ".patch" are special and are expanded into multiple versions of a file. The parts of the file that vary between versions are surrounded by <<<<
and >>>>
and the alternatives are separated by ====
. For example:
``` ==> file.txt.patch <== first <<<< "ex1" v1 ==== "ex2" v2 ==== "ex2" v3 >>>> last ```
Will produce three versions of a file named file.txt.patch
:
Version 1: ``` first v1 last `` With expectation
ex1`
Version 2: ``` first v2 last ```
With expectation ex2
Version 3: ``` first v3 last ```
With expectation ex3
It is possible to have several independent changes in the same patch. However, most of the time, it's problematic to have more than one change in a patch. See topic below on "Making minimal changes". One should only specify the expectations once. For example:
==> main.dart.patch <== class Foo { <<<< "a" ==== "b" var bar; >>>> } main() { var foo = new Foo(); <<<< print("a"); ==== print("b"); >>>> }
An expectation is a JSON string. It is decoded and the resulting object, o
, is converted to a [ProgramExpectation] in the following way:
o
is a [String]: new ProgramExpectation([o])
, otherwiseo
is a [List]: new ProgramExpectation(o)
, otherwiseWhen adding new tests, it's important to keep the changes to the necessary minimum. We do this to ensure that a test actually tests what we intend, and to avoid accidentally relying on side-effects of other changes making the test pass or fail unexpectedly.
Let's look at an example of testing what happens when an instance field is added.
A good test:
==> main.dart.patch <== class Foo { <<<< ["instance is null", "setter threw", "getter threw"] ==== "v2" var bar; >>>> } var instance; main() { if (instance == null) { print("instance is null"); instance = new Foo(); } try { instance.bar = "v2"; } catch (e) { print("setter threw"); } try { print(instance.bar); } catch (e) { print("getter threw"); } }
A problematic version of the same test:
==> main.dart.patch <== class Foo { <<<< "v1" ==== "v2" var bar; >>>> } var instance; main() { <<<< instance = new Foo(); print("v1"); ==== instance.bar = 42; print(instance.bar); >>>> }
The former version tests precisely what happens when an instance field is added to a class, we assume this is the intent of the test.
The latter version tests what happens when:
The latter version does not test:
main
was explicitly changed, we don't know if already compiled accessors behave correctly.