Skip to content

Commit

Permalink
add absolute line numbers in mdtest
Browse files Browse the repository at this point in the history
Summary:

Test Plan:
  • Loading branch information
pilleye committed Oct 18, 2024
1 parent 3d0bdb4 commit 545f85e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 10 deletions.
35 changes: 25 additions & 10 deletions crates/red_knot_test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use red_knot_python_semantic::types::check_types;
use ruff_db::files::system_path_to_file;
use ruff_db::parsed::parsed_module;
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
use ruff_source_file::OneIndexed;
use std::collections::BTreeMap;
use std::path::PathBuf;

type Failures = BTreeMap<SystemPathBuf, matcher::FailuresByLine>;
type Failures = BTreeMap<AbsoluteLineNumberPath, matcher::FailuresByLine>;

mod assertion;
mod db;
Expand All @@ -34,12 +35,17 @@ pub fn run(path: &PathBuf, title: &str) {
any_failures = true;
println!("\n{}\n", test.name().bold().underline());

for (path, by_line) in failures {
println!("{}", path.as_str().bold());
for (lined_path, by_line) in failures {
println!("{}", lined_path.path.as_str().bold());
for (line_number, failures) in by_line.iter() {
for failure in failures {
let absolute_line_info = format!(
"{}:{}",
title,
lined_path.line_number.saturating_add(line_number.get())
);
let line_info = format!("line {line_number}:").cyan();
println!(" {line_info} {failure}");
println!("{absolute_line_info} {line_info} {failure}");
}
}
println!();
Expand All @@ -52,11 +58,17 @@ pub fn run(path: &PathBuf, title: &str) {
assert!(!any_failures, "Some tests failed.");
}

#[derive(PartialEq, PartialOrd, Eq, Ord, Hash)]
struct AbsoluteLineNumberPath {
path: SystemPathBuf,
line_number: OneIndexed,
}

fn run_test(test: &parser::MarkdownTest) -> Result<(), Failures> {
let workspace_root = SystemPathBuf::from("/src");
let mut db = db::Db::setup(workspace_root.clone());

let mut system_paths = vec![];
let mut paths: Vec<AbsoluteLineNumberPath> = Vec::with_capacity(test.files().count());

for file in test.files() {
assert!(
Expand All @@ -65,26 +77,29 @@ fn run_test(test: &parser::MarkdownTest) -> Result<(), Failures> {
);
let full_path = workspace_root.join(file.path);
db.write_file(&full_path, file.code).unwrap();
system_paths.push(full_path);
paths.push(AbsoluteLineNumberPath {
path: full_path,
line_number: file.md_line_number,
});
}

let mut failures = BTreeMap::default();

for path in system_paths {
let file = system_path_to_file(&db, path.clone()).unwrap();
for numbered_path in paths {
let file = system_path_to_file(&db, numbered_path.path.clone()).unwrap();
let parsed = parsed_module(&db, file);

// TODO allow testing against code with syntax errors
assert!(
parsed.errors().is_empty(),
"Python syntax errors in {}, {:?}: {:?}",
test.name(),
path,
numbered_path.path,
parsed.errors()
);

matcher::match_file(&db, file, check_types(&db, file)).unwrap_or_else(|line_failures| {
failures.insert(path, line_failures);
failures.insert(numbered_path, line_failures);
});
}
if failures.is_empty() {
Expand Down
18 changes: 18 additions & 0 deletions crates/red_knot_test/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use once_cell::sync::Lazy;
use regex::{Captures, Regex};
use ruff_index::{newtype_index, IndexVec};
use ruff_source_file::OneIndexed;
use rustc_hash::{FxHashMap, FxHashSet};

/// Parse the Markdown `source` as a test suite with given `title`.
Expand Down Expand Up @@ -131,6 +132,7 @@ pub(crate) struct EmbeddedFile<'s> {
pub(crate) path: &'s str,
pub(crate) lang: &'s str,
pub(crate) code: &'s str,
pub(crate) md_line_number: OneIndexed,
}

/// Matches an arbitrary amount of whitespace (including newlines), followed by a sequence of `#`
Expand Down Expand Up @@ -186,6 +188,9 @@ struct Parser<'s> {
/// The unparsed remainder of the Markdown source.
unparsed: &'s str,

/// Current line number of the parser
current_line_number: OneIndexed,

/// Stack of ancestor sections.
stack: SectionStack,

Expand All @@ -205,6 +210,7 @@ impl<'s> Parser<'s> {
sections,
files: IndexVec::default(),
unparsed: source,
current_line_number: OneIndexed::new(1).unwrap(),
stack: SectionStack::new(root_section_id),
current_section_files: None,
}
Expand All @@ -225,6 +231,12 @@ impl<'s> Parser<'s> {
}
}

fn increment_line_count(&mut self, captures: &Captures<'s>) {
self.current_line_number = self
.current_line_number
.saturating_add(captures[0].lines().count());
}

fn parse_impl(&mut self) -> anyhow::Result<()> {
while !self.unparsed.is_empty() {
if let Some(captures) = self.scan(&HEADER_RE) {
Expand All @@ -235,6 +247,7 @@ impl<'s> Parser<'s> {
// ignore other Markdown syntax (paragraphs, etc) used as comments in the test
if let Some(next_newline) = self.unparsed.find('\n') {
(_, self.unparsed) = self.unparsed.split_at(next_newline + 1);
self.current_line_number = self.current_line_number.saturating_add(1);
} else {
break;
}
Expand Down Expand Up @@ -270,6 +283,8 @@ impl<'s> Parser<'s> {

self.current_section_files = None;

self.increment_line_count(captures);

Ok(())
}

Expand Down Expand Up @@ -303,6 +318,7 @@ impl<'s> Parser<'s> {
// CODE_RE can't match without matches for 'lang' and 'code'.
lang: captures.name("lang").unwrap().into(),
code: captures.name("code").unwrap().into(),
md_line_number: self.current_line_number,
});

if let Some(current_files) = &mut self.current_section_files {
Expand All @@ -324,6 +340,8 @@ impl<'s> Parser<'s> {
self.current_section_files = Some(FxHashSet::from_iter([path]));
}

self.increment_line_count(captures);

Ok(())
}

Expand Down

0 comments on commit 545f85e

Please sign in to comment.