Skip to content

Commit

Permalink
Add starting real goto definition tests
Browse files Browse the repository at this point in the history
These tests are very incomplete,
but they serve as a good basis for future work.

commit-id:2d88cb6c
  • Loading branch information
mkaput committed Dec 19, 2024
1 parent fc8339c commit f470be1
Show file tree
Hide file tree
Showing 8 changed files with 425 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
32 changes: 32 additions & 0 deletions tests/test_data/goto/enum_variants.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! > 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 => {}
Foo::Baz => {}
}
}

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

//! > Goto definition #1
Foo::Ba<caret>r => {}
---
<sel>Bar</sel>,

//! > Goto definition #2
Foo::Ba<caret>z => {}
<sel>Baz</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>
Loading

0 comments on commit f470be1

Please sign in to comment.