diff options
Diffstat (limited to 'crates/ra_ide/src/runnables.rs')
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 200 |
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 | ||
112 | fn runnable_fn( | 112 | fn 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 | ||
190 | impl TestAttr { | 190 | impl 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. |
206 | fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool { | 206 | fn 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 | ||
214 | fn has_doc_test(fn_def: &ast::FnDef) -> bool { | 214 | fn 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 | ||
243 | fn 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)] |
250 | mod tests { | 270 | mod 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 | <|> |
579 | mod foo { | 599 | mod 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 | <|> | ||
645 | mod 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, |