char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somexperiment: use native typescript lsp supportc7a9569

main
4.4 KiB138 linesraw
1#[path = "common/lsp.rs"]
2#[allow(dead_code)]
3mod common;
4
5use common::{Server, backend, files, write_frame};
6use serde_json::{Value, json};
7use std::{fs, process::Command};
8use tempfile::TempDir;
9
10#[test]
11fn queued_document_changes_use_the_latest_full_sync_version() {
12    let Some(backend) = backend() else {
13        return;
14    };
15    let root = TempDir::new().unwrap();
16    files(
17        root.path(),
18        &[
19            ("tsconfig.json", r#"{"compilerOptions":{"strict":true}}"#),
20            ("main.ts", "const value: string = 'first';\nvalue;"),
21        ],
22    );
23    let mut server = Server::start(root.path(), &backend, &[]);
24    server.initialize();
25    server.open_version("main.ts", "const value: string = 'first';\nvalue;", 1);
26    server.change("main.ts", "const value: number = 42;\nvalue;", 3);
27    server.change("main.ts", "const value: boolean = true;\nvalue;", 2);
28
29    let hover = server
30        .call(
31            "textDocument/hover",
32            json!({
33                "textDocument":{"uri":server.uri("main.ts")},
34                "position":{"line":1,"character":2}
35            }),
36        )
37        .unwrap();
38    assert!(
39        common::hover_text(&hover).contains("number"),
40        "stale version replaced the latest full-document change: {hover}"
41    );
42    server.close();
43}
44
45#[test]
46fn queued_changes_publish_diagnostics_once_before_the_query() {
47    let Some(backend) = backend() else {
48        return;
49    };
50    let root = TempDir::new().unwrap();
51    files(
52        root.path(),
53        &[
54            ("tsconfig.json", "{}"),
55            ("main.ts", "const value: string = 'x';\nvalue;"),
56        ],
57    );
58    let mut server = Server::start(root.path(), &backend, &[]);
59    server.initialize();
60    let uri = server.uri("main.ts");
61    let mut batch = Vec::new();
62    let mut append = |mut message: Value| {
63        message["jsonrpc"] = json!("2.0");
64        write_frame(&mut batch, &message).unwrap();
65    };
66    append(
67        json!({"method":"textDocument/didOpen","params":{"textDocument":{"uri":uri,"version":1,"languageId":"typescript","text":"const value: string = 'x';\nvalue;"}}}),
68    );
69    for version in 2..=9 {
70        append(
71            json!({"method":"textDocument/didChange","params":{"textDocument":{"uri":uri,"version":version},"contentChanges":[{"text":format!("const value: number = {version};\nvalue;")}]}}),
72        );
73    }
74    let query_id = 99;
75    append(
76        json!({"id":query_id,"method":"textDocument/hover","params":{"textDocument":{"uri":uri},"position":{"line":1,"character":2}}}),
77    );
78    server.write_raw(&batch);
79    let query = server.request_wait(query_id);
80    assert!(
81        common::hover_text(&query["result"]).contains("number"),
82        "{query}"
83    );
84    let publications = server
85        .notifications
86        .iter()
87        .filter(|message| {
88            message["method"] == "textDocument/publishDiagnostics"
89                && message["params"]["uri"] == uri
90        })
91        .count();
92    assert_eq!(
93        publications, 1,
94        "queued notifications triggered multiple refreshes"
95    );
96    server.close();
97}
98
99#[cfg(target_os = "linux")]
100#[test]
101fn failed_backend_is_restarted_before_the_following_request() {
102    let Some(backend) = backend() else {
103        return;
104    };
105    let root = TempDir::new().unwrap();
106    let source = "const answer: number = 42;\nanswer;";
107    files(root.path(), &[("tsconfig.json", "{}"), ("main.ts", source)]);
108    let mut server = Server::start(root.path(), &backend, &[]);
109    server.initialize();
110    let children = fs::read_to_string(format!(
111        "/proc/{}/task/{}/children",
112        server.pid(),
113        server.pid()
114    ))
115    .unwrap();
116    let pid = children
117        .split_whitespace()
118        .next()
119        .expect("backend child process");
120    assert!(
121        Command::new("kill")
122            .args(["-KILL", pid])
123            .status()
124            .unwrap()
125            .success()
126    );
127
128    let params =
129        json!({"textDocument":{"uri":server.uri("main.ts")},"position":{"line":1,"character":2}});
130    // The reader may notice the crash before the next query arrives.
131    match server.call("textDocument/hover", params.clone()) {
132        Ok(hover) => assert!(common::hover_text(&hover).contains("number"), "{hover}"),
133        Err(error) => assert_eq!(error.code, -32603, "{error:?}"),
134    }
135    let hover = server.call("textDocument/hover", params).unwrap();
136    assert!(common::hover_text(&hover).contains("number"), "{hover}");
137    server.close();
138}