| # UI tests | |
| UI tests are a particular [test suite](compiletest.md#test-suites) of compiletest. | |
| ## Introduction | |
| The tests in [`tests/ui`] are a collection of general-purpose tests which | |
| primarily focus on validating the console output of the compiler, but can be | |
| used for many other purposes. | |
| For example, tests can also be configured to [run | |
| the resulting program](#controlling-passfail-expectations) to verify its behavior. | |
| For a survey of each subdirectory's purpose under `tests/ui`, consult the | |
| [README.md](https://github.com/rust-lang/rust/tree/HEAD/tests/ui/README.md). | |
| This is useful if you write a new test, and are looking for a category to place it in. | |
| If you need to work with `#![no_std]` cross-compiling tests, consult the | |
| [`minicore` test auxiliary](./minicore.md) chapter. | |
| [`tests/ui`]: https://github.com/rust-lang/rust/blob/HEAD/tests/ui | |
| ## General structure of a test | |
| A test consists of a Rust source file located in the `tests/ui` directory. | |
| **Tests must be placed in the appropriate subdirectory** based on their purpose | |
| and testing category - placing tests directly in `tests/ui` is not permitted. | |
| Compiletest will use `rustc` to compile the test, and compare the output against | |
| the expected output which is stored in a `.stdout` or `.stderr` file located next to the test. | |
| See [Output comparison](#output-comparison) for more. | |
| Additionally, errors and warnings should be annotated with comments within the source file. | |
| See [Error annotations](#error-annotations) for more. | |
| Compiletest [directives](directives.md) in the form of special comments prefixed | |
| with `//@` control how the test is compiled and what the expected behavior is. | |
| Tests are expected to fail to compile, since most tests are testing compiler errors. | |
| You can change that behavior with a directive, see [Controlling | |
| pass/fail expectations](#controlling-passfail-expectations). | |
| By default, a test is built as an executable binary. | |
| If you need a different crate type, you can use the `#![crate_type]` attribute to set it as needed. | |
| ## Output comparison | |
| UI tests store the expected output from the compiler in `.stderr` and `.stdout` | |
| snapshots next to the test. | |
| You normally generate these files with the `--bless` | |
| CLI option, and then inspect them manually to verify they contain what you expect. | |
| The output is normalized to ignore unwanted differences, see the | |
| [Normalization](#normalization) section. | |
| If the file is missing, then compiletest expects the corresponding output to be empty. | |
| A common reason to use normalization, revisions, and most of the other following tools, | |
| is to account for platform differences. | |
| Consider alternatives to these tools, like | |
| e.g. using the `extern "rust-invalid"` ABI that is invalid on every platform | |
| instead of fixing the test to use cross-compilation and testing every possibly-invalid ABI. | |
| There can be multiple stdout/stderr files. | |
| The general form is: | |
| ```text | |
| *test-name*`.`*revision*`.`*compare_mode*`.`*extension* | |
| ``` | |
| - *test-name* cannot contain dots. | |
| This is so that the general form of test | |
| output filenames have a predictable form we can pattern match on in order to | |
| track stray test output files. | |
| - *revision* is the [revision](#cfg-revisions) name. | |
| This is not included when not using revisions. | |
| - *compare_mode* is the [compare mode](#compare-modes). | |
| This will only be checked when the given compare mode is active. | |
| If the file does not exist, | |
| then compiletest will check for a file without the compare mode. | |
| - *extension* is the kind of output being checked: | |
| - `stderr` — compiler stderr | |
| - `stdout` — compiler stdout | |
| - `run.stderr` — stderr when running the test | |
| - `run.stdout` — stdout when running the test | |
| - `64bit.stderr` — compiler stderr with `stderr-per-bitwidth` directive on a 64-bit target | |
| - `32bit.stderr` — compiler stderr with `stderr-per-bitwidth` directive on a 32-bit target | |
| A simple example would be `foo.stderr` next to a `foo.rs` test. | |
| A more complex example would be `foo.my-revision.polonius.stderr`. | |
| There are several [directives](directives.md) which will change how compiletest | |
| will check for output files: | |
| - `stderr-per-bitwidth` — checks separate output files based on the target pointer width. | |
| Consider using the `normalize-stderr` directive instead (see [Normalization](#normalization)). | |
| - `dont-check-compiler-stderr` — Ignores stderr from the compiler. | |
| - `dont-check-compiler-stdout` — Ignores stdout from the compiler. | |
| - `compare-output-by-lines` — Some tests have non-deterministic orders of output, so we need to compare by lines. | |
| UI tests run with `-Zdeduplicate-diagnostics=no` flag, which disables rustc's | |
| built-in diagnostic deduplication mechanism. | |
| This means you may see some duplicate messages in the output. | |
| This helps illuminate situations where duplicate diagnostics are being generated. | |
| ### Normalization | |
| The compiler output is normalized to eliminate output difference between | |
| platforms, mainly about filenames. | |
| Compiletest makes the following replacements on the compiler output: | |
| - The directory where the test is defined is replaced with `$DIR`. | |
| Example: `/path/to/rust/tests/ui/error-codes` | |
| - The directory to the standard library source is replaced with `$SRC_DIR`. | |
| Example: `/path/to/rust/library` | |
| - Line and column numbers for paths in `$SRC_DIR` are replaced with `LL:COL`. | |
| This helps ensure that changes to the layout of the standard library do not | |
| cause widespread changes to the `.stderr` files. | |
| Example: `$SRC_DIR/alloc/src/sync.rs:53:46` | |
| - The base directory where the test's output goes is replaced with `$TEST_BUILD_DIR`. | |
| This only comes up in a few rare circumstances. | |
| Example: `/path/to/rust/build/x86_64-unknown-linux-gnu/test/ui` | |
| - The real directory to the standard library source is replaced with `$SRC_DIR_REAL`. | |
| - The real directory to the compiler source is replaced with `$COMPILER_DIR_REAL`. | |
| - Tabs are replaced with `\t`. | |
| - Backslashes (`\`) are converted to forward slashes (`/`) within paths (using a heuristic). | |
| This helps normalize differences with Windows-style paths. | |
| - CRLF newlines are converted to LF. | |
| - Error line annotations like `//~ ERROR some message` are removed. | |
| - Various v0 and legacy symbol hashes are replaced with placeholders like | |
| `[HASH]` or `<SYMBOL_HASH>`. | |
| Additionally, the compiler is run with the `-Z ui-testing` flag which causes | |
| the compiler itself to apply some changes to the diagnostic output to make it | |
| more suitable for UI testing. | |
| For example, it will anonymize line numbers in the output (line numbers | |
| prefixing each source line are replaced with `LL`). | |
| In extremely rare situations, this mode can be disabled with the directive `//@ | |
| compile-flags: -Z ui-testing=no`. | |
| When using `-Z ui-testing=no`, the `--diagnostic-width` argument should also | |
| be set to avoid tests failing or passing depending on the width of the terminal | |
| from which the UI test suite is being run. | |
| Note: The line and column numbers for `-->` lines pointing to the test are *not* | |
| normalized, and left as-is. | |
| This ensures that the compiler continues to point to | |
| the correct location, and keeps the stderr files readable. | |
| Ideally all line/column information would be retained, but small changes to the source | |
| causes large diffs, and more frequent merge conflicts and test errors. | |
| Sometimes these built-in normalizations are not enough. | |
| In such cases, you may | |
| provide custom normalization rules using `normalize-*` directives, e.g. | |
| ```rust,ignore | |
| //@ normalize-stdout: "foo" -> "bar" | |
| //@ normalize-stderr: "foo" -> "bar" | |
| //@ normalize-stderr-32bit: "fn\(\) \(32 bits\)" -> "fn\(\) \($$PTR bits\)" | |
| //@ normalize-stderr-64bit: "fn\(\) \(64 bits\)" -> "fn\(\) \($$PTR bits\)" | |
| ``` | |
| This tells the test, on 32-bit platforms, whenever the compiler writes `fn() (32 | |
| bits)` to stderr, it should be normalized to read `fn() ($PTR bits)` instead. | |
| Similar for 64-bit. | |
| The replacement is performed by regexes using default regex flavor provided by `regex` crate. | |
| The corresponding reference file will use the normalized output to test both | |
| 32-bit and 64-bit platforms: | |
| ```text | |
| ... | |
| | | |
| = note: source type: fn() ($PTR bits) | |
| = note: target type: u16 (16 bits) | |
| ... | |
| ``` | |
| Please see [`ui/transmute/main.rs`][mrs] and [`main.stderr`] for a concrete usage example. | |
| [mrs]: https://github.com/rust-lang/rust/blob/HEAD/tests/ui/transmute/main.rs | |
| [`main.stderr`]: https://github.com/rust-lang/rust/blob/HEAD/tests/ui/transmute/main.stderr | |
| ## Error annotations | |
| Error annotations specify the errors that the compiler is expected to emit. | |
| They are "attached" to the line in source where the error is located. | |
| ```rust,ignore | |
| fn main() { | |
| boom //~ ERROR cannot find value `boom` in this scope [E0425] | |
| } | |
| ``` | |
| Although UI tests have a `.stderr` file which contains the entire compiler | |
| output, UI tests require that errors are also annotated within the source. | |
| This redundancy helps avoid mistakes since the `.stderr` files are usually | |
| auto-generated. | |
| It also helps to directly see where the error spans are expected | |
| to point to by looking at one file instead of having to compare the `.stderr` file with the source. | |
| Finally, they ensure that no additional unexpected errors are generated. | |
| They have several forms, but generally are a comment with the diagnostic level | |
| (such as `ERROR`) and a substring of the expected error output. | |
| You don't have to write out the entire message, | |
| but be sure to include the important part of the message to make it self-documenting. | |
| Most error annotations need to match with the line of the diagnostic. | |
| There are several ways to match the message with the line (see the examples below): | |
| * `~`: Associates the error level and message with the *current* line | |
| * `~^`: Associates the error level and message with the *previous* error annotation line. | |
| Each caret (`^`) that you add adds a line to this, so `~^^^` | |
| is three lines above the error annotation line. | |
| * `~|`: Associates the error level and message with the *same* line as the | |
| *previous comment*. This is more convenient than using multiple carets when | |
| there are multiple messages associated with the same line. | |
| * `~v`: Associates the error level and message with the *next* error annotation line. | |
| Each symbol (`v`) that you add adds a line to this, so `~vvv` | |
| is three lines below the error annotation line. | |
| Example: | |
| ```rust,ignore | |
| let _ = same_line; //~ ERROR undeclared variable | |
| fn meow(_: [u8]) {} | |
| //~^ ERROR unsized | |
| //~| ERROR anonymous parameters | |
| ``` | |
| The space character between `//~` (or other variants) and the subsequent text is | |
| negligible (i.e. there is no semantic difference between `//~ ERROR` and | |
| `//~ERROR` although the former is more common in the codebase). | |
| `~? <diagnostic kind>` (example being `~? ERROR`) | |
| is used to match diagnostics _without_ line info at all, | |
| or where the line info is outside the main test file[^main test file]. | |
| These annotations can be placed on any line in the test file. | |
| [^main test file]: This is a file that has the `~?` annotations, | |
| as distinct from aux files, or sources that we have no control over. | |
| ### Error annotation examples | |
| Here are examples of error annotations on different lines of UI test source. | |
| #### Positioned on error line | |
| Use the `//~ ERROR` idiom: | |
| ```rust,ignore | |
| fn main() { | |
| let x = (1, 2, 3); | |
| match x { | |
| (_a, _x @ ..) => {} //~ ERROR `_x @` is not allowed in a tuple | |
| _ => {} | |
| } | |
| } | |
| ``` | |
| #### Positioned below error line | |
| Use the `//~^` idiom with number of carets in the string to indicate the number of lines above. | |
| In the example below, the error line is four lines above the | |
| error annotation line so four carets are included in the annotation. | |
| ```rust,ignore | |
| fn main() { | |
| let x = (1, 2, 3); | |
| match x { | |
| (_a, _x @ ..) => {} // <- the error is on this line | |
| _ => {} | |
| } | |
| } | |
| //~^^^^ ERROR `_x @` is not allowed in a tuple | |
| ``` | |
| #### Use same error line as defined on error annotation line above | |
| Use the `//~|` idiom to define the same error line as the error annotation | |
| line above: | |
| ```rust,ignore | |
| struct Binder(i32, i32, i32); | |
| fn main() { | |
| let x = Binder(1, 2, 3); | |
| match x { | |
| Binder(_a, _x @ ..) => {} // <- the error is on this line | |
| _ => {} | |
| } | |
| } | |
| //~^^^^ ERROR `_x @` is not allowed in a tuple struct | |
| //~| ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields [E0023] | |
| ``` | |
| #### Positioned above error line | |
| Use the `//~v` idiom with number of v's in the string to indicate the number of lines below. | |
| This is typically used in lexer or parser tests matching on errors like unclosed | |
| delimiter or unclosed literal happening at the end of file. | |
| ```rust,ignore | |
| // ignore-tidy-trailing-newlines | |
| //~v ERROR this file contains an unclosed delimiter | |
| fn main((ؼ | |
| ``` | |
| #### Error without line information | |
| Use `//~?` to match an error without line information. | |
| `//~?` is precise and will not match errors if their line information is available. | |
| It should be preferred over `//@ error-pattern` | |
| for tests wishing to match against compiler diagnostics, | |
| due to `//@ error-pattern` being imprecise and non-exhaustive. | |
| ```rust,ignore | |
| //@ compile-flags: --print yyyy | |
| //~? ERROR unknown print request: `yyyy` | |
| ``` | |
| ### `error-pattern` | |
| The `error-pattern` [directive](directives.md) can be used for runtime messages which don't | |
| have a specific span, or, in exceptional cases, for compile time messages. | |
| Let's think about this test: | |
| ```rust,ignore | |
| fn main() { | |
| let a: *const [_] = &[1, 2, 3]; | |
| unsafe { | |
| let _b = (*a)[3]; | |
| } | |
| } | |
| ``` | |
| We want to ensure this shows "index out of bounds", but we cannot use the `ERROR` | |
| annotation since the runtime error doesn't have any span. | |
| Then it's time to use the `error-pattern` directive: | |
| ```rust,ignore | |
| //@ error-pattern: index out of bounds | |
| fn main() { | |
| let a: *const [_] = &[1, 2, 3]; | |
| unsafe { | |
| let _b = (*a)[3]; | |
| } | |
| } | |
| ``` | |
| For strict testing of compile time output, try to use the line annotations `//~` as much as | |
| possible, including `//~?` annotations for diagnostics without spans. | |
| If the compile time output is target dependent or too verbose, use directive | |
| `//@ dont-require-annotations: <diagnostic-kind>` to make the line annotation checking | |
| non-exhaustive. | |
| Some of the compiler messages can stay uncovered by annotations in this mode. | |
| For checking runtime output, `//@ check-run-results` may be preferable. | |
| Only use `error-pattern` if none of the above works, such as when finding a | |
| specific string pattern in a runtime panic output. | |
| Line annotations `//~` and `error-pattern` are compatible and can be used in the same test. | |
| ### Diagnostic kinds (error levels) | |
| The diagnostic kinds that you can have are: | |
| - `ERROR` | |
| - `WARN` (or `WARNING`) | |
| - `NOTE` | |
| - `HELP` | |
| - `SUGGESTION` | |
| - `RAW` | |
| The `SUGGESTION` kind is used for specifying what the expected replacement text | |
| should be for a diagnostic suggestion. | |
| The `RAW` kind can be used for matching on lines from non-structured output sometimes emitted | |
| by the compiler instead of or in addition to structured json. | |
| `ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations | |
| `//~` by default. | |
| Other kinds only need to be line-annotated if at least one annotation of that kind appears | |
| in the test file. | |
| For example, one `//~ NOTE` will also require all other `//~ NOTE`s in the file | |
| to be written out explicitly. | |
| Use directive `//@ dont-require-annotations` to opt out of exhaustive annotations. | |
| E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively. | |
| Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like | |
| target-dependent compiler output. | |
| Some diagnostics are never required to be line-annotated, regardless of their kind or directives. | |
| Examples are secondary lines of multiline diagnostics, | |
| or ubiquitous diagnostics like `aborting due to N previous errors`. | |
| UI tests use the `-A unused` flag by default to ignore all unused warnings, as | |
| unused warnings are usually not the focus of a test. | |
| However, simple code samples often have unused warnings. | |
| If the test is specifically testing an | |
| unused warning, just add the appropriate `#![warn(unused)]` attribute as needed. | |
| ### `cfg` revisions | |
| When using [revisions](compiletest.md#revisions), different messages can be | |
| conditionally checked based on the current revision. | |
| This is done by placing the revision cfg name in brackets like this: | |
| ```rust,ignore | |
| //@ edition:2018 | |
| //@ revisions: mir thir | |
| //@[thir] compile-flags: -Z thir-unsafeck | |
| async unsafe fn f() {} | |
| async fn g() { | |
| f(); //~ ERROR call to unsafe function is unsafe | |
| } | |
| fn main() { | |
| f(); //[mir]~ ERROR call to unsafe function is unsafe | |
| } | |
| ``` | |
| In this example, the second error message is only emitted in the `mir` revision. | |
| The `thir` revision only emits the first error. | |
| If the `cfg` causes the compiler to emit different output, then a test can have | |
| multiple `.stderr` files for the different outputs. | |
| In the example above, there | |
| would be a `.mir.stderr` and `.thir.stderr` file with the different outputs of | |
| the different revisions. | |
| > Note: cfg revisions also work inside the source code with `#[cfg]` attributes. | |
| > | |
| > By convention, the `FALSE` cfg is used to have an always-false config. | |
| ## Controlling pass/fail expectations | |
| By default, a UI test is expected to **generate a compile error** because most | |
| of the tests are checking for invalid input and error diagnostics. | |
| However, you can also make UI tests where compilation is expected to succeed, and you can | |
| even run the resulting program. | |
| Just add one of the following [directives](directives.md): | |
| - Pass directives: | |
| - `//@ check-pass` — compilation should succeed but skip codegen | |
| (which is expensive and isn't supposed to fail in most cases). | |
| - `//@ build-pass` — compilation and linking should succeed but do | |
| not run the resulting binary. | |
| - `//@ run-pass` — compilation should succeed and running the resulting | |
| binary should make it exit with code 0 which indicates success. | |
| - Fail directives: | |
| - `//@ check-fail` — compilation should fail (the codegen phase is skipped). | |
| This is the default for UI tests. | |
| - `//@ build-fail` — compilation should fail during the codegen phase. | |
| This will run `rustc` twice: | |
| - First time is to ensure that the compile succeeds without the codegen phase | |
| - Second time is to ensure that the full compile fails | |
| - `//@ run-fail` — compilation should succeed, but running the resulting | |
| binary should make it exit with a code in the range `1..=127` which | |
| indicates regular failure. | |
| On targets without unwind support, crashes are also accepted. | |
| - `//@ run-crash` — compilation should succeed, but running the resulting | |
| binary should fail with a crash. | |
| Crashing is defined as "not exiting with a code in the range `0..=127`". | |
| - Example on Linux: Termination by `SIGABRT` or `SIGSEGV`. | |
| - Example on Windows: Exiting with the code for `STATUS_ILLEGAL_INSTRUCTION` (`0xC000001D`). | |
| - `//@ run-fail-or-crash` — compilation should succeed, but running the | |
| resulting binary should either `run-fail` or `run-crash`. | |
| Useful if a test crashes on some targets but just fails on others. | |
| For `run-pass`, `run-fail`, `run-crash`, and `run-fail-or-crash` tests, | |
| the output of the program itself is not checked by default. | |
| If you want to check the output of running the program, include the `check-run-results` directive. | |
| This will check for a `.run.stderr` and | |
| `.run.stdout` files to compare against the actual output of the program. | |
| Tests with the `*-pass` directives can be overridden with the `--pass` command-line option: | |
| ```sh | |
| ./x test tests/ui --pass check | |
| ``` | |
| The `--pass` option only affects UI tests. | |
| Using `--pass check` can run the UI | |
| test suite much faster (roughly twice as fast on my system), though obviously | |
| not exercising as much. | |
| The `no-pass-override` directive can be used to ignore the `--pass` CLI flag if the | |
| test won't work properly with that override. | |
| ## Known bugs | |
| The `known-bug` directive may be used for tests that demonstrate a known bug | |
| that has not yet been fixed. | |
| Adding tests for known bugs is helpful for several reasons, including: | |
| 1. Maintaining a functional test that can be conveniently reused when the bug is fixed. | |
| 2. Providing a sentinel that will fail if the bug is incidentally fixed. | |
| This can alert the developer so they know that the associated issue has been fixed | |
| and can possibly be closed. | |
| This directive takes comma-separated issue numbers as arguments, or `"unknown"`: | |
| - `//@ known-bug: #123, #456` (when the issues are on rust-lang/rust) | |
| - `//@ known-bug: rust-lang/chalk#123456` | |
| (allows arbitrary text before the `#`, which is useful when the issue is on another repo) | |
| - `//@ known-bug: unknown` | |
| (when there is no known issue yet; preferably open one if it does not already exist) | |
| Do not include [error annotations](#error-annotations) in a test with `known-bug`. | |
| The test should still include other normal directives and stdout/stderr files. | |
| ## Test organization | |
| When deciding where to place a test file, please try to find a subdirectory that | |
| best matches what you are trying to exercise. | |
| Do your best to keep things organized. | |
| Admittedly, it can be difficult as some tests can overlap different | |
| categories, and the existing layout may not fit well. | |
| Name the test by a concise description of what the test is checking. | |
| Avoid including the issue number in the test name. | |
| See [best practices](best-practices.md) for a more in-depth discussion of this. | |
| Ideally, the test should be added to a directory that helps identify what piece | |
| of code is being tested here (e.g., | |
| `tests/ui/borrowck/reject-move-out-of-borrow-via-pat.rs`) | |
| When writing a new feature, you may want to **create a subdirectory to store | |
| your tests**. For example, if you are implementing RFC 1234 ("Widgets"), then it | |
| might make sense to put the tests in a directory like `tests/ui/rfc1234-widgets/`. | |
| In other cases, there may already be a suitable directory. | |
| Over time, the [`tests/ui`] directory has grown very fast. | |
| There is a check in [tidy](intro.md#tidy) that will ensure none of the subdirectories has more than | |
| 1000 entries. | |
| Having too many files causes problems because it isn't editor/IDE | |
| friendly and the GitHub UI won't show more than 1000 entries. | |
| However, since `tests/ui` (UI test root directory) and `tests/ui/issues` directories have more | |
| than 1000 entries, we set a different limit for those directories. | |
| So, please avoid putting a new test there and try to find a more relevant place. | |
| For example, if your test is related to closures, you should put it in `tests/ui/closures`. | |
| When you reach the limit, you could increase it by tweaking [here][ui test tidy]. | |
| [ui test tidy]: https://github.com/rust-lang/rust/blob/HEAD/src/tools/tidy/src/ui_tests.rs | |
| ## Rustfix tests | |
| UI tests can validate that diagnostic suggestions apply correctly and that the | |
| resulting changes compile correctly. | |
| This can be done with the `run-rustfix` directive: | |
| ```rust,ignore | |
| //@ run-rustfix | |
| //@ check-pass | |
| #![crate_type = "lib"] | |
| pub struct not_camel_case {} | |
| //~^ WARN `not_camel_case` should have an upper camel case name | |
| //~| HELP convert the identifier to upper camel case | |
| //~| SUGGESTION NotCamelCase | |
| ``` | |
| Rustfix tests should have a file with the `.fixed` extension which contains the | |
| source file after the suggestion has been applied. | |
| - When the test is run, compiletest first checks that the correct lint/warning is generated. | |
| - Then, it applies the suggestion and compares against `.fixed` (they must match). | |
| - Finally, the fixed source is compiled, and this compilation is required to succeed. | |
| Usually when creating a rustfix test you will generate the `.fixed` file | |
| automatically with the `x test --bless` option. | |
| The `run-rustfix` directive will cause *all* suggestions to be applied, even if | |
| they are not [`MachineApplicable`](../diagnostics.md#suggestions). | |
| If this is a problem, then you can add the `rustfix-only-machine-applicable` directive in | |
| addition to `run-rustfix`. | |
| This should be used if there is a mixture of | |
| different suggestion levels, and some of the non-machine-applicable ones do not apply cleanly. | |
| ## Compare modes | |
| [Compare modes](compiletest.md#compare-modes) can be used to run all tests with | |
| different flags from what they are normally compiled with. | |
| In some cases, this might result in different output from the compiler. | |
| To support this, different | |
| output files can be saved which contain the output based on the compare mode. | |
| For example, when using the Polonius mode, a test `foo.rs` will first look for | |
| expected output in `foo.polonius.stderr`, falling back to the usual `foo.stderr` if not found. | |
| This is useful as different modes can sometimes result in different diagnostics and behavior. | |
| This can help track which tests have | |
| differences between the modes, and to visually inspect those diagnostic differences. | |
| If in the rare case you encounter a test that has different behavior, you can | |
| run something like the following to generate the alternate stderr file: | |
| ```sh | |
| ./x test tests/ui --compare-mode=polonius --bless | |
| ``` | |
| Currently none of the compare modes are checked in CI for UI tests. | |
| ## `rustc_*` TEST attributes | |
| The compiler defines several perma-unstable `#[rustc_*]` attributes gated behind | |
| the internal feature `rustc_attrs` that dump extra compiler-internal information. | |
| See the corresponding subsection in [compiler debugging] for more details. | |
| They can be used in tests to more precisely, legibly, and easily test internal | |
| compiler state in cases where it would otherwise be very hard to do the same | |
| with "user-facing" Rust alone. | |
| Indeed, one could say that this slightly abuses | |
| the term "UI" (*user* interface) and turns such UI tests from black-box tests into white-box ones. | |
| Use them carefully and sparingly. | |
| [compiler debugging]: ../compiler-debugging.md#rustc_-test-attributes | |
| ## UI test mode preset lint levels | |
| By default, test suites under UI test mode (`tests/ui`, `tests/ui-fulldeps`, | |
| but not `tests/rustdoc-ui`) will specify | |
| - `-A unused` | |
| - `-W unused_attributes` (since these tend to be interesting for ui tests) | |
| - `-A internal_features` | |
| - `-A incomplete_features` | |
| - `-A unused_parens` | |
| - `-A unused_braces` | |
| For more details, see [runtest]. | |
| [runtest]: https://github.com/rust-lang/rust/blob/HEAD/src/tools/compiletest/src/runtest.rs | |
| If: | |
| - The ui test's pass mode is below `run` (i.e. check or build). | |
| - No compare modes are specified. | |
| Since they can be very noisy in ui tests. | |
| You can override them with `compile-flags` lint level flags or | |
| in-source lint level attributes as required. | |
| Note that the `rustfix` version will *not* have `-A unused` passed, | |
| meaning that you may have to `#[allow(unused)]` to suppress `unused` | |
| lints on the rustfix'd file (because we might be testing rustfix on `unused` lints themselves). |