use std::path::PathBuf;
use anyhow::Result;
use iri_string::types::IriAbsoluteString;
use xee_xpath::{
context::{self, StaticContextBuilder},
Queries, Query,
};
use xee_xpath_load::{convert_string, ContextLoadable};
use crate::{
catalog::{Catalog, LoadContext},
language::XsltLanguage,
runcontext::RunContext,
testset::TestSet,
};
use super::{
core::{Runnable, TestCase},
outcome::TestOutcome,
};
#[derive(Debug)]
pub(crate) struct XsltTestCase {
pub(crate) test_case: TestCase<XsltLanguage>,
pub(crate) test: XsltTest,
}
impl XsltTestCase {}
#[derive(Debug)]
pub(crate) struct XsltTest {
pub(crate) base_dir: PathBuf,
pub(crate) stylesheets: Vec<Stylesheet>,
}
#[derive(Debug)]
pub(crate) struct Stylesheet {
pub(crate) path: Option<String>,
}
impl Runnable<XsltLanguage> for XsltTestCase {
fn test_case(&self) -> &TestCase<XsltLanguage> {
&self.test_case
}
fn run(
&self,
run_context: &mut RunContext,
catalog: &Catalog<XsltLanguage>,
test_set: &TestSet<XsltLanguage>,
) -> TestOutcome {
if self.test.stylesheets.is_empty() {
return TestOutcome::EnvironmentError("No stylesheet found".to_string());
}
let stylesheet = &self.test.stylesheets[0];
let path = self.test.base_dir.join(stylesheet.path.as_ref().unwrap());
let f = std::fs::File::open(&path).unwrap();
let xslt = std::io::read_to_string(f);
let xslt = match xslt {
Ok(xslt) => xslt,
Err(error) => {
return TestOutcome::EnvironmentError(format!(
"Error reading stylesheet: {}",
error
))
}
};
let static_context_builder = StaticContextBuilder::default();
let static_context = static_context_builder.build();
let program = xee_xslt_compiler::parse(static_context, &xslt);
let program = match program {
Ok(program) => program,
Err(error) => {
return TestOutcome::EnvironmentError(format!(
"Error parsing stylesheet: {}",
error
))
}
};
let static_base_uri = self.test_case.static_base_uri(catalog, test_set);
let static_base_uri = match static_base_uri {
Ok(static_base_uri) => static_base_uri,
Err(error) => return TestOutcome::EnvironmentError(error.to_string()),
};
let static_base_uri = if let Some(static_base_uri) = static_base_uri {
if static_base_uri != "#UNDEFINED" {
let iri: IriAbsoluteString = static_base_uri.try_into().unwrap();
Some(iri)
} else {
None
}
} else {
Some(test_set.file_uri())
};
let r =
self.test_case
.load_sources(run_context, catalog, test_set, static_base_uri.as_deref());
match r {
Ok(_) => (),
Err(error) => return TestOutcome::EnvironmentError(error.to_string()),
}
let context_item =
self.test_case
.context_item(run_context, catalog, test_set, static_base_uri.as_deref());
let context_item = match context_item {
Ok(context_item) => context_item,
Err(error) => return TestOutcome::EnvironmentError(error.to_string()),
};
let mut builder = program.dynamic_context_builder();
if let Some(context_item) = context_item {
builder.context_item(context_item);
}
builder.documents(run_context.documents.documents().clone());
let context = builder.build();
let runnable = program.runnable(&context);
let result = runnable.many(run_context.documents.xot_mut());
self.test_case.result.assert_result(
&context,
run_context.documents,
&result.map_err(|error| error.error),
)
}
fn load(queries: &Queries, context: &LoadContext) -> Result<impl Query<Self>> {
XsltTestCase::load_with_context(queries, context)
}
}
impl ContextLoadable<LoadContext> for XsltTestCase {
fn static_context_builder(context: &LoadContext) -> context::StaticContextBuilder {
let mut builder = context::StaticContextBuilder::default();
builder.default_element_namespace(context.catalog_ns);
builder
}
fn load_with_context(queries: &Queries, context: &LoadContext) -> Result<impl Query<Self>> {
let file_query = queries.option("@file/string()", convert_string)?;
let stylesheets_query = queries.many("stylesheet", move |documents, item| {
let file = file_query.execute(documents, item)?;
Ok(Stylesheet { path: file })
})?;
let xslt_test_query = queries.one("test", move |documents, item| {
let base_dir = context.path.parent().unwrap();
let stylesheets = stylesheets_query.execute(documents, item)?;
Ok(XsltTest {
stylesheets,
base_dir: base_dir.to_path_buf(),
})
})?;
let test_case_query = TestCase::load_with_context(queries, context)?;
let xslt_test_case_query = queries.one(".", move |documents, item| {
let test_case = test_case_query.execute(documents, item)?;
let xslt_test = xslt_test_query.execute(documents, item)?;
Ok(XsltTestCase {
test_case,
test: xslt_test,
})
})?;
Ok(xslt_test_case_query)
}
}