Auto merge of #18057 - alibektas:better_ratoml_testing, r=Veykril

internal: Better testing infra for ratoml

This PR makes some improvements on how we test configs that come from `rust-analyzer.toml` files.
It was primarily used to solve #18021 but along the way I could not really determine the cause of the said issue which makes me think that it may not be related to the changes that I made earlier to the ratoml infra. In either way `custom_snippets` are now made `global` because we still don't have a tree that maps a `SourceRootId` to a set of `Snippet`s.
This commit is contained in:
bors 2024-09-11 11:02:50 +00:00
commit e26ad2116d
5 changed files with 228 additions and 103 deletions

View File

@ -75,6 +75,8 @@
/// How many worker threads to handle priming caches. The default `0` means to pick automatically. /// How many worker threads to handle priming caches. The default `0` means to pick automatically.
cachePriming_numThreads: NumThreads = NumThreads::Physical, cachePriming_numThreads: NumThreads = NumThreads::Physical,
/// Custom completion snippets.
completion_snippets_custom: FxHashMap<String, SnippetDef> = Config::completion_snippets_default(),
/// These directories will be ignored by rust-analyzer. They are /// These directories will be ignored by rust-analyzer. They are
@ -442,48 +444,6 @@
completion_postfix_enable: bool = true, completion_postfix_enable: bool = true,
/// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
completion_privateEditable_enable: bool = false, completion_privateEditable_enable: bool = false,
/// Custom completion snippets.
completion_snippets_custom: FxHashMap<String, SnippetDef> = serde_json::from_str(r#"{
"Arc::new": {
"postfix": "arc",
"body": "Arc::new(${receiver})",
"requires": "std::sync::Arc",
"description": "Put the expression into an `Arc`",
"scope": "expr"
},
"Rc::new": {
"postfix": "rc",
"body": "Rc::new(${receiver})",
"requires": "std::rc::Rc",
"description": "Put the expression into an `Rc`",
"scope": "expr"
},
"Box::pin": {
"postfix": "pinbox",
"body": "Box::pin(${receiver})",
"requires": "std::boxed::Box",
"description": "Put the expression into a pinned `Box`",
"scope": "expr"
},
"Ok": {
"postfix": "ok",
"body": "Ok(${receiver})",
"description": "Wrap the expression in a `Result::Ok`",
"scope": "expr"
},
"Err": {
"postfix": "err",
"body": "Err(${receiver})",
"description": "Wrap the expression in a `Result::Err`",
"scope": "expr"
},
"Some": {
"postfix": "some",
"body": "Some(${receiver})",
"description": "Wrap the expression in an `Option::Some`",
"scope": "expr"
}
}"#).unwrap(),
/// Whether to enable term search based snippets like `Some(foo.bar().baz())`. /// Whether to enable term search based snippets like `Some(foo.bar().baz())`.
completion_termSearch_enable: bool = false, completion_termSearch_enable: bool = false,
/// Term search fuel in "units of work" for autocompletion (Defaults to 1000). /// Term search fuel in "units of work" for autocompletion (Defaults to 1000).
@ -893,7 +853,7 @@ fn apply_change_with_sink(&self, change: ConfigChange) -> (Config, bool) {
// IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`. // IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`.
config.snippets.clear(); config.snippets.clear();
let snips = self.completion_snippets_custom(None).to_owned(); let snips = self.completion_snippets_custom().to_owned();
for (name, def) in snips.iter() { for (name, def) in snips.iter() {
if def.prefix.is_empty() && def.postfix.is_empty() { if def.prefix.is_empty() && def.postfix.is_empty() {
@ -1270,7 +1230,7 @@ pub struct NotificationsConfig {
pub cargo_toml_not_found: bool, pub cargo_toml_not_found: bool,
} }
#[derive(Debug, Clone)] #[derive(Deserialize, Serialize, Debug, Clone)]
pub enum RustfmtConfig { pub enum RustfmtConfig {
Rustfmt { extra_args: Vec<String>, enable_range_formatting: bool }, Rustfmt { extra_args: Vec<String>, enable_range_formatting: bool },
CustomCommand { command: String, args: Vec<String> }, CustomCommand { command: String, args: Vec<String> },
@ -1902,6 +1862,53 @@ pub fn cargo(&self, source_root: Option<SourceRootId>) -> CargoConfig {
} }
} }
pub(crate) fn completion_snippets_default() -> FxHashMap<String, SnippetDef> {
serde_json::from_str(
r#"{
"Arc::new": {
"postfix": "arc",
"body": "Arc::new(${receiver})",
"requires": "std::sync::Arc",
"description": "Put the expression into an `Arc`",
"scope": "expr"
},
"Rc::new": {
"postfix": "rc",
"body": "Rc::new(${receiver})",
"requires": "std::rc::Rc",
"description": "Put the expression into an `Rc`",
"scope": "expr"
},
"Box::pin": {
"postfix": "pinbox",
"body": "Box::pin(${receiver})",
"requires": "std::boxed::Box",
"description": "Put the expression into a pinned `Box`",
"scope": "expr"
},
"Ok": {
"postfix": "ok",
"body": "Ok(${receiver})",
"description": "Wrap the expression in a `Result::Ok`",
"scope": "expr"
},
"Err": {
"postfix": "err",
"body": "Err(${receiver})",
"description": "Wrap the expression in a `Result::Err`",
"scope": "expr"
},
"Some": {
"postfix": "some",
"body": "Some(${receiver})",
"description": "Wrap the expression in an `Option::Some`",
"scope": "expr"
}
}"#,
)
.unwrap()
}
pub fn rustfmt(&self, source_root_id: Option<SourceRootId>) -> RustfmtConfig { pub fn rustfmt(&self, source_root_id: Option<SourceRootId>) -> RustfmtConfig {
match &self.rustfmt_overrideCommand(source_root_id) { match &self.rustfmt_overrideCommand(source_root_id) {
Some(args) if !args.is_empty() => { Some(args) if !args.is_empty() => {

View File

@ -40,7 +40,10 @@
hack_recover_crate_name, hack_recover_crate_name,
line_index::LineEndings, line_index::LineEndings,
lsp::{ lsp::{
ext::InternalTestingFetchConfigParams, ext::{
InternalTestingFetchConfigOption, InternalTestingFetchConfigParams,
InternalTestingFetchConfigResponse,
},
from_proto, to_proto, from_proto, to_proto,
utils::{all_edits_are_disjoint, invalid_params_error}, utils::{all_edits_are_disjoint, invalid_params_error},
LspError, LspError,
@ -2292,7 +2295,7 @@ pub(crate) fn fetch_dependency_list(
pub(crate) fn internal_testing_fetch_config( pub(crate) fn internal_testing_fetch_config(
state: GlobalStateSnapshot, state: GlobalStateSnapshot,
params: InternalTestingFetchConfigParams, params: InternalTestingFetchConfigParams,
) -> anyhow::Result<serde_json::Value> { ) -> anyhow::Result<Option<InternalTestingFetchConfigResponse>> {
let source_root = params let source_root = params
.text_document .text_document
.map(|it| { .map(|it| {
@ -2302,15 +2305,18 @@ pub(crate) fn internal_testing_fetch_config(
.map_err(anyhow::Error::from) .map_err(anyhow::Error::from)
}) })
.transpose()?; .transpose()?;
serde_json::to_value(match &*params.config { Ok(Some(match params.config {
"local" => state.config.assist(source_root).assist_emit_must_use, InternalTestingFetchConfigOption::AssistEmitMustUse => {
"workspace" => matches!( InternalTestingFetchConfigResponse::AssistEmitMustUse(
state.config.rustfmt(source_root), state.config.assist(source_root).assist_emit_must_use,
RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } )
), }
_ => return Err(anyhow::anyhow!("Unknown test config key: {}", params.config)), InternalTestingFetchConfigOption::CheckWorkspace => {
}) InternalTestingFetchConfigResponse::CheckWorkspace(
.map_err(Into::into) state.config.flycheck_workspace(source_root),
)
}
}))
} }
/// Searches for the directory of a Rust crate given this crate's root file path. /// Searches for the directory of a Rust crate given this crate's root file path.

View File

@ -16,9 +16,22 @@
pub enum InternalTestingFetchConfig {} pub enum InternalTestingFetchConfig {}
#[derive(Deserialize, Serialize, Debug)]
pub enum InternalTestingFetchConfigOption {
AssistEmitMustUse,
CheckWorkspace,
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub enum InternalTestingFetchConfigResponse {
AssistEmitMustUse(bool),
CheckWorkspace(bool),
}
impl Request for InternalTestingFetchConfig { impl Request for InternalTestingFetchConfig {
type Params = InternalTestingFetchConfigParams; type Params = InternalTestingFetchConfigParams;
type Result = serde_json::Value; // Option is solely to circumvent Default bound.
type Result = Option<InternalTestingFetchConfigResponse>;
const METHOD: &'static str = "rust-analyzer-internal/internalTestingFetchConfig"; const METHOD: &'static str = "rust-analyzer-internal/internalTestingFetchConfig";
} }
@ -26,7 +39,7 @@ impl Request for InternalTestingFetchConfig {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct InternalTestingFetchConfigParams { pub struct InternalTestingFetchConfigParams {
pub text_document: Option<TextDocumentIdentifier>, pub text_document: Option<TextDocumentIdentifier>,
pub config: String, pub config: InternalTestingFetchConfigOption,
} }
pub enum AnalyzerStatus {} pub enum AnalyzerStatus {}

View File

@ -9,18 +9,13 @@
use paths::Utf8PathBuf; use paths::Utf8PathBuf;
use rust_analyzer::config::Config; use rust_analyzer::config::Config;
use rust_analyzer::lsp::ext::{InternalTestingFetchConfig, InternalTestingFetchConfigParams}; use rust_analyzer::lsp::ext::{
InternalTestingFetchConfig, InternalTestingFetchConfigOption, InternalTestingFetchConfigParams,
InternalTestingFetchConfigResponse,
};
use serde_json::json; use serde_json::json;
use test_utils::skip_slow_tests; use test_utils::skip_slow_tests;
enum QueryType {
Local,
/// A query whose config key is a part of the global configs, so that
/// testing for changes to this config means testing if global changes
/// take affect.
Workspace,
}
struct RatomlTest { struct RatomlTest {
urls: Vec<Url>, urls: Vec<Url>,
server: Server, server: Server,
@ -158,20 +153,24 @@ fn edit(&mut self, file_idx: usize, text: String) {
}); });
} }
fn query(&self, query: QueryType, source_file_idx: usize) -> bool { fn query(
let config = match query { &self,
QueryType::Local => "local".to_owned(), query: InternalTestingFetchConfigOption,
QueryType::Workspace => "workspace".to_owned(), source_file_idx: usize,
}; expected: InternalTestingFetchConfigResponse,
) {
let res = self.server.send_request::<InternalTestingFetchConfig>( let res = self.server.send_request::<InternalTestingFetchConfig>(
InternalTestingFetchConfigParams { InternalTestingFetchConfigParams {
text_document: Some(TextDocumentIdentifier { text_document: Some(TextDocumentIdentifier {
uri: self.urls[source_file_idx].clone(), uri: self.urls[source_file_idx].clone(),
}), }),
config, config: query,
}, },
); );
res.as_bool().unwrap() assert_eq!(
serde_json::from_value::<InternalTestingFetchConfigResponse>(res).unwrap(),
expected
)
} }
} }
@ -206,7 +205,11 @@ enum Value {
})), })),
); );
assert!(server.query(QueryType::Local, 1)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
1,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
} }
/// Checks if client config can be modified. /// Checks if client config can be modified.
@ -311,7 +314,11 @@ enum Value {
None, None,
); );
assert!(server.query(QueryType::Local, 2)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
2,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
} }
#[test] #[test]
@ -341,12 +348,20 @@ enum Value {
None, None,
); );
assert!(!server.query(QueryType::Local, 1)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
1,
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
);
server.create( server.create(
"//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml", "//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml",
RatomlTest::EMIT_MUST_USE.to_owned(), RatomlTest::EMIT_MUST_USE.to_owned(),
); );
assert!(server.query(QueryType::Local, 1)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
1,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
} }
#[test] #[test]
@ -378,9 +393,17 @@ enum Value {
None, None,
); );
assert!(server.query(QueryType::Local, 1)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
1,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
server.edit(2, String::new()); server.edit(2, String::new());
assert!(!server.query(QueryType::Local, 1)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
1,
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
);
} }
#[test] #[test]
@ -412,9 +435,17 @@ enum Value {
None, None,
); );
assert!(server.query(QueryType::Local, 1)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
1,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
server.delete(2); server.delete(2);
assert!(!server.query(QueryType::Local, 1)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
1,
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
);
} }
#[test] #[test]
@ -461,7 +492,11 @@ pub fn add(left: usize, right: usize) -> usize {
None, None,
); );
assert!(server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
} }
#[test] #[test]
@ -508,9 +543,17 @@ pub fn add(left: usize, right: usize) -> usize {
None, None,
); );
assert!(!server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
);
server.edit(1, "assist.emitMustUse = true".to_owned()); server.edit(1, "assist.emitMustUse = true".to_owned());
assert!(server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
} }
#[test] #[test]
@ -557,9 +600,17 @@ pub fn add(left: usize, right: usize) -> usize {
None, None,
); );
assert!(server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
server.delete(1); server.delete(1);
assert!(!server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
);
} }
#[test] #[test]
@ -606,9 +657,17 @@ pub fn add(left: usize, right: usize) -> usize {
None, None,
); );
assert!(server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
server.create("//- /p1/p2/rust-analyzer.toml", RatomlTest::EMIT_MUST_NOT_USE.to_owned()); server.create("//- /p1/p2/rust-analyzer.toml", RatomlTest::EMIT_MUST_NOT_USE.to_owned());
assert!(!server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
);
} }
#[test] #[test]
@ -656,9 +715,17 @@ pub fn add(left: usize, right: usize) -> usize {
None, None,
); );
assert!(server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
server.delete(1); server.delete(1);
assert!(!server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
);
} }
#[test] #[test]
@ -705,8 +772,16 @@ enum Value {
None, None,
); );
assert!(server.query(QueryType::Local, 3)); server.query(
assert!(server.query(QueryType::Local, 4)); InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
4,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
} }
#[test] #[test]
@ -744,7 +819,11 @@ enum Value {
None, None,
); );
assert!(server.query(QueryType::Local, 3)); server.query(
InternalTestingFetchConfigOption::AssistEmitMustUse,
3,
InternalTestingFetchConfigResponse::AssistEmitMustUse(true),
);
} }
/// If a root is non-local, so we cannot find what its parent is /// If a root is non-local, so we cannot find what its parent is
@ -836,7 +915,7 @@ fn ratoml_in_root_is_workspace() {
"#, "#,
r#" r#"
//- /p1/rust-analyzer.toml //- /p1/rust-analyzer.toml
rustfmt.rangeFormatting.enable = true check.workspace = false
"#, "#,
r#" r#"
//- /p1/src/lib.rs //- /p1/src/lib.rs
@ -848,7 +927,11 @@ fn main() {
None, None,
); );
assert!(server.query(QueryType::Workspace, 2)); server.query(
InternalTestingFetchConfigOption::CheckWorkspace,
2,
InternalTestingFetchConfigResponse::CheckWorkspace(false),
)
} }
#[test] #[test]
@ -868,7 +951,7 @@ fn ratoml_root_is_updateable() {
"#, "#,
r#" r#"
//- /p1/rust-analyzer.toml //- /p1/rust-analyzer.toml
rustfmt.rangeFormatting.enable = true check.workspace = false
"#, "#,
r#" r#"
//- /p1/src/lib.rs //- /p1/src/lib.rs
@ -880,9 +963,17 @@ fn main() {
None, None,
); );
assert!(server.query(QueryType::Workspace, 2)); server.query(
server.edit(1, "rustfmt.rangeFormatting.enable = false".to_owned()); InternalTestingFetchConfigOption::CheckWorkspace,
assert!(!server.query(QueryType::Workspace, 2)); 2,
InternalTestingFetchConfigResponse::CheckWorkspace(false),
);
server.edit(1, "check.workspace = true".to_owned());
server.query(
InternalTestingFetchConfigOption::CheckWorkspace,
2,
InternalTestingFetchConfigResponse::CheckWorkspace(true),
);
} }
#[test] #[test]
@ -902,7 +993,7 @@ fn ratoml_root_is_deletable() {
"#, "#,
r#" r#"
//- /p1/rust-analyzer.toml //- /p1/rust-analyzer.toml
rustfmt.rangeFormatting.enable = true check.workspace = false
"#, "#,
r#" r#"
//- /p1/src/lib.rs //- /p1/src/lib.rs
@ -914,7 +1005,15 @@ fn main() {
None, None,
); );
assert!(server.query(QueryType::Workspace, 2)); server.query(
InternalTestingFetchConfigOption::CheckWorkspace,
2,
InternalTestingFetchConfigResponse::CheckWorkspace(false),
);
server.delete(1); server.delete(1);
assert!(!server.query(QueryType::Workspace, 2)); server.query(
InternalTestingFetchConfigOption::CheckWorkspace,
2,
InternalTestingFetchConfigResponse::CheckWorkspace(true),
);
} }

View File

@ -1,5 +1,5 @@
<!--- <!---
lsp/ext.rs hash: c6e83d3d08d993de lsp/ext.rs hash: 6292ee8d88d4c9ec
If you need to change the above hash to make the test pass, please check if you If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue: need to adjust this doc as well and ping this issue: