Skip to content

Commit

Permalink
Add starting real goto definition tests (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkaput authored Dec 21, 2024
1 parent fc8339c commit 1ba7081
Show file tree
Hide file tree
Showing 8 changed files with 421 additions and 27 deletions.
49 changes: 32 additions & 17 deletions tests/e2e/goto.rs → tests/e2e/goto_definition.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use cairo_lang_test_utils::parse_test_file::TestRunnerResult;
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
use indoc::indoc;
use lsp_types::{
ClientCapabilities, GotoCapability, GotoDefinitionParams, GotoDefinitionResponse,
TextDocumentClientCapabilities, TextDocumentPositionParams, lsp_request,
Expand All @@ -9,12 +10,17 @@ use crate::support::cursor::{peek_caret, peek_selection};
use crate::support::{cursors, sandbox};

cairo_lang_test_utils::test_file_test!(
goto,
goto_definition,
"tests/test_data/goto",
{
enum_variants: "enum_variants.txt",
inline_macros: "inline_macros.txt",
items: "items.txt",
modules: "modules.txt",
struct_members: "struct_members.txt",
variables: "variables.txt",
},
test_goto_members
test_goto_definition
);

fn caps(base: ClientCapabilities) -> ClientCapabilities {
Expand All @@ -32,21 +38,21 @@ fn caps(base: ClientCapabilities) -> ClientCapabilities {
}
}

/// Perform hover test.
///
/// This function spawns a sandbox language server with the given code in the `src/lib.cairo` file.
/// The Cairo source code is expected to contain caret markers.
/// The function then requests goto definition information at each caret position and compares
/// the result with the expected hover information from the snapshot file.
fn test_goto_members(
fn test_goto_definition(
inputs: &OrderedHashMap<String, String>,
_args: &OrderedHashMap<String, String>,
) -> TestRunnerResult {
let (cairo, cursors) = cursors(&inputs["cairo_code"]);

let mut ls = sandbox! {
files {
"cairo_project.toml" => inputs["cairo_project.toml"].clone(),
"cairo_project.toml" => indoc! {r#"
[crate_roots]
hello = "src"
[config.global]
edition = "2024_07"
"#},
"src/lib.cairo" => cairo.clone(),
}
client_capabilities = caps;
Expand All @@ -68,17 +74,26 @@ fn test_goto_members(
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let goto_definition_response =
let response =
ls.send_request::<lsp_request!("textDocument/definition")>(code_action_params);

if let Some(goto_definition_response) = goto_definition_response {
if let GotoDefinitionResponse::Scalar(location) = goto_definition_response {
match response {
Some(GotoDefinitionResponse::Scalar(location)) => {
report.push_str("---\n");
report.push_str(&peek_selection(&cairo, &location.range));
} else {
panic!("Unexpected GotoDefinitionResponse variant.")
}
} else {
panic!("Goto definition request failed.");
Some(GotoDefinitionResponse::Array(locations)) => {
for location in locations {
report.push_str("---\n");
report.push_str(&peek_selection(&cairo, &location.range));
}
}
Some(GotoDefinitionResponse::Link(_)) => {
panic!("unexpected GotoDefinitionResponse::Link");
}
None => {
report.push_str("None");
}
}
goto_definitions.insert(format!("Goto definition #{}", n), report);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod analysis;
mod code_actions;
mod completions;
mod goto;
mod goto_definition;
mod hover;
mod macro_expand;
mod semantic_tokens;
Expand Down
28 changes: 28 additions & 0 deletions tests/test_data/goto/enum_variants.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! > Test goto definition of an enum variant.

//! > test_runner_name
test_goto_definition

//! > cairo_code
enum Foo {
Bar,
Baz,
}

fn main() {
let foo = Foo::Ba<caret>r;
match foo {
Foo::Ba<caret>r => {}
_ => {}
}
}

//! > Goto definition #0
let foo = Foo::Ba<caret>r;
---
<sel>Bar</sel>,

//! > Goto definition #1
Foo::Ba<caret>r => {}
---
<sel>Bar</sel>,
17 changes: 17 additions & 0 deletions tests/test_data/goto/inline_macros.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! > Test goto definition on inline macro.

//! > test_runner_name
test_goto_definition

//! > cairo_code
// FIXME(#116): This is wrong.
fn main() {
prin<caret>t!("Hello, world!");
}

//! > Goto definition #0
prin<caret>t!("Hello, world!");
---
<sel>fn main() {
print!("Hello, world!");
}</sel>
185 changes: 185 additions & 0 deletions tests/test_data/goto/items.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
//! > Test goto definition of a function.

//! > test_runner_name
test_goto_definition

//! > cairo_code
fn main() {
fo<caret>o();
}

fn foo() {} // good

mod bar {
fn foo() {} // bad
}

//! > Goto definition #0
fo<caret>o();
---
<sel>fn foo() {}</sel> // good

//! > ==========================================================================

//! > Test goto definition of a struct.

//! > test_runner_name
test_goto_definition

//! > cairo_code
struct Foo {
field: felt252,
}

fn main() {
let foo = Fo<caret>o { field: 0 };
}

fn calc(foo: Fo<caret>o) {}

//! > Goto definition #0
let foo = Fo<caret>o { field: 0 };
---
<sel>struct Foo {
field: felt252,
}</sel>

//! > Goto definition #1
fn calc(foo: Fo<caret>o) {}
---
<sel>struct Foo {
field: felt252,
}</sel>

//! > ==========================================================================

//! > Test goto definition of an enum.

//! > test_runner_name
test_goto_definition

//! > cairo_code
enum Foo {
Bar,
Baz,
}

fn main() {
let foo = Fo<caret>o::Bar;
}

fn calc(foo: Fo<caret>o) {}

//! > Goto definition #0
let foo = Fo<caret>o::Bar;
---
<sel>enum Foo {
Bar,
Baz,
}</sel>

//! > Goto definition #1
fn calc(foo: Fo<caret>o) {}
---
<sel>enum Foo {
Bar,
Baz,
}</sel>

//! > ==========================================================================

//! > Test goto definition with traits.

//! > test_runner_name
test_goto_definition

//! > cairo_code
pub trait ShapeGeometry<T> {
fn boundary(self: T) -> u64;
fn area(self: T) -> u64;
}

mod rectangle {
use super::Sha<caret>peGeometry;

#[derive(Copy, Drop)]
pub struct Rectangle {
pub height: u64,
pub width: u64,
}

impl RectangleGeometry of ShapeGe<caret>ometry<Recta<caret>ngle> {
fn boun<caret>dary(self: Recta<caret>ngle) -> u64 {
2 * (self.height + self.width)
}
fn area(self: Rectangle) -> u64 {
self.height * self.width
}
}
}

use rectangle::Rectangle;

fn main() {
let rect = Rectangle { height: 5, width: 7 };
let area = ShapeGeo<caret>metry::ar<caret>ea(rect);
}

//! > Goto definition #0
use super::Sha<caret>peGeometry;
---
<sel>pub trait ShapeGeometry<T> {
fn boundary(self: T) -> u64;
fn area(self: T) -> u64;
}</sel>

//! > Goto definition #1
impl RectangleGeometry of ShapeGe<caret>ometry<Rectangle> {
---
<sel>pub trait ShapeGeometry<T> {
fn boundary(self: T) -> u64;
fn area(self: T) -> u64;
}</sel>

//! > Goto definition #2
impl RectangleGeometry of ShapeGeometry<Recta<caret>ngle> {
---
<sel>#[derive(Copy, Drop)]
pub struct Rectangle {
pub height: u64,
pub width: u64,
}</sel>

//! > Goto definition #3
fn boun<caret>dary(self: Rectangle) -> u64 {
---
<sel>impl RectangleGeometry of ShapeGeometry<Rectangle> {
fn boundary(self: Rectangle) -> u64 {
2 * (self.height + self.width)
}
fn area(self: Rectangle) -> u64 {
self.height * self.width
}
}</sel>

//! > Goto definition #4
fn boundary(self: Recta<caret>ngle) -> u64 {
---
<sel>#[derive(Copy, Drop)]
pub struct Rectangle {
pub height: u64,
pub width: u64,
}</sel>

//! > Goto definition #5
let area = ShapeGeo<caret>metry::area(rect);
---
<sel>pub trait ShapeGeometry<T> {
fn boundary(self: T) -> u64;
fn area(self: T) -> u64;
}</sel>

//! > Goto definition #6
let area = ShapeGeometry::ar<caret>ea(rect);
---
<sel>fn area(self: T) -> u64;</sel>
64 changes: 64 additions & 0 deletions tests/test_data/goto/modules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//! > Test goto definition of a module.

//! > test_runner_name
test_goto_definition

//! > cairo_code
fn main() {
modu<caret>le::ba<caret>r::foo();
}

mod module {
// good
mod module {
// bad
}

mod bar { // good
fn foo() {}
}
}

//! > Goto definition #0
modu<caret>le::bar::foo();
---
mod module <sel>{
// good
mod module {
// bad
}

mod bar { // good
fn foo() {}
}
}</sel>

//! > Goto definition #1
module::ba<caret>r::foo();
---
mod bar <sel>{ // good
fn foo() {}
}</sel>

//! > ==========================================================================

//! > Test goto definition of a function in a submodule.

//! > test_runner_name
test_goto_definition

//! > cairo_code
fn main() {
module::fo<caret>o();
}

fn foo() {} // bad

mod module {
fn foo() {} // good
}

//! > Goto definition #0
module::fo<caret>o();
---
<sel>fn foo() {}</sel> // good
Loading

0 comments on commit 1ba7081

Please sign in to comment.