diff options
author | Aleksey Kladov <[email protected]> | 2020-07-04 08:53:54 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-07-04 08:53:54 +0100 |
commit | 5c68dd6b59cd5006a96280217bc88a6e26f90f1f (patch) | |
tree | d8dce79c52d266d9a79edfa673b5e315d195d304 /crates/ra_ide/src | |
parent | aaba2300fb14360a00e75da1916b11fd99c0afce (diff) |
Better tests for completion scoring
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/completion/completion_item.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 246 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/test_utils.rs | 5 |
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)] |
99 | pub enum CompletionScore { | 99 | pub 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)] |
463 | mod tests { | 463 | mod 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#" | ||
909 | struct S { foo: i64, bar: u32, baz: () } | ||
910 | fn test(x: u32) { } | ||
911 | fn 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#" |
949 | struct S { foo: i64, bar: u32, baz: u32 } | 939 | struct S { foo: i64, bar: u32, baz: u32 } |
950 | fn test(bar: u32) { } | 940 | fn test(bar: u32) { } |
951 | fn foo(s: S) { test(s.<|>) } | 941 | fn 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#" |
991 | struct A { foo: i64, bar: u32, baz: u32 } | 956 | struct A { foo: i64, bar: u32, baz: u32 } |
992 | struct B { x: (), y: f32, bar: u32 } | 957 | struct B { x: (), y: f32, bar: u32 } |
993 | fn foo(a: A) { B { bar: a.<|> }; } | 958 | fn 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#" |
1032 | struct A { foo: i64, bar: u32, baz: u32 } | 972 | struct A { foo: i64, bar: u32, baz: u32 } |
1033 | struct B { x: (), y: f32, bar: u32 } | 973 | struct B { x: (), y: f32, bar: u32 } |
@@ -1035,36 +975,12 @@ fn f(foo: i64) { } | |||
1035 | fn foo(a: A) { B { bar: f(a.<|>) }; } | 975 | fn 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#" |
1069 | struct A { foo: i64, bar: u32, baz: u32 } | 985 | struct A { foo: i64, bar: u32, baz: u32 } |
1070 | struct B { x: (), y: f32, bar: u32 } | 986 | struct B { x: (), y: f32, bar: u32 } |
@@ -1072,74 +988,24 @@ fn f(foo: i64) { } | |||
1072 | fn foo(a: A) { f(B { bar: a.<|> }); } | 988 | fn 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#" |
1111 | struct WorldSnapshot { _f: () }; | 1002 | struct WorldSnapshot { _f: () }; |
1112 | fn go(world: &WorldSnapshot) { go(w<|>) } | 1003 | fn 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 | ||
95 | fn get_all_completion_items(code: &str, options: &CompletionConfig) -> Vec<CompletionItem> { | 95 | pub(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 | } |