Skip to content

Commit

Permalink
Add tests for automatic annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
snobee committed Nov 5, 2024
1 parent cf3bf58 commit 518e340
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 1 deletion.
72 changes: 71 additions & 1 deletion crates/cli/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,8 @@ pub fn annotation_edit(
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use indoc::indoc;
use std::fs::{read_to_string, File};
use std::io::Write;
use tempfile::{tempdir, TempDir};

Expand Down Expand Up @@ -512,4 +513,73 @@ main =

cleanup_temp_dir(dir);
}

const HEADER: &str = indoc! {r#"
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br" }
"#};

fn annotate_string(before: String) -> String {
let dir = tempdir().unwrap();
let file_path = setup_test_file(dir.path(), "before.roc", &before);

let arena = Bump::new();
let result = annotate_file(&arena, file_path.clone());
result.unwrap();

let annotated = read_to_string(file_path).unwrap();

cleanup_temp_dir(dir);
annotated
}

#[test]
fn test_annotate_simple() {
let before = HEADER.to_string()
+ indoc! {r#"
main =
Task.ok {}"#};

let after = HEADER.to_string()
+ indoc! {r#"
main : Task {} *
main =
Task.ok {}
"#};

let annotated = annotate_string(before);

assert_eq!(annotated, after);
}

#[test]
fn test_annotate_empty() {
let before = HEADER.to_string();
let after = HEADER.to_string() + "\n";
let annotated = annotate_string(before);

assert_eq!(annotated, after);
}

#[test]
fn test_annotate_destructure() {
let before = HEADER.to_string()
+ indoc! {r#"
{a, b} = {a: Task.ok {}, b: (1, 2)}
main = a"#};

let after = HEADER.to_string()
+ indoc! {r#"
{a, b} : { a : Task {} *, b : ( Num *, Num * )* }
{a, b} = {a: Task.ok {}, b: (1, 2)}
main : Task {} *
main = a
"#};

let annotated = annotate_string(before);

assert_eq!(annotated, after);
}
}
183 changes: 183 additions & 0 deletions crates/language_server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,4 +626,187 @@ mod tests {
"#]]
.assert_debug_eq(&actual);
}

const HEADER: &str = indoc! {r#"
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br" }
"#};

async fn code_action_edits(doc: String, position: Position, name: &str) -> Vec<TextEdit> {
let (inner, url) = test_setup(doc.clone()).await;
let registry = &inner.registry;

let actions = registry
.code_actions(&url, Range::new(position, position))
.await
.unwrap();

actions
.into_iter()
.find_map(|either| match either {
CodeActionOrCommand::CodeAction(action) if name == action.title => Some(action),
_ => None,
})
.expect("Code action not present")
.edit
.expect("Code action does not have an associated edit")
.changes
.expect("Edit does not have any changes")
.get(&url)
.expect("Edit does not have changes for this file")
.clone()
}

#[tokio::test]
async fn test_annotate_single() {
let edit = code_action_edits(
HEADER.to_string() + "main = Task.ok {}",
Position::new(2, 2),
"Add signature",
)
.await;

expect![[r#"
[
TextEdit {
range: Range {
start: Position {
line: 2,
character: 0,
},
end: Position {
line: 2,
character: 0,
},
},
new_text: "main : Task {} *\n",
},
]
"#]]
.assert_debug_eq(&edit);
}

#[tokio::test]
async fn test_annotate_top_level() {
let edit = code_action_edits(
HEADER.to_string()
+ indoc! {r#"
other = \_ ->
Task.ok {}
main =
other {}
"#},
Position::new(4, 0),
"Add top-level signatures",
)
.await;

expect![[r#"
[
TextEdit {
range: Range {
start: Position {
line: 2,
character: 0,
},
end: Position {
line: 2,
character: 0,
},
},
new_text: "other : * -> Task {} *\n",
},
TextEdit {
range: Range {
start: Position {
line: 5,
character: 0,
},
end: Position {
line: 5,
character: 0,
},
},
new_text: "main : Task {} *\n",
},
]
"#]]
.assert_debug_eq(&edit);
}

#[tokio::test]
async fn test_annotate_inner() {
let edit = code_action_edits(
HEADER.to_string()
+ indoc! {r#"
main =
start = 10
fib start 0 1
fib = \n, a, b ->
if n == 0 then
a
else
fib (n - 1) b (a + b)
"#},
Position::new(3, 8),
"Add signature",
)
.await;

expect![[r#"
[
TextEdit {
range: Range {
start: Position {
line: 3,
character: 0,
},
end: Position {
line: 3,
character: 0,
},
},
new_text: " start : Num *\n",
},
]
"#]]
.assert_debug_eq(&edit);
}

#[tokio::test]
async fn test_annotate_inner_effectful() {
let edit = code_action_edits(
HEADER.to_string()
+ indoc! {r#"
main =
Stdout.line! "What's your name?"
name = Stdin.line!
Stdout.line! "Hi $(name)!"
"#},
Position::new(4, 6),
"Add signature",
)
.await;

expect![[r#"
[
TextEdit {
range: Range {
start: Position {
line: 4,
character: 0,
},
end: Position {
line: 4,
character: 0,
},
},
new_text: " name : Str\n",
},
]
"#]]
.assert_debug_eq(&edit);
}
}

0 comments on commit 518e340

Please sign in to comment.