@@ -18,7 +18,18 @@ use common::Config;
18
18
use common;
19
19
use util;
20
20
21
+ #[ derive( Clone , Debug ) ]
21
22
pub struct TestProps {
23
+ // For the main test file, this is initialized to `None`. But
24
+ // when running tests that test multiple revisions, such as
25
+ // incremental tests, we will set this to `Some(foo)` where `foo`
26
+ // is the current revision identifier.
27
+ //
28
+ // Note that, unlike the other options here, this value is never
29
+ // loaded from the input file (though it is always set to one of
30
+ // the values listed in the vec `self.revisions`, which is loaded
31
+ // from the file).
32
+ pub revision : Option < String > ,
22
33
// Lines that should be expected, in order, on standard out
23
34
pub error_patterns : Vec < String > ,
24
35
// Extra flags to pass to the compiler
@@ -50,6 +61,8 @@ pub struct TestProps {
50
61
pub pretty_compare_only : bool ,
51
62
// Patterns which must not appear in the output of a cfail test.
52
63
pub forbid_output : Vec < String > ,
64
+ // Revisions to test for incremental compilation.
65
+ pub revisions : Vec < String > ,
53
66
}
54
67
55
68
// Load any test directives embedded in the file
@@ -68,11 +81,13 @@ pub fn load_props(testfile: &Path) -> TestProps {
68
81
let pretty_compare_only = false ;
69
82
let forbid_output = Vec :: new ( ) ;
70
83
let mut props = TestProps {
84
+ revision : None ,
71
85
error_patterns : error_patterns,
72
86
compile_flags : vec ! [ ] ,
73
87
run_flags : run_flags,
74
88
pp_exact : pp_exact,
75
89
aux_builds : aux_builds,
90
+ revisions : vec ! [ ] ,
76
91
exec_env : exec_env,
77
92
check_lines : check_lines,
78
93
build_aux_docs : build_aux_docs,
@@ -84,12 +99,16 @@ pub fn load_props(testfile: &Path) -> TestProps {
84
99
pretty_compare_only : pretty_compare_only,
85
100
forbid_output : forbid_output,
86
101
} ;
87
- load_props_into ( & mut props, testfile) ;
102
+ load_props_into ( & mut props, testfile, None ) ;
88
103
props
89
104
}
90
105
91
- pub fn load_props_into ( props : & mut TestProps , testfile : & Path ) {
92
- iter_header ( testfile, & mut |ln| {
106
+ /// Load properties from `testfile` into `props`. If a property is
107
+ /// tied to a particular revision `foo` (indicated by writing
108
+ /// `//[foo]`), then the property is ignored unless `cfg` is
109
+ /// `Some("foo")`.
110
+ pub fn load_props_into ( props : & mut TestProps , testfile : & Path , cfg : Option < & str > ) {
111
+ iter_header ( testfile, cfg, & mut |ln| {
93
112
if let Some ( ep) = parse_error_pattern ( ln) {
94
113
props. error_patterns . push ( ep) ;
95
114
}
@@ -101,6 +120,10 @@ pub fn load_props_into(props: &mut TestProps, testfile: &Path) {
101
120
. map ( |s| s. to_owned ( ) ) ) ;
102
121
}
103
122
123
+ if let Some ( r) = parse_revisions ( ln) {
124
+ props. revisions . extend ( r) ;
125
+ }
126
+
104
127
if props. run_flags . is_none ( ) {
105
128
props. run_flags = parse_run_flags ( ln) ;
106
129
}
@@ -235,7 +258,7 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
235
258
}
236
259
}
237
260
238
- let val = iter_header ( testfile, & mut |ln| {
261
+ let val = iter_header ( testfile, None , & mut |ln| {
239
262
!parse_name_directive ( ln, "ignore-test" ) &&
240
263
!parse_name_directive ( ln, & ignore_target ( config) ) &&
241
264
!parse_name_directive ( ln, & ignore_architecture ( config) ) &&
@@ -250,7 +273,10 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
250
273
!val
251
274
}
252
275
253
- fn iter_header ( testfile : & Path , it : & mut FnMut ( & str ) -> bool ) -> bool {
276
+ fn iter_header ( testfile : & Path ,
277
+ cfg : Option < & str > ,
278
+ it : & mut FnMut ( & str ) -> bool )
279
+ -> bool {
254
280
let rdr = BufReader :: new ( File :: open ( testfile) . unwrap ( ) ) ;
255
281
for ln in rdr. lines ( ) {
256
282
// Assume that any directives will be found before the first
@@ -260,6 +286,21 @@ fn iter_header(testfile: &Path, it: &mut FnMut(&str) -> bool) -> bool {
260
286
let ln = ln. trim ( ) ;
261
287
if ln. starts_with ( "fn" ) || ln. starts_with ( "mod" ) {
262
288
return true ;
289
+ } else if ln. starts_with ( "//[" ) {
290
+ // A comment like `//[foo]` is specific to revision `foo`
291
+ if let Some ( close_brace) = ln. find ( "]" ) {
292
+ let lncfg = & ln[ 3 ..close_brace] ;
293
+ let matches = match cfg {
294
+ Some ( s) => s == & lncfg[ ..] ,
295
+ None => false ,
296
+ } ;
297
+ if matches && !it ( & ln[ close_brace+1 ..] ) {
298
+ return false ;
299
+ }
300
+ } else {
301
+ panic ! ( "malformed condition directive: expected `//[foo]`, found `{}`" ,
302
+ ln)
303
+ }
263
304
} else if ln. starts_with ( "//" ) {
264
305
if !it ( & ln[ 2 ..] ) {
265
306
return false ;
@@ -285,6 +326,11 @@ fn parse_compile_flags(line: &str) -> Option<String> {
285
326
parse_name_value_directive ( line, "compile-flags" )
286
327
}
287
328
329
+ fn parse_revisions ( line : & str ) -> Option < Vec < String > > {
330
+ parse_name_value_directive ( line, "revisions" )
331
+ . map ( |r| r. split_whitespace ( ) . map ( |t| t. to_string ( ) ) . collect ( ) )
332
+ }
333
+
288
334
fn parse_run_flags ( line : & str ) -> Option < String > {
289
335
parse_name_value_directive ( line, "run-flags" )
290
336
}
0 commit comments