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