Merge 31a59a92dd into 6739742fb6
This commit is contained in:
commit
e42e2ca7ab
2 changed files with 251 additions and 35 deletions
|
|
@ -13,10 +13,10 @@ use crate::{
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Failure {
|
||||
row: usize,
|
||||
column: usize,
|
||||
expected_highlight: String,
|
||||
actual_highlights: Vec<String>,
|
||||
pub(crate) row: usize,
|
||||
pub(crate) column: usize,
|
||||
pub(crate) expected_highlight: String,
|
||||
pub(crate) actual_highlights: Vec<String>,
|
||||
}
|
||||
|
||||
impl std::error::Error for Failure {}
|
||||
|
|
@ -126,6 +126,7 @@ pub fn test_highlights(
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iterate_assertions(
|
||||
assertions: &[Assertion],
|
||||
highlights: &[(Utf8Point, Utf8Point, Highlight)],
|
||||
|
|
@ -134,7 +135,6 @@ pub fn iterate_assertions(
|
|||
// Iterate through all of the highlighting assertions, checking each one against the
|
||||
// actual highlights.
|
||||
let mut i = 0;
|
||||
let mut actual_highlights = Vec::new();
|
||||
for Assertion {
|
||||
position,
|
||||
length,
|
||||
|
|
@ -142,49 +142,47 @@ pub fn iterate_assertions(
|
|||
expected_capture_name: expected_highlight,
|
||||
} in assertions
|
||||
{
|
||||
// Iterate through all of the highlights that start at or before this assertion's
|
||||
// position, looking for one that matches the assertion.
|
||||
let mut actual_highlights = Vec::new();
|
||||
let mut passed = false;
|
||||
let mut end_column = position.column + length - 1;
|
||||
actual_highlights.clear();
|
||||
|
||||
// The assertions are ordered by position, so skip past all of the highlights that
|
||||
// end at or before this assertion's position.
|
||||
'highlight_loop: while let Some(highlight) = highlights.get(i) {
|
||||
for highlight in &highlights[i..] {
|
||||
// The assertions are ordered by position, so skip past all of the highlights that
|
||||
// end at or before this assertion's position.
|
||||
if highlight.1 <= *position {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
end_column = position.column + length - 1;
|
||||
if highlight.0.row >= position.row && highlight.0.column > end_column {
|
||||
break;
|
||||
}
|
||||
|
||||
// Iterate through all of the highlights that start at or before this assertion's
|
||||
// position, looking for one that matches the assertion.
|
||||
let mut j = i;
|
||||
while let (false, Some(highlight)) = (passed, highlights.get(j)) {
|
||||
end_column = position.column + length - 1;
|
||||
if highlight.0.row >= position.row && highlight.0.column > end_column {
|
||||
break 'highlight_loop;
|
||||
}
|
||||
|
||||
// If the highlight matches the assertion, or if the highlight doesn't
|
||||
// match the assertion but it's negative, this test passes. Otherwise,
|
||||
// add this highlight to the list of actual highlights that span the
|
||||
// assertion's position, in order to generate an error message in the event
|
||||
// of a failure.
|
||||
let highlight_name = &highlight_names[(highlight.2).0];
|
||||
if (*highlight_name == *expected_highlight) == *negative {
|
||||
actual_highlights.push(highlight_name);
|
||||
} else {
|
||||
passed = true;
|
||||
break 'highlight_loop;
|
||||
}
|
||||
|
||||
j += 1;
|
||||
// If the highlight matches the assertion, or if the highlight doesn't
|
||||
// match the assertion but it's negative, this test passes. Otherwise,
|
||||
// add this highlight to the list of actual highlights that span the
|
||||
// assertion's position, in order to generate an error message in the event
|
||||
// of a failure.
|
||||
let highlight_name = &highlight_names[(highlight.2).0];
|
||||
if (*highlight_name == *expected_highlight) == *negative {
|
||||
actual_highlights.push(highlight_name);
|
||||
} else {
|
||||
passed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !passed {
|
||||
let mut expected = String::with_capacity(expected_highlight.len() + 1);
|
||||
if *negative {
|
||||
expected.push('!');
|
||||
}
|
||||
expected.push_str(expected_highlight);
|
||||
return Err(Failure {
|
||||
row: position.row,
|
||||
column: end_column,
|
||||
expected_highlight: expected_highlight.clone(),
|
||||
expected_highlight: expected,
|
||||
actual_highlights: actual_highlights.into_iter().cloned().collect(),
|
||||
}
|
||||
.into());
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use tree_sitter_highlight::{Highlight, Highlighter};
|
|||
use super::helpers::fixtures::{get_highlight_config, get_language, test_loader};
|
||||
use crate::{
|
||||
query_testing::{parse_position_comments, Assertion, Utf8Point},
|
||||
test_highlight::get_highlight_positions,
|
||||
test_highlight::{get_highlight_positions, iterate_assertions, Failure},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
|
@ -68,3 +68,221 @@ fn test_highlight_test_with_basic_test() {
|
|||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assertion_with_non_matching_highlight_at_same_position() {
|
||||
// Test that an assertion fails when the highlight at the position does not match
|
||||
|
||||
let highlight_names = vec!["keyword".to_string(), "variable".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(1, 0, 1, false, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![
|
||||
(Utf8Point::new(1, 0), Utf8Point::new(1, 5), Highlight(1)), // "variable" highlight
|
||||
];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err().downcast::<Failure>().unwrap();
|
||||
assert_eq!(err.row, 1);
|
||||
assert_eq!(err.column, 0);
|
||||
assert_eq!(err.expected_highlight, "keyword");
|
||||
assert_eq!(err.actual_highlights, vec!["variable".to_string()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assertion_with_exact_matching_highlight() {
|
||||
// Test exact match: assertion and highlight have same start and end
|
||||
|
||||
let highlight_names = vec!["keyword".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 5, 3, false, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![(Utf8Point::new(0, 5), Utf8Point::new(0, 8), Highlight(0))];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assertion_contained_within_highlight() {
|
||||
// Test where assertion is fully contained within a larger highlight
|
||||
|
||||
let highlight_names = vec!["keyword".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 3, 2, false, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![(Utf8Point::new(0, 0), Utf8Point::new(0, 10), Highlight(0))];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assertion_overlapping_highlight_start() {
|
||||
// Test where assertion starts before highlight but overlaps with it
|
||||
|
||||
let highlight_names = vec!["keyword".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 3, 4, false, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![(Utf8Point::new(0, 5), Utf8Point::new(0, 10), Highlight(0))];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assertion_with_no_highlights() {
|
||||
// Test that an assertion fails when there are no highlights at all
|
||||
|
||||
let highlight_names = vec!["keyword".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 0, 1, false, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err().downcast::<Failure>().unwrap();
|
||||
assert_eq!(err.row, 0);
|
||||
assert_eq!(err.column, 0);
|
||||
assert_eq!(err.expected_highlight, "keyword");
|
||||
assert_eq!(err.actual_highlights, Vec::<String>::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assertion_with_highlight_ending_before() {
|
||||
// Test where highlight ends before the assertion starts
|
||||
|
||||
let highlight_names = vec!["keyword".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 10, 1, false, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![(Utf8Point::new(0, 0), Utf8Point::new(0, 5), Highlight(0))];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err().downcast::<Failure>().unwrap();
|
||||
assert_eq!(err.row, 0);
|
||||
assert_eq!(err.column, 10);
|
||||
assert_eq!(err.expected_highlight, "keyword");
|
||||
assert_eq!(err.actual_highlights, Vec::<String>::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_assertion_with_non_matching_highlight() {
|
||||
// Test that a negative assertion passes when the specified highlight is NOT present
|
||||
|
||||
let highlight_names = vec!["keyword".to_string(), "variable".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 0, 1, true, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![
|
||||
(Utf8Point::new(0, 0), Utf8Point::new(0, 5), Highlight(1)), // "variable" highlight
|
||||
];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_assertion_with_matching_highlight() {
|
||||
// Test that a negative assertion fails when the specified highlight IS present
|
||||
|
||||
let highlight_names = vec!["keyword".to_string()];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 0, 1, true, String::from("keyword"))];
|
||||
|
||||
let highlights = vec![
|
||||
(Utf8Point::new(0, 0), Utf8Point::new(0, 5), Highlight(0)), // "keyword" highlight
|
||||
];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err().downcast::<Failure>().unwrap();
|
||||
assert_eq!(err.row, 0);
|
||||
assert_eq!(err.column, 0);
|
||||
assert_eq!(err.expected_highlight, "!keyword");
|
||||
assert_eq!(err.actual_highlights, vec!["keyword".to_string()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_assertions_sequential() {
|
||||
// Test multiple assertions in sequence with non-overlapping highlights
|
||||
|
||||
let highlight_names = vec!["keyword".to_string(), "variable".to_string()];
|
||||
|
||||
let assertions = vec![
|
||||
Assertion::new(0, 0, 3, false, String::from("keyword")),
|
||||
Assertion::new(0, 10, 1, false, String::from("variable")),
|
||||
];
|
||||
|
||||
let highlights = vec![
|
||||
(Utf8Point::new(0, 0), Utf8Point::new(0, 3), Highlight(0)), // "keyword"
|
||||
(Utf8Point::new(0, 10), Utf8Point::new(0, 11), Highlight(1)), // "variable"
|
||||
];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_highlights_at_same_position() {
|
||||
// Test where multiple highlights overlap at the assertion position
|
||||
|
||||
let highlight_names = vec![
|
||||
"keyword".to_string(),
|
||||
"variable".to_string(),
|
||||
"function".to_string(),
|
||||
];
|
||||
|
||||
let assertions = vec![Assertion::new(0, 5, 1, false, String::from("variable"))];
|
||||
|
||||
let highlights = vec![
|
||||
(Utf8Point::new(0, 0), Utf8Point::new(0, 10), Highlight(0)), // "keyword" spans entire range
|
||||
(Utf8Point::new(0, 5), Utf8Point::new(0, 8), Highlight(1)), // "variable" at assertion position
|
||||
(Utf8Point::new(0, 7), Utf8Point::new(0, 12), Highlight(2)), // "function" overlaps
|
||||
];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assertions_across_multiple_rows() {
|
||||
// Test assertions on different rows
|
||||
|
||||
let highlight_names = vec!["keyword".to_string(), "variable".to_string()];
|
||||
|
||||
let assertions = vec![
|
||||
Assertion::new(0, 5, 3, false, String::from("keyword")),
|
||||
Assertion::new(2, 10, 1, false, String::from("variable")),
|
||||
];
|
||||
|
||||
let highlights = vec![
|
||||
(Utf8Point::new(0, 5), Utf8Point::new(0, 8), Highlight(0)), // "keyword" on row 0
|
||||
(Utf8Point::new(2, 10), Utf8Point::new(2, 11), Highlight(1)), // "variable" on row 2
|
||||
];
|
||||
|
||||
let result = iterate_assertions(&assertions, &highlights, &highlight_names);
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 2);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue