Skip to content

Commit ae0e543

Browse files
committed
Add directive //@ run-pass
Signed-off-by: xizheyin <[email protected]>
1 parent 676f785 commit ae0e543

File tree

2 files changed

+90
-77
lines changed

2 files changed

+90
-77
lines changed

bootstrap/src/test.rs

Lines changed: 87 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,8 @@ impl Run for TestCommand {
7272
self.log_action_context("output", &testcase.output_file.display());
7373
testcase.build_lib(manifest);
7474
}
75-
TestType::Runtime => {
76-
self.log_action_start("TEST Runtime", &testcase.name);
77-
self.log_action_context("source", &testcase.source.display());
78-
self.log_action_context("output", &testcase.output_file.display());
79-
testcase.build(manifest);
80-
self.run_and_check_output(&testcase);
81-
}
8275
}
76+
self.check_and_run_directives(&testcase);
8377
}
8478
}
8579

@@ -123,20 +117,6 @@ impl TestCommand {
123117
cases.push(testcase);
124118
}
125119

126-
// Runtime tests
127-
for case in glob("tests/runit/*.rs").unwrap() {
128-
let case = case.unwrap();
129-
let filename = case.file_stem().unwrap();
130-
// Skip the test runner
131-
if filename == "runner" {
132-
continue;
133-
}
134-
let name = format!("runit/{}", filename.to_string_lossy());
135-
let output_file = manifest.out_dir.join("tests/runit").join(filename);
136-
let testcase = TestCase::new(name, case, output_file, TestType::Runtime, verbose);
137-
cases.push(testcase);
138-
}
139-
140120
// Collect and process auxiliary builds from directives
141121
let mut auxiliaries = vec![];
142122
for case in cases.iter() {
@@ -197,11 +177,48 @@ impl TestCommand {
197177
}
198178

199179
/// Run a runtime test and check its output against directives
200-
fn run_and_check_output(&self, testcase: &TestCase) {
180+
fn check_and_run_directives(&self, testcase: &TestCase) {
201181
// Parse directives from source
202182
let directives = testcase.parse_directives();
203183
self.log_action_context("directives", &format!("found {} directives", directives.len()));
204184

185+
let mut runpass = false;
186+
let mut exitcode = None;
187+
let mut stdout = None;
188+
let mut stderr = None;
189+
190+
// Check each directive
191+
for directive in directives {
192+
match directive {
193+
TestDirective::RunPass => runpass = true,
194+
TestDirective::CheckStdout(expected) => stdout = Some(expected),
195+
TestDirective::CheckStderr(expected) => stderr = Some(expected),
196+
TestDirective::ExitCode(expected) => exitcode = Some(expected),
197+
TestDirective::AuxBuild(_) => {
198+
// AuxBuild directives are handled during test collection
199+
// No need to check them during test execution
200+
}
201+
}
202+
}
203+
204+
if !runpass && (exitcode.is_some() | stdout.is_some() | stderr.is_some()) {
205+
panic!("Directives conflicts, lack of '//@ run-pass'");
206+
}
207+
208+
if runpass {
209+
self.run_and_check_output(testcase, exitcode, stdout, stderr);
210+
}
211+
212+
self.log_action_context("result", "all checks passed");
213+
}
214+
215+
fn run_and_check_output(
216+
&self,
217+
testcase: &TestCase,
218+
expected_exit: Option<i32>,
219+
expected_stdout: Option<String>,
220+
expected_stderr: Option<String>,
221+
) {
205222
// Run the test
206223
self.log_action_context("running", &testcase.output_file.display());
207224
let output = std::process::Command::new(&testcase.output_file)
@@ -215,63 +232,53 @@ impl TestCommand {
215232
let actual_stdout = String::from_utf8_lossy(&output.stdout).into_owned();
216233
let actual_stderr = String::from_utf8_lossy(&output.stderr).into_owned();
217234

218-
// Check each directive
219-
for directive in directives {
220-
match directive {
221-
TestDirective::CheckStdout(expected) => {
222-
self.log_action_context("checking stdout", &expected);
223-
let diff = TextDiff::from_lines(&expected, &actual_stdout);
224-
if diff.ratio() < 1.0 {
225-
cprintln!("<r,s>stdout does not match expected output</r,s>");
226-
for change in diff.iter_all_changes() {
227-
let lineno =
228-
change.old_index().unwrap_or(change.new_index().unwrap_or(0));
229-
match change.tag() {
230-
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
231-
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
232-
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
233-
}
234-
}
235-
std::process::exit(1);
236-
}
237-
self.log_action_context("stdout", "passed");
238-
}
239-
TestDirective::CheckStderr(expected) => {
240-
self.log_action_context("checking stderr", &expected);
241-
let diff = TextDiff::from_lines(&expected, &actual_stderr);
242-
if diff.ratio() < 1.0 {
243-
cprintln!("<r,s>stderr does not match expected output</r,s>");
244-
for change in diff.iter_all_changes() {
245-
let lineno =
246-
change.old_index().unwrap_or(change.new_index().unwrap_or(0));
247-
match change.tag() {
248-
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
249-
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
250-
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
251-
}
252-
}
253-
std::process::exit(1);
235+
{
236+
let expected_exit = expected_exit.unwrap_or(0);
237+
self.log_action_context("checking exit code", &expected_exit.to_string());
238+
if actual_return != expected_exit {
239+
cprintln!("<r,s>exit code does not match expected value</r,s>");
240+
cprintln!("expected: {}", expected_exit);
241+
cprintln!("actual: {}", actual_return);
242+
std::process::exit(1);
243+
}
244+
self.log_action_context("exit code", "passed");
245+
}
246+
247+
if let Some(expected_stdout) = expected_stdout {
248+
self.log_action_context("checking stdout", &expected_stdout);
249+
let diff = TextDiff::from_lines(&expected_stdout, &actual_stdout);
250+
if diff.ratio() < 1.0 {
251+
cprintln!("<r,s>stdout does not match expected output</r,s>");
252+
for change in diff.iter_all_changes() {
253+
let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0));
254+
match change.tag() {
255+
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
256+
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
257+
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
254258
}
255-
self.log_action_context("stderr", "passed");
256259
}
257-
TestDirective::ExitCode(expected) => {
258-
self.log_action_context("checking exit code", &expected.to_string());
259-
if actual_return != expected {
260-
cprintln!("<r,s>exit code does not match expected value</r,s>");
261-
cprintln!("expected: {}", expected);
262-
cprintln!("actual: {}", actual_return);
263-
std::process::exit(1);
260+
std::process::exit(1);
261+
}
262+
self.log_action_context("stdout", "passed");
263+
}
264+
265+
if let Some(expected_stderr) = expected_stderr {
266+
self.log_action_context("checking stderr", &expected_stderr);
267+
let diff = TextDiff::from_lines(&expected_stderr, &actual_stderr);
268+
if diff.ratio() < 1.0 {
269+
cprintln!("<r,s>stderr does not match expected output</r,s>");
270+
for change in diff.iter_all_changes() {
271+
let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0));
272+
match change.tag() {
273+
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
274+
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
275+
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
264276
}
265-
self.log_action_context("exit code", "passed");
266-
}
267-
TestDirective::AuxBuild(_) => {
268-
// AuxBuild directives are handled during test collection
269-
// No need to check them during test execution
270277
}
278+
std::process::exit(1);
271279
}
280+
self.log_action_context("stderr", "passed");
272281
}
273-
274-
self.log_action_context("result", "all checks passed");
275282
}
276283
}
277284

@@ -285,8 +292,6 @@ pub enum TestType {
285292
FileCheck,
286293
/// Bless test - the output should be the same as the last run
287294
Bless,
288-
/// Runtime test - compile, run and compare output
289-
Runtime,
290295
}
291296

292297
impl TestType {
@@ -296,7 +301,6 @@ impl TestType {
296301
TestType::CompileLib => "compile-lib",
297302
TestType::FileCheck => "filecheck",
298303
TestType::Bless => "bless",
299-
TestType::Runtime => "runtime",
300304
}
301305
}
302306
}
@@ -381,6 +385,7 @@ impl TestCase {
381385
let mut directives = Vec::new();
382386

383387
// Regular expressions for matching directives
388+
let run_pass = regex::Regex::new(r"^//@\s*run-pass").unwrap();
384389
let stdout_re = regex::Regex::new(r"^//@\s*check-stdout:\s*(.*)").unwrap();
385390
let stderr_re = regex::Regex::new(r"^//@\s*check-stderr:\s*(.*)").unwrap();
386391
let exit_re = regex::Regex::new(r"^//@\s*exit-code:\s*(\d+)").unwrap();
@@ -389,7 +394,9 @@ impl TestCase {
389394
let directive_re = regex::Regex::new(r"^//@\s*([^:]+)").unwrap();
390395

391396
for (line_num, line) in source.lines().enumerate() {
392-
if let Some(cap) = stdout_re.captures(line) {
397+
if let Some(_cap) = run_pass.captures(line) {
398+
directives.push(TestDirective::RunPass);
399+
} else if let Some(cap) = stdout_re.captures(line) {
393400
let content = cap[1].trim().to_string();
394401
directives.push(TestDirective::CheckStdout(content));
395402
} else if let Some(cap) = stderr_re.captures(line) {
@@ -471,6 +478,9 @@ impl FileChecker {
471478
/// Test directives that can appear in source files
472479
#[derive(Debug)]
473480
enum TestDirective {
481+
/// Compile and run a testcase,
482+
/// expect a success (exit with 0)
483+
RunPass,
474484
/// Expected stdout content
475485
CheckStdout(String),
476486
/// Expected stderr content

tests/codegen/func_call.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ pub fn single(a: i32) -> i32 {
2323
pub fn main() -> i32 {
2424
single(1)
2525
}
26+
27+
//@ run-pass
28+
//@ exit-code: 1

0 commit comments

Comments
 (0)