@@ -42,10 +42,13 @@ cases like `#[test]` (both the built-in one and quickcheck), `#[bench]` (both bu
42
42
ones like [ criterion] ), ` examples ` , and things like fuzzing. While we may not necessarily rewrite
43
43
the built in test/bench/example infra in terms of the new framework, it should be possible to do so.
44
44
45
- The main two problems that we need to solve are:
45
+ The main two features proposed are:
46
46
47
- - Having a nice API for generating custom post-build binaries
48
- - Having good ` cargo ` integration so that custom tests are at the same level of integration as regular tests as far as build processes are concerned
47
+ - An API for crates that generate custom binaries, including
48
+ introspection into the target crate.
49
+ - A mechanism for ` cargo ` integration so that custom post-build
50
+ contexts are at the same level of integration as ` test ` or ` bench ` as
51
+ far as build processes are concerned.
49
52
50
53
[ cargo-fuzz ] : https://github.com/rust-fuzz/cargo-fuzz
51
54
[ criterion ] : https://github.com/japaric/criterion.rs
@@ -63,15 +66,16 @@ A custom post-build context is essentially a whole-crate procedural
63
66
macro that is evaluated after all other macros in the target crate have
64
67
been evaluated. It is passed the ` TokenStream ` for every element in the
65
68
target crate that has a set of attributes the post-build context has
66
- registered interest in. Essentially:
69
+ registered interest in. For example, to declare a post-build context
70
+ called ` mytest ` :
67
71
68
72
``` rust
69
73
extern crate proc_macro;
70
74
use proc_macro :: TokenStream ;
71
75
72
76
// attributes() is optional
73
- #[post_build_context(test, attributes(foo, bar))]
74
- pub fn like_todays_test (items : & [AnnotatedItem ]) -> TokenStream {
77
+ #[post_build_context(attributes(foo, bar))]
78
+ pub fn mytest (items : & [AnnotatedItem ]) -> TokenStream {
75
79
// ...
76
80
}
77
81
```
@@ -87,24 +91,28 @@ struct AnnotatedItem
87
91
}
88
92
```
89
93
90
- ` items ` here contains an ` AnnotatedItem ` for every element in the
94
+ ` items ` here contains an ` AnnotatedItem ` for every item in the
91
95
target crate that has one of the attributes declared in ` attributes `
92
- along with attributes sharing the name of the context (` test ` , here).
96
+ along with attributes sharing the name of the context (` mytest ` , here).
93
97
94
98
A post-build context could declare that it reacts to multiple different
95
99
attributes, in which case it would get all items with any of the
96
100
listed attributes. These items be modules, functions, structs,
97
101
statics, or whatever else the post-build context wants to support. Note
98
102
that the post-build context function can only see all the annotated
99
103
items, not modify them; modification would have to happen with regular
100
- procedural macros The returned ` TokenStream ` will become the ` main() `
101
- when this post-build context is used.
104
+ procedural macros. The returned ` TokenStream ` must declare the ` main() `
105
+ that is to become the entry-point for the binary produced when this
106
+ post-build context is used.
102
107
103
108
Because this procedural macro is only loaded when it is used as the
104
- post-build context, the ` #[test] ` annotation should probably be kept
105
- behind ` #[cfg(test)] ` so that you don't get unknown attribute warnings
106
- whilst loading. (We could change this by asking attributes to be
107
- registered in Cargo.toml, but we don't find this necessary)
109
+ post-build context, the ` #[mytest] ` annotation should probably be kept
110
+ behind ` #[cfg(mytest)] ` (which is automatically set when the ` mytest `
111
+ context is used) so that you don't get unknown attribute warnings
112
+ whilst loading, and to avoid conflicts with other post-build contexts
113
+ that may use the same attributes. (We could change this by asking
114
+ attributes to be registered in Cargo.toml, but we don't find this
115
+ necessary)
108
116
109
117
## Cargo integration
110
118
@@ -118,87 +126,76 @@ these are named according to the name of their `#[post_build_context]`
118
126
function.
119
127
120
128
Crates which define a post-build context must have an ` post-build-context = true `
121
- key.
129
+ key in their ` Cargo.toml ` . It can also specify
122
130
123
- For crates that wish to * use* a custom post-build context, they do so by
124
- defining a new post-build context under a new ` post-build ` section in
125
- their ` Cargo.toml ` :
131
+ ``` rust
132
+ single - target = true # false by default
133
+ ```
134
+
135
+ ` single-target ` indicates that only a single target can be run with this
136
+ context at once (some tools, like cargo-fuzz, run forever, and so it
137
+ does not make sense to specify multiple targets).
138
+
139
+ Crates that wish to * use* a custom post-build context, do so by defining
140
+ a new post-build context under a new ` build-context ` section in their
141
+ ` Cargo.toml ` :
126
142
127
143
``` toml
128
144
[post-build .context .fuzz ]
129
145
provider = { rust-fuzz = " 1.0" }
130
- folder = " fuzz/"
131
- specify-single-target = true # false by default
146
+ folders = [" fuzz/" ]
132
147
```
133
148
134
- This defines a post-build context named ` fuzz ` , which uses the
149
+ This defines an post-build context named ` fuzz ` , which uses the
135
150
implementation provided by the ` rust-fuzz ` crate. When run, it will be
136
- applies to all files in the ` fuzz ` directory. ` specify-single-target `
137
- addresses whether it must be run with a single target. If true, you will
138
- be forced to run ` cargo post-build foobar --test foo ` . This is useful for cases
139
- like ` cargo-fuzz ` where running tests on everything isn't possible.
140
-
141
- By default, the following contexts are defined:
151
+ applied to all files in the ` fuzz ` directory. By default, the following
152
+ contexts are defined:
142
153
143
154
``` toml
144
155
[post-build .context .test ]
145
156
provider = { test = " 1.0" , context = " test" }
146
- folder = " tests/"
157
+ folders = [ " tests/" ]
147
158
148
159
[post-build .context .bench ]
149
160
provider = { test = " 1.0" , context = " bench" }
150
- folder = [" benchmarks/ " , " morebenchmarks /" ]
161
+ folders = [" benchmarks/" ]
151
162
```
152
163
164
+ There's also an ` example ` context defined that just runs the ` main() ` of
165
+ any files given.
166
+
153
167
These can be overridden by a crate's ` Cargo.toml ` . The ` context `
154
168
property is used to disambiguate when a single crate has multiple
155
169
functions tagged ` #[post_build_context] ` (if we were using the example
156
- post-build provider further up, we'd give ` like_todays_test ` here).
170
+ post-build context further up as a provider , we'd give ` mytest ` here).
157
171
` test ` here is ` libtest ` , though note that it could be maintained
158
172
out-of-tree, and shipped with rustup.
159
173
160
- To invoke a particular post-build context, a user invokes `cargo post-build
174
+ To invoke a particular post-build context, a user invokes `cargo context
161
175
<context >` . ` cargo test` and ` cargo bench` are aliases for ` cargo
162
- post-build test` and ` cargo post-build bench` respectively. Any additional
176
+ context test` and ` cargo context bench` respectively. Any additional
163
177
arguments are passed to the post-build context binary. By convention, the
164
- first position argument should allow filtering which
165
- test/benchmarks/etc. are run.
166
-
167
-
168
- By default, the crate has an implicit "test", "bench", and "example" context that use the default libtest stuff.
169
- (example is a no-op context that just runs stuff). However, declaring a context with the name ` test `
170
- will replace the existing ` test ` context. In case you wish to supplement the context, use a different
171
- name.
178
+ first position argument should allow filtering which targets
179
+ (tests/benchmarks/etc.) are run.
172
180
173
- By default, ` cargo test ` will run doctests and the ` test ` and ` examples ` context. This can be customized:
181
+ To run multiple contexts at once, a crate can declare post-build context
182
+ * sets* . One such example is the ` test ` post-build context set, which
183
+ will run doctests and the ` test ` and ` examples ` context. This can be
184
+ customized:
174
185
175
186
``` toml
176
187
[post-build .set .test ]
177
188
contexts = [test, quickcheck, examples]
178
189
```
179
190
180
- This means that `cargo test` will, aside from doctests, run `cargo post-build test`, `cargo post-build quickcheck`,
181
- and `cargo post-build examples` (and similar stuff for `cargo bench`). It is not possible to make `cargo test`
182
- _not_ run doctests.
183
-
184
- There are currently only two custom post-build sets (test and bench).
185
-
186
- Custom test targets can be declared via `[[post-build.target]]`
187
-
188
- ```toml
189
- [[post-build.target]]
190
- context = fuzz
191
- path = " foo.rs"
192
- name = "foo"
193
- ```
194
-
195
- `[[test]]` is an alias for `[[post-build.target]] context = test` (same goes for `[[bench]]` and `[[example]]`).
196
-
197
-
198
- The generated test binary should be able to take one identifier argument, used for narrowing down what tests to run.
199
- I.e. `cargo test --kind quickcheck my_test_fn` will build the test(s) and call them with `./testbinary my_test_fn`.
200
- Typically, this argument is used to filter tests further; test harnesses should try to use it for the same purpose.
191
+ This means that `cargo test` will, aside from doctests, run `cargo
192
+ context test`, `cargo context quickcheck`, and `cargo context examples`
193
+ (and similar stuff for `cargo bench`). It is not possible to make `cargo
194
+ test` _not_ run doctests. If both a context and a set exists with a
195
+ given name, the set takes precedence.
201
196
197
+ `[[test]]` and `[[example]]` in a crate's `Cargo.toml` add files to the
198
+ `test` and `example` contexts respectively.
202
199
203
200
# # To be designed
204
201
@@ -213,11 +210,6 @@ like json output and whatnot.
213
210
214
211
@killercup is working on a proposal for this which I will try to work in.
215
212
216
- # ## Configuration
217
-
218
- Currently we have `cfg(test)` and `cfg(bench)`. Should `cfg(test)` be applied to all? Should `cfg(nameofharness)`
219
- be used instead? Ideally we'd have a way when declaring a framework to declare what cfgs it should be built with.
220
-
221
213
# Drawbacks
222
214
[drawbacks]: # drawbacks
223
215
@@ -231,15 +223,18 @@ be used instead? Ideally we'd have a way when declaring a framework to declare w
231
223
# Rationale and alternatives
232
224
[alternatives]: # alternatives
233
225
234
- We should either do this or stabilize the existing bencher.
226
+ We could stabilize `#[bench]` and extend libtest with setup/teardown and
227
+ other requested features. This would complicate the in-tree libtest,
228
+ introduce a barrier for community contributions, and discourage other
229
+ forms of testing or benchmarking.
235
230
236
231
# # Alternative procedural macro
237
232
238
233
An alternative proposal was to expose an extremely general whole-crate proc macro:
239
234
240
235
```rust
241
- # [post_build_context(test, attributes(foo, bar))]
242
- pub fn context (crate: TokenStream) -> TokenStream {
236
+ # [post_build_context(attributes(foo, bar))]
237
+ pub fn mytest (crate: TokenStream) -> TokenStream {
243
238
// ...
244
239
}
245
240
```
@@ -264,7 +259,7 @@ It also lets crates like `cargo-fuzz` introduce things like a `#![no_main]` attr
264
259
other antics.
265
260
266
261
Finally, it handles the "profiling framework" case as mentioned in the motivation. On the other hand,
267
- these tools usually operate at a differeny layer of abstraction so it might not be necessary.
262
+ these tools usually operate at a different layer of abstraction so it might not be necessary.
268
263
269
264
A major drawback of this proposal is that it is very general, and perhaps too powerful. We're currently using the
270
265
more focused API in the eRFC, and may switch to this during experimentation if a pressing need crops up.
@@ -304,9 +299,9 @@ there's consensus on some of these we can move them into the main RFC.
304
299
305
300
Documentation tests are somewhat special, in that they cannot easily be
306
301
expressed as `TokenStream` manipulations. In the first instance, the
307
- right thing to do is probably to have an implicitly defined execution
308
- context called `doctest` which is included in the execution context set
309
- `test` by default.
302
+ right thing to do is probably to have an implicitly defined post-build
303
+ context called `doctest` which is included in the post-build context set
304
+ `test` by default (as proposed above) .
310
305
311
306
Another argument for punting on doctests is that they are intended to
312
307
demonstrate code that the user of a library would write. They're there
@@ -317,12 +312,12 @@ less sense to have different "ways" of running them.
317
312
318
313
Today, `cargo test` takes a number of flags such as `--lib`, `--test
319
314
foo`, and `--doc`. As it would be a breaking change to change these,
320
- cargo should recognize them and map to the appropriate execution
315
+ cargo should recognize them and map to the appropriate post-build
321
316
contexts.
322
317
323
- Currently , `cargo test` lets you pick a single testing target via `--test`,
318
+ Furthermore , `cargo test` lets you pick a single testing target via `--test`,
324
319
and `cargo bench` via `--bench`. We'll need to create an agnostic flag
325
- for `cargo post-build ` (we cannot use `--target` because it is already used for
320
+ for `cargo context ` (we cannot use `--target` because it is already used for
326
321
the target architecture, and `--test` is too specific for tests). `--post-build-target`
327
322
is one rather verbose suggestion.
328
323
@@ -333,30 +328,31 @@ stuff so that if test harnesses desire, they can use the same output
333
328
formatting as a regular test. This also provides a centralized location
334
329
to standardize things like json output and whatnot.
335
330
336
- # # Configuration
331
+ # # Namespacing
337
332
338
- Currently we have `cfg(test)` and `cfg(bench)`. Should `cfg(test)` be
339
- applied to all? Should `cfg(post_build_context)` be used instead?
340
- Ideally we'd have a way when declaring a post-build context to declare
341
- what cfgs it should be built with.
333
+ Currently, two post-build contexts can both declare interest in the same
334
+ attributes. How do we deal with collisions (e.g., most test crates will
335
+ want the attribute `#[test]`). Do we namespace the attributes by the
336
+ context name (e.g., `#[mytest::test]`)? Do we require them to be behind
337
+ `#[cfg(mytest)]`?
342
338
343
339
# # Runtime dependencies and flags
344
340
345
- The generated harness itself may have some dependencies. Currently there's
346
- no way for the post-build context to specify this. One proposal is for the crate
347
- to specify _runtime_ dependencies of the post-build context via:
341
+ The code generated by the post-build context may itself have dependencies.
342
+ Currently there's no way for the post-build context to specify this. One
343
+ proposal is for the crate to specify _runtime_ dependencies of the
344
+ post-build context via:
348
345
349
346
```toml
350
- [post-build. dependencies]
347
+ [context- dependencies]
351
348
libfuzzer-sys = ...
352
349
```
353
350
354
- If a crate is currently running this post-build context, its dev-dependencies
355
- will be semver-merged with the post-build-context.dependencies.
356
-
357
- However, this may not be strictly necessary. Custom derives have
358
- a similar problem and they solve it by just asking users to import the correct
359
- crate and keep it in their dev-dependencies.
351
+ If a crate is currently running this post-build context, its
352
+ dev-dependencies will be semver-merged with the post-build context's
353
+ `context-dependencies`. However, this may not be strictly necessary.
354
+ Custom derives have a similar problem and they solve it by just asking
355
+ users to import the correct crate.
360
356
361
357
# # Naming
362
358
@@ -378,7 +374,7 @@ This could be done in the Cargo.toml as:
378
374
379
375
```toml
380
376
[post-build.defaults]
381
- folder = "tests/"
377
+ folders = [ "tests/"]
382
378
set = "test" # will automatically be added to the `test` set
383
379
```
384
380
@@ -393,21 +389,5 @@ If this RFC lands and [RFC 2287] is rejected, we should probably try to stabiliz
393
389
`test::black_box` in some form (maybe `mem::black_box` and `mem::clobber` as detailed
394
390
in [this amendment]).
395
391
396
-
397
-
398
392
[RFC 2287]: https://github.com/rust-lang/rfcs/pull/2287
399
393
[this amendment]: https://github.com/Manishearth/rfcs/pull/1
400
-
401
- # # Specify-single-target
402
-
403
- `specify-single-target = true` probably should be specified by the execution context itself, not the
404
- consumer. It's also questionable if it's necessary -- cargo-fuzz is going to need a wrapper script
405
- anyway, so it's fine if the CLI isn't as ergonomic for that use case.
406
-
407
- If we do `post-build.defaults` it would just make sense to include that there.
408
-
409
-
410
-
411
-
412
-
413
-
0 commit comments