aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/runnables.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/runnables.rs')
-rw-r--r--crates/ra_ide/src/runnables.rs200
1 files changed, 128 insertions, 72 deletions
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 95a35a28d..3b7162b84 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -102,7 +102,7 @@ pub(crate) fn runnable(
102) -> Option<Runnable> { 102) -> Option<Runnable> {
103 match_ast! { 103 match_ast! {
104 match item { 104 match item {
105 ast::FnDef(it) => runnable_fn(sema, it, file_id), 105 ast::Fn(it) => runnable_fn(sema, it, file_id),
106 ast::Module(it) => runnable_mod(sema, it, file_id), 106 ast::Module(it) => runnable_mod(sema, it, file_id),
107 _ => None, 107 _ => None,
108 } 108 }
@@ -111,7 +111,7 @@ pub(crate) fn runnable(
111 111
112fn runnable_fn( 112fn runnable_fn(
113 sema: &Semantics<RootDatabase>, 113 sema: &Semantics<RootDatabase>,
114 fn_def: ast::FnDef, 114 fn_def: ast::Fn,
115 file_id: FileId, 115 file_id: FileId,
116) -> Option<Runnable> { 116) -> Option<Runnable> {
117 let name_string = fn_def.name()?.text().to_string(); 117 let name_string = fn_def.name()?.text().to_string();
@@ -188,7 +188,7 @@ pub struct TestAttr {
188} 188}
189 189
190impl TestAttr { 190impl TestAttr {
191 fn from_fn(fn_def: &ast::FnDef) -> TestAttr { 191 fn from_fn(fn_def: &ast::Fn) -> TestAttr {
192 let ignore = fn_def 192 let ignore = fn_def
193 .attrs() 193 .attrs()
194 .filter_map(|attr| attr.simple_name()) 194 .filter_map(|attr| attr.simple_name())
@@ -203,7 +203,7 @@ impl TestAttr {
203/// 203///
204/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test, 204/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
205/// but it's better than not to have the runnables for the tests at all. 205/// but it's better than not to have the runnables for the tests at all.
206fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool { 206fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
207 fn_def 207 fn_def
208 .attrs() 208 .attrs()
209 .filter_map(|attr| attr.path()) 209 .filter_map(|attr| attr.path())
@@ -211,7 +211,7 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
211 .any(|attribute_text| attribute_text.contains("test")) 211 .any(|attribute_text| attribute_text.contains("test"))
212} 212}
213 213
214fn has_doc_test(fn_def: &ast::FnDef) -> bool { 214fn has_doc_test(fn_def: &ast::Fn) -> bool {
215 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) 215 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```"))
216} 216}
217 217
@@ -220,15 +220,7 @@ fn runnable_mod(
220 module: ast::Module, 220 module: ast::Module,
221 file_id: FileId, 221 file_id: FileId,
222) -> Option<Runnable> { 222) -> Option<Runnable> {
223 let has_test_function = module 223 if !has_test_function_or_multiple_test_submodules(&module) {
224 .item_list()?
225 .items()
226 .filter_map(|it| match it {
227 ast::ModuleItem::FnDef(it) => Some(it),
228 _ => None,
229 })
230 .any(|f| has_test_related_attribute(&f));
231 if !has_test_function {
232 return None; 224 return None;
233 } 225 }
234 let module_def = sema.to_def(&module)?; 226 let module_def = sema.to_def(&module)?;
@@ -246,6 +238,34 @@ fn runnable_mod(
246 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) 238 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs })
247} 239}
248 240
241// We could create runnables for modules with number_of_test_submodules > 0,
242// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already
243fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
244 if let Some(item_list) = module.item_list() {
245 let mut number_of_test_submodules = 0;
246
247 for item in item_list.items() {
248 match item {
249 ast::Item::Fn(f) => {
250 if has_test_related_attribute(&f) {
251 return true;
252 }
253 }
254 ast::Item::Module(submodule) => {
255 if has_test_function_or_multiple_test_submodules(&submodule) {
256 number_of_test_submodules += 1;
257 }
258 }
259 _ => (),
260 }
261 }
262
263 number_of_test_submodules > 1
264 } else {
265 false
266 }
267}
268
249#[cfg(test)] 269#[cfg(test)]
250mod tests { 270mod tests {
251 use expect::{expect, Expect}; 271 use expect::{expect, Expect};
@@ -300,7 +320,7 @@ fn bench() {}
300 4..8, 320 4..8,
301 ), 321 ),
302 name: "main", 322 name: "main",
303 kind: FN_DEF, 323 kind: FN,
304 container_name: None, 324 container_name: None,
305 description: None, 325 description: None,
306 docs: None, 326 docs: None,
@@ -318,7 +338,7 @@ fn bench() {}
318 26..34, 338 26..34,
319 ), 339 ),
320 name: "test_foo", 340 name: "test_foo",
321 kind: FN_DEF, 341 kind: FN,
322 container_name: None, 342 container_name: None,
323 description: None, 343 description: None,
324 docs: None, 344 docs: None,
@@ -343,7 +363,7 @@ fn bench() {}
343 62..70, 363 62..70,
344 ), 364 ),
345 name: "test_foo", 365 name: "test_foo",
346 kind: FN_DEF, 366 kind: FN,
347 container_name: None, 367 container_name: None,
348 description: None, 368 description: None,
349 docs: None, 369 docs: None,
@@ -368,7 +388,7 @@ fn bench() {}
368 89..94, 388 89..94,
369 ), 389 ),
370 name: "bench", 390 name: "bench",
371 kind: FN_DEF, 391 kind: FN,
372 container_name: None, 392 container_name: None,
373 description: None, 393 description: None,
374 docs: None, 394 docs: None,
@@ -411,7 +431,7 @@ fn foo() {}
411 4..8, 431 4..8,
412 ), 432 ),
413 name: "main", 433 name: "main",
414 kind: FN_DEF, 434 kind: FN,
415 container_name: None, 435 container_name: None,
416 description: None, 436 description: None,
417 docs: None, 437 docs: None,
@@ -427,7 +447,7 @@ fn foo() {}
427 full_range: 15..57, 447 full_range: 15..57,
428 focus_range: None, 448 focus_range: None,
429 name: "foo", 449 name: "foo",
430 kind: FN_DEF, 450 kind: FN,
431 container_name: None, 451 container_name: None,
432 description: None, 452 description: None,
433 docs: None, 453 docs: None,
@@ -473,7 +493,7 @@ impl Data {
473 4..8, 493 4..8,
474 ), 494 ),
475 name: "main", 495 name: "main",
476 kind: FN_DEF, 496 kind: FN,
477 container_name: None, 497 container_name: None,
478 description: None, 498 description: None,
479 docs: None, 499 docs: None,
@@ -489,7 +509,7 @@ impl Data {
489 full_range: 44..98, 509 full_range: 44..98,
490 focus_range: None, 510 focus_range: None,
491 name: "foo", 511 name: "foo",
492 kind: FN_DEF, 512 kind: FN,
493 container_name: None, 513 container_name: None,
494 description: None, 514 description: None,
495 docs: None, 515 docs: None,
@@ -550,7 +570,7 @@ mod test_mod {
550 35..44, 570 35..44,
551 ), 571 ),
552 name: "test_foo1", 572 name: "test_foo1",
553 kind: FN_DEF, 573 kind: FN,
554 container_name: None, 574 container_name: None,
555 description: None, 575 description: None,
556 docs: None, 576 docs: None,
@@ -571,19 +591,33 @@ mod test_mod {
571 } 591 }
572 592
573 #[test] 593 #[test]
574 fn test_runnables_one_depth_layer_module() { 594 fn only_modules_with_test_functions_or_more_than_one_test_submodule_have_runners() {
575 check( 595 check(
576 r#" 596 r#"
577//- /lib.rs 597//- /lib.rs
578<|> 598<|>
579mod foo { 599mod root_tests {
580 mod test_mod { 600 mod nested_tests_0 {
581 #[test] 601 mod nested_tests_1 {
582 fn test_foo1() {} 602 #[test]
603 fn nested_test_11() {}
604
605 #[test]
606 fn nested_test_12() {}
607 }
608
609 mod nested_tests_2 {
610 #[test]
611 fn nested_test_2() {}
612 }
613
614 mod nested_tests_3 {}
583 } 615 }
616
617 mod nested_tests_4 {}
584} 618}
585"#, 619"#,
586 &[&TEST, &TEST], 620 &[&TEST, &TEST, &TEST, &TEST, &TEST, &TEST],
587 expect![[r#" 621 expect![[r#"
588 [ 622 [
589 Runnable { 623 Runnable {
@@ -591,18 +625,18 @@ mod foo {
591 file_id: FileId( 625 file_id: FileId(
592 1, 626 1,
593 ), 627 ),
594 full_range: 15..77, 628 full_range: 22..323,
595 focus_range: Some( 629 focus_range: Some(
596 19..27, 630 26..40,
597 ), 631 ),
598 name: "test_mod", 632 name: "nested_tests_0",
599 kind: MODULE, 633 kind: MODULE,
600 container_name: None, 634 container_name: None,
601 description: None, 635 description: None,
602 docs: None, 636 docs: None,
603 }, 637 },
604 kind: TestMod { 638 kind: TestMod {
605 path: "foo::test_mod", 639 path: "root_tests::nested_tests_0",
606 }, 640 },
607 cfg_exprs: [], 641 cfg_exprs: [],
608 }, 642 },
@@ -611,19 +645,39 @@ mod foo {
611 file_id: FileId( 645 file_id: FileId(
612 1, 646 1,
613 ), 647 ),
614 full_range: 38..71, 648 full_range: 51..192,
615 focus_range: Some( 649 focus_range: Some(
616 57..66, 650 55..69,
617 ), 651 ),
618 name: "test_foo1", 652 name: "nested_tests_1",
619 kind: FN_DEF, 653 kind: MODULE,
654 container_name: None,
655 description: None,
656 docs: None,
657 },
658 kind: TestMod {
659 path: "root_tests::nested_tests_0::nested_tests_1",
660 },
661 cfg_exprs: [],
662 },
663 Runnable {
664 nav: NavigationTarget {
665 file_id: FileId(
666 1,
667 ),
668 full_range: 84..126,
669 focus_range: Some(
670 107..121,
671 ),
672 name: "nested_test_11",
673 kind: FN,
620 container_name: None, 674 container_name: None,
621 description: None, 675 description: None,
622 docs: None, 676 docs: None,
623 }, 677 },
624 kind: Test { 678 kind: Test {
625 test_id: Path( 679 test_id: Path(
626 "foo::test_mod::test_foo1", 680 "root_tests::nested_tests_0::nested_tests_1::nested_test_11",
627 ), 681 ),
628 attr: TestAttr { 682 attr: TestAttr {
629 ignore: false, 683 ignore: false,
@@ -631,46 +685,48 @@ mod foo {
631 }, 685 },
632 cfg_exprs: [], 686 cfg_exprs: [],
633 }, 687 },
634 ]
635 "#]],
636 );
637 }
638
639 #[test]
640 fn test_runnables_multiple_depth_module() {
641 check(
642 r#"
643//- /lib.rs
644<|>
645mod foo {
646 mod bar {
647 mod test_mod {
648 #[test]
649 fn test_foo1() {}
650 }
651 }
652}
653"#,
654 &[&TEST, &TEST],
655 expect![[r#"
656 [
657 Runnable { 688 Runnable {
658 nav: NavigationTarget { 689 nav: NavigationTarget {
659 file_id: FileId( 690 file_id: FileId(
660 1, 691 1,
661 ), 692 ),
662 full_range: 33..107, 693 full_range: 140..182,
663 focus_range: Some( 694 focus_range: Some(
664 37..45, 695 163..177,
665 ), 696 ),
666 name: "test_mod", 697 name: "nested_test_12",
698 kind: FN,
699 container_name: None,
700 description: None,
701 docs: None,
702 },
703 kind: Test {
704 test_id: Path(
705 "root_tests::nested_tests_0::nested_tests_1::nested_test_12",
706 ),
707 attr: TestAttr {
708 ignore: false,
709 },
710 },
711 cfg_exprs: [],
712 },
713 Runnable {
714 nav: NavigationTarget {
715 file_id: FileId(
716 1,
717 ),
718 full_range: 202..286,
719 focus_range: Some(
720 206..220,
721 ),
722 name: "nested_tests_2",
667 kind: MODULE, 723 kind: MODULE,
668 container_name: None, 724 container_name: None,
669 description: None, 725 description: None,
670 docs: None, 726 docs: None,
671 }, 727 },
672 kind: TestMod { 728 kind: TestMod {
673 path: "foo::bar::test_mod", 729 path: "root_tests::nested_tests_0::nested_tests_2",
674 }, 730 },
675 cfg_exprs: [], 731 cfg_exprs: [],
676 }, 732 },
@@ -679,19 +735,19 @@ mod foo {
679 file_id: FileId( 735 file_id: FileId(
680 1, 736 1,
681 ), 737 ),
682 full_range: 60..97, 738 full_range: 235..276,
683 focus_range: Some( 739 focus_range: Some(
684 83..92, 740 258..271,
685 ), 741 ),
686 name: "test_foo1", 742 name: "nested_test_2",
687 kind: FN_DEF, 743 kind: FN,
688 container_name: None, 744 container_name: None,
689 description: None, 745 description: None,
690 docs: None, 746 docs: None,
691 }, 747 },
692 kind: Test { 748 kind: Test {
693 test_id: Path( 749 test_id: Path(
694 "foo::bar::test_mod::test_foo1", 750 "root_tests::nested_tests_0::nested_tests_2::nested_test_2",
695 ), 751 ),
696 attr: TestAttr { 752 attr: TestAttr {
697 ignore: false, 753 ignore: false,
@@ -727,7 +783,7 @@ fn test_foo1() {}
727 36..45, 783 36..45,
728 ), 784 ),
729 name: "test_foo1", 785 name: "test_foo1",
730 kind: FN_DEF, 786 kind: FN,
731 container_name: None, 787 container_name: None,
732 description: None, 788 description: None,
733 docs: None, 789 docs: None,
@@ -775,7 +831,7 @@ fn test_foo1() {}
775 58..67, 831 58..67,
776 ), 832 ),
777 name: "test_foo1", 833 name: "test_foo1",
778 kind: FN_DEF, 834 kind: FN,
779 container_name: None, 835 container_name: None,
780 description: None, 836 description: None,
781 docs: None, 837 docs: None,