22
33<!-- toc -->
44
5- Today, Rust programmers rely on a built in attribute called ` #[test] ` . All
6- you have to do is mark a function as a test and include some asserts like so:
5+ Many Rust programmers rely on a built- in attribute called ` #[test] ` . All
6+ you have to do is mark a function and include some asserts like so:
77
88``` rust,ignore
99#[test]
@@ -35,14 +35,14 @@ How does any sort of `main` function invoke these tests if they're not visible?
3535What exactly is ` rustc --test ` doing?
3636
3737` #[test] ` is implemented as a syntactic transformation inside the compiler's
38- [ ` rustc_ast ` crate ] [ rustc_ast ] . Essentially, it's a fancy macro, that
38+ [ ` rustc_ast ` ] [ rustc_ast ] . Essentially, it's a fancy [ ` macro ` ] that
3939rewrites the crate in 3 steps:
4040
4141## Step 1: Re-Exporting
4242
4343As mentioned earlier, tests can exist inside private modules, so we need a
4444way of exposing them to the main function, without breaking any existing
45- code. To that end, ` rustc_ast ` will create local modules called
45+ code. To that end, [ ` rustc_ast ` ] [ rustc_ast ] will create local modules called
4646` __test_reexports ` that recursively reexport tests. This expansion translates
4747the above example into:
4848
@@ -68,22 +68,22 @@ test at `a::b::my_test` becomes
6868pretty safe, what happens if there is an existing ` __test_reexports ` module?
6969The answer: nothing.
7070
71- To explain, we need to understand [ how the AST represents
72- identifiers] [ Ident ] . The name of every function, variable, module, etc. is
73- not stored as a string, but rather as an opaque [ Symbol] [ Symbol ] which is
74- essentially an ID number for each identifier. The compiler keeps a separate
71+ To explain, we need to understand how Rust's [ Abstract Syntax Tree ] [ ast ]
72+ represents [ identifiers] [ Ident ] . The name of every function, variable, module,
73+ etc. is not stored as a string, but rather as an opaque [ Symbol] [ Symbol ] which
74+ is essentially an ID number for each identifier. The compiler keeps a separate
7575hashtable that allows us to recover the human-readable name of a Symbol when
7676necessary (such as when printing a syntax error). When the compiler generates
77- the ` __test_reexports ` module, it generates a new Symbol for the identifier,
78- so while the compiler-generated ` __test_reexports ` may share a name with your
79- hand-written one, it will not share a Symbol. This technique prevents name
80- collision during code generation and is the foundation of Rust's macro
81- hygiene.
77+ the ` __test_reexports ` module, it generates a new [ Symbol] [ Symbol ] for the
78+ identifier, so while the compiler-generated ` __test_reexports ` may share a name
79+ with your hand-written one, it will not share a [ Symbol] [ Symbol ] . This
80+ technique prevents name collision during code generation and is the foundation
81+ of Rust's [ ` macro ` ] hygiene.
8282
8383## Step 2: Harness Generation
8484
8585Now that our tests are accessible from the root of our crate, we need to do
86- something with them. ` rustc_ast ` generates a module like so:
86+ something with them using [ ` rustc_ast ` ] [ ast ] generates a module like so:
8787
8888``` rust,ignore
8989#[main]
@@ -93,14 +93,14 @@ pub fn main() {
9393}
9494```
9595
96- where ` path::to::test1 ` is a constant of type ` test::TestDescAndFn ` .
96+ Here ` path::to::test1 ` is a constant of type [ ` test::TestDescAndFn ` ] [ tdaf ] .
9797
9898While this transformation is simple, it gives us a lot of insight into how
9999tests are actually run. The tests are aggregated into an array and passed to
100100a test runner called ` test_main_static ` . We'll come back to exactly what
101- ` TestDescAndFn ` is, but for now, the key takeaway is that there is a crate
101+ [ ` TestDescAndFn ` ] [ tdaf ] is, but for now, the key takeaway is that there is a crate
102102called [ ` test ` ] [ test ] that is part of Rust core, that implements all of the
103- runtime for testing. ` test ` 's interface is unstable, so the only stable way
103+ runtime for testing. [ ` test ` ] [ test ] 's interface is unstable, so the only stable way
104104to interact with it is through the ` #[test] ` macro.
105105
106106## Step 3: Test Object Generation
@@ -119,12 +119,13 @@ fn foo() {
119119```
120120
121121This means our tests are more than just simple functions, they have
122- configuration information as well. ` test ` encodes this configuration data
123- into a struct called [ ` TestDesc ` ] [ TestDesc ] . For each test function in a
124- crate, ` rustc_ast ` will parse its attributes and generate a ` TestDesc `
125- instance. It then combines the ` TestDesc ` and test function into the
126- predictably named ` TestDescAndFn ` struct, that ` test_main_static ` operates
127- on. For a given test, the generated ` TestDescAndFn ` instance looks like so:
122+ configuration information as well. ` test ` encodes this configuration data into
123+ a ` struct ` called [ ` TestDesc ` ] . For each test function in a crate,
124+ [ ` rustc_ast ` ] [ rustc_ast ] will parse its attributes and generate a [ ` TestDesc ` ]
125+ instance. It then combines the [ ` TestDesc ` ] and test function into the
126+ predictably named [ ` TestDescAndFn ` ] [ tdaf ] ` struct ` , that [ ` test_main_static ` ]
127+ operates on.
128+ For a given test, the generated [ ` TestDescAndFn ` ] [ tdaf ] instance looks like so:
128129
129130``` rust,ignore
130131self::test::TestDescAndFn{
@@ -140,19 +141,23 @@ self::test::TestDescAndFn{
140141```
141142
142143Once we've constructed an array of these test objects, they're passed to the
143- test runner via the harness generated in step 2.
144+ test runner via the harness generated in Step 2.
144145
145146## Inspecting the generated code
146147
147- On nightly rust , there's an unstable flag called ` unpretty ` that you can use
148- to print out the module source after macro expansion:
148+ On ` nightly ` ` rustc ` , there's an unstable flag called ` unpretty ` that you can use
149+ to print out the module source after [ ` macro ` ] expansion:
149150
150151``` bash
151152$ rustc my_mod.rs -Z unpretty=hir
152153```
153154
154- [ test ] : https://doc.rust-lang.org/test/index.html
155- [ TestDesc ] : https://doc.rust-lang.org/test/struct.TestDesc.html
156- [ Symbol ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
155+ [ `macro` ] : ./macro-expansion.md
156+ [ ` TestDesc` ] : https://doc.rust-lang.org/test/struct.TestDesc.html
157+ [ ast ] : ./ast-validation.md
157158[ Ident ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html
158159[ rustc_ast ] : https://github.com/rust-lang/rust/tree/master/compiler/rustc_ast
160+ [ Symbol ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
161+ [ test ] : https://doc.rust-lang.org/test/index.html
162+ [ tdaf ] : https://doc.rust-lang.org/test/struct.TestDescAndFn.html
163+ [ `test_main_static` ] : https://doc.rust-lang.org/test/fn.test_main_static.html
0 commit comments