Skip to content

Commit

Permalink
Rewrite textDocument/references tests to autocheck include_declarations
Browse files Browse the repository at this point in the history
commit-id:f6eb2292
  • Loading branch information
mkaput committed Jan 13, 2025
1 parent 6cd5254 commit dc00663
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 196 deletions.
148 changes: 108 additions & 40 deletions tests/e2e/references.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std::collections::HashSet;
use std::hash::{Hash, Hasher};

use cairo_lang_test_utils::parse_test_file::TestRunnerResult;
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
use itertools::Itertools;
use lsp_types::{
ClientCapabilities, ReferenceClientCapabilities, ReferenceContext, ReferenceParams,
ClientCapabilities, Location, ReferenceClientCapabilities, ReferenceContext, ReferenceParams,
TextDocumentClientCapabilities, TextDocumentPositionParams, lsp_request,
};

Expand Down Expand Up @@ -40,7 +44,7 @@ fn caps(base: ClientCapabilities) -> ClientCapabilities {

fn test_references(
inputs: &OrderedHashMap<String, String>,
args: &OrderedHashMap<String, String>,
_args: &OrderedHashMap<String, String>,
) -> TestRunnerResult {
let (cairo, cursors) = cursors(&inputs["cairo_code"]);

Expand All @@ -56,53 +60,117 @@ fn test_references(

let mut outputs = OrderedHashMap::default();
for (n, position) in cursors.carets().into_iter().enumerate() {
let mut query = |include_declaration: bool| {
let params = ReferenceParams {
text_document_position: TextDocumentPositionParams {
text_document: ls.doc_id("src/lib.cairo"),
position,
},
context: ReferenceContext { include_declaration },
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let locations = ls.send_request::<lsp_request!("textDocument/references")>(params)?;
Some(locations.into_iter().map(LocationForComparison).collect::<HashSet<_>>())
};

let mut report = String::new();
report.push_str(&peek_caret(&cairo, position));

let params = ReferenceParams {
text_document_position: TextDocumentPositionParams {
text_document: ls.doc_id("src/lib.cairo"),
position,
},
context: ReferenceContext {
include_declaration: args["include_declaration"] == "true",
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let response = ls.send_request::<lsp_request!("textDocument/references")>(params);

if let Some(mut locations) = response {
report.push_str("---\n");

// LS does not guarantee any order of the results.
locations
.sort_by_key(|loc| (loc.uri.as_str().to_owned(), loc.range.start, loc.range.end));

// Remove any references found in the core crate.
// We do not want to test core crate contents here, but we want to note that they exist.
let mut found_core_refs = false;
locations.retain(|loc| {
let path = loc.uri.path();
if path.contains("/core/src/") || path.contains("/corelib/src/") {
found_core_refs = true;
false
} else {
true
match (query(false), query(true)) {
(None, None) => report.push_str("none response"),
(Some(_), None) => panic!(
"references excluding declaration returned response, but including declaration \
did not"
),
(None, Some(_)) => panic!(
"references including declaration returned response, but excluding declaration \
did not"
),
(Some(excluding_declaration), Some(including_declaration)) => {
assert!(
excluding_declaration.is_subset(&including_declaration),
"include_declarations: true should return a superset of include_declarations: \
false"
);

let mut declarations: Vec<Location> = including_declaration
.difference(&excluding_declaration)
.sorted()
.map(|l| l.0.clone())
.collect();

let mut usages = excluding_declaration
.intersection(&including_declaration)
.sorted()
.map(|l| l.0.clone())
.collect::<Vec<_>>();

report.push_str("\nDECLARATIONS:\n");

remove_core_references(&mut declarations, &mut report);

for location in declarations {
report.push_str(&peek_selection(&cairo, &location.range));
}
});
if found_core_refs {
report.push_str("found several references in the core crate\n");
}

for location in locations {
report.push_str(&peek_selection(&cairo, &location.range));
report.push_str("\nUSAGES:\n");

remove_core_references(&mut usages, &mut report);

for location in usages {
report.push_str(&peek_selection(&cairo, &location.range));
}
}
} else {
report.push_str("none response")
}

outputs.insert(format!("References #{n}"), report);
}
TestRunnerResult::success(outputs)
}

fn remove_core_references(locations: &mut Vec<Location>, report: &mut String) {
// Remove any references found in the core crate.
// We do not want to test core crate contents here, but we want to note that they
// exist.
let mut found_core_refs = false;
locations.retain(|loc| {
let path = loc.uri.path();
if path.contains("/core/src/") || path.contains("/corelib/src/") {
found_core_refs = true;
false
} else {
true
}
});
if found_core_refs {
report.push_str("found several references in the core crate\n");
}
}

#[derive(PartialEq, Eq)]
struct LocationForComparison(Location);

impl PartialOrd for LocationForComparison {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for LocationForComparison {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
#[expect(clippy::needless_borrowed_reference)] // Clippy asks to write erroneous code.
let key = |&Self(ref loc)| (loc.uri.as_str(), loc.range.start, loc.range.end);
key(self).cmp(&key(other))
}
}

impl Hash for LocationForComparison {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.uri.hash(state);
self.0.range.start.line.hash(state);
self.0.range.start.character.hash(state);
self.0.range.end.line.hash(state);
self.0.range.end.character.hash(state);
}
}
30 changes: 4 additions & 26 deletions tests/test_data/references/enum_variants.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! > Test references of enum variants.

//! > test_runner_name
test_references(include_declaration: false)
test_references

//! > cairo_code
enum Foo {
Expand All @@ -19,30 +19,8 @@ fn main() {

//! > References #0
let foo = Foo::Ba<caret>r;
---

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

//! > Test references of enum variants including declaration.

//! > test_runner_name
test_references(include_declaration: true)

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

fn main() {
let foo = Foo::Ba<caret>r;
match foo {
Foo::Bar => {} // FIXME(#164): This should work.
_ => {}
}
}

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

USAGES:
27 changes: 21 additions & 6 deletions tests/test_data/references/enums.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! > Test find references of an enum.

//! > test_runner_name
test_references(include_declaration: true)
test_references

//! > cairo_code
enum Fo<caret>o {
Expand All @@ -22,11 +22,14 @@ mod rectangle {

//! > References #0
enum Fo<caret>o {
---

DECLARATIONS:
<sel>enum Foo {
Bar,
Baz,
}</sel>

USAGES:
enum <sel>Foo</sel> {
let foo = <sel>Foo</sel>::Bar;
let foobar: <sel>Foo</sel> = foo;
Expand All @@ -35,11 +38,14 @@ fn calc(foo: <sel>Foo</sel>) {}

//! > References #1
let foo = Fo<caret>o::Bar;
---

DECLARATIONS:
<sel>enum Foo {
Bar,
Baz,
}</sel>

USAGES:
enum <sel>Foo</sel> {
let foo = <sel>Foo</sel>::Bar;
let foobar: <sel>Foo</sel> = foo;
Expand All @@ -48,11 +54,14 @@ fn calc(foo: <sel>Foo</sel>) {}

//! > References #2
let foobar: Fo<caret>o = foo;
---

DECLARATIONS:
<sel>enum Foo {
Bar,
Baz,
}</sel>

USAGES:
enum <sel>Foo</sel> {
let foo = <sel>Foo</sel>::Bar;
let foobar: <sel>Foo</sel> = foo;
Expand All @@ -61,11 +70,14 @@ fn calc(foo: <sel>Foo</sel>) {}

//! > References #3
fn calc(foo: Fo<caret>o) {}
---

DECLARATIONS:
<sel>enum Foo {
Bar,
Baz,
}</sel>

USAGES:
enum <sel>Foo</sel> {
let foo = <sel>Foo</sel>::Bar;
let foobar: <sel>Foo</sel> = foo;
Expand All @@ -74,11 +86,14 @@ fn calc(foo: <sel>Foo</sel>) {}

//! > References #4
use super::Fo<caret>o;
---

DECLARATIONS:
<sel>enum Foo {
Bar,
Baz,
}</sel>

USAGES:
enum <sel>Foo</sel> {
let foo = <sel>Foo</sel>::Bar;
let foobar: <sel>Foo</sel> = foo;
Expand Down
Loading

0 comments on commit dc00663

Please sign in to comment.