]> git.lizzy.rs Git - rust.git/blob - src/compiletest/header.rs
test: Make manual changes to deal with the fallout from removal of
[rust.git] / src / compiletest / header.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use common::config;
12 use common;
13 use util;
14
15 use std::vec_ng::Vec;
16
17 pub struct TestProps {
18     // Lines that should be expected, in order, on standard out
19     error_patterns: Vec<~str> ,
20     // Extra flags to pass to the compiler
21     compile_flags: Option<~str>,
22     // If present, the name of a file that this test should match when
23     // pretty-printed
24     pp_exact: Option<Path>,
25     // Modules from aux directory that should be compiled
26     aux_builds: Vec<~str> ,
27     // Environment settings to use during execution
28     exec_env: Vec<(~str,~str)> ,
29     // Commands to be given to the debugger, when testing debug info
30     debugger_cmds: Vec<~str> ,
31     // Lines to check if they appear in the expected debugger output
32     check_lines: Vec<~str> ,
33     // Flag to force a crate to be built with the host architecture
34     force_host: bool,
35     // Check stdout for error-pattern output as well as stderr
36     check_stdout: bool,
37     // Don't force a --crate-type=dylib flag on the command line
38     no_prefer_dynamic: bool,
39 }
40
41 // Load any test directives embedded in the file
42 pub fn load_props(testfile: &Path) -> TestProps {
43     let mut error_patterns = Vec::new();
44     let mut aux_builds = Vec::new();
45     let mut exec_env = Vec::new();
46     let mut compile_flags = None;
47     let mut pp_exact = None;
48     let mut debugger_cmds = Vec::new();
49     let mut check_lines = Vec::new();
50     let mut force_host = false;
51     let mut check_stdout = false;
52     let mut no_prefer_dynamic = false;
53     iter_header(testfile, |ln| {
54         match parse_error_pattern(ln) {
55           Some(ep) => error_patterns.push(ep),
56           None => ()
57         };
58
59         if compile_flags.is_none() {
60             compile_flags = parse_compile_flags(ln);
61         }
62
63         if pp_exact.is_none() {
64             pp_exact = parse_pp_exact(ln, testfile);
65         }
66
67         if !force_host {
68             force_host = parse_force_host(ln);
69         }
70
71         if !check_stdout {
72             check_stdout = parse_check_stdout(ln);
73         }
74
75         if !no_prefer_dynamic {
76             no_prefer_dynamic = parse_no_prefer_dynamic(ln);
77         }
78
79         match parse_aux_build(ln) {
80             Some(ab) => { aux_builds.push(ab); }
81             None => {}
82         }
83
84         match parse_exec_env(ln) {
85             Some(ee) => { exec_env.push(ee); }
86             None => {}
87         }
88
89         match parse_debugger_cmd(ln) {
90             Some(dc) => debugger_cmds.push(dc),
91             None => ()
92         };
93
94         match parse_check_line(ln) {
95             Some(cl) => check_lines.push(cl),
96             None => ()
97         };
98
99         true
100     });
101     return TestProps {
102         error_patterns: error_patterns,
103         compile_flags: compile_flags,
104         pp_exact: pp_exact,
105         aux_builds: aux_builds,
106         exec_env: exec_env,
107         debugger_cmds: debugger_cmds,
108         check_lines: check_lines,
109         force_host: force_host,
110         check_stdout: check_stdout,
111         no_prefer_dynamic: no_prefer_dynamic,
112     };
113 }
114
115 pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
116     fn ignore_target(config: &config) -> ~str {
117         ~"ignore-" + util::get_os(config.target)
118     }
119     fn ignore_stage(config: &config) -> ~str {
120         ~"ignore-" + config.stage_id.split('-').next().unwrap()
121     }
122
123     let val = iter_header(testfile, |ln| {
124         if parse_name_directive(ln, "ignore-test") { false }
125         else if parse_name_directive(ln, ignore_target(config)) { false }
126         else if parse_name_directive(ln, ignore_stage(config)) { false }
127         else if config.mode == common::mode_pretty &&
128             parse_name_directive(ln, "ignore-pretty") { false }
129         else if config.target != config.host &&
130             parse_name_directive(ln, "ignore-cross-compile") { false }
131         else { true }
132     });
133
134     !val
135 }
136
137 fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
138     use std::io::{BufferedReader, File};
139
140     let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
141     for ln in rdr.lines() {
142         // Assume that any directives will be found before the first
143         // module or function. This doesn't seem to be an optimization
144         // with a warm page cache. Maybe with a cold one.
145         let ln = ln.unwrap();
146         if ln.starts_with("fn") || ln.starts_with("mod") {
147             return true;
148         } else { if !(it(ln.trim())) { return false; } }
149     }
150     return true;
151 }
152
153 fn parse_error_pattern(line: &str) -> Option<~str> {
154     parse_name_value_directive(line, ~"error-pattern")
155 }
156
157 fn parse_aux_build(line: &str) -> Option<~str> {
158     parse_name_value_directive(line, ~"aux-build")
159 }
160
161 fn parse_compile_flags(line: &str) -> Option<~str> {
162     parse_name_value_directive(line, ~"compile-flags")
163 }
164
165 fn parse_debugger_cmd(line: &str) -> Option<~str> {
166     parse_name_value_directive(line, ~"debugger")
167 }
168
169 fn parse_check_line(line: &str) -> Option<~str> {
170     parse_name_value_directive(line, ~"check")
171 }
172
173 fn parse_force_host(line: &str) -> bool {
174     parse_name_directive(line, "force-host")
175 }
176
177 fn parse_check_stdout(line: &str) -> bool {
178     parse_name_directive(line, "check-stdout")
179 }
180
181 fn parse_no_prefer_dynamic(line: &str) -> bool {
182     parse_name_directive(line, "no-prefer-dynamic")
183 }
184
185 fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
186     parse_name_value_directive(line, ~"exec-env").map(|nv| {
187         // nv is either FOO or FOO=BAR
188         let mut strs: Vec<~str> = nv.splitn('=', 1).map(|s| s.to_owned()).collect();
189
190         match strs.len() {
191           1u => (strs.pop().unwrap(), ~""),
192           2u => {
193               let end = strs.pop().unwrap();
194               (strs.pop().unwrap(), end)
195           }
196           n => fail!("Expected 1 or 2 strings, not {}", n)
197         }
198     })
199 }
200
201 fn parse_pp_exact(line: &str, testfile: &Path) -> Option<Path> {
202     match parse_name_value_directive(line, ~"pp-exact") {
203       Some(s) => Some(Path::new(s)),
204       None => {
205         if parse_name_directive(line, "pp-exact") {
206             testfile.filename().map(|s| Path::new(s))
207         } else {
208             None
209         }
210       }
211     }
212 }
213
214 fn parse_name_directive(line: &str, directive: &str) -> bool {
215     line.contains(directive)
216 }
217
218 fn parse_name_value_directive(line: &str,
219                               directive: ~str) -> Option<~str> {
220     let keycolon = directive + ":";
221     match line.find_str(keycolon) {
222         Some(colon) => {
223             let value = line.slice(colon + keycolon.len(),
224                                    line.len()).to_owned();
225             debug!("{}: {}", directive,  value);
226             Some(value)
227         }
228         None => None
229     }
230 }