From 8fb58c3d4471796297f71cb5536b75ccd10098f8 Mon Sep 17 00:00:00 2001 From: Mike Bryant Date: Tue, 28 Oct 2025 14:46:13 +0000 Subject: [PATCH] Add relative file resolver base path to mapping launcher. Typically (the default) ShExML relative file sources are resolved for loading, uh, relative to the CWD. This can be tricky in some environments where you can't necessarily know this when writing the mapping rules. This change allows explicitly providing the base path from which relative files are loaded. --- .../shexml/MappingLauncher.scala | 39 +++++-- .../shexml/helper/SourceHelper.scala | 28 +++-- .../shexml/visitor/QuerySearcher.scala | 2 +- .../shexml/visitor/RDFGeneratorVisitor.scala | 16 ++- .../shexml/visitor/RMLGeneratorVisitor.scala | 6 +- .../herminiogarcia/shexml/FilmsStdin.scala | 2 +- ...eratorExpressionWithCSVFromStdinTest.scala | 2 +- .../shexml/ParallelConfigFixtures.scala | 13 +++ .../shexml/ParallelConfigurations.scala | 7 ++ .../shexml/RelativeBasePathFunctionTest.scala | 105 ++++++++++++++++++ .../SourceRelativePathWithWildcardTest.scala | 8 +- ...PathWithWildcardWindowsBackslashTest.scala | 8 +- 12 files changed, 200 insertions(+), 36 deletions(-) create mode 100644 src/test/scala/com/herminiogarcia/shexml/RelativeBasePathFunctionTest.scala diff --git a/src/main/scala/com/herminiogarcia/shexml/MappingLauncher.scala b/src/main/scala/com/herminiogarcia/shexml/MappingLauncher.scala index 70b1c0d..96b2c8d 100644 --- a/src/main/scala/com/herminiogarcia/shexml/MappingLauncher.scala +++ b/src/main/scala/com/herminiogarcia/shexml/MappingLauncher.scala @@ -6,13 +6,15 @@ import com.herminiogarcia.shexml.helper.{OrphanBNodeRemover, ParallelExecutionCo import com.herminiogarcia.shexml.parser.ASTCreatorVisitor import com.herminiogarcia.shexml.shex._ import com.herminiogarcia.shexml.visitor.{PushedOrPoppedValueSearchVisitor, RDFGeneratorVisitor, RMLGeneratorVisitor, VarTableBuilderVisitor} +import com.typesafe.scalalogging.Logger import org.antlr.v4.runtime.{CharStreams, CommonTokenStream} import org.apache.jena.query.{Dataset, DatasetFactory} import org.apache.jena.riot.{RDFDataMgr, RDFFormat, RDFLanguages} -import com.typesafe.scalalogging.Logger + import java.io.ByteArrayOutputStream -import scala.collection.JavaConverters._ +import java.nio.file.Path import java.util.concurrent.ConcurrentLinkedQueue +import scala.collection.JavaConverters._ import scala.collection.mutable /** @@ -21,7 +23,21 @@ import scala.collection.mutable class MappingLauncher(val username: String = "", val password: String = "", drivers: String = "", val inferenceDatatype: Boolean = false, val normaliseURIs: Boolean = false, - val parallelCollectionConfigurator: ParallelExecutionConfigurator = new ParallelExecutionConfigurator(Map(), None)) { + val parallelCollectionConfigurator: ParallelExecutionConfigurator = new ParallelExecutionConfigurator(Map(), None), + val basePath: Path = Path.of("")) { + + /** + * Java compatibility constructor. + */ + def this( + username: String, + password: String, + drivers: String, + inferenceDatatype: Boolean, + normaliseURIs: Boolean, + parallelCollectionConfigurator: ParallelExecutionConfigurator) = { + this(username, password, drivers, inferenceDatatype, normaliseURIs, parallelCollectionConfigurator, Path.of("")) + } private val logger = Logger[MappingLauncher] @@ -158,7 +174,8 @@ class MappingLauncher(val username: String = "", val password: String = "", driv pushedOrPoppedFieldsPresent = pushedOrPoppedFields, inferenceDatatype = inferenceDatatype, normaliseURIs = normaliseURIs, - parallelCollectionConfigurator = parallelCollectionConfigurator).doVisit(ast, null) + parallelCollectionConfigurator = parallelCollectionConfigurator, + basePath = basePath).doVisit(ast, null) //val in = new ByteArrayInputStream(output.toString().getBytes) //val model = ModelFactory.createDefaultModel() //model.read(in, null, "TURTLE") @@ -167,7 +184,7 @@ class MappingLauncher(val username: String = "", val password: String = "", driv private def generateResultingRML(ast: AST, varTable: mutable.HashMap[Variable, VarResult], prettify: Boolean): Dataset = { val output = DatasetFactory.create() - new RMLGeneratorVisitor(output, varTable.toMap, prettify, username, password).doVisit(ast, null) + new RMLGeneratorVisitor(output, varTable.toMap, prettify, username, password, basePath = basePath).doVisit(ast, null) output } @@ -179,7 +196,9 @@ class MappingLauncher(val username: String = "", val password: String = "", driv pushedOrPoppedFieldsPresent = searchForPushedOrPoppedFields(ast), inferenceDatatype = inferenceDatatype, normaliseURIs = normaliseURIs, - parallelCollectionConfigurator = parallelCollectionConfigurator).doVisit(ast, null) + parallelCollectionConfigurator = parallelCollectionConfigurator, + basePath = basePath + ).doVisit(ast, null) } private def generateShapeMaps(ast: AST, varTable: mutable.HashMap[Variable, VarResult]): List[ShapeMapInference] = { @@ -191,7 +210,9 @@ class MappingLauncher(val username: String = "", val password: String = "", driv pushedOrPoppedFieldsPresent = searchForPushedOrPoppedFields(ast), inferenceDatatype = inferenceDatatype, normaliseURIs = normaliseURIs, - parallelCollectionConfigurator = parallelCollectionConfigurator).doVisit(ast, null) + parallelCollectionConfigurator = parallelCollectionConfigurator, + basePath = basePath + ).doVisit(ast, null) shapeMapTable.asScala.toList } @@ -206,13 +227,13 @@ class MappingLauncher(val username: String = "", val password: String = "", driv private def searchForPushedOrPoppedFields(ast: AST): Boolean = new PushedOrPoppedValueSearchVisitor().doVisit(ast, null) private def resolveImports(mappingRules: String): String = { - val sourceHelper = new SourceHelper() + val sourceHelper = SourceHelper() val regex = "[Ii][Mm][Pp][Oo][Rr][Tt]\\s*<(.+)>".r regex.replaceAllIn(mappingRules, matchedPart => { val importSource = matchedPart.group(1) val loadedSource = if(importSource.contains("://")) sourceHelper.getURLContent(importSource) - else sourceHelper.getContentFromRelativePath(importSource) + else sourceHelper.getContentFromRelativePath(importSource, basePath) java.util.regex.Matcher.quoteReplacement(loadedSource.fileContent) }) } diff --git a/src/main/scala/com/herminiogarcia/shexml/helper/SourceHelper.scala b/src/main/scala/com/herminiogarcia/shexml/helper/SourceHelper.scala index 6bea6de..4967b1c 100644 --- a/src/main/scala/com/herminiogarcia/shexml/helper/SourceHelper.scala +++ b/src/main/scala/com/herminiogarcia/shexml/helper/SourceHelper.scala @@ -2,18 +2,20 @@ package com.herminiogarcia.shexml.helper import com.herminiogarcia.shexml.helper.SourceHelper.{saveFileResult, searchFileResult} +import java.nio.charset.StandardCharsets +import java.nio.file.Path import scala.collection.mutable /** * Created by herminio on 21/2/18. */ -class SourceHelper { +case class SourceHelper() { def getURLContent(url: String): LoadedSource = searchFileResult(url) match { case Some(result) => result case None => val parsedURL = new java.net.URL(url) - val file = scala.io.Source.fromURL(parsedURL, "UTF-8") + val file = scala.io.Source.fromURL(parsedURL, StandardCharsets.UTF_8.toString) try { val content = LoadedSource(file.mkString, url) saveFileResult(url, content) @@ -21,21 +23,23 @@ class SourceHelper { } finally { file.close() } } - def getContentFromRelativePath(path: String): LoadedSource = searchFileResult(path) match { - case Some(result) => result - case None => - val file = scala.io.Source.fromFile(path, "UTF-8") - try { - val content = LoadedSource(file.mkString, path) - saveFileResult(path, content) - content - } finally { file.close() } + def getContentFromRelativePath(path: String, base: Path = Path.of("")): LoadedSource = { + val fullPath = base.resolve(path).normalize().toString + searchFileResult(fullPath) match { + case Some(result) => result + case None => + val file = scala.io.Source.fromFile(fullPath, StandardCharsets.UTF_8.toString) + try { + val content = LoadedSource(file.mkString, fullPath) + saveFileResult(fullPath, content) + content + } finally { file.close() } + } } def getStdinContents(): LoadedSource = { LoadedSource(scala.io.Source.stdin.mkString, "-") } - } object SourceHelper { diff --git a/src/main/scala/com/herminiogarcia/shexml/visitor/QuerySearcher.scala b/src/main/scala/com/herminiogarcia/shexml/visitor/QuerySearcher.scala index d05ef76..4b13626 100644 --- a/src/main/scala/com/herminiogarcia/shexml/visitor/QuerySearcher.scala +++ b/src/main/scala/com/herminiogarcia/shexml/visitor/QuerySearcher.scala @@ -28,7 +28,7 @@ class QuerySearcher(val varTable: Map[Variable, VarResult]) { private def getURLContents(u: URL): QueryClause = { val parts = u.value.split('.') val extension = parts(parts.length - 1) - val file = new SourceHelper().getURLContent(u.value) + val file = SourceHelper().getURLContent(u.value) if(extension == "xpath") { XmlPath(file.fileContent) } else if(extension == "jsonpath") { diff --git a/src/main/scala/com/herminiogarcia/shexml/visitor/RDFGeneratorVisitor.scala b/src/main/scala/com/herminiogarcia/shexml/visitor/RDFGeneratorVisitor.scala index 72a0233..4a1af29 100644 --- a/src/main/scala/com/herminiogarcia/shexml/visitor/RDFGeneratorVisitor.scala +++ b/src/main/scala/com/herminiogarcia/shexml/visitor/RDFGeneratorVisitor.scala @@ -18,6 +18,7 @@ import org.apache.jena.util.SplitIRI import scala.collection.concurrent import java.io.{File, StringReader} +import java.nio.file.Path import java.sql.DriverManager import java.util.concurrent.ConcurrentLinkedQueue import javax.xml.transform.stream.StreamSource @@ -35,7 +36,8 @@ class RDFGeneratorVisitor(dataset: Dataset, varTable: Map[Variable, VarResult], pushedOrPoppedFieldsPresent: Boolean = true, inferenceDatatype: Boolean = false, normaliseURIs: Boolean = false, - parallelCollectionConfigurator: ParallelExecutionConfigurator = new ParallelExecutionConfigurator(Map(), None)) + parallelCollectionConfigurator: ParallelExecutionConfigurator = new ParallelExecutionConfigurator(Map(), None), + basePath: Path) extends DefaultVisitor[Any, Any] with JdbcDriverRegistry { protected val prefixTable = concurrent.TrieMap[String, String](("rdf:", "http://www.w3.org/1999/02/22-rdf-syntax-ns#")) @@ -49,6 +51,7 @@ class RDFGeneratorVisitor(dataset: Dataset, varTable: Map[Variable, VarResult], protected val xpathQueryResultsCache = new XpathQueryResultsCache(pushedOrPoppedFieldsPresent) protected val xmlDocumentCache = new XMLDocumentCache() protected val functionHubExecuterCache = new FunctionHubExecutorCache() + protected val sourceHelper: SourceHelper = SourceHelper() protected val defaultModel = dataset.getDefaultModel protected val jsonPathConfiguration = Configuration.defaultConfiguration() .addOptions(com.jayway.jsonpath.Option.ALWAYS_RETURN_LIST) @@ -614,7 +617,7 @@ class RDFGeneratorVisitor(dataset: Dataset, varTable: Map[Variable, VarResult], else if(url.contains('*')) throw new Exception("* wildcard not allowed over remote files") else - List(new SourceHelper().getURLContent(url)) + List(sourceHelper.getURLContent(url)) case RelativePath(path) => if(isRDFSource(path)) { @@ -625,11 +628,11 @@ class RDFGeneratorVisitor(dataset: Dataset, varTable: Map[Variable, VarResult], List(LoadedSource("", fileProtocol + fileAbsolutePath)) } else if(path.contains('*')) getAllFilesContents(path) - else List(new SourceHelper().getContentFromRelativePath(path)) + else List(sourceHelper.getContentFromRelativePath(path, basePath)) case JdbcURL(url) => List(LoadedSource("", url)) - case Stdin() => List(new SourceHelper().getStdinContents()) + case Stdin() => List(sourceHelper.getStdinContents()) case default => visit(default, optionalArgument) @@ -1007,10 +1010,11 @@ class RDFGeneratorVisitor(dataset: Dataset, varTable: Map[Variable, VarResult], val fileBeginning = slices(0).splitAt(slices(0).lastIndexOf("/"))._2.replace("/", "") val fileEnding = slices(1).splitAt(slices(1).lastIndexOf("."))._1 val fileExtension = slices(1).splitAt(slices(1).lastIndexOf("."))._2 - val files = new File(path).listFiles().filter(_.isFile) + val normPath = basePath.resolve(path).normalize() + val files = normPath.toFile.listFiles().filter(_.isFile) .filter(_.getName.endsWith(fileEnding + fileExtension)).filter(_.getName.startsWith(fileBeginning)) val fileProtocol = if(path.startsWith("/")) "file://" else "file:///" - files.map(file => new SourceHelper().getURLContent(fileProtocol + file.getAbsolutePath.replaceAll("\\\\", "/"))).toList + files.map(file => sourceHelper.getURLContent(fileProtocol + file.getAbsolutePath.replaceAll("\\\\", "/"))).toList } private def visitAction(actionOrLiteral: ActionOrLiteral, predicateObjectsList: List[Any], optionalArgument: Any): List[Result] = actionOrLiteral match { diff --git a/src/main/scala/com/herminiogarcia/shexml/visitor/RMLGeneratorVisitor.scala b/src/main/scala/com/herminiogarcia/shexml/visitor/RMLGeneratorVisitor.scala index 4566e41..2b382cb 100644 --- a/src/main/scala/com/herminiogarcia/shexml/visitor/RMLGeneratorVisitor.scala +++ b/src/main/scala/com/herminiogarcia/shexml/visitor/RMLGeneratorVisitor.scala @@ -5,8 +5,10 @@ import com.typesafe.scalalogging.Logger import org.apache.jena.query.Dataset import org.apache.jena.rdf.model.{Resource, Statement} -class RMLGeneratorVisitor(dataset: Dataset, varTable: Map[Variable, VarResult], prettify: Boolean ,username: String, password: String) - extends RDFGeneratorVisitor(dataset, varTable, username, password) with JdbcDriverRegistry { +import java.nio.file.Path + +class RMLGeneratorVisitor(dataset: Dataset, varTable: Map[Variable, VarResult], prettify: Boolean ,username: String, password: String, basePath: Path) + extends RDFGeneratorVisitor(dataset, varTable, username, password, basePath = basePath) with JdbcDriverRegistry { private val mapPrefix = "http://mapping.example.com/" private val rmlPrefix = "http://semweb.mmlab.be/ns/rml#" diff --git a/src/test/scala/com/herminiogarcia/shexml/FilmsStdin.scala b/src/test/scala/com/herminiogarcia/shexml/FilmsStdin.scala index 8a49325..635b297 100644 --- a/src/test/scala/com/herminiogarcia/shexml/FilmsStdin.scala +++ b/src/test/scala/com/herminiogarcia/shexml/FilmsStdin.scala @@ -48,7 +48,7 @@ class FilmsStdin extends AnyFunSuite override def beforeAll(configMap: ConfigMap): Unit = { super.beforeAll(configMap) - val stream = new ByteArrayInputStream(new SourceHelper().getContentFromRelativePath("./src/test/resources/filmsAlt.json").fileContent.getBytes()) + val stream = new ByteArrayInputStream(SourceHelper().getContentFromRelativePath("./src/test/resources/filmsAlt.json").fileContent.getBytes()) System.setIn(stream) stream.close() output = mappingLauncher.launchMapping(example).getDefaultModel diff --git a/src/test/scala/com/herminiogarcia/shexml/MultipleElementIteratorExpressionWithCSVFromStdinTest.scala b/src/test/scala/com/herminiogarcia/shexml/MultipleElementIteratorExpressionWithCSVFromStdinTest.scala index 5b777c1..e03c0d3 100644 --- a/src/test/scala/com/herminiogarcia/shexml/MultipleElementIteratorExpressionWithCSVFromStdinTest.scala +++ b/src/test/scala/com/herminiogarcia/shexml/MultipleElementIteratorExpressionWithCSVFromStdinTest.scala @@ -57,7 +57,7 @@ class MultipleElementIteratorExpressionWithCSVFromStdinTest extends AnyFunSuite override def beforeAll(configMap: ConfigMap): Unit = { super.beforeAll(configMap) - val stream = new ByteArrayInputStream(new SourceHelper().getURLContent("https://rawgit.com/herminiogg/ShExML/enhancement-%239/src/test/resources/films.csv").fileContent.getBytes()) + val stream = new ByteArrayInputStream(SourceHelper().getURLContent("https://rawgit.com/herminiogg/ShExML/enhancement-%239/src/test/resources/films.csv").fileContent.getBytes()) System.setIn(stream) stream.close() output = mappingLauncher.launchMapping(example).getDefaultModel diff --git a/src/test/scala/com/herminiogarcia/shexml/ParallelConfigFixtures.scala b/src/test/scala/com/herminiogarcia/shexml/ParallelConfigFixtures.scala index e998a90..32b8dd3 100644 --- a/src/test/scala/com/herminiogarcia/shexml/ParallelConfigFixtures.scala +++ b/src/test/scala/com/herminiogarcia/shexml/ParallelConfigFixtures.scala @@ -3,6 +3,8 @@ package com.herminiogarcia.shexml import com.herminiogarcia.shexml.helper.ParallelExecutionConfigurator import org.scalatest.{BeforeAndAfterAllConfigMap, ConfigMap, TestSuite} +import java.nio.file.Path + trait ParallelConfigInferenceDatatypesNormaliseURIsFixture extends BeforeAndAfterAllConfigMap with MappingLauncherInitializer { this: TestSuite => var mappingLauncher: MappingLauncher = _ @@ -49,6 +51,17 @@ trait ParallelConfigSparql extends BeforeAndAfterAllConfigMap with MappingLaunch } } +trait ParallelConfigBasePath extends BeforeAndAfterAllConfigMap with MappingLauncherInitializer { this: TestSuite => + var mappingLauncher: MappingLauncher = _ + + def relativeBasePath: Path + + override def beforeAll(configMap: ConfigMap): Unit = { + mappingLauncher = configMapToParallelConfiguration(configMap).parallelConfigurationBasePath(relativeBasePath) + super.beforeAll(configMap) + } +} + trait ParallelConfigValidation extends BeforeAndAfterAllConfigMap with MappingLauncherInitializer { this: TestSuite => var parallelConfiguration: ParallelExecutionConfigurator = _ diff --git a/src/test/scala/com/herminiogarcia/shexml/ParallelConfigurations.scala b/src/test/scala/com/herminiogarcia/shexml/ParallelConfigurations.scala index f634e7e..5c85e72 100644 --- a/src/test/scala/com/herminiogarcia/shexml/ParallelConfigurations.scala +++ b/src/test/scala/com/herminiogarcia/shexml/ParallelConfigurations.scala @@ -2,6 +2,8 @@ package com.herminiogarcia.shexml import com.herminiogarcia.shexml.helper.ParallelExecutionConfigurator +import java.nio.file.Path + class ParallelConfigurations(val parallelConfiguration: ParallelExecutionConfigurator) { val parallelConfigurationInferenceDatatypesNormaliseURIs = new MappingLauncher( @@ -34,6 +36,11 @@ class ParallelConfigurations(val parallelConfiguration: ParallelExecutionConfigu "root", parallelCollectionConfigurator = parallelConfiguration ) + + def parallelConfigurationBasePath(basePath: Path) = new MappingLauncher( + parallelCollectionConfigurator = parallelConfiguration, + basePath = basePath + ) } object ParallelConfigurations { diff --git a/src/test/scala/com/herminiogarcia/shexml/RelativeBasePathFunctionTest.scala b/src/test/scala/com/herminiogarcia/shexml/RelativeBasePathFunctionTest.scala new file mode 100644 index 0000000..1b5dfe0 --- /dev/null +++ b/src/test/scala/com/herminiogarcia/shexml/RelativeBasePathFunctionTest.scala @@ -0,0 +1,105 @@ +package com.herminiogarcia.shexml + +import org.apache.jena.datatypes.xsd.XSDDatatype +import org.apache.jena.rdf.model.Model +import org.scalatest.ConfigMap +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.must.Matchers + +import java.nio.file.{Path, Paths} + +class RelativeBasePathFunctionTest extends AnyFunSuite + with Matchers with RDFStatementCreator + with ParallelConfigBasePath { + + // This path is used to resolve films.xml, films.json, functions.json + override def relativeBasePath: Path = Path.of("src/test/resources/") + + private val example = + """ + PREFIX : + |PREFIX xs: + |SOURCE films_xml_file <./films.xml> + |SOURCE films_json_file <./films.json> + |FUNCTIONS helper + |AUTOINCREMENT my_code1 <"something: " + 1 to 10 by 2> + |AUTOINCREMENT code1 <1 to 10 by 2> + |ITERATOR film_xml { + | FIELD id <@id> + | FIELD name + | FIELD year + | FIELD country + | FIELD directors + |} + |ITERATOR film_json { + | FIELD id + | FIELD name + | FIELD year + | FIELD country + | FIELD directors + |} + |EXPRESSION films + | + |:Films :[films.id] { + | :type :Film ; + | :internalId1 [helper.concatenate(films.id, my_code1)] ; + | #:internalIdPlusOne [helper.addOneAutoIncrement(code1)] ; + | :name [films.name] ; + | :year [films.year] xs:gYear ; + | :country [films.country] ; + | :director [films.directors] ; + |} + """.stripMargin + + private var output: Model = _ + private val prefix = "http://example.com/" + + override def beforeAll(configMap: ConfigMap): Unit = { + super.beforeAll(configMap) + output = mappingLauncher.launchMapping(example).getDefaultModel + } + + test("Shape 1 is translated correctly") { + assert(output.contains(createStatement(prefix, "1", "type", "Film"))) + assert(output.contains(createStatementWithLiteral(prefix, "1", "internalId1", "1something: 5", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "1", "name", "Dunkirk", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "1", "year", "2017", XSDDatatype.XSDgYear))) + assert(output.contains(createStatementWithLiteral(prefix, "1", "country", "USA", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "1", "director", "Christopher Nolan", XSDDatatype.XSDstring))) + } + + test("Shape 2 is translated correctly") { + assert(output.contains(createStatement(prefix, "2", "type", "Film"))) + assert(output.contains(createStatementWithLiteral(prefix, "2", "internalId1", "2something: 7", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "2", "name", "Interstellar", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "2", "year", "2014", XSDDatatype.XSDgYear))) + assert(output.contains(createStatementWithLiteral(prefix, "2", "country", "USA", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "2", "director", "Christopher Nolan", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "2", "director", "Jonathan Nolan", XSDDatatype.XSDstring))) + } + + test("Shape 3 is translated correctly") { + assert(output.contains(createStatement(prefix, "3", "type", "Film"))) + assert(output.contains(createStatementWithLiteral(prefix, "3", "internalId1", "3something: 1", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "3", "name", "Inception", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "3", "year", "2010", XSDDatatype.XSDgYear))) + assert(output.contains(createStatementWithLiteral(prefix, "3", "country", "USA", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "3", "director", "Christopher Nolan", XSDDatatype.XSDstring))) + } + + test("Shape 4 is translated correctly") { + assert(output.contains(createStatement(prefix, "4", "type", "Film"))) + assert(output.contains(createStatementWithLiteral(prefix, "4", "internalId1", "4something: 3", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "4", "name", "The Prestige", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "4", "year", "2006", XSDDatatype.XSDgYear))) + assert(output.contains(createStatementWithLiteral(prefix, "4", "country", "USA", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "4", "director", "Christopher Nolan", XSDDatatype.XSDstring))) + assert(output.contains(createStatementWithLiteral(prefix, "4", "director", "Jonathan Nolan", XSDDatatype.XSDstring))) + } + + test("No additional triples are generated") { + val triplesCount = 26 + assert(output.size() == triplesCount) + } + +} diff --git a/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardTest.scala b/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardTest.scala index 16e9f86..85bedc6 100644 --- a/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardTest.scala +++ b/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardTest.scala @@ -6,15 +6,19 @@ import org.scalatest.ConfigMap import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.must.Matchers +import java.nio.file.Path + class SourceRelativePathWithWildcardTest extends AnyFunSuite with Matchers with RDFStatementCreator - with ParallelConfigInferenceDatatypesNormaliseURIsFixture { + with ParallelConfigBasePath { + + override def relativeBasePath: Path = Path.of("src/test/resources/") private val example = """ |PREFIX : |PREFIX xs: - |SOURCE films_json_file + |SOURCE films_json_file |ITERATOR film_json { | FIELD id | FIELD name diff --git a/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardWindowsBackslashTest.scala b/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardWindowsBackslashTest.scala index b241a2a..f255a01 100644 --- a/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardWindowsBackslashTest.scala +++ b/src/test/scala/com/herminiogarcia/shexml/SourceRelativePathWithWildcardWindowsBackslashTest.scala @@ -6,15 +6,19 @@ import org.scalatest.ConfigMap import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.must.Matchers +import java.nio.file.Path + class SourceRelativePathWithWildcardWindowsBackslashTest extends AnyFunSuite with Matchers with RDFStatementCreator - with ParallelConfigInferenceDatatypesNormaliseURIsFixture { + with ParallelConfigBasePath { + + override def relativeBasePath: Path = Path.of("src/test"); private val example = """ |PREFIX : |PREFIX xs: - |SOURCE films_json_file + |SOURCE films_json_file |ITERATOR film_json { | FIELD id | FIELD name