Makes SPARQL test suite local

pull/10/head
Tpt 5 years ago
parent ebb74d1560
commit a62602298d
  1. 3
      lib/Cargo.toml
  2. 124
      lib/tests/sparql_test_cases.rs

@ -32,6 +32,3 @@ regex = "1"
[build-dependencies] [build-dependencies]
peg = "0.5" peg = "0.5"
[dev-dependencies]
reqwest = "0.9"

@ -1,7 +1,5 @@
///! Integration tests based on [SPARQL 1.1 Test Cases](https://www.w3.org/2009/sparql/docs/tests/README.html) ///! Integration tests based on [SPARQL 1.1 Test Cases](https://www.w3.org/2009/sparql/docs/tests/README.html)
use failure::format_err; use failure::format_err;
use reqwest::Client;
use reqwest::Response;
use rudf::model::vocab::rdf; use rudf::model::vocab::rdf;
use rudf::model::vocab::rdfs; use rudf::model::vocab::rdfs;
use rudf::model::*; use rudf::model::*;
@ -17,16 +15,17 @@ use rudf::store::isomorphism::GraphIsomorphism;
use rudf::store::MemoryDataset; use rudf::store::MemoryDataset;
use rudf::store::MemoryGraph; use rudf::store::MemoryGraph;
use rudf::Result; use rudf::Result;
use std::error::Error;
use std::fmt; use std::fmt;
use std::io::BufReader; use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use url::Url; use url::Url;
#[test] #[test]
fn sparql_w3c_syntax_testsuite() { fn sparql_w3c_syntax_testsuite() {
let manifest_10_url = let manifest_10_url =
Url::parse("https://www.w3.org/2001/sw/DataAccess/tests/data-r2/manifest-syntax.ttl") Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/manifest-syntax.ttl")
.unwrap(); .unwrap();
let manifest_11_url = Url::parse( let manifest_11_url = Url::parse(
"http://www.w3.org/2009/sparql/docs/tests/data-sparql11/syntax-query/manifest.ttl", "http://www.w3.org/2009/sparql/docs/tests/data-sparql11/syntax-query/manifest.ttl",
@ -39,17 +38,15 @@ fn sparql_w3c_syntax_testsuite() {
NamedNode::from_str("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/syntax-sparql2/manifest#syntax-function-04").unwrap(), NamedNode::from_str("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/syntax-sparql2/manifest#syntax-function-04").unwrap(),
NamedNode::from_str("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/syntax-sparql1/manifest#syntax-qname-04").unwrap(), NamedNode::from_str("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/syntax-sparql1/manifest#syntax-qname-04").unwrap(),
]; ];
let client = RDFClient::default();
for test_result in TestManifest::new(&client, manifest_10_url) for test_result in TestManifest::new(manifest_10_url).chain(TestManifest::new(manifest_11_url))
.chain(TestManifest::new(&client, manifest_11_url))
{ {
let test = test_result.unwrap(); let test = test_result.unwrap();
if test_blacklist.contains(&test.id) { if test_blacklist.contains(&test.id) {
continue; continue;
} }
if test.kind == "PositiveSyntaxTest" || test.kind == "PositiveSyntaxTest11" { if test.kind == "PositiveSyntaxTest" || test.kind == "PositiveSyntaxTest11" {
match client.load_sparql_query(test.query.clone()) { match load_sparql_query(test.query.clone()) {
Err(error) => assert!(false, "Failure on {} with error: {}", test, error), Err(error) => assert!(false, "Failure on {} with error: {}", test, error),
Ok(query) => { Ok(query) => {
if let Err(error) = read_sparql_query(query.to_string().as_bytes(), None) { if let Err(error) = read_sparql_query(query.to_string().as_bytes(), None) {
@ -65,7 +62,7 @@ fn sparql_w3c_syntax_testsuite() {
} }
} else if test.kind == "NegativeSyntaxTest" || test.kind == "NegativeSyntaxTest11" { } else if test.kind == "NegativeSyntaxTest" || test.kind == "NegativeSyntaxTest11" {
//TODO //TODO
if let Ok(result) = client.load_sparql_query(test.query.clone()) { if let Ok(result) = load_sparql_query(test.query.clone()) {
eprintln!("Failure on {}. The output tree is: {}", test, result); eprintln!("Failure on {}. The output tree is: {}", test, result);
} }
} else { } else {
@ -107,9 +104,6 @@ fn sparql_w3c_query_evaluation_testsuite() {
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/graph/manifest.ttl") Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/graph/manifest.ttl")
.unwrap(), .unwrap(),
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/i18n/manifest.ttl").unwrap(), Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/i18n/manifest.ttl").unwrap(),
Url::parse(
"http://www.w3.org/2001/sw/DataAccess/tests/data-r2/optional-filter/manifest.ttl",
).unwrap(),
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/optional/manifest.ttl") Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/optional/manifest.ttl")
.unwrap(), .unwrap(),
Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/reduced/manifest.ttl") Url::parse("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/reduced/manifest.ttl")
@ -171,13 +165,12 @@ fn sparql_w3c_query_evaluation_testsuite() {
//DATATYPE("foo"@en) returns rdf:langString in SPARQL 1.1 //DATATYPE("foo"@en) returns rdf:langString in SPARQL 1.1
NamedNode::from_str( NamedNode::from_str(
"http://www.w3.org/2001/sw/DataAccess/tests/data-r2/expr-builtin/manifest#dawg-datatype-2", "http://www.w3.org/2001/sw/DataAccess/tests/data-r2/expr-builtin/manifest#dawg-datatype-2",
).unwrap(), ).unwrap()
]; ];
let client = RDFClient::default();
for test_result in manifest_10_urls for test_result in manifest_10_urls
.into_iter() .into_iter()
.flat_map(|manifest| TestManifest::new(&client, manifest)) .flat_map(|manifest| TestManifest::new(manifest))
{ {
let test = test_result.unwrap(); let test = test_result.unwrap();
if test_blacklist.contains(&test.id) { if test_blacklist.contains(&test.id) {
@ -188,8 +181,7 @@ fn sparql_w3c_query_evaluation_testsuite() {
Some(data) => { Some(data) => {
let dataset = MemoryDataset::default(); let dataset = MemoryDataset::default();
let dataset_default = dataset.default_graph(); let dataset_default = dataset.default_graph();
client load_graph(data.clone())
.load_graph(data.clone())
.unwrap() .unwrap()
.iter() .iter()
.unwrap() .unwrap()
@ -202,14 +194,13 @@ fn sparql_w3c_query_evaluation_testsuite() {
let named_graph = data let named_graph = data
.named_graph(&NamedNode::from(graph_data.clone()).into()) .named_graph(&NamedNode::from(graph_data.clone()).into())
.unwrap(); .unwrap();
client load_graph(graph_data.clone())
.load_graph(graph_data.clone())
.unwrap() .unwrap()
.iter() .iter()
.unwrap() .unwrap()
.for_each(|triple| named_graph.insert(&triple.unwrap()).unwrap()); .for_each(|triple| named_graph.insert(&triple.unwrap()).unwrap());
} }
match data.prepare_query(client.get(&test.query).unwrap()) { match data.prepare_query(read_file(&test.query).unwrap()) {
Err(error) => assert!( Err(error) => assert!(
false, false,
"Failure to parse query of {} with error: {}", "Failure to parse query of {} with error: {}",
@ -222,9 +213,8 @@ fn sparql_w3c_query_evaluation_testsuite() {
test, error test, error
), ),
Ok(result) => { Ok(result) => {
let expected_graph = client let expected_graph =
.load_sparql_query_result_graph(test.result.clone().unwrap()) load_sparql_query_result_graph(test.result.clone().unwrap()).unwrap();
.unwrap();
let with_order = expected_graph let with_order = expected_graph
.triples_for_predicate(&rs::INDEX) .triples_for_predicate(&rs::INDEX)
.unwrap() .unwrap()
@ -237,7 +227,7 @@ fn sparql_w3c_query_evaluation_testsuite() {
test, test,
expected_graph, expected_graph,
actual_graph, actual_graph,
client.load_sparql_query(test.query.clone()).unwrap(), load_sparql_query(test.query.clone()).unwrap(),
data data
) )
} }
@ -249,55 +239,55 @@ fn sparql_w3c_query_evaluation_testsuite() {
} }
} }
pub struct RDFClient { fn load_graph(url: Url) -> Result<MemoryGraph> {
client: Client,
}
impl Default for RDFClient {
fn default() -> Self {
Self {
client: Client::new(),
}
}
}
impl RDFClient {
fn load_graph(&self, url: Url) -> Result<MemoryGraph> {
if url.as_str().ends_with(".ttl") { if url.as_str().ends_with(".ttl") {
Ok(read_turtle(self.get(&url)?, Some(url))?.collect()) Ok(read_turtle(read_file(&url)?, Some(url))?.collect())
} else if url.as_str().ends_with(".rdf") { } else if url.as_str().ends_with(".rdf") {
read_rdf_xml(BufReader::new(self.get(&url)?), Some(url)).collect() read_rdf_xml(read_file(&url)?, Some(url)).collect()
} else { } else {
Err(format_err!("Serialization type not found for {}", url)) Err(format_err!("Serialization type not found for {}", url))
} }
} }
fn load_sparql_query(&self, url: Url) -> Result<Query> { fn load_sparql_query(url: Url) -> Result<Query> {
read_sparql_query(self.get(&url)?, Some(url)) read_sparql_query(read_file(&url)?, Some(url))
} }
fn load_sparql_query_result_graph(&self, url: Url) -> Result<MemoryGraph> { fn load_sparql_query_result_graph(url: Url) -> Result<MemoryGraph> {
if url.as_str().ends_with(".srx") { if url.as_str().ends_with(".srx") {
to_graph(read_xml_results(BufReader::new(self.get(&url)?))?, false) to_graph(read_xml_results(read_file(&url)?)?, false)
} else { } else {
self.load_graph(url) load_graph(url)
}
} }
}
fn get(&self, url: &Url) -> Result<Response> { fn to_relative_path(url: &Url) -> Result<String> {
match self.client.get(url.clone()).send() { let url = url.as_str();
Ok(response) => Ok(response), if url.starts_with("http://www.w3.org/2001/sw/DataAccess/tests/data-r2/") {
Err(error) => { Ok(url.replace(
if error.description() == "parsed HTTP message from remote is incomplete" { "http://www.w3.org/2001/sw/DataAccess/tests/",
self.get(url) "rdf-tests/sparql11/",
))
} else if url.starts_with("http://www.w3.org/2009/sparql/docs/tests/data-sparql11/") {
Ok(url.replace(
"http://www.w3.org/2009/sparql/docs/tests/",
"rdf-tests/sparql11/",
))
} else { } else {
Err(format_err!("HTTP request error: {}", error.description())) Err(format_err!("Not supported url for file: {}", url))
}
}
}
} }
} }
fn read_file(url: &Url) -> Result<impl BufRead> {
let mut base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
base_path.push("tests");
base_path.push(to_relative_path(url)?);
Ok(BufReader::new(File::open(&base_path).map_err(|e| {
format_err!("Opening file {} failed with {}", base_path.display(), e)
})?))
}
mod rs { mod rs {
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rudf::model::NamedNode; use rudf::model::NamedNode;
@ -441,17 +431,15 @@ impl fmt::Display for Test {
} }
} }
pub struct TestManifest<'a> { pub struct TestManifest {
client: &'a RDFClient,
graph: MemoryGraph, graph: MemoryGraph,
tests_to_do: Vec<Term>, tests_to_do: Vec<Term>,
manifests_to_do: Vec<Url>, manifests_to_do: Vec<Url>,
} }
impl<'a> TestManifest<'a> { impl TestManifest {
pub fn new(client: &'a RDFClient, url: Url) -> TestManifest<'a> { pub fn new(url: Url) -> TestManifest {
Self { Self {
client,
graph: MemoryGraph::default(), graph: MemoryGraph::default(),
tests_to_do: Vec::default(), tests_to_do: Vec::default(),
manifests_to_do: vec![url], manifests_to_do: vec![url],
@ -501,7 +489,7 @@ pub mod qt {
} }
} }
impl<'a> Iterator for TestManifest<'a> { impl Iterator for TestManifest {
type Item = Result<Test>; type Item = Result<Test>;
fn next(&mut self) -> Option<Result<Test>> { fn next(&mut self) -> Option<Result<Test>> {
@ -515,9 +503,9 @@ impl<'a> Iterator for TestManifest<'a> {
{ {
Some(Term::NamedNode(c)) => match c.as_str().split("#").last() { Some(Term::NamedNode(c)) => match c.as_str().split("#").last() {
Some(k) => k.to_string(), Some(k) => k.to_string(),
None => return Some(Err(format_err!("no type"))), None => return self.next(), //We ignore the test
}, },
_ => return Some(Err(format_err!("no type"))), _ => return self.next(), //We ignore the test
}; };
let name = match self let name = match self
.graph .graph
@ -604,7 +592,7 @@ impl<'a> Iterator for TestManifest<'a> {
match self.manifests_to_do.pop() { match self.manifests_to_do.pop() {
Some(url) => { Some(url) => {
let manifest = NamedOrBlankNode::from(NamedNode::new(url.clone())); let manifest = NamedOrBlankNode::from(NamedNode::new(url.clone()));
match self.client.load_graph(url) { match load_graph(url) {
Ok(g) => g Ok(g) => g
.iter() .iter()
.unwrap() .unwrap()

Loading…
Cancel
Save