feat(test): test all queries
Fallback to default testing for all queries present in the parser's queries directory. For a given query <QUERY>.scm, the test files are searched in test/<QUERY>/* Also mimic the output of other test-running subcommands when testing queries. Co-authored-by: Thomas Vigouroux <thomas.vigouroux@protonmail.com>
This commit is contained in:
parent
b695568516
commit
cc4378e751
3 changed files with 85 additions and 18 deletions
|
|
@ -735,6 +735,46 @@ fn run() -> Result<()> {
|
|||
color,
|
||||
)?;
|
||||
}
|
||||
|
||||
// For the rest of the queries, find their tests and run them
|
||||
for entry in walkdir::WalkDir::new(current_dir.join("queries"))
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| e.file_type().is_file())
|
||||
{
|
||||
let stem = entry
|
||||
.path()
|
||||
.file_stem()
|
||||
.map(|s| s.to_str().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
if stem != "highlights" && stem != "tags" {
|
||||
let paths = walkdir::WalkDir::new(test_dir.join(stem))
|
||||
.into_iter()
|
||||
.filter_map(|e| {
|
||||
let entry = e.ok()?;
|
||||
if entry.file_type().is_file() {
|
||||
Some(String::from(entry.path().to_string_lossy()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
if !paths.is_empty() {
|
||||
println!("{stem}:");
|
||||
}
|
||||
query::query_files_at_paths(
|
||||
language,
|
||||
paths,
|
||||
entry.path(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Commands::Fuzz(fuzz_options) => {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@ use std::{
|
|||
time::Instant,
|
||||
};
|
||||
|
||||
use anstyle::AnsiColor;
|
||||
use anyhow::{Context, Result};
|
||||
use tree_sitter::{Language, Parser, Point, Query, QueryCursor};
|
||||
|
||||
use crate::query_testing::{self, to_utf8_point};
|
||||
use crate::{
|
||||
query_testing::{self, to_utf8_point},
|
||||
test::paint,
|
||||
};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn query_files_at_paths(
|
||||
|
|
@ -44,7 +48,9 @@ pub fn query_files_at_paths(
|
|||
for path in paths {
|
||||
let mut results = Vec::new();
|
||||
|
||||
writeln!(&mut stdout, "{path}")?;
|
||||
if !should_test {
|
||||
writeln!(&mut stdout, "{path}")?;
|
||||
}
|
||||
|
||||
let source_code =
|
||||
fs::read(&path).with_context(|| format!("Error reading source file {path:?}"))?;
|
||||
|
|
@ -57,7 +63,7 @@ pub fn query_files_at_paths(
|
|||
{
|
||||
let capture = mat.captures[capture_index];
|
||||
let capture_name = &query.capture_names()[capture.index as usize];
|
||||
if !quiet {
|
||||
if !quiet && !should_test {
|
||||
writeln!(
|
||||
&mut stdout,
|
||||
" pattern: {:>2}, capture: {} - {capture_name}, start: {}, end: {}, text: `{}`",
|
||||
|
|
@ -76,14 +82,14 @@ pub fn query_files_at_paths(
|
|||
}
|
||||
} else {
|
||||
for m in query_cursor.matches(&query, tree.root_node(), source_code.as_slice()) {
|
||||
if !quiet {
|
||||
if !quiet && !should_test {
|
||||
writeln!(&mut stdout, " pattern: {}", m.pattern_index)?;
|
||||
}
|
||||
for capture in m.captures {
|
||||
let start = capture.node.start_position();
|
||||
let end = capture.node.end_position();
|
||||
let capture_name = &query.capture_names()[capture.index as usize];
|
||||
if !quiet {
|
||||
if !quiet && !should_test {
|
||||
if end.row == start.row {
|
||||
writeln!(
|
||||
&mut stdout,
|
||||
|
|
@ -113,7 +119,20 @@ pub fn query_files_at_paths(
|
|||
)?;
|
||||
}
|
||||
if should_test {
|
||||
query_testing::assert_expected_captures(&results, path, &mut parser, language)?;
|
||||
let path_name = Path::new(&path).file_name().unwrap().to_str().unwrap();
|
||||
match query_testing::assert_expected_captures(&results, &path, &mut parser, language) {
|
||||
Ok(assertion_count) => {
|
||||
println!(
|
||||
" ✓ {} ({} assertions)",
|
||||
paint(Some(AnsiColor::Green), path_name),
|
||||
assertion_count
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
println!(" ✗ {}", paint(Some(AnsiColor::Red), path_name));
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if print_time {
|
||||
writeln!(&mut stdout, "{:?}", start.elapsed())?;
|
||||
|
|
|
|||
|
|
@ -199,25 +199,33 @@ pub fn parse_position_comments(
|
|||
|
||||
pub fn assert_expected_captures(
|
||||
infos: &[CaptureInfo],
|
||||
path: String,
|
||||
path: &str,
|
||||
parser: &mut Parser,
|
||||
language: &Language,
|
||||
) -> Result<()> {
|
||||
) -> Result<usize> {
|
||||
let contents = fs::read_to_string(path)?;
|
||||
let pairs = parse_position_comments(parser, language, contents.as_bytes())?;
|
||||
for info in infos {
|
||||
if let Some(found) = pairs.iter().find(|p| {
|
||||
p.position.row == info.start.row && p.position >= info.start && p.position < info.end
|
||||
for assertion in &pairs {
|
||||
if let Some(found) = &infos.iter().find(|p| {
|
||||
assertion.position.row == p.start.row
|
||||
&& assertion.position >= p.start
|
||||
&& assertion.position < p.end
|
||||
}) {
|
||||
if found.expected_capture_name != info.name && info.name != "name" {
|
||||
Err(anyhow!(
|
||||
if assertion.expected_capture_name != found.name && found.name != "name" {
|
||||
return Err(anyhow!(
|
||||
"Assertion failed: at {}, found {}, expected {}",
|
||||
info.start,
|
||||
found.expected_capture_name,
|
||||
info.name
|
||||
))?;
|
||||
found.start,
|
||||
assertion.expected_capture_name,
|
||||
found.name
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"Assertion failed: could not match {} at {}",
|
||||
assertion.expected_capture_name,
|
||||
assertion.position
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
Ok(pairs.len())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue