use super::*;
use expect_test::expect;
use serde_json::json;
#[tokio::test]
async fn pull_diagnostics_returns_parse_errors() {
let mut s = TestServer::new().await;
let uri = s.uri("test.php");
s.open(
"test.php",
r#"<?php
class {
"#,
)
.await;
let resp = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()}
}),
)
.await;
let out = render_pull_diagnostics(&resp);
expect![[r#"
1:6-1:7 [1] SyntaxError: expected class name, found '{'
2:0-2:1 [1] SyntaxError: expected '}', found end of file"#]]
.assert_eq(&out);
}
#[tokio::test]
async fn pull_diagnostics_includes_semantic_errors() {
let mut s = TestServer::new().await;
let uri = s.uri("test.php");
s.open(
"test.php",
r#"<?php
function foo() {
echo undefined_function();
}
"#,
)
.await;
let resp = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()}
}),
)
.await;
expect!["2:9-2:29 [1] UndefinedFunction: Function undefined_function() is not defined"]
.assert_eq(&render_pull_diagnostics(&resp));
}
#[tokio::test]
async fn pull_diagnostics_empty_on_valid_code() {
let mut s = TestServer::new().await;
let uri = s.uri("test.php");
s.open(
"test.php",
r#"<?php
function foo(): int {
return 42;
}
"#,
)
.await;
let resp = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()}
}),
)
.await;
expect!["<empty>"].assert_eq(&render_pull_diagnostics(&resp));
}
#[tokio::test]
async fn pull_diagnostics_result_id_stable() {
let mut s = TestServer::new().await;
let uri = s.uri("test.php");
s.open(
"test.php",
r#"<?php
$x = 1;
"#,
)
.await;
let resp1 = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()}
}),
)
.await;
let resp2 = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()}
}),
)
.await;
let id1 = resp1["result"]["resultId"].clone();
let id2 = resp2["result"]["resultId"].clone();
assert_eq!(id1, id2, "result_id should be stable for same content");
}
#[tokio::test]
async fn pull_diagnostics_unchanged_when_previous_result_id_matches() {
let mut s = TestServer::new().await;
let uri = s.uri("test.php");
s.open(
"test.php",
r#"<?php
function foo() {
echo undefined_function();
}
"#,
)
.await;
let resp1 = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()}
}),
)
.await;
assert_eq!(resp1["result"]["kind"], "full");
let result_id = resp1["result"]["resultId"].as_str().unwrap().to_owned();
let resp2 = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()},
"previousResultId": result_id,
}),
)
.await;
assert_eq!(
resp2["result"]["kind"], "unchanged",
"expected an unchanged report when previousResultId matches: {resp2:?}"
);
assert_eq!(resp2["result"]["resultId"], result_id);
assert!(
resp2["result"]["items"].is_null(),
"an unchanged report must not carry an items array: {resp2:?}"
);
}
#[tokio::test]
async fn pull_diagnostics_full_when_previous_result_id_stale() {
let mut s = TestServer::new().await;
let uri = s.uri("test.php");
s.open("test.php", "<?php\n$x = 1;\n").await;
s.client()
.notify(
"textDocument/didChange",
json!({
"textDocument": {"uri": uri.to_string(), "version": 2},
"contentChanges": [{"text": "<?php\nundefined_function();\n"}]
}),
)
.await;
let resp = s
.client()
.request(
"textDocument/diagnostic",
json!({
"textDocument": {"uri": uri.to_string()},
"previousResultId": "stale-id-from-before-the-edit",
}),
)
.await;
assert_eq!(resp["result"]["kind"], "full");
expect!["1:0-1:20 [1] UndefinedFunction: Function undefined_function() is not defined"]
.assert_eq(&render_pull_diagnostics(&resp));
}