use std::{fmt::Write, path::Path};
use cstree::{build::NodeCache, syntax::SyntaxNode};
use insta::assert_snapshot;
use skullbrain_diagnostics::{
Cache, CharSet, Emitter, FileCache, LocalizableLanguage, ReportConfig, Source, StringWriter,
};
use crate::{state::ConcreteSyntaxTreeBuilder, CstreeBuilder, ParserState, SyntaxKind};
pub(crate) fn create_parsing_test(
glob: &str,
parse: impl Fn(&mut ParserState<&mut Emitter<StringWriter>, CstreeBuilder<&str>>) + Clone,
) {
insta::glob!(&format!("inputs/{glob}"), |source| {
actual_test_impl(source, parse.clone())
})
}
fn actual_test_impl(
source: &Path,
parse: impl Fn(&mut ParserState<&mut Emitter<StringWriter>, CstreeBuilder<&str>>),
) {
let mut cache = NodeCache::new();
let input = std::fs::read_to_string(source).expect("Failed reading path");
let builder = CstreeBuilder::new(&mut cache, input.as_str());
let source_file = {
let file_name = source.file_name().expect("failed to get file name");
Path::new(file_name)
};
let mut diagnostics = {
let report_config = ReportConfig::new()
.with_char_set(CharSet::Ascii)
.with_color(false);
let writer = StringWriter::default();
let cache = FileCache::default();
Emitter::new(LocalizableLanguage::LangEn, cache, report_config, writer)
};
let mut state = ParserState::new(source_file, input.as_str(), &mut diagnostics, builder);
parse(&mut state);
let green = state.finish();
let resolved_node: SyntaxNode<SyntaxKind> = SyntaxNode::new_root(green);
let mut display_target = String::new();
resolved_node
.write_debug(cache.interner(), &mut display_target, true)
.expect("Failed writing to display");
let _ = display_target.write_char('\n');
let _ = display_target.write_char('\n');
let _ = display_target.write_str(diagnostics.writer().as_str());
insta::with_settings!({ info => &input }, {
assert_snapshot!(display_target);
});
}
pub(crate) struct CustomCache<'a>(Source<&'a str>);
impl<'a> Cache<Path> for CustomCache<'a> {
type Storage = &'a str;
fn fetch(&mut self, _id: &Path) -> Result<&Source<Self::Storage>, impl std::fmt::Debug> {
Ok::<_, ()>(&self.0)
}
fn display<'l>(&self, id: &'l Path) -> Option<impl std::fmt::Display + 'l> {
Some(id.display())
}
}