diff --git a/cli/src/main.rs b/cli/src/main.rs index 1f24ccc9..7dfc3dc5 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -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::>(); + 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) => { diff --git a/cli/src/query.rs b/cli/src/query.rs index f32c5450..085fb967 100644 --- a/cli/src/query.rs +++ b/cli/src/query.rs @@ -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())?; diff --git a/cli/src/query_testing.rs b/cli/src/query_testing.rs index 1020874b..87c08d23 100644 --- a/cli/src/query_testing.rs +++ b/cli/src/query_testing.rs @@ -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 { 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()) }