aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-07-04 08:53:54 +0100
committerAleksey Kladov <[email protected]>2020-07-04 08:53:54 +0100
commit5c68dd6b59cd5006a96280217bc88a6e26f90f1f (patch)
treed8dce79c52d266d9a79edfa673b5e315d195d304 /crates/ra_ide/src
parentaaba2300fb14360a00e75da1916b11fd99c0afce (diff)
Better tests for completion scoring
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs2
-rw-r--r--crates/ra_ide/src/completion/presentation.rs246
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs5
3 files changed, 61 insertions, 192 deletions
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index 4db371d57..477d6f6f6 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -95,7 +95,7 @@ impl fmt::Debug for CompletionItem {
95 } 95 }
96} 96}
97 97
98#[derive(Debug, Clone, Copy)] 98#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
99pub enum CompletionScore { 99pub enum CompletionScore {
100 /// If only type match 100 /// If only type match
101 TypeMatch, 101 TypeMatch,
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 9ec33a050..ee810b59f 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -461,12 +461,19 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s
461 461
462#[cfg(test)] 462#[cfg(test)]
463mod tests { 463mod tests {
464 use std::cmp::Reverse;
465
464 use expect::{expect, Expect}; 466 use expect::{expect, Expect};
465 use test_utils::mark; 467 use test_utils::mark;
466 468
467 use crate::completion::{ 469 use crate::{
468 test_utils::{check_edit, check_edit_with_config, do_completion}, 470 completion::{
469 CompletionConfig, CompletionKind, 471 test_utils::{
472 check_edit, check_edit_with_config, do_completion, get_all_completion_items,
473 },
474 CompletionConfig, CompletionKind,
475 },
476 CompletionScore,
470 }; 477 };
471 478
472 fn check(ra_fixture: &str, expect: Expect) { 479 fn check(ra_fixture: &str, expect: Expect) {
@@ -474,6 +481,29 @@ mod tests {
474 expect.assert_debug_eq(&actual); 481 expect.assert_debug_eq(&actual);
475 } 482 }
476 483
484 fn check_scores(ra_fixture: &str, expect: Expect) {
485 fn display_score(score: Option<CompletionScore>) -> &'static str {
486 match score {
487 Some(CompletionScore::TypeMatch) => "[type]",
488 Some(CompletionScore::TypeAndNameMatch) => "[type+name]",
489 None => "[]".into(),
490 }
491 }
492
493 let mut completions = get_all_completion_items(ra_fixture, &CompletionConfig::default());
494 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
495 let actual = completions
496 .into_iter()
497 .filter(|it| it.completion_kind == CompletionKind::Reference)
498 .map(|it| {
499 let tag = it.kind().unwrap().tag();
500 let score = display_score(it.score());
501 format!("{} {} {}\n", tag, it.label(), score)
502 })
503 .collect::<String>();
504 expect.assert_eq(&actual);
505 }
506
477 #[test] 507 #[test]
478 fn enum_detail_includes_record_fields() { 508 fn enum_detail_includes_record_fields() {
479 check( 509 check(
@@ -902,132 +932,42 @@ fn main() { frobnicate!(); }
902 } 932 }
903 933
904 #[test] 934 #[test]
905 fn active_param_type_match() { 935 fn active_param_score() {
906 mark::check!(active_param_type_match); 936 mark::check!(active_param_type_match);
907 check( 937 check_scores(
908 r#"
909struct S { foo: i64, bar: u32, baz: () }
910fn test(x: u32) { }
911fn foo(s: S) { test(s.<|>) }
912"#,
913 expect![[r#"
914 [
915 CompletionItem {
916 label: "bar",
917 source_range: 83..83,
918 delete: 83..83,
919 insert: "bar",
920 kind: Field,
921 detail: "u32",
922 score: TypeMatch,
923 },
924 CompletionItem {
925 label: "baz",
926 source_range: 83..83,
927 delete: 83..83,
928 insert: "baz",
929 kind: Field,
930 detail: "()",
931 },
932 CompletionItem {
933 label: "foo",
934 source_range: 83..83,
935 delete: 83..83,
936 insert: "foo",
937 kind: Field,
938 detail: "i64",
939 },
940 ]
941 "#]],
942 );
943 }
944
945 #[test]
946 fn active_param_type_and_name_match() {
947 check(
948 r#" 938 r#"
949struct S { foo: i64, bar: u32, baz: u32 } 939struct S { foo: i64, bar: u32, baz: u32 }
950fn test(bar: u32) { } 940fn test(bar: u32) { }
951fn foo(s: S) { test(s.<|>) } 941fn foo(s: S) { test(s.<|>) }
952"#, 942"#,
953 expect![[r#" 943 expect![[r#"
954 [ 944 fd bar [type+name]
955 CompletionItem { 945 fd baz [type]
956 label: "bar", 946 fd foo []
957 source_range: 86..86,
958 delete: 86..86,
959 insert: "bar",
960 kind: Field,
961 detail: "u32",
962 score: TypeAndNameMatch,
963 },
964 CompletionItem {
965 label: "baz",
966 source_range: 86..86,
967 delete: 86..86,
968 insert: "baz",
969 kind: Field,
970 detail: "u32",
971 score: TypeMatch,
972 },
973 CompletionItem {
974 label: "foo",
975 source_range: 86..86,
976 delete: 86..86,
977 insert: "foo",
978 kind: Field,
979 detail: "i64",
980 },
981 ]
982 "#]], 947 "#]],
983 ); 948 );
984 } 949 }
985 950
986 #[test] 951 #[test]
987 fn record_field_type_match() { 952 fn record_field_scores() {
988 mark::check!(record_field_type_match); 953 mark::check!(record_field_type_match);
989 check( 954 check_scores(
990 r#" 955 r#"
991struct A { foo: i64, bar: u32, baz: u32 } 956struct A { foo: i64, bar: u32, baz: u32 }
992struct B { x: (), y: f32, bar: u32 } 957struct B { x: (), y: f32, bar: u32 }
993fn foo(a: A) { B { bar: a.<|> }; } 958fn foo(a: A) { B { bar: a.<|> }; }
994"#, 959"#,
995 expect![[r#" 960 expect![[r#"
996 [ 961 fd bar [type+name]
997 CompletionItem { 962 fd baz [type]
998 label: "bar", 963 fd foo []
999 source_range: 105..105,
1000 delete: 105..105,
1001 insert: "bar",
1002 kind: Field,
1003 detail: "u32",
1004 score: TypeAndNameMatch,
1005 },
1006 CompletionItem {
1007 label: "baz",
1008 source_range: 105..105,
1009 delete: 105..105,
1010 insert: "baz",
1011 kind: Field,
1012 detail: "u32",
1013 score: TypeMatch,
1014 },
1015 CompletionItem {
1016 label: "foo",
1017 source_range: 105..105,
1018 delete: 105..105,
1019 insert: "foo",
1020 kind: Field,
1021 detail: "i64",
1022 },
1023 ]
1024 "#]], 964 "#]],
1025 ) 965 )
1026 } 966 }
1027 967
1028 #[test] 968 #[test]
1029 fn record_field_type_match_and_fn_call() { 969 fn record_field_and_call_scores() {
1030 check( 970 check_scores(
1031 r#" 971 r#"
1032struct A { foo: i64, bar: u32, baz: u32 } 972struct A { foo: i64, bar: u32, baz: u32 }
1033struct B { x: (), y: f32, bar: u32 } 973struct B { x: (), y: f32, bar: u32 }
@@ -1035,36 +975,12 @@ fn f(foo: i64) { }
1035fn foo(a: A) { B { bar: f(a.<|>) }; } 975fn foo(a: A) { B { bar: f(a.<|>) }; }
1036"#, 976"#,
1037 expect![[r#" 977 expect![[r#"
1038 [ 978 fd foo [type+name]
1039 CompletionItem { 979 fd bar []
1040 label: "bar", 980 fd baz []
1041 source_range: 127..127,
1042 delete: 127..127,
1043 insert: "bar",
1044 kind: Field,
1045 detail: "u32",
1046 },
1047 CompletionItem {
1048 label: "baz",
1049 source_range: 127..127,
1050 delete: 127..127,
1051 insert: "baz",
1052 kind: Field,
1053 detail: "u32",
1054 },
1055 CompletionItem {
1056 label: "foo",
1057 source_range: 127..127,
1058 delete: 127..127,
1059 insert: "foo",
1060 kind: Field,
1061 detail: "i64",
1062 score: TypeAndNameMatch,
1063 },
1064 ]
1065 "#]], 981 "#]],
1066 ); 982 );
1067 check( 983 check_scores(
1068 r#" 984 r#"
1069struct A { foo: i64, bar: u32, baz: u32 } 985struct A { foo: i64, bar: u32, baz: u32 }
1070struct B { x: (), y: f32, bar: u32 } 986struct B { x: (), y: f32, bar: u32 }
@@ -1072,74 +988,24 @@ fn f(foo: i64) { }
1072fn foo(a: A) { f(B { bar: a.<|> }); } 988fn foo(a: A) { f(B { bar: a.<|> }); }
1073"#, 989"#,
1074 expect![[r#" 990 expect![[r#"
1075 [ 991 fd bar [type+name]
1076 CompletionItem { 992 fd baz [type]
1077 label: "bar", 993 fd foo []
1078 source_range: 127..127,
1079 delete: 127..127,
1080 insert: "bar",
1081 kind: Field,
1082 detail: "u32",
1083 score: TypeAndNameMatch,
1084 },
1085 CompletionItem {
1086 label: "baz",
1087 source_range: 127..127,
1088 delete: 127..127,
1089 insert: "baz",
1090 kind: Field,
1091 detail: "u32",
1092 score: TypeMatch,
1093 },
1094 CompletionItem {
1095 label: "foo",
1096 source_range: 127..127,
1097 delete: 127..127,
1098 insert: "foo",
1099 kind: Field,
1100 detail: "i64",
1101 },
1102 ]
1103 "#]], 994 "#]],
1104 ); 995 );
1105 } 996 }
1106 997
1107 #[test] 998 #[test]
1108 fn prioritize_exact_ref_match() { 999 fn prioritize_exact_ref_match() {
1109 check( 1000 check_scores(
1110 r#" 1001 r#"
1111struct WorldSnapshot { _f: () }; 1002struct WorldSnapshot { _f: () };
1112fn go(world: &WorldSnapshot) { go(w<|>) } 1003fn go(world: &WorldSnapshot) { go(w<|>) }
1113"#, 1004"#,
1114 expect![[r#" 1005 expect![[r#"
1115 [ 1006 bn world [type+name]
1116 CompletionItem { 1007 st WorldSnapshot []
1117 label: "WorldSnapshot", 1008 fn go(…) []
1118 source_range: 67..68,
1119 delete: 67..68,
1120 insert: "WorldSnapshot",
1121 kind: Struct,
1122 },
1123 CompletionItem {
1124 label: "go(…)",
1125 source_range: 67..68,
1126 delete: 67..68,
1127 insert: "go(${1:world})$0",
1128 kind: Function,
1129 lookup: "go",
1130 detail: "fn go(world: &WorldSnapshot)",
1131 trigger_call_info: true,
1132 },
1133 CompletionItem {
1134 label: "world",
1135 source_range: 67..68,
1136 delete: 67..68,
1137 insert: "world",
1138 kind: Binding,
1139 detail: "&WorldSnapshot",
1140 score: TypeAndNameMatch,
1141 },
1142 ]
1143 "#]], 1009 "#]],
1144 ); 1010 );
1145 } 1011 }
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index 329acdc8b..cbae1da85 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -92,7 +92,10 @@ pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -
92 .unwrap(); 92 .unwrap();
93} 93}
94 94
95fn get_all_completion_items(code: &str, options: &CompletionConfig) -> Vec<CompletionItem> { 95pub(crate) fn get_all_completion_items(
96 code: &str,
97 options: &CompletionConfig,
98) -> Vec<CompletionItem> {
96 let (analysis, position) = analysis_and_position(code); 99 let (analysis, position) = analysis_and_position(code);
97 analysis.completions(options, position).unwrap().unwrap().into() 100 analysis.completions(options, position).unwrap().unwrap().into()
98} 101}