22
33use crate :: testcase:: collect_test_dirs;
44use anyhow:: Result ;
5+ use libtest_mimic:: { Arguments , Trial } ;
56use runner:: Runner ;
7+ use std:: process:: ExitCode ;
8+ use std:: sync:: Arc ;
69use std:: {
710 env, fs,
8- process:: { self , Command } ,
9- } ;
10- use tester:: {
11- ColorConfig , DynTestName , OutputFormat , RunIgnored , ShouldPanic , TestDesc , TestDescAndFn ,
12- TestFn , TestType , run_tests_console,
13- test:: { TestOpts , parse_opts} ,
11+ process:: { self } ,
1412} ;
1513use tracing_subscriber:: FmtSubscriber ;
1614
1715mod differ;
1816mod runner;
1917mod testcase;
2018
21- fn run ( ) -> Result < ( ) > {
19+ pub fn run ( ) -> Result < ExitCode > {
2220 let subscriber = FmtSubscriber :: builder ( )
2321 . with_env_filter ( tracing_subscriber:: EnvFilter :: from_default_env ( ) )
2422 . finish ( ) ;
2523 tracing:: subscriber:: set_global_default ( subscriber) . expect ( "Failed to set global subscriber" ) ;
2624
27- let args: Vec < String > = env:: args ( ) . collect ( ) ;
28- let opts: TestOpts = match parse_opts ( & args) {
29- Some ( Ok ( o) ) => TestOpts {
30- test_threads : Some ( 1 ) ,
31- ..o
32- } ,
33- Some ( Err ( e) ) => {
34- eprintln ! ( "Error parsing test options: {e}" ) ;
35- process:: exit ( 1 ) ;
36- }
37- None => TestOpts {
38- list : false ,
39- filters : vec ! [ ] ,
40- filter_exact : false ,
41- force_run_in_process : false ,
42- exclude_should_panic : false ,
43- run_ignored : RunIgnored :: No ,
44- run_tests : true ,
45- bench_benchmarks : false ,
46- logfile : None ,
47- nocapture : false ,
48- color : ColorConfig :: AutoColor ,
49- format : OutputFormat :: Pretty ,
50- test_threads : Some ( 1 ) ,
51- skip : vec ! [ ] ,
52- time_options : None ,
53- options : tester:: Options {
54- display_output : true ,
55- panic_abort : true ,
56- } ,
57- } ,
58- } ;
25+ let mut args = Arguments :: from_args ( ) ;
26+
27+ // If filters are provided that look like paths (contain '/'), convert them to test names
28+ if let Some ( filter) = & mut args. filter {
29+ * filter = filter. replace ( '/' , "::" ) ;
30+ }
5931
32+ let tests = collect_tests ( ) ?;
33+ Ok ( libtest_mimic:: run ( & args, tests) . exit_code ( ) )
34+ }
35+
36+ fn collect_tests ( ) -> Result < Vec < Trial > > {
6037 // Find the manifest directory at compile time and locate tests in ../tests.
6138 let manifest_dir = env ! ( "CARGO_MANIFEST_DIR" ) ;
6239 let base = std:: path:: Path :: new ( manifest_dir)
@@ -72,77 +49,23 @@ fn run() -> Result<()> {
7249 . expect ( "Failed to canonicalize tests directory" ) ;
7350 tracing:: debug!( "Using output directory: {}" , output_dir. display( ) ) ;
7451
75- let runner = Runner {
52+ let runner = Arc :: new ( Runner {
7653 base_dir : base. clone ( ) ,
7754 output_dir,
78- } ;
55+ } ) ;
7956
8057 let test_cases = collect_test_dirs ( & base) . expect ( "Failed to collect test case directories" ) ;
8158 if test_cases. is_empty ( ) {
8259 eprintln ! ( "No valid tests found in {}" , base. display( ) ) ;
8360 process:: exit ( 1 ) ;
8461 }
8562
86- // We build first to ensure that the tests are compiled before running them and to
87- // passthrough stdout and stderr from cargo to help debugging.
88- let mut cmd = Command :: new ( "cargo" ) ;
89- let cmd = cmd. arg ( "build" ) . arg ( "--release" ) ;
90- runner:: forward_features ( cmd) ;
91- cmd. current_dir ( & base)
92- . stderr ( process:: Stdio :: inherit ( ) )
93- . stdout ( process:: Stdio :: inherit ( ) ) ;
94- tracing:: debug!( "Running cargo command: {:?}" , cmd) ;
95-
96- let output = cmd. output ( ) . expect ( "build output" ) ;
97- let exit_code = output. status . code ( ) . unwrap_or ( -1 ) ;
98- tracing:: debug!( "Cargo build exited with code {}" , exit_code) ;
99- if !output. status . success ( ) {
100- tracing:: error!( "Cargo build failed" ) ;
101- process:: exit ( exit_code) ;
102- }
103-
104- let tests: Vec < TestDescAndFn > = test_cases
63+ let trails = test_cases
10564 . into_iter ( )
106- . map ( |case| TestDescAndFn {
107- desc : TestDesc {
108- name : DynTestName ( case. to_string ( ) ) ,
109- ignore : false ,
110- should_panic : ShouldPanic :: No ,
111- allow_fail : false ,
112- test_type : TestType :: IntegrationTest ,
113- } ,
114- testfn : TestFn :: DynTestFn ( Box :: new ( {
115- let runner = runner. clone ( ) ;
116- move || {
117- runner
118- . run_test_case ( & case)
119- . unwrap_or_else ( |e| panic ! ( "{}" , e) ) ;
120- }
121- } ) ) ,
65+ . map ( |case| {
66+ let runner = runner. clone ( ) ;
67+ Trial :: test ( case. to_string ( ) , move || Ok ( runner. run_test_case ( & case) ?) )
12268 } )
12369 . collect ( ) ;
124-
125- // If filters are provided that look like paths (contain '/'), convert them to test names
126- let opts = if opts. filters . iter ( ) . any ( |f| f. contains ( '/' ) ) {
127- let mut new_opts = opts;
128- new_opts. filters = new_opts
129- . filters
130- . into_iter ( )
131- . map ( |filter| {
132- if filter. contains ( '/' ) {
133- // Convert path-like filter to test name format
134- filter. replace ( '/' , "::" )
135- } else {
136- filter
137- }
138- } )
139- . collect ( ) ;
140- new_opts
141- } else {
142- opts
143- } ;
144-
145- let passed = run_tests_console ( & opts, tests) . expect ( "Failed to run tests" ) ;
146-
147- process:: exit ( if passed { 0 } else { 1 } ) ;
70+ Ok ( trails)
14871}
0 commit comments