11
11
use std:: error:: Error ;
12
12
use std:: fs;
13
13
use std:: path:: Path ;
14
- use std:: process:: Command ;
14
+ use std:: process:: { Command , Output } ;
15
15
16
16
fn main ( ) {
17
17
if let Err ( e) = doit ( ) {
@@ -24,19 +24,18 @@ const SEPARATOR: &str = "///////////////////////////////////////////////////////
24
24
25
25
fn doit ( ) -> Result < ( ) , Box < dyn Error > > {
26
26
let filename = std:: env:: args ( )
27
- . skip ( 1 )
28
- . next ( )
27
+ . nth ( 1 )
29
28
. unwrap_or_else ( || "../src/reference/semver.md" . to_string ( ) ) ;
30
29
let contents = fs:: read_to_string ( filename) ?;
31
30
let mut lines = contents. lines ( ) . enumerate ( ) ;
32
31
33
32
loop {
34
33
// Find a rust block.
35
- let block_start = loop {
34
+ let ( block_start, run_program ) = loop {
36
35
match lines. next ( ) {
37
36
Some ( ( lineno, line) ) => {
38
37
if line. trim ( ) . starts_with ( "```rust" ) && !line. contains ( "skip" ) {
39
- break lineno + 1 ;
38
+ break ( lineno + 1 , line . contains ( "run-fail" ) ) ;
40
39
}
41
40
}
42
41
None => return Ok ( ( ) ) ,
@@ -83,12 +82,16 @@ fn doit() -> Result<(), Box<dyn Error>> {
83
82
} ;
84
83
let expect_success = parts[ 0 ] [ 0 ] . contains ( "MINOR" ) ;
85
84
println ! ( "Running test from line {}" , block_start) ;
86
- if let Err ( e) = run_test (
85
+
86
+ let result = run_test (
87
87
join ( parts[ 1 ] ) ,
88
88
join ( parts[ 2 ] ) ,
89
89
join ( parts[ 3 ] ) ,
90
90
expect_success,
91
- ) {
91
+ run_program,
92
+ ) ;
93
+
94
+ if let Err ( e) = result {
92
95
return Err ( format ! (
93
96
"test failed for example starting on line {}: {}" ,
94
97
block_start, e
@@ -105,15 +108,23 @@ fn run_test(
105
108
after : String ,
106
109
example : String ,
107
110
expect_success : bool ,
111
+ run_program : bool ,
108
112
) -> Result < ( ) , Box < dyn Error > > {
109
113
let tempdir = tempfile:: TempDir :: new ( ) ?;
110
114
let before_p = tempdir. path ( ) . join ( "before.rs" ) ;
111
115
let after_p = tempdir. path ( ) . join ( "after.rs" ) ;
112
116
let example_p = tempdir. path ( ) . join ( "example.rs" ) ;
113
- compile ( before, & before_p, CRATE_NAME , false , true ) ?;
114
- compile ( example. clone ( ) , & example_p, "example" , true , true ) ?;
115
- compile ( after, & after_p, CRATE_NAME , false , true ) ?;
116
- compile ( example, & example_p, "example" , true , expect_success) ?;
117
+
118
+ let check_fn = if run_program {
119
+ run_check
120
+ } else {
121
+ compile_check
122
+ } ;
123
+
124
+ compile_check ( before, & before_p, CRATE_NAME , false , true ) ?;
125
+ check_fn ( example. clone ( ) , & example_p, "example" , true , true ) ?;
126
+ compile_check ( after, & after_p, CRATE_NAME , false , true ) ?;
127
+ check_fn ( example, & example_p, "example" , true , expect_success) ?;
117
128
Ok ( ( ) )
118
129
}
119
130
@@ -127,34 +138,18 @@ fn check_formatting(path: &Path) -> Result<(), Box<dyn Error>> {
127
138
if !status. success ( ) {
128
139
return Err ( format ! ( "failed to run rustfmt: {}" , status) . into ( ) ) ;
129
140
}
130
- return Ok ( ( ) ) ;
131
- }
132
- Err ( e) => {
133
- return Err ( format ! ( "failed to run rustfmt: {}" , e) . into ( ) ) ;
141
+ Ok ( ( ) )
134
142
}
143
+ Err ( e) => Err ( format ! ( "failed to run rustfmt: {}" , e) . into ( ) ) ,
135
144
}
136
145
}
137
146
138
147
fn compile (
139
- mut contents : String ,
148
+ contents : & str ,
140
149
path : & Path ,
141
150
crate_name : & str ,
142
151
extern_path : bool ,
143
- expect_success : bool ,
144
- ) -> Result < ( ) , Box < dyn Error > > {
145
- // If the example has an error message, remove it so that it can be
146
- // compared with the actual output, and also to avoid issues with rustfmt
147
- // moving it around.
148
- let expected_error = match contents. find ( "// Error:" ) {
149
- Some ( index) => {
150
- let start = contents[ ..index] . rfind ( |ch| ch != ' ' ) . unwrap ( ) ;
151
- let end = contents[ index..] . find ( '\n' ) . unwrap ( ) ;
152
- let error = contents[ index + 9 ..index + end] . trim ( ) . to_string ( ) ;
153
- contents. replace_range ( start + 1 ..index + end, "" ) ;
154
- Some ( error)
155
- }
156
- None => None ,
157
- } ;
152
+ ) -> Result < Output , Box < dyn Error > > {
158
153
let crate_type = if contents. contains ( "fn main()" ) {
159
154
"bin"
160
155
} else {
@@ -166,7 +161,7 @@ fn compile(
166
161
let out_dir = path. parent ( ) . unwrap ( ) ;
167
162
let mut cmd = Command :: new ( "rustc" ) ;
168
163
cmd. args ( & [
169
- "--edition=2018 " ,
164
+ "--edition=2021 " ,
170
165
"--crate-type" ,
171
166
crate_type,
172
167
"--crate-name" ,
@@ -180,7 +175,32 @@ fn compile(
180
175
. arg ( format ! ( "{}={}" , CRATE_NAME , epath. display( ) ) ) ;
181
176
}
182
177
cmd. arg ( path) ;
183
- let output = cmd. output ( ) ?;
178
+ cmd. output ( ) . map_err ( Into :: into)
179
+ }
180
+
181
+ fn compile_check (
182
+ mut contents : String ,
183
+ path : & Path ,
184
+ crate_name : & str ,
185
+ extern_path : bool ,
186
+ expect_success : bool ,
187
+ ) -> Result < ( ) , Box < dyn Error > > {
188
+ // If the example has an error message, remove it so that it can be
189
+ // compared with the actual output, and also to avoid issues with rustfmt
190
+ // moving it around.
191
+ let expected_error = match contents. find ( "// Error:" ) {
192
+ Some ( index) => {
193
+ let start = contents[ ..index] . rfind ( |ch| ch != ' ' ) . unwrap ( ) ;
194
+ let end = contents[ index..] . find ( '\n' ) . unwrap ( ) ;
195
+ let error = contents[ index + 9 ..index + end] . trim ( ) . to_string ( ) ;
196
+ contents. replace_range ( start + 1 ..index + end, "" ) ;
197
+ Some ( error)
198
+ }
199
+ None => None ,
200
+ } ;
201
+
202
+ let output = compile ( & contents, path, crate_name, extern_path) ?;
203
+
184
204
let stderr = std:: str:: from_utf8 ( & output. stderr ) . unwrap ( ) ;
185
205
match ( output. status . success ( ) , expect_success) {
186
206
( true , true ) => Ok ( ( ) ) ,
@@ -215,3 +235,48 @@ fn compile(
215
235
}
216
236
}
217
237
}
238
+
239
+ fn run_check (
240
+ contents : String ,
241
+ path : & Path ,
242
+ crate_name : & str ,
243
+ extern_path : bool ,
244
+ expect_success : bool ,
245
+ ) -> Result < ( ) , Box < dyn Error > > {
246
+ let compile_output = compile ( & contents, path, crate_name, extern_path) ?;
247
+
248
+ if !compile_output. status . success ( ) {
249
+ let stderr = std:: str:: from_utf8 ( & compile_output. stderr ) . unwrap ( ) ;
250
+ return Err ( format ! (
251
+ "expected success, got error {}\n ===== Contents:\n {}\n ===== Output:\n {}\n " ,
252
+ path. display( ) ,
253
+ contents,
254
+ stderr
255
+ )
256
+ . into ( ) ) ;
257
+ }
258
+
259
+ let binary_path = path. parent ( ) . unwrap ( ) . join ( crate_name) ;
260
+
261
+ let output = Command :: new ( binary_path) . output ( ) ?;
262
+
263
+ let stderr = std:: str:: from_utf8 ( & output. stderr ) . unwrap ( ) ;
264
+
265
+ match ( output. status . success ( ) , expect_success) {
266
+ ( true , false ) => Err ( format ! (
267
+ "expected panic, got success {}\n ===== Contents:\n {}\n ===== Output:\n {}\n " ,
268
+ path. display( ) ,
269
+ contents,
270
+ stderr
271
+ )
272
+ . into ( ) ) ,
273
+ ( false , true ) => Err ( format ! (
274
+ "expected success, got panic {}\n ===== Contents:\n {}\n ===== Output:\n {}\n " ,
275
+ path. display( ) ,
276
+ contents,
277
+ stderr,
278
+ )
279
+ . into ( ) ) ,
280
+ ( _, _) => Ok ( ( ) ) ,
281
+ }
282
+ }
0 commit comments