use serde_json::Value;
use crate::local_fixture::LocalFixture;
use crate::manifest::CommandStrategy;
#[test]
fn lsp_fixture_command_paths_are_covered() {
let fixture = LocalFixture::new().expect("local fixture should initialize");
for command in fixture.commands_for(CommandStrategy::LspFixture) {
run_query(&fixture, command);
}
}
fn run_query(fixture: &LocalFixture, command: &str) {
let mut args = command_prefix(command);
args.extend([
"--lsp".to_string(),
fixture.server_name().to_string(),
"--no-download".to_string(),
"--no-detach".to_string(),
"--timeout".to_string(),
"5".to_string(),
]);
if !matches!(command, "server-capabilities" | "format" | "build-index") {
args.push("--json".to_string());
}
if command == "format" {
args.push("--stdout".to_string());
}
let refs = args.iter().map(String::as_str).collect::<Vec<_>>();
let output = fixture.context().run(&refs);
output.assert_success();
match command {
"server-capabilities" => assert!(output.stdout_text().contains("workspace symbols")),
"build-index" => assert!(output.stdout_text().is_empty()),
"format" => {
assert!(output.stdout_text().contains(" formatted"));
assert!(
std::fs::read_to_string(fixture.context().workspace().join("main.fake"))
.expect("fixture source should remain readable")
.contains(" unformatted")
);
}
"diagnostics" => {
let value: Value = output.json();
assert_eq!(
value
.pointer("/diagnostics/0/message")
.and_then(Value::as_str),
Some("synthetic diagnostic")
);
}
other => {
let value: Value = output.json();
assert_eq!(
value.pointer("/matches/0/name").and_then(Value::as_str),
Some("Target"),
"command {other}"
);
}
}
}
fn command_prefix(command: &str) -> Vec<String> {
match command {
"grep" | "references" | "callers" | "callees" | "definition" | "declaration"
| "implementation" | "type-definition" => {
vec![command.to_string(), "Target".to_string(), ".".to_string()]
}
"format" => vec![command.to_string(), "main.fake".to_string()],
"server-capabilities"
| "diagnostics"
| "list-symbols"
| "list-functions"
| "build-index" => vec![command.to_string(), ".".to_string()],
other => panic!("LSP fixture strategy has no scenario for {other:?}"),
}
}
#[test]
fn unadvertised_capabilities_produce_user_facing_errors() {
let fixture = LocalFixture::new_unsupported().expect("local fixture should initialize");
for (command, expected) in [
("grep", "does not support workspace/symbol"),
("format", "does not support format"),
] {
let mut args = command_prefix(command);
args.extend([
"--lsp".to_string(),
fixture.unsupported_server_name().to_string(),
"--no-download".to_string(),
"--no-detach".to_string(),
"--timeout".to_string(),
"5".to_string(),
]);
if command == "format" {
args.push("--stdout".to_string());
}
let refs = args.iter().map(String::as_str).collect::<Vec<_>>();
let output = fixture.context().run(&refs);
assert!(output.ensure_success().is_err(), "{command} should fail");
assert!(output.stderr_text().contains(expected), "{command}");
}
}