Run syntax highlighting tests as part of the main test command
Also, allow `corpus` to be in the `test/corpus` directory, and expect highlighting tests to be in the `test/highlight` directory.
This commit is contained in:
parent
6dbfbaed07
commit
4b9feccd13
3 changed files with 82 additions and 43 deletions
|
|
@ -8,7 +8,6 @@ use tree_sitter_cli::{
|
|||
config, error, generate, highlight, loader, logger, parse, query, test, test_highlight, wasm,
|
||||
web_ui,
|
||||
};
|
||||
use tree_sitter_highlight::Highlighter;
|
||||
|
||||
const BUILD_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
const BUILD_SHA: Option<&'static str> = option_env!("BUILD_SHA");
|
||||
|
|
@ -100,9 +99,6 @@ fn run() -> error::Result<()> {
|
|||
.arg(Arg::with_name("debug").long("debug").short("d"))
|
||||
.arg(Arg::with_name("debug-graph").long("debug-graph").short("D")),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("test-highlight").about("Run a parser's highlighting tests"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("highlight")
|
||||
.about("Highlight a file")
|
||||
|
|
@ -167,38 +163,28 @@ fn run() -> error::Result<()> {
|
|||
let debug = matches.is_present("debug");
|
||||
let debug_graph = matches.is_present("debug-graph");
|
||||
let filter = matches.value_of("filter");
|
||||
if let Some(language) = loader.languages_at_path(¤t_dir)?.first() {
|
||||
test::run_tests_at_path(
|
||||
*language,
|
||||
¤t_dir.join("corpus"),
|
||||
debug,
|
||||
debug_graph,
|
||||
filter,
|
||||
)?;
|
||||
test::check_queries_at_path(*language, ¤t_dir.join("queries"))?;
|
||||
} else {
|
||||
eprintln!("No language found");
|
||||
}
|
||||
} else if matches.subcommand_matches("test-highlight").is_some() {
|
||||
loader.find_language_configurations_at_path(¤t_dir)?;
|
||||
let mut highlighter = Highlighter::new();
|
||||
let languages = loader.languages_at_path(¤t_dir)?;
|
||||
let language = languages
|
||||
.first()
|
||||
.ok_or_else(|| "No language found".to_string())?;
|
||||
let test_dir = current_dir.join("test");
|
||||
|
||||
for highlight_test_file in fs::read_dir(current_dir.join("highlight-test"))? {
|
||||
let test_file_path = highlight_test_file?.path();
|
||||
if let Some((language, language_config)) =
|
||||
loader.language_configuration_for_file_name(&test_file_path)?
|
||||
{
|
||||
if let Some(highlight_config) = language_config.highlight_config(language)? {
|
||||
test_highlight::test_highlight(
|
||||
&loader,
|
||||
&mut highlighter,
|
||||
highlight_config,
|
||||
fs::read(test_file_path)?.as_slice(),
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
return Error::err(format!("No language found for path {:?}", test_file_path));
|
||||
}
|
||||
// Run the corpus tests. Look for them at two paths: `test/corpus` and `corpus`.
|
||||
let mut test_corpus_dir = test_dir.join("corpus");
|
||||
if !test_corpus_dir.is_dir() {
|
||||
test_corpus_dir = current_dir.join("corpus");
|
||||
}
|
||||
if test_corpus_dir.is_dir() {
|
||||
test::run_tests_at_path(*language, &test_corpus_dir, debug, debug_graph, filter)?;
|
||||
}
|
||||
|
||||
// Check that all of the queries are valid.
|
||||
test::check_queries_at_path(*language, ¤t_dir.join("queries"))?;
|
||||
|
||||
// Run the syntax highlighting tests.
|
||||
let test_highlight_dir = test_dir.join("highlight");
|
||||
if test_highlight_dir.is_dir() {
|
||||
test_highlight::test_highlights(&loader, &test_highlight_dir)?;
|
||||
}
|
||||
} else if let Some(matches) = matches.subcommand_matches("parse") {
|
||||
let debug = matches.is_present("debug");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use super::error::Result;
|
||||
use crate::loader::Loader;
|
||||
use ansi_term::Colour;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use tree_sitter::{Language, Parser, Point};
|
||||
use tree_sitter_highlight::{Highlight, HighlightConfiguration, HighlightEvent, Highlighter};
|
||||
|
||||
|
|
@ -19,7 +22,7 @@ pub struct Failure {
|
|||
impl Failure {
|
||||
pub fn message(&self) -> String {
|
||||
let mut result = format!(
|
||||
"Failed assertion at row: {}, column: {}.\nExpected highlight: '{}'.\nActual highlights: ",
|
||||
"Failure - row: {}, column: {}, expected highlight '{}', actual highlights: ",
|
||||
self.row, self.column, self.expected_highlight
|
||||
);
|
||||
if self.actual_highlights.is_empty() {
|
||||
|
|
@ -38,12 +41,58 @@ impl Failure {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn test_highlights(loader: &Loader, directory: &Path) -> Result<()> {
|
||||
let mut failed = false;
|
||||
let mut highlighter = Highlighter::new();
|
||||
|
||||
println!("syntax highlighting:");
|
||||
for highlight_test_file in fs::read_dir(directory)? {
|
||||
let highlight_test_file = highlight_test_file?;
|
||||
let test_file_path = highlight_test_file.path();
|
||||
let test_file_name = highlight_test_file.file_name();
|
||||
let (language, language_config) = loader
|
||||
.language_configuration_for_file_name(&test_file_path)?
|
||||
.ok_or_else(|| format!("No language found for path {:?}", test_file_path))?;
|
||||
let highlight_config = language_config
|
||||
.highlight_config(language)?
|
||||
.ok_or_else(|| format!("No highlighting config found for {:?}", test_file_path))?;
|
||||
match test_highlight(
|
||||
&loader,
|
||||
&mut highlighter,
|
||||
highlight_config,
|
||||
fs::read(&test_file_path)?.as_slice(),
|
||||
) {
|
||||
Ok(assertion_count) => {
|
||||
println!(
|
||||
" ✓ {} ({} assertions)",
|
||||
Colour::Green.paint(test_file_name.to_string_lossy().as_ref()),
|
||||
assertion_count
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
println!(
|
||||
" ✗ {}",
|
||||
Colour::Red.paint(test_file_name.to_string_lossy().as_ref())
|
||||
);
|
||||
println!(" {}", e.message());
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if failed {
|
||||
Err(String::new().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_highlight(
|
||||
loader: &Loader,
|
||||
highlighter: &mut Highlighter,
|
||||
highlight_config: &HighlightConfiguration,
|
||||
source: &[u8],
|
||||
) -> Result<()> {
|
||||
) -> Result<usize> {
|
||||
// Highlight the file, and parse out all of the highlighting assertions.
|
||||
let highlight_names = loader.highlight_names();
|
||||
let highlights = get_highlight_positions(loader, highlighter, highlight_config, source)?;
|
||||
|
|
@ -53,7 +102,7 @@ pub fn test_highlight(
|
|||
// actual highlights.
|
||||
let mut i = 0;
|
||||
let mut actual_highlights = Vec::<&String>::new();
|
||||
for (position, expected_highlight) in assertions {
|
||||
for (position, expected_highlight) in &assertions {
|
||||
let mut passed = false;
|
||||
actual_highlights.clear();
|
||||
|
||||
|
|
@ -61,7 +110,7 @@ pub fn test_highlight(
|
|||
// The assertions are ordered by position, so skip past all of the highlights that
|
||||
// end at or before this assertion's position.
|
||||
if let Some(highlight) = highlights.get(i) {
|
||||
if highlight.1 <= position {
|
||||
if highlight.1 <= *position {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -70,7 +119,7 @@ pub fn test_highlight(
|
|||
// position, looking for one that matches the assertion.
|
||||
let mut j = i;
|
||||
while let (false, Some(highlight)) = (passed, highlights.get(j)) {
|
||||
if highlight.0 > position {
|
||||
if highlight.0 > *position {
|
||||
break 'highlight_loop;
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +128,7 @@ pub fn test_highlight(
|
|||
// 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 {
|
||||
if *highlight_name == *expected_highlight {
|
||||
passed = true;
|
||||
break 'highlight_loop;
|
||||
} else {
|
||||
|
|
@ -104,7 +153,7 @@ pub fn test_highlight(
|
|||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(assertions.len())
|
||||
}
|
||||
|
||||
/// Parse the given source code, finding all of the comments that contain
|
||||
|
|
|
|||
|
|
@ -58,7 +58,11 @@ fn test_real_language_corpus_files() {
|
|||
}
|
||||
|
||||
let language = get_language(language_name);
|
||||
let corpus_dir = grammars_dir.join(language_name).join("corpus");
|
||||
let mut corpus_dir = grammars_dir.join(language_name).join("corpus");
|
||||
if !corpus_dir.is_dir() {
|
||||
corpus_dir = grammars_dir.join(language_name).join("test").join("corpus");
|
||||
}
|
||||
|
||||
let error_corpus_file = error_corpus_dir.join(&format!("{}_errors.txt", language_name));
|
||||
let main_tests = parse_tests(&corpus_dir).unwrap();
|
||||
let error_tests = parse_tests(&error_corpus_file).unwrap_or(TestEntry::default());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue