Improves error handling code in testsuite and server

pull/334/head
Tpt 2 years ago committed by Thomas Tanon
parent 1ded5ac4b4
commit 7fdd045516
  1. 39
      server/src/main.rs
  2. 33
      testsuite/src/files.rs
  3. 12
      testsuite/src/manifest.rs
  4. 54
      testsuite/src/parser_evaluator.rs
  5. 272
      testsuite/src/sparql_evaluator.rs

@ -1,4 +1,4 @@
use anyhow::{anyhow, bail}; use anyhow::bail;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use flate2::read::MultiGzDecoder; use flate2::read::MultiGzDecoder;
use oxhttp::model::{Body, HeaderName, HeaderValue, Request, Response, Status}; use oxhttp::model::{Body, HeaderName, HeaderValue, Request, Response, Status};
@ -189,30 +189,31 @@ impl GraphOrDatasetFormat {
} }
fn from_extension(name: &str) -> anyhow::Result<Self> { fn from_extension(name: &str) -> anyhow::Result<Self> {
match (GraphFormat::from_extension(name), DatasetFormat::from_extension(name)) { Ok( match (GraphFormat::from_extension(name), DatasetFormat::from_extension(name)) {
(Some(g), Some(d)) => Err(anyhow!("The file extension '{}' can be resolved to both '{}' and '{}', not sure what to pick", name, g.file_extension(), d.file_extension())), (Some(g), Some(d)) => bail!("The file extension '{name}' can be resolved to both '{}' and '{}', not sure what to pick", g.file_extension(), d.file_extension()),
(Some(g), None) => Ok(GraphOrDatasetFormat::Graph(g)), (Some(g), None) => GraphOrDatasetFormat::Graph(g),
(None, Some(d)) => Ok(GraphOrDatasetFormat::Dataset(d)), (None, Some(d)) => GraphOrDatasetFormat::Dataset(d),
(None, None) => (None, None) =>
Err(anyhow!("The file extension '{}' is unknown", name)) bail!("The file extension '{name}' is unknown")
} })
} }
fn from_media_type(name: &str) -> anyhow::Result<Self> { fn from_media_type(name: &str) -> anyhow::Result<Self> {
match ( Ok(
GraphFormat::from_media_type(name), match (
DatasetFormat::from_media_type(name), GraphFormat::from_media_type(name),
) { DatasetFormat::from_media_type(name),
(Some(g), Some(d)) => Err(anyhow!( ) {
"The media type '{}' can be resolved to both '{}' and '{}', not sure what to pick", (Some(g), Some(d)) => bail!(
name, "The media type '{name}' can be resolved to both '{}' and '{}', not sure what to pick",
g.file_extension(), g.file_extension(),
d.file_extension() d.file_extension()
)), ),
(Some(g), None) => Ok(GraphOrDatasetFormat::Graph(g)), (Some(g), None) => GraphOrDatasetFormat::Graph(g),
(None, Some(d)) => Ok(GraphOrDatasetFormat::Dataset(d)), (None, Some(d)) => GraphOrDatasetFormat::Dataset(d),
(None, None) => Err(anyhow!("The media type '{}' is unknown", name)), (None, None) => bail!("The media type '{name}' is unknown"),
} },
)
} }
} }

@ -1,4 +1,4 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, bail, Result};
use oxigraph::io::{DatasetFormat, DatasetParser, GraphFormat, GraphParser}; use oxigraph::io::{DatasetFormat, DatasetParser, GraphFormat, GraphParser};
use oxigraph::model::{Dataset, Graph, GraphNameRef}; use oxigraph::model::{Dataset, Graph, GraphNameRef};
use oxigraph::store::Store; use oxigraph::store::Store;
@ -9,29 +9,29 @@ use std::path::PathBuf;
pub fn read_file(url: &str) -> Result<impl BufRead> { pub fn read_file(url: &str) -> Result<impl BufRead> {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push(if url.starts_with("http://w3c.github.io/rdf-tests/") { path.push(if url.starts_with("http://w3c.github.io/rdf-tests/") {
Ok(url.replace("http://w3c.github.io/rdf-tests/", "rdf-tests/")) url.replace("http://w3c.github.io/rdf-tests/", "rdf-tests/")
} else if url.starts_with("http://www.w3.org/2013/RDFXMLTests/") { } else if url.starts_with("http://www.w3.org/2013/RDFXMLTests/") {
Ok(url.replace("http://www.w3.org/2013/RDFXMLTests/", "rdf-tests/rdf-xml/")) url.replace("http://www.w3.org/2013/RDFXMLTests/", "rdf-tests/rdf-xml/")
} else if url.starts_with("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/") { } else if url.starts_with("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/") {
Ok(url.replace( url.replace(
"http://www.w3.org/2001/sw/DataAccess/tests/", "http://www.w3.org/2001/sw/DataAccess/tests/",
"rdf-tests/sparql11/", "rdf-tests/sparql11/",
)) )
} else if url.starts_with("http://www.w3.org/2009/sparql/docs/tests/data-sparql11/") { } else if url.starts_with("http://www.w3.org/2009/sparql/docs/tests/data-sparql11/") {
Ok(url.replace( url.replace(
"http://www.w3.org/2009/sparql/docs/tests/", "http://www.w3.org/2009/sparql/docs/tests/",
"rdf-tests/sparql11/", "rdf-tests/sparql11/",
)) )
} else if url.starts_with("https://w3c.github.io/rdf-star/") { } else if url.starts_with("https://w3c.github.io/rdf-star/") {
Ok(url.replace("https://w3c.github.io/", "")) url.replace("https://w3c.github.io/", "")
} else if url.starts_with("https://github.com/oxigraph/oxigraph/tests/") { } else if url.starts_with("https://github.com/oxigraph/oxigraph/tests/") {
Ok(url.replace( url.replace(
"https://github.com/oxigraph/oxigraph/tests/", "https://github.com/oxigraph/oxigraph/tests/",
"oxigraph-tests/", "oxigraph-tests/",
)) )
} else { } else {
Err(anyhow!("Not supported url for file: {}", url)) bail!("Not supported url for file: {url}")
}?); });
Ok(BufReader::new(File::open(&path)?)) Ok(BufReader::new(File::open(&path)?))
} }
@ -72,7 +72,7 @@ pub fn load_to_store<'a>(
} else if url.ends_with(".trig") { } else if url.ends_with(".trig") {
store.load_dataset(read_file(url)?, DatasetFormat::TriG, Some(url))? store.load_dataset(read_file(url)?, DatasetFormat::TriG, Some(url))?
} else { } else {
return Err(anyhow!("Serialization type not found for {}", url)); bail!("Serialization type not found for {url}");
} }
Ok(()) Ok(())
} }
@ -81,7 +81,7 @@ pub fn load_to_graph(url: &str, graph: &mut Graph) -> Result<()> {
let format = url let format = url
.rsplit_once('.') .rsplit_once('.')
.and_then(|(_, extension)| GraphFormat::from_extension(extension)) .and_then(|(_, extension)| GraphFormat::from_extension(extension))
.ok_or_else(|| anyhow!("Serialization type not found for {}", url))?; .ok_or_else(|| anyhow!("Serialization type not found for {url}"))?;
let parser = GraphParser::from_format(format).with_base_iri(url)?; let parser = GraphParser::from_format(format).with_base_iri(url)?;
for t in parser.read_triples(read_file(url)?)? { for t in parser.read_triples(read_file(url)?)? {
graph.insert(&t?); graph.insert(&t?);
@ -107,16 +107,15 @@ pub fn load_to_dataset<'a>(
for t in parser.read_triples(read_file(url)?)? { for t in parser.read_triples(read_file(url)?)? {
dataset.insert(&t?.in_graph(to_graph_name)); dataset.insert(&t?.in_graph(to_graph_name));
} }
Ok(())
} else if let Some(format) = extension.and_then(DatasetFormat::from_extension) { } else if let Some(format) = extension.and_then(DatasetFormat::from_extension) {
let parser = DatasetParser::from_format(format).with_base_iri(url)?; let parser = DatasetParser::from_format(format).with_base_iri(url)?;
for q in parser.read_quads(read_file(url)?)? { for q in parser.read_quads(read_file(url)?)? {
dataset.insert(&q?); dataset.insert(&q?);
} }
Ok(())
} else { } else {
Err(anyhow!("Serialization type not found for {}", url)) bail!("Serialization type not found for {url}")
} }
Ok(())
} }
pub fn load_dataset(url: &str) -> Result<Dataset> { pub fn load_dataset(url: &str) -> Result<Dataset> {

@ -89,7 +89,7 @@ impl TestManifest {
let test_node = match test_node { let test_node = match test_node {
Term::NamedNode(n) => n, Term::NamedNode(n) => n,
_ => { _ => {
return Some(Err(anyhow!("Invalid test identifier. Got {}", test_node))); return Some(Err(anyhow!("Invalid test identifier. Got {test_node}")));
} }
}; };
@ -107,8 +107,7 @@ impl TestManifest {
Some(TermRef::NamedNode(c)) => c.into_owned(), Some(TermRef::NamedNode(c)) => c.into_owned(),
_ => { _ => {
return Some(Err(anyhow!( return Some(Err(anyhow!(
"The test {} named {} has no rdf:type", "The test {test_node} named {} has no rdf:type",
test_node,
name.as_deref().unwrap_or("") name.as_deref().unwrap_or("")
))); )));
} }
@ -202,7 +201,7 @@ impl TestManifest {
} }
Some(_) => return Some(Err(anyhow!("invalid action"))), Some(_) => return Some(Err(anyhow!("invalid action"))),
None => { None => {
return Some(Err(anyhow!("action not found for test {}", test_node))); return Some(Err(anyhow!("action not found for test {test_node}")));
} }
}; };
let (result, result_graph_data) = match self let (result, result_graph_data) = match self
@ -276,8 +275,7 @@ impl TestManifest {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if manifests.len() != 1 { if manifests.len() != 1 {
return Some(Err(anyhow!( return Some(Err(anyhow!(
"The file {} should contain a single manifest", "The file {url} should contain a single manifest"
url
))); )));
} }
for manifest in manifests { for manifest in manifests {
@ -307,7 +305,7 @@ impl TestManifest {
.extend(RdfListIterator::iter(&self.graph, list.into())); .extend(RdfListIterator::iter(&self.graph, list.into()));
} }
Some(term) => { Some(term) => {
return Some(Err(anyhow!("Invalid tests list. Got term {}", term))); return Some(Err(anyhow!("Invalid tests list. Got term {term}")));
} }
None => (), None => (),
} }

@ -2,7 +2,7 @@ use crate::evaluator::TestEvaluator;
use crate::files::load_dataset; use crate::files::load_dataset;
use crate::manifest::Test; use crate::manifest::Test;
use crate::report::dataset_diff; use crate::report::dataset_diff;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, bail, Result};
pub fn register_parser_tests(evaluator: &mut TestEvaluator) { pub fn register_parser_tests(evaluator: &mut TestEvaluator) {
evaluator.register( evaluator.register(
@ -67,20 +67,18 @@ fn evaluate_positive_syntax_test(test: &Test) -> Result<()> {
let action = test let action = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match load_dataset(action) { load_dataset(action).map_err(|e| anyhow!("Parse error: {e}"))?;
Ok(_) => Ok(()), Ok(())
Err(e) => Err(anyhow!(format!("Parse error: {e}"))),
}
} }
fn evaluate_negative_syntax_test(test: &Test) -> Result<()> { fn evaluate_negative_syntax_test(test: &Test) -> Result<()> {
let action = test let action = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match load_dataset(action) { match load_dataset(action) {
Ok(_) => Err(anyhow!("File parsed with an error even if it should not",)), Ok(_) => bail!("File parsed with an error even if it should not"),
Err(_) => Ok(()), Err(_) => Ok(()),
} }
} }
@ -89,29 +87,23 @@ fn evaluate_eval_test(test: &Test) -> Result<()> {
let action = test let action = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match load_dataset(action) { let mut actual_graph =
Ok(mut actual_graph) => { load_dataset(action).map_err(|e| anyhow!("Parse error on file {action}: {e}"))?;
actual_graph.canonicalize(); actual_graph.canonicalize();
if let Some(result) = &test.result { if let Some(result) = &test.result {
match load_dataset(result) { let mut expected_graph =
Ok(mut expected_graph) => { load_dataset(result).map_err(|e| anyhow!("Parse error on file {action}: {e}"))?;
expected_graph.canonicalize(); expected_graph.canonicalize();
if expected_graph == actual_graph { if expected_graph == actual_graph {
Ok(()) Ok(())
} else { } else {
Err(anyhow!( bail!(
"The two files are not isomorphic. Diff:\n{}", "The two files are not isomorphic. Diff:\n{}",
dataset_diff(&expected_graph, &actual_graph) dataset_diff(&expected_graph, &actual_graph)
)) )
}
}
Err(e) => Err(anyhow!("Parse error on file {}: {}", action, e)),
}
} else {
Err(anyhow!("No tests result found"))
}
} }
Err(e) => Err(anyhow!("Parse error on file {}: {}", action, e)), } else {
bail!("No tests result found")
} }
} }

@ -3,7 +3,7 @@ use crate::files::*;
use crate::manifest::*; use crate::manifest::*;
use crate::report::dataset_diff; use crate::report::dataset_diff;
use crate::vocab::*; use crate::vocab::*;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, bail, Result};
use oxigraph::model::vocab::*; use oxigraph::model::vocab::*;
use oxigraph::model::*; use oxigraph::model::*;
use oxigraph::sparql::*; use oxigraph::sparql::*;
@ -73,32 +73,23 @@ fn evaluate_positive_syntax_test(test: &Test) -> Result<()> {
let query_file = test let query_file = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match Query::parse(&read_file_to_string(query_file)?, Some(query_file)) { let query = Query::parse(&read_file_to_string(query_file)?, Some(query_file))
Err(error) => Err(anyhow!("Not able to parse {} with error: {}", test, error)), .map_err(|e| anyhow!("Not able to parse {test} with error: {e}"))?;
Ok(query) => match Query::parse(&query.to_string(), None) { Query::parse(&query.to_string(), None)
Ok(_) => Ok(()), .map_err(|e| anyhow!("Failure to deserialize \"{query}\" of {test} with error: {e}"))?;
Err(error) => Err(anyhow!( Ok(())
"Failure to deserialize \"{}\" of {} with error: {}",
query.to_string(),
test,
error
)),
},
}
} }
fn evaluate_negative_syntax_test(test: &Test) -> Result<()> { fn evaluate_negative_syntax_test(test: &Test) -> Result<()> {
let query_file = test let query_file = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match Query::parse(&read_file_to_string(query_file)?, Some(query_file)) { match Query::parse(&read_file_to_string(query_file)?, Some(query_file)) {
Ok(result) => Err(anyhow!( Ok(result) => {
"Oxigraph parses even if it should not {}. The output tree is: {}", bail!("Oxigraph parses even if it should not {test}. The output tree is: {result}")
test, }
result
)),
Err(_) => Ok(()), Err(_) => Ok(()),
} }
} }
@ -109,7 +100,7 @@ fn evaluate_positive_json_result_syntax_test(test: &Test) -> Result<()> {
fn evaluate_negative_json_result_syntax_test(test: &Test) -> Result<()> { fn evaluate_negative_json_result_syntax_test(test: &Test) -> Result<()> {
if result_syntax_check(test, QueryResultsFormat::Json).is_ok() { if result_syntax_check(test, QueryResultsFormat::Json).is_ok() {
Err(anyhow!("Oxigraph parses even if it should not {}.", test)) bail!("Oxigraph parses even if it should not {test}.")
} else { } else {
Ok(()) Ok(())
} }
@ -121,7 +112,7 @@ fn evaluate_positive_xml_result_syntax_test(test: &Test) -> Result<()> {
fn evaluate_negative_xml_result_syntax_test(test: &Test) -> Result<()> { fn evaluate_negative_xml_result_syntax_test(test: &Test) -> Result<()> {
if result_syntax_check(test, QueryResultsFormat::Xml).is_ok() { if result_syntax_check(test, QueryResultsFormat::Xml).is_ok() {
Err(anyhow!("Oxigraph parses even if it should not {}.", test)) bail!("Oxigraph parses even if it should not {test}.")
} else { } else {
Ok(()) Ok(())
} }
@ -129,7 +120,7 @@ fn evaluate_negative_xml_result_syntax_test(test: &Test) -> Result<()> {
fn evaluate_negative_tsv_result_syntax_test(test: &Test) -> Result<()> { fn evaluate_negative_tsv_result_syntax_test(test: &Test) -> Result<()> {
if result_syntax_check(test, QueryResultsFormat::Tsv).is_ok() { if result_syntax_check(test, QueryResultsFormat::Tsv).is_ok() {
Err(anyhow!("Oxigraph parses even if it should not {}.", test)) bail!("Oxigraph parses even if it should not {test}.")
} else { } else {
Ok(()) Ok(())
} }
@ -139,7 +130,7 @@ fn result_syntax_check(test: &Test, format: QueryResultsFormat) -> Result<()> {
let results_file = test let results_file = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match QueryResults::read(Cursor::new(read_file_to_string(results_file)?), format)? { match QueryResults::read(Cursor::new(read_file_to_string(results_file)?), format)? {
QueryResults::Solutions(solutions) => { QueryResults::Solutions(solutions) => {
for s in solutions { for s in solutions {
@ -167,125 +158,83 @@ fn evaluate_evaluation_test(test: &Test) -> Result<()> {
let query_file = test let query_file = test
.query .query
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
let options = QueryOptions::default() let options = QueryOptions::default()
.with_service_handler(StaticServiceHandler::new(&test.service_data)?); .with_service_handler(StaticServiceHandler::new(&test.service_data)?);
match Query::parse(&read_file_to_string(query_file)?, Some(query_file)) { let query = Query::parse(&read_file_to_string(query_file)?, Some(query_file))
Err(error) => Err(anyhow!( .map_err(|e| anyhow!("Failure to parse query of {test} with error: {e}"))?;
"Failure to parse query of {} with error: {}",
test, // We check parsing roundtrip
error Query::parse(&query.to_string(), None)
)), .map_err(|e| anyhow!("Failure to deserialize \"{query}\" of {test} with error: {e}"))?;
Ok(query) => {
// We check parsing roundtrip // FROM and FROM NAMED support. We make sure the data is in the store
if let Err(error) = Query::parse(&query.to_string(), None) { if !query.dataset().is_default_dataset() {
return Err(anyhow!( for graph_name in query.dataset().default_graph_graphs().unwrap_or(&[]) {
"Failure to deserialize \"{}\" of {} with error: {}", if let GraphName::NamedNode(graph_name) = graph_name {
query.to_string(), load_to_store(graph_name.as_str(), &store, graph_name.as_ref())?;
test, } else {
error bail!("Invalid FROM in query {query} for test {test}");
));
} }
}
// FROM and FROM NAMED support. We make sure the data is in the store for graph_name in query.dataset().available_named_graphs().unwrap_or(&[]) {
if !query.dataset().is_default_dataset() { if let NamedOrBlankNode::NamedNode(graph_name) = graph_name {
for graph_name in query.dataset().default_graph_graphs().unwrap_or(&[]) { load_to_store(graph_name.as_str(), &store, graph_name.as_ref())?;
if let GraphName::NamedNode(graph_name) = graph_name { } else {
load_to_store(graph_name.as_str(), &store, graph_name.as_ref())?; bail!("Invalid FROM NAMED in query {query} for test {test}");
} else {
return Err(anyhow!("Invalid FROM in query {} for test {}", query, test));
}
}
for graph_name in query.dataset().available_named_graphs().unwrap_or(&[]) {
if let NamedOrBlankNode::NamedNode(graph_name) = graph_name {
load_to_store(graph_name.as_str(), &store, graph_name.as_ref())?;
} else {
return Err(anyhow!(
"Invalid FROM NAMED in query {} for test {}",
query,
test
));
}
}
} }
}
}
for with_query_optimizer in [true, false] { let expected_results = load_sparql_query_result(test.result.as_ref().unwrap())
let mut options = options.clone(); .map_err(|e| anyhow!("Error constructing expected graph for {test}: {e}"))?;
if !with_query_optimizer { let with_order = if let StaticQueryResults::Solutions { ordered, .. } = &expected_results {
options = options.without_optimizations(); *ordered
} } else {
match store.query_opt(query.clone(), options) { false
Err(error) => { };
return Err(anyhow!(
"Failure to execute query of {} with error: {}", for with_query_optimizer in [true, false] {
test, let mut options = options.clone();
error if !with_query_optimizer {
)) options = options.without_optimizations();
} }
Ok(actual_results) => { let actual_results = store
let expected_results = load_sparql_query_result( .query_opt(query.clone(), options)
test.result.as_ref().unwrap(), .map_err(|e| anyhow!("Failure to execute query of {test} with error: {e}"))?;
) let actual_results = StaticQueryResults::from_query_results(actual_results, with_order)?;
.map_err(|e| {
anyhow!("Error constructing expected graph for {}: {}", test, e) if !are_query_results_isomorphic(&expected_results, &actual_results) {
})?; bail!(
let with_order = if let StaticQueryResults::Solutions { ordered, .. } = "Failure on {test}.\nExpected file:\n{expected_results}\nOutput file:\n{actual_results}\nParsed query:\n{}\nData:\n{store}\n",
&expected_results Query::parse(&read_file_to_string(query_file)?, Some(query_file)).unwrap()
{ );
*ordered
} else {
false
};
let actual_results =
StaticQueryResults::from_query_results(actual_results, with_order)?;
if !are_query_results_isomorphic(&expected_results, &actual_results) {
return Err(anyhow!("Failure on {}.\nExpected file:\n{}\nOutput file:\n{}\nParsed query:\n{}\nData:\n{}\n",
test,
expected_results,
actual_results,
Query::parse(&read_file_to_string(query_file)?, Some(query_file)).unwrap(),
store
));
}
}
}
}
Ok(())
} }
} }
Ok(())
} }
fn evaluate_positive_update_syntax_test(test: &Test) -> Result<()> { fn evaluate_positive_update_syntax_test(test: &Test) -> Result<()> {
let update_file = test let update_file = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match Update::parse(&read_file_to_string(update_file)?, Some(update_file)) { let update = Update::parse(&read_file_to_string(update_file)?, Some(update_file))
Err(error) => Err(anyhow!("Not able to parse {} with error: {}", test, error)), .map_err(|e| anyhow!("Not able to parse {test} with error: {e}"))?;
Ok(update) => match Update::parse(&update.to_string(), None) { Update::parse(&update.to_string(), None)
Ok(_) => Ok(()), .map_err(|e| anyhow!("Failure to deserialize \"{update}\" of {test} with error: {e}"))?;
Err(error) => Err(anyhow!( Ok(())
"Failure to deserialize \"{}\" of {} with error: {}",
update.to_string(),
test,
error
)),
},
}
} }
fn evaluate_negative_update_syntax_test(test: &Test) -> Result<()> { fn evaluate_negative_update_syntax_test(test: &Test) -> Result<()> {
let update_file = test let update_file = test
.action .action
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match Update::parse(&read_file_to_string(update_file)?, Some(update_file)) { match Update::parse(&read_file_to_string(update_file)?, Some(update_file)) {
Ok(result) => Err(anyhow!( Ok(result) => {
"Oxigraph parses even if it should not {}. The output tree is: {}", bail!("Oxigraph parses even if it should not {test}. The output tree is: {result}")
test, }
result
)),
Err(_) => Ok(()), Err(_) => Ok(()),
} }
} }
@ -310,50 +259,29 @@ fn evaluate_update_evaluation_test(test: &Test) -> Result<()> {
let update_file = test let update_file = test
.update .update
.as_deref() .as_deref()
.ok_or_else(|| anyhow!("No action found for test {}", test))?; .ok_or_else(|| anyhow!("No action found for test {test}"))?;
match Update::parse(&read_file_to_string(update_file)?, Some(update_file)) { let update = Update::parse(&read_file_to_string(update_file)?, Some(update_file))
Err(error) => Err(anyhow!( .map_err(|e| anyhow!("Failure to parse update of {test} with error: {e}"))?;
"Failure to parse update of {} with error: {}",
test, // We check parsing roundtrip
error Update::parse(&update.to_string(), None)
)), .map_err(|e| anyhow!("Failure to deserialize \"{update}\" of {test} with error: {e}"))?;
Ok(update) => {
// We check parsing roundtrip store
if let Err(error) = Update::parse(&update.to_string(), None) { .update(update)
return Err(anyhow!( .map_err(|e| anyhow!("Failure to execute update of {test} with error: {e}"))?;
"Failure to deserialize \"{}\" of {} with error: {}", let mut store_dataset: Dataset = store.iter().collect::<Result<_, _>>()?;
update.to_string(), store_dataset.canonicalize();
test, let mut result_store_dataset: Dataset = result_store.iter().collect::<Result<_, _>>()?;
error result_store_dataset.canonicalize();
)); if store_dataset == result_store_dataset {
} Ok(())
} else {
match store.update(update) { bail!(
Err(error) => Err(anyhow!( "Failure on {test}.\nDiff:\n{}\nParsed update:\n{}\n",
"Failure to execute update of {} with error: {}", dataset_diff(&result_store_dataset, &store_dataset),
test, Update::parse(&read_file_to_string(update_file)?, Some(update_file)).unwrap(),
error )
)),
Ok(()) => {
let mut store_dataset: Dataset = store.iter().collect::<Result<_, _>>()?;
store_dataset.canonicalize();
let mut result_store_dataset: Dataset =
result_store.iter().collect::<Result<_, _>>()?;
result_store_dataset.canonicalize();
if store_dataset == result_store_dataset {
Ok(())
} else {
Err(anyhow!(
"Failure on {}.\nDiff:\n{}\nParsed update:\n{}\n",
test,
dataset_diff(&result_store_dataset, &store_dataset),
Update::parse(&read_file_to_string(update_file)?, Some(update_file))
.unwrap(),
))
}
}
}
}
} }
} }
@ -624,7 +552,7 @@ impl StaticQueryResults {
if let TermRef::Literal(l) = object { if let TermRef::Literal(l) = object {
Ok(Variable::new_unchecked(l.value())) Ok(Variable::new_unchecked(l.value()))
} else { } else {
Err(anyhow!("Invalid rs:resultVariable: {}", object)) bail!("Invalid rs:resultVariable: {object}")
} }
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
@ -650,10 +578,10 @@ impl StaticQueryResults {
value.into_owned(), value.into_owned(),
)) ))
} else { } else {
Err(anyhow!("Invalid rs:binding: {}", binding)) bail!("Invalid rs:binding: {binding}")
} }
} else { } else {
Err(anyhow!("Invalid rs:binding: {}", object)) bail!("Invalid rs:binding: {object}")
} }
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
@ -664,13 +592,13 @@ impl StaticQueryResults {
if let TermRef::Literal(l) = object { if let TermRef::Literal(l) = object {
Ok(u64::from_str(l.value())?) Ok(u64::from_str(l.value())?)
} else { } else {
Err(anyhow!("Invalid rs:index: {}", object)) bail!("Invalid rs:index: {object}")
} }
}) })
.transpose()?; .transpose()?;
Ok((bindings, index)) Ok((bindings, index))
} else { } else {
Err(anyhow!("Invalid rs:solution: {}", object)) bail!("Invalid rs:solution: {object}")
} }
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;

Loading…
Cancel
Save