@@ -1267,6 +1267,166 @@ pub(crate) trait Tester {
1267
1267
fn register_header ( & mut self , _name : & str , _level : u32 ) { }
1268
1268
}
1269
1269
1270
+ /// If there are too many doctests than can be compiled at once, we need to limit the size
1271
+ /// of the generated test to prevent everything to break down.
1272
+ ///
1273
+ /// We add all doctests one by one through [`DocTestRunner::add_test`] and when it reaches
1274
+ /// `TEST_BATCH_SIZE` size or is dropped, it runs all stored doctests at once.
1275
+ struct DocTestRunner < ' a > {
1276
+ nb_errors : & ' a mut usize ,
1277
+ ran_edition_tests : & ' a mut usize ,
1278
+ standalone : & ' a mut Vec < TestDescAndFn > ,
1279
+ crate_attrs : FxHashSet < String > ,
1280
+ edition : Edition ,
1281
+ ids : String ,
1282
+ output : String ,
1283
+ supports_color : bool ,
1284
+ rustdoc_test_options : & ' a Arc < IndividualTestOptions > ,
1285
+ outdir : & ' a Arc < DirState > ,
1286
+ nb_tests : usize ,
1287
+ doctests : Vec < DocTest > ,
1288
+ opts : & ' a GlobalTestOptions ,
1289
+ test_args : & ' a [ String ] ,
1290
+ unused_externs : & ' a Arc < Mutex < Vec < UnusedExterns > > > ,
1291
+ }
1292
+
1293
+ impl < ' a > DocTestRunner < ' a > {
1294
+ const TEST_BATCH_SIZE : usize = 250 ;
1295
+
1296
+ fn new (
1297
+ nb_errors : & ' a mut usize ,
1298
+ ran_edition_tests : & ' a mut usize ,
1299
+ standalone : & ' a mut Vec < TestDescAndFn > ,
1300
+ edition : Edition ,
1301
+ rustdoc_test_options : & ' a Arc < IndividualTestOptions > ,
1302
+ outdir : & ' a Arc < DirState > ,
1303
+ opts : & ' a GlobalTestOptions ,
1304
+ test_args : & ' a [ String ] ,
1305
+ unused_externs : & ' a Arc < Mutex < Vec < UnusedExterns > > > ,
1306
+ ) -> Self {
1307
+ Self {
1308
+ nb_errors,
1309
+ ran_edition_tests,
1310
+ standalone,
1311
+ edition,
1312
+ crate_attrs : FxHashSet :: default ( ) ,
1313
+ ids : String :: new ( ) ,
1314
+ output : String :: new ( ) ,
1315
+ supports_color : true ,
1316
+ rustdoc_test_options,
1317
+ outdir,
1318
+ nb_tests : 0 ,
1319
+ doctests : Vec :: with_capacity ( Self :: TEST_BATCH_SIZE ) ,
1320
+ opts,
1321
+ test_args,
1322
+ unused_externs,
1323
+ }
1324
+ }
1325
+
1326
+ fn add_test ( & mut self , doctest : DocTest ) {
1327
+ for line in doctest. crate_attrs . split ( '\n' ) {
1328
+ self . crate_attrs . insert ( line. to_string ( ) ) ;
1329
+ }
1330
+ if !self . ids . is_empty ( ) {
1331
+ self . ids . push ( ',' ) ;
1332
+ }
1333
+ self . ids . push_str ( & format ! (
1334
+ "{}::TEST" ,
1335
+ doctest. generate_test_desc( self . nb_tests, & mut self . output)
1336
+ ) ) ;
1337
+ self . supports_color &= doctest. supports_color ;
1338
+ self . nb_tests += 1 ;
1339
+ self . doctests . push ( doctest) ;
1340
+
1341
+ if self . nb_tests >= Self :: TEST_BATCH_SIZE {
1342
+ self . run_tests ( ) ;
1343
+ }
1344
+ }
1345
+
1346
+ fn run_tests ( & mut self ) {
1347
+ if self . nb_tests == 0 {
1348
+ return ;
1349
+ }
1350
+ let mut code = "\
1351
+ #![allow(unused_extern_crates)]
1352
+ #![allow(internal_features)]
1353
+ #![feature(test)]
1354
+ #![feature(rustc_attrs)]
1355
+ #![feature(coverage_attribute)]\n "
1356
+ . to_string ( ) ;
1357
+
1358
+ for crate_attr in & self . crate_attrs {
1359
+ code. push_str ( crate_attr) ;
1360
+ code. push ( '\n' ) ;
1361
+ }
1362
+
1363
+ DocTest :: push_attrs ( & mut code, & self . opts , & mut 0 ) ;
1364
+ code. push_str ( "extern crate test;\n " ) ;
1365
+
1366
+ let test_args =
1367
+ self . test_args . iter ( ) . map ( |arg| format ! ( "{arg:?}.to_string()," ) ) . collect :: < String > ( ) ;
1368
+ write ! (
1369
+ code,
1370
+ "\
1371
+ {output}
1372
+ #[rustc_main]
1373
+ #[coverage(off)]
1374
+ fn main() {{
1375
+ test::test_main(&[{test_args}], vec![{ids}], None);
1376
+ }}" ,
1377
+ output = self . output,
1378
+ ids = self . ids,
1379
+ )
1380
+ . expect ( "failed to generate test code" ) ;
1381
+ let ret = run_test (
1382
+ code,
1383
+ self . supports_color ,
1384
+ None ,
1385
+ Arc :: clone ( self . rustdoc_test_options ) ,
1386
+ true ,
1387
+ Arc :: clone ( self . outdir ) ,
1388
+ LangString :: empty_for_test ( ) ,
1389
+ self . edition ,
1390
+ |_: UnusedExterns | { } ,
1391
+ false ,
1392
+ ) ;
1393
+ if let Err ( TestFailure :: CompileError ) = ret {
1394
+ // We failed to compile all compatible tests as one so we push them into the
1395
+ // "standalone" doctests.
1396
+ debug ! (
1397
+ "Failed to compile compatible doctests for edition {} all at once" ,
1398
+ self . edition
1399
+ ) ;
1400
+ for doctest in self . doctests . drain ( ..) {
1401
+ self . standalone . push ( doctest. generate_test_desc_and_fn (
1402
+ & self . opts ,
1403
+ self . edition ,
1404
+ Arc :: clone ( self . unused_externs ) ,
1405
+ ) ) ;
1406
+ }
1407
+ } else {
1408
+ * self . ran_edition_tests += 1 ;
1409
+ if ret. is_err ( ) {
1410
+ * self . nb_errors += 1 ;
1411
+ }
1412
+ }
1413
+
1414
+ // We reset values.
1415
+ self . supports_color = true ;
1416
+ self . ids . clear ( ) ;
1417
+ self . output . clear ( ) ;
1418
+ self . crate_attrs . clear ( ) ;
1419
+ self . nb_tests = 0 ;
1420
+ self . doctests . clear ( ) ;
1421
+ }
1422
+ }
1423
+
1424
+ impl < ' a > Drop for DocTestRunner < ' a > {
1425
+ fn drop ( & mut self ) {
1426
+ self . run_tests ( ) ;
1427
+ }
1428
+ }
1429
+
1270
1430
#[ derive( Default ) ]
1271
1431
pub ( crate ) struct DocTestKinds {
1272
1432
/// Tests that cannot be run together with the rest (`compile_fail` and `test_harness`).
@@ -1317,73 +1477,24 @@ impl DocTestKinds {
1317
1477
1318
1478
for ( edition, mut doctests) in others {
1319
1479
doctests. sort_by ( |a, b| a. name . cmp ( & b. name ) ) ;
1320
- let mut ids = String :: new ( ) ;
1321
- let mut output = "\
1322
- #![allow(unused_extern_crates)]
1323
- #![allow(internal_features)]
1324
- #![feature(test)]
1325
- #![feature(rustc_attrs)]
1326
- #![feature(coverage_attribute)]\n "
1327
- . to_string ( ) ;
1328
-
1329
- for doctest in & doctests {
1330
- output. push_str ( & doctest. crate_attrs ) ;
1331
- }
1332
-
1333
- DocTest :: push_attrs ( & mut output, & opts, & mut 0 ) ;
1334
- output. push_str ( "extern crate test;\n " ) ;
1335
-
1336
1480
let rustdoc_test_options = Arc :: clone ( & doctests[ 0 ] . rustdoc_test_options ) ;
1337
1481
let outdir = Arc :: clone ( & doctests[ 0 ] . outdir ) ;
1338
1482
1339
- let mut supports_color = true ;
1340
- for ( pos, doctest) in doctests. iter ( ) . enumerate ( ) {
1341
- if !ids. is_empty ( ) {
1342
- ids. push ( ',' ) ;
1343
- }
1344
- ids. push_str ( & format ! ( "{}::TEST" , doctest. generate_test_desc( pos, & mut output) ) ) ;
1345
- supports_color &= doctest. supports_color ;
1346
- }
1347
- let test_args =
1348
- test_args. iter ( ) . map ( |arg| format ! ( "{arg:?}.to_string()," ) ) . collect :: < String > ( ) ;
1349
- write ! (
1350
- output,
1351
- "\
1352
- #[rustc_main]
1353
- #[coverage(off)]
1354
- fn main() {{
1355
- test::test_main(&[{test_args}], vec![{ids}], None);
1356
- }}" ,
1357
- )
1358
- . unwrap ( ) ;
1359
- let ret = run_test (
1360
- output,
1361
- supports_color,
1362
- None ,
1363
- rustdoc_test_options,
1364
- true ,
1365
- outdir,
1366
- LangString :: empty_for_test ( ) ,
1483
+ // When `DocTestRunner` is dropped, it'll run all pending doctests it didn't already
1484
+ // run, so no need to worry about it.
1485
+ let mut tests_runner = DocTestRunner :: new (
1486
+ & mut nb_errors,
1487
+ & mut ran_edition_tests,
1488
+ & mut standalone,
1367
1489
edition,
1368
- |_: UnusedExterns | { } ,
1369
- false ,
1490
+ & rustdoc_test_options,
1491
+ & outdir,
1492
+ & opts,
1493
+ & test_args,
1494
+ unused_externs,
1370
1495
) ;
1371
- if let Err ( TestFailure :: CompileError ) = ret {
1372
- // We failed to compile all compatible tests as one so we push them into the
1373
- // "standalone" doctests.
1374
- debug ! ( "Failed to compile compatible doctests for edition {edition} all at once" ) ;
1375
- for doctest in doctests {
1376
- standalone. push ( doctest. generate_test_desc_and_fn (
1377
- & opts,
1378
- edition,
1379
- Arc :: clone ( unused_externs) ,
1380
- ) ) ;
1381
- }
1382
- } else {
1383
- ran_edition_tests += 1 ;
1384
- if ret. is_err ( ) {
1385
- nb_errors += 1 ;
1386
- }
1496
+ for doctest in doctests {
1497
+ tests_runner. add_test ( doctest) ;
1387
1498
}
1388
1499
}
1389
1500
0 commit comments