Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

UIテスト

UIテストは、compiletest の特定のテストスイートです。

はじめに

tests/ui 内のテストは、汎用テストの集合であり、 主にコンパイラのコンソール出力の検証に焦点を当てていますが、 他にも多くの目的に使用できます。 たとえば、テストは、その動作を検証するために 生成されたプログラムを実行するように設定することもできます。

tests/ui 配下の各サブディレクトリの目的の概要については、 README.mdを参照してください。 これは、新しいテストを書き、それを配置するカテゴリを探している場合に役立ちます。

#![no_std] のクロスコンパイルテストを扱う必要がある場合は、 minicore テスト補助の章を参照してください。

テストの一般的な構造

テストは、tests/ui ディレクトリに配置された Rust ソースファイルで構成されます。 テストは、その目的とテストカテゴリに基づいて適切なサブディレクトリに配置しなければなりません。 テストを tests/ui に直接配置することは許可されていません。

Compiletest は rustc を使用してテストをコンパイルし、その出力を、 テストの隣に配置された .stdout または .stderr ファイルに保存されている期待出力と比較します。 詳細については、出力の比較を参照してください。

さらに、エラーと警告はソースファイル内のコメントで注釈付けするべきです。 詳細については、エラー注釈を参照してください。

//@ で始まる特殊なコメント形式の compiletest ディレクティブは、 テストをどのようにコンパイルするか、および期待される動作が何かを制御します。

ほとんどのテストはコンパイラエラーをテストするため、テストはコンパイルに失敗することが期待されます。 その動作はディレクティブで変更できます。pass/fail 期待値の制御を参照してください。

デフォルトでは、テストは実行可能バイナリとしてビルドされます。 異なるクレートタイプが必要な場合は、必要に応じて #![crate_type] 属性を使用して設定できます。

出力の比較

UIテストは、コンパイラからの期待出力を、テストの隣にある .stderr および .stdout スナップショットに保存します。 通常、これらのファイルは --bless CLI オプションで生成し、その後手動で検査して、期待する内容が含まれていることを確認します。

不要な差異を無視するために出力は正規化されます。正規化セクションを参照してください。 ファイルが存在しない場合、compiletest は対応する出力が空であることを期待します。

正規化、リビジョン、および以下の他のツールの大半を使用する一般的な理由は、 プラットフォーム間の差異に対処することです。 これらのツールの代替案も検討してください。 たとえば、テストをクロスコンパイルを使用するように修正して、無効である可能性のあるすべての ABI をテストする代わりに、 すべてのプラットフォームで無効な extern "rust-invalid" ABI を使用するなどです。

stdout/stderr ファイルは複数存在できます。 一般的な形式は次のとおりです。

*test-name*`.`*revision*`.`*compare_mode*`.`*extension*
  • test-name にドットを含めることはできません。 これは、テスト出力ファイル名の一般形式を予測可能な形式にして、 迷子のテスト出力ファイルを追跡するためにパターンマッチできるようにするためです。
  • revisionリビジョン名です。 リビジョンを使用していない場合は含まれません。
  • compare_mode比較モードです。 これは、指定された比較モードが有効な場合にのみチェックされます。 ファイルが存在しない場合、 compiletest は比較モードなしのファイルをチェックします。
  • extension はチェック対象の出力の種類です。
    • stderr — コンパイラの stderr
    • stdout — コンパイラの stdout
    • run.stderr — テスト実行時の stderr
    • run.stdout — テスト実行時の stdout
    • 64bit.stderr — 64ビットターゲットで stderr-per-bitwidth ディレクティブを使用したコンパイラの stderr
    • 32bit.stderr — 32ビットターゲットで stderr-per-bitwidth ディレクティブを使用したコンパイラの stderr

単純な例は、foo.rs テストの隣にある foo.stderr です。 より複雑な例は foo.my-revision.polonius.stderr です。

compiletest が出力ファイルをチェックする方法を変更するディレクティブがいくつかあります。

  • stderr-per-bitwidth — ターゲットのポインタ幅に基づいて別々の出力ファイルをチェックします。 代わりに normalize-stderr ディレクティブを使用することを検討してください(正規化を参照)。
  • dont-check-compiler-stderr — コンパイラからの stderr を無視します。
  • dont-check-compiler-stdout — コンパイラからの stdout を無視します。
  • compare-output-by-lines — 一部のテストでは出力の順序が非決定的であるため、行単位で比較する必要があります。

UIテストは -Zdeduplicate-diagnostics=no フラグ付きで実行されます。これは rustc の 組み込みの診断重複排除メカニズムを無効にします。 つまり、出力に重複したメッセージが表示される場合があります。 これは、重複した診断が生成されている状況を明らかにするのに役立ちます。

正規化

コンパイラ出力は、主にファイル名に関するプラットフォーム間の出力差異をなくすために正規化されます。

Compiletest はコンパイラ出力に対して次の置換を行います。

  • テストが定義されているディレクトリは $DIR に置換されます。 例: /path/to/rust/tests/ui/error-codes
  • 標準ライブラリソースへのディレクトリは $SRC_DIR に置換されます。 例: /path/to/rust/library
  • $SRC_DIR 内のパスの行番号と列番号は LL:COL に置換されます。 これは、標準ライブラリのレイアウト変更が .stderr ファイルに広範な変更を 引き起こさないようにするのに役立ちます。 例: $SRC_DIR/alloc/src/sync.rs:53:46
  • テストの出力が置かれるベースディレクトリは $TEST_BUILD_DIR に置換されます。 これは、ごくまれな状況でのみ現れます。 例: /path/to/rust/build/x86_64-unknown-linux-gnu/test/ui
  • 標準ライブラリソースへの実ディレクトリは $SRC_DIR_REAL に置換されます。
  • コンパイラソースへの実ディレクトリは $COMPILER_DIR_REAL に置換されます。
  • タブは \t に置換されます。
  • パス内のバックスラッシュ(\)は、(ヒューリスティックを使用して)スラッシュ(/)に変換されます。 これは Windows スタイルのパスとの差異を正規化するのに役立ちます。
  • CRLF 改行は LF に変換されます。
  • //~ ERROR some message のようなエラー行注釈は削除されます。
  • さまざまな v0 およびレガシーのシンボルハッシュは、 [HASH]<SYMBOL_HASH> のようなプレースホルダーに置換されます。

さらに、コンパイラは -Z ui-testing フラグ付きで実行されます。これにより、 コンパイラ自身が診断出力にいくつかの変更を適用し、UIテストにより適したものにします。

たとえば、出力内の行番号を匿名化します(各ソース行の先頭に付く行番号は LL に置換されます)。 極めてまれな状況では、このモードはディレクティブ //@ compile-flags: -Z ui-testing=no で無効化できます。

-Z ui-testing=no を使用する場合、UIテストスイートを実行しているターミナルの幅に応じて テストが失敗または成功しないように、--diagnostic-width 引数も設定するべきです。 注: テストを指す --> 行の行番号と列番号は正規化されず、 そのまま残されます。 これにより、コンパイラが引き続き正しい位置を指し示し、 stderr ファイルの可読性が保たれます。 理想的にはすべての行/列情報が保持されるべきですが、ソースへの小さな変更によって 大きな diff が発生し、マージコンフリクトやテストエラーがより頻繁に発生します。

場合によっては、これらの組み込みの正規化では不十分です。 そのような場合は、 normalize-* ディレクティブを使用してカスタム正規化ルールを指定できます。例:

//@ 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\)"

これは、32 ビットプラットフォームでは、コンパイラが stderr に fn() (32 bits) を書き込むたびに、代わりに fn() ($PTR bits) と読めるよう正規化する必要があることをテストに伝えます。 64 ビットについても同様です。 置換は、regex クレートが提供するデフォルトの正規表現フレーバーを使用する正規表現によって実行されます。

対応する参照ファイルは、正規化された出力を使用して 32 ビットプラットフォームと 64 ビットプラットフォームの両方をテストします。

...
   |
   = note: source type: fn() ($PTR bits)
   = note: target type: u16 (16 bits)
...

具体的な使用例については、ui/transmute/main.rsmain.stderr を参照してください。

エラーアノテーション

エラーアノテーションは、コンパイラが出力すると期待されるエラーを指定します。 これらは、エラーが位置するソース内の行に「関連付け」られます。

fn main() {
    boom  //~ ERROR このスコープに値 `boom` が見つかりません [E0425]
}

UI テストにはコンパイラ出力全体を含む .stderr ファイルがありますが、 UI テストでは、エラーがソース内にもアノテーションされている必要があります。 この冗長性は、.stderr ファイルが通常 自動生成されるため、ミスを避けるのに役立ちます。 また、.stderr ファイルとソースを比較しなくても、1 つのファイルを見るだけで、 エラーのスパンがどこを指すと期待されるかを直接確認するのにも役立ちます。 最後に、追加の予期しないエラーが生成されないことを保証します。

これらにはいくつかの形式がありますが、一般的には診断レベル (ERROR など)と、期待されるエラー出力の部分文字列を含むコメントです。 メッセージ全体を書き出す必要はありませんが、 自己説明的になるよう、メッセージの重要な部分を必ず含めてください。

ほとんどのエラーアノテーションは、診断の行と一致する必要があります。 メッセージを行と一致させる方法はいくつかあります(以下の例を参照してください)。

  • ~: エラーレベルとメッセージを現在の行に関連付けます
  • ~^: エラーレベルとメッセージを直前のエラーアノテーション行に関連付けます。 追加するキャレット(^)ごとに 1 行ずつ加算されるため、~^^^ は エラーアノテーション行の 3 行上を意味します。
  • ~|: エラーレベルとメッセージを、直前のコメント同じ行に関連付けます。これは、同じ行に関連付けられたメッセージが 複数ある場合に、複数のキャレットを使用するより便利です。
  • ~v: エラーレベルとメッセージを次のエラーアノテーション行に関連付けます。 追加する記号(v)ごとに 1 行ずつ加算されるため、~vvv は エラーアノテーション行の 3 行下を意味します。

例:

let _ = same_line; //~ ERROR 未宣言の変数
fn meow(_: [u8]) {}
//~^ ERROR サイズ不定
//~| ERROR 無名パラメーター

//~(または他のバリアント)と後続のテキストの間の空白文字は 無視できます(つまり、//~ ERROR//~ERROR の間に意味上の違いはありませんが、 コードベースでは前者の方が一般的です)。

~? <diagnostic kind>(例: ~? ERROR)は、 行情報がまったくない診断、または行情報がメインのテストファイル1 の外側にある診断を一致させるために使用されます。 これらのアノテーションは、テストファイル内の任意の行に配置できます。

エラーアノテーションの例

以下は、UI テストソースの異なる行にあるエラーアノテーションの例です。

エラー行に配置

//~ ERROR イディオムを使用します。

fn main() {
    let x = (1, 2, 3);
    match x {
        (_a, _x @ ..) => {} //~ ERROR `_x @` はタプル内では許可されていません
        _ => {}
    }
}

エラー行の下に配置

上の行数を示すために、文字列内のキャレット数を指定して //~^ イディオムを使用します。 以下の例では、エラー行は エラーアノテーション行の 4 行上にあるため、アノテーションには 4 つのキャレットが含まれています。

fn main() {
    let x = (1, 2, 3);
    match x {
        (_a, _x @ ..) => {}  // <- エラーはこの行にあります
        _ => {}
    }
}
//~^^^^ ERROR `_x @` はタプル内では許可されていません

上のエラーアノテーション行で定義されたものと同じエラー行を使用

上のエラーアノテーション行と同じエラー行を定義するには、 //~| イディオムを使用します。

struct Binder(i32, i32, i32);

fn main() {
    let x = Binder(1, 2, 3);
    match x {
        Binder(_a, _x @ ..) => {}  // <- エラーはこの行にあります
        _ => {}
    }
}
//~^^^^ ERROR `_x @` はタプル構造体内では許可されていません
//~| ERROR このパターンには 1 個のフィールドがありますが、対応するタプル構造体には 3 個のフィールドがあります [E0023]

エラー行の上に配置

下の行数を示すために、文字列内の v の数を指定して //~v イディオムを使用します。 これは通常、ファイル末尾で発生する閉じられていない区切り文字や 閉じられていないリテラルのようなエラーに一致する lexer または parser テストで使用されます。

// ignore-tidy-trailing-newlines
//~v ERROR このファイルには閉じられていない区切り文字があります
fn main((ؼ

行情報のないエラー

行情報のないエラーに一致させるには、//~? を使用します。 //~? は精密であり、行情報が利用可能なエラーには一致しません。 コンパイラ診断に対して一致させたいテストでは、 //@ error-pattern は不正確で網羅的ではないため、これよりも //~? を優先すべきです。

//@ compile-flags: --print yyyy

//~? ERROR 不明な print 要求: `yyyy`

error-pattern

error-pattern ディレクティブ は、特定のスパンを持たない実行時メッセージや、 例外的な場合にはコンパイル時メッセージに使用できます。

このテストについて考えてみましょう。

fn main() {
    let a: *const [_] = &[1, 2, 3];
    unsafe {
        let _b = (*a)[3];
    }
}

これが「インデックスが範囲外」を表示することを保証したいものの、実行時エラーにはスパンがないため、 ERROR アノテーションを使用することはできません。 その場合は、error-pattern ディレクティブを使用します。

//@ error-pattern: インデックスが範囲外
fn main() {
    let a: *const [_] = &[1, 2, 3];
    unsafe {
        let _b = (*a)[3];
    }
}

コンパイル時出力を厳密にテストするには、スパンのない診断に対する //~? アノテーションを含め、 可能な限り行アノテーション //~ を使用するようにしてください。 コンパイル時の出力がターゲット依存である、または冗長すぎる場合は、ディレクティブ //@ dont-require-annotations: <diagnostic-kind> を使用して、行アノテーションのチェックを 網羅的でないものにします。 このモードでは、コンパイラーメッセージの一部がアノテーションでカバーされないままでもかまいません。

実行時出力をチェックする場合は、//@ check-run-results の方が望ましい場合があります。

error-pattern は、上記のいずれもうまくいかない場合にのみ使用してください。たとえば、実行時のパニック出力に含まれる 特定の文字列パターンを探す場合などです。

行アノテーション //~error-pattern は互換性があり、同じテスト内で使用できます。

診断の種類(エラーレベル)

使用できる診断の種類は次のとおりです。

  • ERROR
  • WARN(または WARNING
  • NOTE
  • HELP
  • SUGGESTION
  • RAW

SUGGESTION 種類は、診断の提案に対して期待される置換テキストを指定するために使用されます。 RAW 種類は、構造化 JSON の代わりに、またはそれに加えて、コンパイラーによって出力されることがある非構造化出力の行にマッチさせるために使用できます。

ERRORWARN 種類は、デフォルトで行アノテーション //~ によって網羅的にカバーされている必要があります。

他の種類は、その種類のアノテーションがテストファイル内に少なくとも 1 つ現れる場合にのみ、行アノテーションが必要です。 たとえば、//~ NOTE が 1 つあると、ファイル内の他のすべての //~ NOTE も 明示的に書き出す必要があります。

網羅的なアノテーションを無効にするには、ディレクティブ //@ dont-require-annotations を使用します。 たとえば、ノートを選択的にアノテーションするには //@ dont-require-annotations: NOTE を使用します。 ターゲット依存のコンパイラー出力のような重大な理由がない限り、このディレクティブを ERRORWARN に使用するのは避けてください。

一部の診断は、その種類やディレクティブに関係なく、行アノテーションが必要になることはありません。 例としては、複数行診断の副次的な行や、 aborting due to N previous errors のような一般的な診断があります。

UI テストは、未使用警告をすべて無視するために、デフォルトで -A unused フラグを使用します。これは、 未使用警告が通常テストの焦点ではないためです。 ただし、単純なコードサンプルでは未使用警告が発生することがよくあります。 テストが特に 未使用警告をテストしている場合は、必要に応じて適切な #![warn(unused)] 属性を追加してください。

cfg リビジョン

リビジョンを使用する場合、現在のリビジョンに基づいて異なるメッセージを 条件付きでチェックできます。 これは、次のようにリビジョンの cfg 名を角括弧内に配置することで行います。

//@ edition:2018
//@ revisions: mir thir
//@[thir] compile-flags: -Z thir-unsafeck

async unsafe fn f() {}

async fn g() {
    f(); //~ ERROR unsafe 関数の呼び出しは unsafe です
}

fn main() {
    f(); //[mir]~ ERROR unsafe 関数の呼び出しは unsafe です
}

この例では、2 番目のエラーメッセージは mir リビジョンでのみ出力されます。 thir リビジョンでは最初のエラーのみが出力されます。

cfg によってコンパイラーが異なる出力を生成する場合、テストは異なる出力に対応する 複数の .stderr ファイルを持つことができます。 上記の例では、異なるリビジョンの異なる出力を含む .mir.stderr ファイルと .thir.stderr ファイルが存在することになります。

注: cfg リビジョンは、ソースコード内の #[cfg] 属性でも機能します。

慣例として、常に偽となる設定を持たせるために FALSE cfg が使用されます。

合格/不合格の期待値を制御する

デフォルトでは、UI テストは コンパイルエラーを生成する ことが期待されます。これは、ほとんどの テストが無効な入力とエラー診断をチェックしているためです。 ただし、コンパイルが成功することを期待する UI テストを作成することもでき、さらに結果のプログラムを 実行することもできます。 次のディレクティブのいずれかを追加してください。

  • 合格ディレクティブ:
    • //@ check-pass — コンパイルは成功する必要がありますが、codegen はスキップします (これはコストが高く、ほとんどの場合失敗するはずがないためです)。
    • //@ build-pass — コンパイルとリンクは成功する必要がありますが、 結果のバイナリは実行しません。
    • //@ run-pass — コンパイルは成功する必要があり、結果の バイナリを実行すると、成功を示すコード 0 で終了する必要があります。
  • 不合格ディレクティブ:
    • //@ check-fail — コンパイルは失敗する必要があります(codegen フェーズはスキップされます)。 これは UI テストのデフォルトです。
    • //@ build-fail — コンパイルは codegen フェーズ中に失敗する必要があります。 これにより rustc が 2 回実行されます。
      • 1 回目は、codegen フェーズなしでコンパイルが成功することを確認するためです
      • 2 回目は、完全なコンパイルが失敗することを確認するためです
    • //@ run-fail — コンパイルは成功する必要がありますが、結果の バイナリを実行すると、通常の失敗を示す範囲 1..=127 のコードで 終了する必要があります。 unwind サポートのないターゲットでは、クラッシュも受け入れられます。
    • //@ run-crash — コンパイルは成功する必要がありますが、結果の バイナリを実行するとクラッシュして失敗する必要があります。 クラッシュは「範囲 0..=127 のコードで終了しないこと」と定義されます。
      • Linux での例: SIGABRT または SIGSEGV による終了。
      • Windows での例: STATUS_ILLEGAL_INSTRUCTION0xC000001D)のコードで終了。
    • //@ run-fail-or-crash — コンパイルは成功する必要がありますが、結果の バイナリを実行すると、run-fail または run-crash のいずれかになる必要があります。 一部のターゲットではテストがクラッシュするが、他のターゲットでは単に失敗する場合に便利です。

run-passrun-failrun-crash、および run-fail-or-crash テストでは、 プログラム自体の出力はデフォルトではチェックされません。

プログラムの実行出力をチェックしたい場合は、check-run-results ディレクティブを含めてください。 これにより、プログラムの実際の出力と比較するための .run.stderr および .run.stdout ファイルがチェックされます。

*-pass ディレクティブを持つテストは、--pass コマンドラインオプションで上書きできます。

./x test tests/ui --pass check

--pass オプションは UI テストにのみ影響します。 --pass check を使用すると、UI テストスイートをはるかに高速に実行できます(私のシステムではおよそ 2 倍高速です)が、当然ながら それほど多くの部分は実行されません。

その上書きではテストが正しく動作しない場合、--pass CLI フラグを無視するために no-pass-override ディレクティブを使用できます。

既知のバグ

known-bug ディレクティブは、まだ修正されていない既知のバグを示すテストに使用できます。 既知のバグに対するテストを追加することは、次のような複数の理由で有用です。

  1. バグが修正されたときに便利に再利用できる機能テストを維持する。
  2. バグが偶然修正された場合に失敗する番兵を提供する。 これにより開発者に通知され、関連する issue が修正されたことを把握でき、 場合によってはクローズできます。

このディレクティブは、カンマ区切りの issue 番号を引数として取るか、"unknown" を取ります。

  • //@ known-bug: #123, #456(issue が rust-lang/rust 上にある場合)
  • //@ known-bug: rust-lang/chalk#123456# の前に任意のテキストを許可します。これは issue が別のリポジトリにある場合に便利です)
  • //@ known-bug: unknown (既知の issue がまだない場合。存在しない場合は、開くことが望ましいです)

known-bug を含むテストには、エラーアノテーションを含めないでください。 テストには、他の通常のディレクティブと stdout/stderr ファイルは引き続き含める必要があります。

テストの編成

テストファイルを配置する場所を決めるときは、実行しようとしている内容に 最も一致するサブディレクトリを探すようにしてください。 できるだけ整理された状態を保つよう努めてください。 確かに、一部のテストは複数のカテゴリにまたがる場合があり、 既存のレイアウトがうまく合わないこともあるため、難しい場合があります。

テストには、そのテストが何をチェックしているかを簡潔に説明する名前を付けてください。 テスト名に issue 番号を含めることは避けてください。 これについてより詳しい説明は、ベストプラクティスを参照してください。

理想的には、そのテストでどのコードがテストされているかを識別しやすくする ディレクトリにテストを追加するべきです(例: tests/ui/borrowck/reject-move-out-of-borrow-via-pat.rs

新しい機能を書くときは、テストを保存するサブディレクトリを作成することを検討してもよいでしょう。 たとえば、RFC 1234(“Widgets”)を実装している場合は、 tests/ui/rfc1234-widgets/ のようなディレクトリにテストを配置するのが理にかなっているかもしれません。

別の場合には、すでに適切なディレクトリが存在していることもあります。

時間の経過とともに、tests/ui ディレクトリは非常に速く成長してきました。 tidy には、どのサブディレクトリも 1000 個を超えるエントリを持たないことを 保証するチェックがあります。 ファイルが多すぎると、エディタ/IDE に優しくなく、 GitHub UI も 1000 個を超えるエントリを表示しないため、問題が発生します。 ただし、tests/ui(UI テストのルートディレクトリ)と tests/ui/issues ディレクトリには 1000 個を超えるエントリがあるため、これらのディレクトリには別の上限を設定しています。 そのため、そこに新しいテストを置くことは避け、より関連性の高い場所を探すようにしてください。

たとえば、テストがクロージャに関連している場合は、tests/ui/closures に配置するべきです。 上限に達した場合は、ここを調整することで上限を増やすことができます。

Rustfix テスト

UI テストでは、診断の提案が正しく適用されること、および 結果の変更が正しくコンパイルされることを検証できます。 これは run-rustfix ディレクティブで行えます。

//@ run-rustfix
//@ check-pass
#![crate_type = "lib"]

pub struct not_camel_case {}
//~^ WARN `not_camel_case` はアッパーキャメルケースの名前にするべきです
//~| HELP 識別子をアッパーキャメルケースに変換してください
//~| SUGGESTION NotCamelCase

Rustfix テストには、提案が適用された後のソースファイルを含む .fixed 拡張子のファイルが必要です。

  • テストが実行されると、compiletest はまず正しい lint/警告が生成されることをチェックします。
  • 次に、提案を適用して .fixed と比較します(一致している必要があります)。
  • 最後に、修正済みソースがコンパイルされ、このコンパイルは成功する必要があります。

通常、rustfix テストを作成するときは、x test --bless オプションで .fixed ファイルを自動生成します。

run-rustfix ディレクティブは、たとえそれらが MachineApplicable でなくても、すべての提案を適用します。 これが問題になる場合は、run-rustfix に加えて rustfix-only-machine-applicable ディレクティブを追加できます。 これは、異なる提案レベルが混在しており、 機械的に適用可能ではないものの一部がきれいに適用されない場合に使用するべきです。

比較モード

比較モードは、通常コンパイルされるときとは 異なるフラグで全テストを実行するために使用できます。 場合によっては、これによりコンパイラから異なる出力が生成されることがあります。 これをサポートするために、比較モードに基づく出力を含む 異なる出力ファイルを保存できます。

たとえば、Polonius モードを使用している場合、テスト foo.rs はまず 期待される出力を foo.polonius.stderr で探し、見つからない場合は通常の foo.stderr にフォールバックします。 これは、異なるモードによって異なる診断や動作が生じることがあるため便利です。 これにより、モード間で差分があるテストを追跡し、 それらの診断の違いを視覚的に確認しやすくなります。

まれに、動作が異なるテストに遭遇した場合は、 代替の stderr ファイルを生成するために、次のようなものを実行できます。

./x test tests/ui --compare-mode=polonius --bless

現在、UI テストについては CI でチェックされている比較モードはありません。

rustc_* TEST 属性

コンパイラは、内部機能 rustc_attrs によってゲートされる、 追加のコンパイラ内部情報をダンプする perma-unstable な #[rustc_*] 属性をいくつか定義しています。 詳細については、コンパイラのデバッグの対応するサブセクションを参照してください。

これらは、通常なら「ユーザー向け」の Rust だけで同じことを行うのが非常に難しい場合に、 内部コンパイラ状態をより正確に、読みやすく、簡単にテストするために使用できます。 実際、これは「UI」(ユーザーインターフェイス)という用語をわずかに悪用し、 そのような UI テストをブラックボックステストからホワイトボックステストに変えるものだと言えるでしょう。 慎重かつ控えめに使用してください。

UI テストモードでプリセットされる lint レベル

デフォルトでは、UI テストモード配下のテストスイート(tests/uitests/ui-fulldeps、 ただし tests/rustdoc-ui は除く)は、次を指定します。

  • -A unused
  • -W unused_attributes(これらは ui テストにとって関心の対象になりやすいため)
  • -A internal_features
  • -A incomplete_features
  • -A unused_parens
  • -A unused_braces

詳細については、runtestを参照してください。

条件は次のとおりです。

  • ui テストの pass モードが run 未満である(つまり check または build)。
  • 比較モードが指定されていない。

これは、ui テストでは非常にノイズが多くなる可能性があるためです。

必要に応じて、compile-flags の lint レベルフラグや ソース内の lint レベル属性でこれらを上書きできます。

なお、rustfix バージョンには -A unused が渡されないため、 rustfix 済みファイルで unused lint を抑制するには、#[allow(unused)] が必要になる場合があります (unused lint 自体に対して rustfix をテストしている可能性があるためです)。


  1. これは、aux ファイルや、こちらで制御できないソースとは異なる、~? アノテーションを持つファイルです。