@@ -1264,28 +1264,75 @@ impl Step for Compiletest {
12641264 }
12651265}
12661266
1267- #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
1268- struct DocTest {
1267+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
1268+ struct BookTest {
12691269 compiler : Compiler ,
1270- path : & ' static str ,
1270+ path : PathBuf ,
12711271 name : & ' static str ,
12721272 is_ext_doc : bool ,
12731273}
12741274
1275- impl Step for DocTest {
1275+ impl Step for BookTest {
12761276 type Output = ( ) ;
12771277 const ONLY_HOSTS : bool = true ;
12781278
12791279 fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
12801280 run. never ( )
12811281 }
12821282
1283- /// Runs `rustdoc --test` for all documentation in `src/doc`.
1283+ /// Runs the documentation tests for a book in `src/doc`.
12841284 ///
1285- /// This will run all tests in our markdown documentation (e.g., the book)
1286- /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to
1287- /// `compiler`.
1285+ /// This uses the `rustdoc` that sits next to `compiler`.
12881286 fn run ( self , builder : & Builder < ' _ > ) {
1287+ // External docs are different from local because:
1288+ // - Some books need pre-processing by mdbook before being tested.
1289+ // - They need to save their state to toolstate.
1290+ // - They are only tested on the "checktools" builders.
1291+ //
1292+ // The local docs are tested by default, and we don't want to pay the
1293+ // cost of building mdbook, so they use `rustdoc --test` directly.
1294+ // Also, the unstable book is special because SUMMARY.md is generated,
1295+ // so it is easier to just run `rustdoc` on its files.
1296+ if self . is_ext_doc {
1297+ self . run_ext_doc ( builder) ;
1298+ } else {
1299+ self . run_local_doc ( builder) ;
1300+ }
1301+ }
1302+ }
1303+
1304+ impl BookTest {
1305+ /// This runs the equivalent of `mdbook test` (via the rustbook wrapper)
1306+ /// which in turn runs `rustdoc --test` on each file in the book.
1307+ fn run_ext_doc ( self , builder : & Builder < ' _ > ) {
1308+ let compiler = self . compiler ;
1309+
1310+ builder. ensure ( compile:: Std { compiler, target : compiler. host } ) ;
1311+
1312+ // mdbook just executes a binary named "rustdoc", so we need to update
1313+ // PATH so that it points to our rustdoc.
1314+ let mut rustdoc_path = builder. rustdoc ( compiler) ;
1315+ rustdoc_path. pop ( ) ;
1316+ let old_path = env:: var_os ( "PATH" ) . unwrap_or_default ( ) ;
1317+ let new_path = env:: join_paths ( iter:: once ( rustdoc_path) . chain ( env:: split_paths ( & old_path) ) )
1318+ . expect ( "could not add rustdoc to PATH" ) ;
1319+
1320+ let mut rustbook_cmd = builder. tool_cmd ( Tool :: Rustbook ) ;
1321+ let path = builder. src . join ( & self . path ) ;
1322+ rustbook_cmd. env ( "PATH" , new_path) . arg ( "test" ) . arg ( path) ;
1323+ builder. add_rust_test_threads ( & mut rustbook_cmd) ;
1324+ builder. info ( & format ! ( "Testing rustbook {}" , self . path. display( ) ) ) ;
1325+ let _time = util:: timeit ( & builder) ;
1326+ let toolstate = if try_run ( builder, & mut rustbook_cmd) {
1327+ ToolState :: TestPass
1328+ } else {
1329+ ToolState :: TestFail
1330+ } ;
1331+ builder. save_toolstate ( self . name , toolstate) ;
1332+ }
1333+
1334+ /// This runs `rustdoc --test` on all `.md` files in the path.
1335+ fn run_local_doc ( self , builder : & Builder < ' _ > ) {
12891336 let compiler = self . compiler ;
12901337
12911338 builder. ensure ( compile:: Std { compiler, target : compiler. host } ) ;
@@ -1294,7 +1341,6 @@ impl Step for DocTest {
12941341 // tests for all files that end in `*.md`
12951342 let mut stack = vec ! [ builder. src. join( self . path) ] ;
12961343 let _time = util:: timeit ( & builder) ;
1297-
12981344 let mut files = Vec :: new ( ) ;
12991345 while let Some ( p) = stack. pop ( ) {
13001346 if p. is_dir ( ) {
@@ -1306,25 +1352,13 @@ impl Step for DocTest {
13061352 continue ;
13071353 }
13081354
1309- // The nostarch directory in the book is for no starch, and so isn't
1310- // guaranteed to builder. We don't care if it doesn't build, so skip it.
1311- if p. to_str ( ) . map_or ( false , |p| p. contains ( "nostarch" ) ) {
1312- continue ;
1313- }
1314-
13151355 files. push ( p) ;
13161356 }
13171357
13181358 files. sort ( ) ;
13191359
1320- let mut toolstate = ToolState :: TestPass ;
13211360 for file in files {
1322- if !markdown_test ( builder, compiler, & file) {
1323- toolstate = ToolState :: TestFail ;
1324- }
1325- }
1326- if self . is_ext_doc {
1327- builder. save_toolstate ( self . name , toolstate) ;
1361+ markdown_test ( builder, compiler, & file) ;
13281362 }
13291363 }
13301364}
@@ -1353,9 +1387,9 @@ macro_rules! test_book {
13531387 }
13541388
13551389 fn run( self , builder: & Builder <' _>) {
1356- builder. ensure( DocTest {
1390+ builder. ensure( BookTest {
13571391 compiler: self . compiler,
1358- path: $path,
1392+ path: PathBuf :: from ( $path) ,
13591393 name: $book_name,
13601394 is_ext_doc: !$default,
13611395 } ) ;
0 commit comments