// Runs the official RDFa 1.1 test suite (https://rdfa.info/test-suite/)
// for the html5 and xhtml1 host languages, plus the rdfa1.1-vocab
// vocabulary-expansion tests.
//
// Fixtures are vendored into tests/rdfa11/ — see README.md for the
// download commands. Each test parses an (X)HTML input with the
// appropriate parser and checks the resulting store against the test's
// SPARQL ASK query; expectedResults false means the ASK must be false.

from test/more import *;

author_testing();
requires_capability( "fs" );

from rdf import RDFStore, sparql_query;
from rdf/parser/html_rdfa import HtmlRdfaParser;
from rdf/parser/xhtml_rdfa import XhtmlRdfaParser;
from std/data/json import JSON;
from std/io import Path;

let root := new Path("tests/rdfa11");
if ( not root.child("manifest.jsonld").exists() ) {
	pass("RDFa test suite not vendored");
	done_testing();
}

let json := new JSON();
let manifest := json.load(root.child("manifest.jsonld"));

let html_parser := new HtmlRdfaParser();
let xhtml_parser := new XhtmlRdfaParser();

// Tests excluded from the run, with reasons. Currently empty: every
// vendored rdfa1.1 and rdfa1.1-vocab test passes on all three runtimes.
let unsupported := {};

function _applicable ( Dict entry, String hl ) {
	return false unless "rdfa1.1" in entry{versions};
	return false unless hl in entry{hostLanguages};
	return true;
}

function _run_case ( parser, Path input, Path sparql, String base, Boolean expected, String label, ... PairList extra ) {
	let store := RDFStore.temp();
	store.install_schema();
	let ok_parse := true;
	try {
		parser.parse_file( input, base: base, into: store, ...extra );
	}
	catch ( Exception e ) {
		ok_parse := false;
		// A parse failure can only satisfy a negative test.
		is( false, expected, label _ " (parse error: " _ e.message _ ")" );
	}
	if ( ok_parse ) {
		let ask := sparql.slurp_utf8();
		let got := false;
		try {
			got := sparql_query( store, ask ){boolean} ? true : false;
		}
		catch ( Exception e ) {
			fail( label _ " (sparql error: " _ e.message _ ")" );
			return null;
		}
		is( got, expected, label );
	}
	return null;
}

let counts := { html5: 0, xhtml1: 0, vocab: 0 };

for ( let hl in [ "html5", "xhtml1" ] ) {
	let ext := hl eq "html5" ? ".html" : ".xhtml";
	let parser := hl eq "html5" ? html_parser : xhtml_parser;
	for ( let entry in manifest{"@graph"} ) {
		next unless _applicable( entry, hl );
		let num := "" _ entry{num};
		next if unsupported.exists(num);
		let input := root.child(hl).child(num _ ext);
		let sparql := root.child(hl).child(num _ ".sparql");
		next unless input.exists() and sparql.exists();
		counts.set( hl, counts.get(hl) + 1 );
		let base := "http://rdfa.info/test-suite/test-cases/rdfa1.1/" _
			hl _ "/" _ num _ ext;
		let expected := entry{expectedResults} ? true : false;
		_run_case(
			parser, input, sparql, base, expected,
			"RDFa " _ hl _ " " _ num _ ": " _ entry{description},
		);
	}
}

// Vocabulary expansion tests (rdfa1.1-vocab) use a vendored copy of the
// http://rdfa.info/vocabs/rdfa-test# vocabulary, itself an HTML+RDFa
// document, loaded through our own parser.
let vocab_file := root.child("vocabs").child("rdfa-test.html");
if ( vocab_file.exists() ) {
	let vocab_loader := fn ( String iri ) -> html_parser.parse_file(
		vocab_file,
		base: "http://rdfa.info/vocabs/rdfa-test",
	);
	for ( let hl in [ "html5", "xhtml1" ] ) {
		let ext := hl eq "html5" ? ".html" : ".xhtml";
		let parser := hl eq "html5" ? html_parser : xhtml_parser;
		let dir := root.child( "vocab-" _ hl );
		for ( let entry in manifest{"@graph"} ) {
			next unless "rdfa1.1-vocab" in entry{versions};
			next unless hl in entry{hostLanguages};
			let num := "" _ entry{num};
			next if unsupported.exists(num);
			let input := dir.child(num _ ext);
			let sparql := dir.child(num _ ".sparql");
			next unless input.exists() and sparql.exists();
			counts{vocab}++;
			let base := "http://rdfa.info/test-suite/test-cases/rdfa1.1-vocab/" _
				hl _ "/" _ num _ ext;
			let expected := entry{expectedResults} ? true : false;
			_run_case(
				parser, input, sparql, base, expected,
				"RDFa vocab " _ hl _ " " _ num _ ": " _ entry{description},
				vocab_expansion: true,
				vocab_loader: vocab_loader,
			);
		}
	}
}

ok( counts{html5} > 0, "html5 cases executed (" _ counts{html5} _ ")" );
ok( counts{xhtml1} > 0, "xhtml1 cases executed (" _ counts{xhtml1} _ ")" );
ok( counts{vocab} > 0, "vocab-expansion cases executed (" _ counts{vocab} _ ")" );

done_testing();
