diff --git a/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala b/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala index 2714d0f..89657c7 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala @@ -15,6 +15,7 @@ trait HasJellyOptions: val common: JellyOptions abstract class JellyCommand[T <: HasJellyOptions: {Parser, Help}] extends Command[T]: + private var isTest = false private var isDebug = false final protected[cli] var out = System.out diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfCommand.scala b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfCommand.scala new file mode 100644 index 0000000..26c8946 --- /dev/null +++ b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfCommand.scala @@ -0,0 +1,74 @@ +package eu.neverblink.jelly.cli.command.rdf + +import com.google.protobuf.InvalidProtocolBufferException +import org.apache.jena.riot.RiotException +import eu.neverblink.jelly.cli.* +import caseapp.* + +import scala.reflect.TypeTest +import eu.ostrzyciel.jelly.core.{RdfProtoDeserializationError, RdfProtoSerializationError} + +import java.io.{InputStream, OutputStream} + +/** This abstract class is responsible for the common logic in both RDF parsing commands + */ +abstract class RdfCommand[T <: HasJellyOptions: {Parser, Help}, F <: RdfFormat](using + tt: TypeTest[RdfFormat, F], +) extends JellyCommand[T]: + + override final def group = "rdf" + + /** What is the default action if no formats specified */ + val defaultAction: (InputStream, OutputStream) => Unit + + /** The print util responsible for handling the specific formats etc the command requires */ + lazy val printUtil: RdfCommandPrintUtil[F] + + /** The method responsible for matching the format to a given action */ + def matchToAction(option: F): Option[(InputStream, OutputStream) => Unit] + + /** This method takes care of proper error handling and takes care of the parameter priorities in + * matching the input to a given format conversion + * + * @param inputStream + * InputStream + * @param outputStream + * OutputStream + * @param format + * Option[String] + * @param fileName + * Option[String] + * @throws JellyDeserializationError + * @throws JenaRiotException + * @throws InvalidJellyFile + */ + def parseFormatArgs( + inputStream: InputStream, + outputStream: OutputStream, + format: Option[String], + fileName: Option[String], + ): Unit = + try { + val explicitFormat = if (format.isDefined) RdfFormat.find(format.get) else None + val implicitFormat = + if (fileName.isDefined) RdfFormat.inferFormat(fileName.get) else None + (explicitFormat, implicitFormat) match { + case (Some(f: F), _) => + matchToAction(f).get(inputStream, outputStream) + // If format explicitely defined but does not match any available actions or formats, we throw an error + case (_, _) if format.isDefined => + throw InvalidFormatSpecified(format.get, printUtil.validFormatsString) + case (_, Some(f: F)) => + matchToAction(f).get(inputStream, outputStream) + // If format not explicitely defined but implicitely not understandable we default to this + case (_, _) => defaultAction(inputStream, outputStream) + } + } catch + case e: RiotException => + throw JenaRiotException(e) + case e: InvalidProtocolBufferException => + throw InvalidJellyFile(e) + case e: RdfProtoDeserializationError => + throw JellyDeserializationError(e.getMessage) + case e: RdfProtoSerializationError => + throw JellySerializationError(e.getMessage) diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfCommandPrintUtil.scala b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfCommandPrintUtil.scala index 3512576..9d0174c 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfCommandPrintUtil.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfCommandPrintUtil.scala @@ -1,13 +1,16 @@ package eu.neverblink.jelly.cli.command.rdf -trait RdfCommandPrintUtil: - val validFormats: List[RdfFormatOption] - val defaultFormat: RdfFormatOption +import scala.reflect.TypeTest + +trait RdfCommandPrintUtil[F <: RdfFormat](using tt: TypeTest[RdfFormat, F]): + val defaultFormat: RdfFormat + + lazy val validFormats: List[RdfFormat] = RdfFormat.all.collect { case x: F => x } /** Prints the available RDF formats to the user. */ lazy val validFormatsString: String = - validFormats.map(RdfFormatOption.optionString).mkString(", ") + validFormats.map(RdfFormat.optionString).mkString(", ") lazy val helpMsg: String = f"Possible values: ${validFormatsString}. Default format: ${defaultFormat.fullName}" diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFormat.scala b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFormat.scala new file mode 100644 index 0000000..6d436cb --- /dev/null +++ b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFormat.scala @@ -0,0 +1,69 @@ +package eu.neverblink.jelly.cli.command.rdf + +import eu.ostrzyciel.jelly.convert.jena.riot.JellyLanguage +import org.apache.jena.riot.{Lang, RDFLanguages} + +sealed trait RdfFormat: + val fullName: String + val cliOptions: List[String] + +object RdfFormat: + + sealed trait Writeable extends RdfFormat + + sealed trait Jena extends RdfFormat: + val jenaLang: Lang + + object Jena: + sealed trait Writeable extends Jena, RdfFormat.Writeable + sealed trait Readable extends Jena + + case object NQuads extends RdfFormat.Jena.Writeable, RdfFormat.Jena.Readable: + override val fullName: String = "N-Quads" + override val cliOptions: List[String] = List("nq", "nquads") + override val jenaLang: Lang = RDFLanguages.NQUADS + + case object NTriples extends RdfFormat.Jena.Writeable, RdfFormat.Jena.Readable: + override val fullName: String = "N-Triples" + override val cliOptions: List[String] = List("nt", "ntriples") + override val jenaLang: Lang = RDFLanguages.NTRIPLES + + // We do not ever want to write or read from Jelly to Jelly + // So better not have it as Writeable or Readable, just mark that it's integrated into Jena + case object JellyBinary extends RdfFormat.Jena: + override val fullName: String = "Jelly binary format" + override val cliOptions: List[String] = List("jelly") + override val jenaLang: Lang = JellyLanguage.JELLY + + case object JellyText extends RdfFormat, RdfFormat.Writeable: + override val fullName: String = "Jelly text format" + override val cliOptions: List[String] = List("jelly-text") + val extension = ".jelly.txt" + + private val rdfFormats: List[RdfFormat] = List(NQuads, NTriples, JellyBinary, JellyText) + + def all: List[RdfFormat] = rdfFormats + + /** Returns a string representation of the option for the user. + */ + def optionString(option: RdfFormat): String = + f"${option.cliOptions.map(s => f"\"${s}\"").mkString(", ")} for ${option.fullName}" + + /** Finds the appropriate RdfFormat based on supplied option string. + */ + def find(cliOption: String): Option[RdfFormat] = + rdfFormats.find(_.cliOptions.contains(cliOption)) + + /** Infers the format based on the file name. + */ + def inferFormat(fileName: String): Option[RdfFormat] = + val jenaImpl = RdfFormat.all.collect({ case x: RdfFormat.Jena => x }) + val guessType = RDFLanguages.guessContentType(fileName) + val formatGuessed = jenaImpl.collectFirst({ + case x if x.jenaLang.getContentType == guessType => x + }) + formatGuessed match { + case Some(f: RdfFormat.Jena) => formatGuessed + case _ if fileName.endsWith(JellyText.extension) => Some(RdfFormat.JellyText) + case _ => None + } diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFormatOption.scala b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFormatOption.scala deleted file mode 100644 index 83735a6..0000000 --- a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFormatOption.scala +++ /dev/null @@ -1,17 +0,0 @@ -package eu.neverblink.jelly.cli.command.rdf - -enum RdfFormatOption(val cliOptions: List[String], val fullName: String): - case NQuads extends RdfFormatOption(List("nq", "nt", "nquads", "ntriples"), "N-Quads") - case JellyBinary extends RdfFormatOption(List("jelly"), "Jelly binary format") - case JellyText extends RdfFormatOption(List("jelly-text"), "Jelly text format") - -object RdfFormatOption: - /** Returns a string representation of the option for the user. - */ - def optionString(option: RdfFormatOption): String = - f"${option.cliOptions.map(s => f"\"${s}\"").mkString(", ")} for ${option.fullName}" - - /** Finds the appropriate RdfFormatOption based on supplied option string. - */ - def find(cliOption: String): Option[RdfFormatOption] = - RdfFormatOption.values.find(_.cliOptions.contains(cliOption)) diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFromJelly.scala b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFromJelly.scala index 550e2ee..6189769 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFromJelly.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfFromJelly.scala @@ -1,19 +1,18 @@ package eu.neverblink.jelly.cli.command.rdf import caseapp.* -import com.google.protobuf.InvalidProtocolBufferException import eu.neverblink.jelly.cli.* -import eu.neverblink.jelly.cli.command.rdf.RdfFormatOption.* +import eu.neverblink.jelly.cli.command.rdf.RdfFormat.* +import eu.neverblink.jelly.cli.command.rdf.RdfFormat.Jena.* import eu.ostrzyciel.jelly.convert.jena.riot.JellyLanguage import eu.ostrzyciel.jelly.core.proto.v1.RdfStreamFrame -import eu.ostrzyciel.jelly.core.{IoUtils, RdfProtoDeserializationError} +import eu.ostrzyciel.jelly.core.IoUtils import org.apache.jena.riot.system.StreamRDFWriter -import org.apache.jena.riot.{RDFLanguages, RDFParser, RiotException} +import org.apache.jena.riot.{Lang, RDFParser} import java.io.{InputStream, OutputStream} -object RdfFromJellyPrint extends RdfCommandPrintUtil: - override val validFormats: List[RdfFormatOption] = List(JellyText, NQuads) - override val defaultFormat: RdfFormatOption = NQuads +object RdfFromJellyPrint extends RdfCommandPrintUtil[RdfFormat.Writeable]: + override val defaultFormat: RdfFormat = RdfFormat.NQuads case class RdfFromJellyOptions( @Recurse @@ -26,64 +25,44 @@ case class RdfFromJellyOptions( @ExtraName("out-format") outputFormat: Option[String] = None, ) extends HasJellyOptions -object RdfFromJelly extends JellyCommand[RdfFromJellyOptions]: - override def group = "rdf" +object RdfFromJelly extends RdfCommand[RdfFromJellyOptions, RdfFormat.Writeable]: override def names: List[List[String]] = List( List("rdf", "from-jelly"), ) + lazy val printUtil: RdfCommandPrintUtil[RdfFormat.Writeable] = RdfFromJellyPrint + + val defaultAction: (InputStream, OutputStream) => Unit = + jellyToLang(RdfFormat.NQuads.jenaLang, _, _) + override def doRun(options: RdfFromJellyOptions, remainingArgs: RemainingArgs): Unit = val (inputStream, outputStream) = this.getIoStreamsFromOptions(remainingArgs.remaining.headOption, options.outputFile) - doConversion(inputStream, outputStream, options.outputFormat) + parseFormatArgs(inputStream, outputStream, options.outputFormat, options.outputFile) + + override def matchToAction( + option: RdfFormat.Writeable, + ): Option[(InputStream, OutputStream) => Unit] = + option match + case j: RdfFormat.Jena.Writeable => Some(jellyToLang(j.jenaLang, _, _)) + case RdfFormat.JellyText => Some(jellyBinaryToText) - /** This method takes care of proper error handling and matches the desired output format to the - * correct conversion - * + /** This method reads the Jelly file, rewrites it to specified format and writes it to some output + * stream + * @param jenaLang + * Language that jelly should be converted to * @param inputStream * InputStream * @param outputStream * OutputStream - * @throws JellyDeserializationError - * @throws JenaRiotException - * @throws InvalidJellyFile */ - private def doConversion( + private def jellyToLang( + jenaLang: Lang, inputStream: InputStream, outputStream: OutputStream, - format: Option[String], ): Unit = - try { - format match { - case Some(f: String) => - RdfFormatOption.find(f) match - case Some(JellyText) => jellyBinaryToText(inputStream, outputStream) - case Some(NQuads) => jellyToNQuad(inputStream, outputStream) - case _ => - throw InvalidFormatSpecified( - f, - RdfFromJellyPrint.validFormatsString, - ) // if anything else, it's an invalid option - case None => - jellyToNQuad(inputStream, outputStream) // default option if no parameter supplied - } - } catch - case e: RdfProtoDeserializationError => - throw JellyDeserializationError(e.getMessage) - case e: RiotException => - throw JenaRiotException(e) - case e: InvalidProtocolBufferException => - throw InvalidJellyFile(e) - - /** This method reads the Jelly file, rewrites it to NQuads and writes it to some output stream - * @param inputStream - * InputStream - * @param outputStream - * OutputStream - */ - private def jellyToNQuad(inputStream: InputStream, outputStream: OutputStream): Unit = - val nQuadWriter = StreamRDFWriter.getWriterStream(outputStream, RDFLanguages.NQUADS) + val nQuadWriter = StreamRDFWriter.getWriterStream(outputStream, jenaLang) RDFParser.source(inputStream).lang(JellyLanguage.JELLY).parse(nQuadWriter) /** This method reads the Jelly file, rewrites it to Jelly text and writes it to some output diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJelly.scala b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJelly.scala index ceb397e..9915c50 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJelly.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJelly.scala @@ -1,18 +1,15 @@ package eu.neverblink.jelly.cli.command.rdf import caseapp.* -import com.google.protobuf.InvalidProtocolBufferException import eu.neverblink.jelly.cli.* -import eu.neverblink.jelly.cli.command.rdf.RdfFormatOption.* +import eu.neverblink.jelly.cli.command.rdf.RdfFormat.* import eu.ostrzyciel.jelly.convert.jena.riot.JellyLanguage -import eu.ostrzyciel.jelly.core.RdfProtoSerializationError import org.apache.jena.riot.system.StreamRDFWriter -import org.apache.jena.riot.{RDFLanguages, RDFParser, RiotException} +import org.apache.jena.riot.{Lang, RDFParser} import java.io.{InputStream, OutputStream} -object RdfToJellyPrint extends RdfCommandPrintUtil: - override val validFormats: List[RdfFormatOption] = List(NQuads) - override val defaultFormat: RdfFormatOption = NQuads +object RdfToJellyPrint extends RdfCommandPrintUtil[RdfFormat.Jena.Readable]: + override val defaultFormat: RdfFormat = RdfFormat.NQuads case class RdfToJellyOptions( @Recurse @@ -25,61 +22,44 @@ case class RdfToJellyOptions( @ExtraName("in-format") inputFormat: Option[String] = None, ) extends HasJellyOptions -object RdfToJelly extends JellyCommand[RdfToJellyOptions]: - override def group = "rdf" +object RdfToJelly extends RdfCommand[RdfToJellyOptions, RdfFormat.Jena.Readable]: override def names: List[List[String]] = List( List("rdf", "to-jelly"), ) + lazy val printUtil: RdfCommandPrintUtil[RdfFormat.Jena.Readable] = RdfToJellyPrint + + val defaultAction: (InputStream, OutputStream) => Unit = + langToJelly(RdfFormat.NQuads.jenaLang, _, _) + override def doRun(options: RdfToJellyOptions, remainingArgs: RemainingArgs): Unit = val (inputStream, outputStream) = getIoStreamsFromOptions(remainingArgs.remaining.headOption, options.outputFile) - doConversion(inputStream, outputStream, options.inputFormat) + parseFormatArgs( + inputStream, + outputStream, + options.inputFormat, + remainingArgs.remaining.headOption, + ) - /** This method takes care of proper error handling and matches the desired output format to the - * correct conversion - * + override def matchToAction( + option: RdfFormat.Jena.Readable, + ): Option[(InputStream, OutputStream) => Unit] = + Some(langToJelly(option.jenaLang, _, _)) + + /** This method reads the file, rewrites it to Jelly and writes it to some output stream + * @param jenaLang + * Language that should be converted to Jelly * @param inputStream * InputStream * @param outputStream * OutputStream - * @throws JellySerializationError - * @throws JenaRiotException - * @throws InvalidJellyFile */ - private def doConversion( + private def langToJelly( + jenaLang: Lang, inputStream: InputStream, outputStream: OutputStream, - format: Option[String], ): Unit = - try { - format match { - case Some(f: String) => - RdfFormatOption.find(f) match - case Some(NQuads) => nQuadToJelly(inputStream, outputStream) - case _ => - throw InvalidFormatSpecified( - f, - RdfToJellyPrint.validFormatsString, - ) // if anything else, it's an invalid option - case None => - nQuadToJelly(inputStream, outputStream) // default option if no parameter supplied - } - } catch - case e: RdfProtoSerializationError => - throw JellySerializationError(e.getMessage) - case e: RiotException => - throw JenaRiotException(e) - case e: InvalidProtocolBufferException => - throw InvalidJellyFile(e) - - /** This method reads the NQuad file, rewrites it to Jelly and writes it to some output stream - * @param inputStream - * InputStream - * @param outputStream - * OutputStream - */ - private def nQuadToJelly(inputStream: InputStream, outputStream: OutputStream): Unit = val jellyWriter = StreamRDFWriter.getWriterStream(outputStream, JellyLanguage.JELLY) - RDFParser.source(inputStream).lang(RDFLanguages.NQUADS).parse(jellyWriter) + RDFParser.source(inputStream).lang(jenaLang).parse(jellyWriter) diff --git a/src/main/scala/eu/neverblink/jelly/cli/util/IoUtil.scala b/src/main/scala/eu/neverblink/jelly/cli/util/IoUtil.scala index 1f7ac3f..6c675af 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/util/IoUtil.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/util/IoUtil.scala @@ -31,5 +31,6 @@ object IoUtil: val file = File(fileName) val suppFile = file.getParentFile val parentFile = if (suppFile != null) suppFile else File(".") - if !parentFile.canWrite || !file.canWrite then throw OutputFileCannotBeCreated(fileName) + if !parentFile.canWrite || (file.exists() && !file.canWrite) then + throw OutputFileCannotBeCreated(fileName) FileOutputStream(file, true) diff --git a/src/test/scala/eu/neverblink/jelly/cli/command/RdfFromJellySpec.scala b/src/test/scala/eu/neverblink/jelly/cli/command/RdfFromJellySpec.scala index 7cb96e7..aa58018 100644 --- a/src/test/scala/eu/neverblink/jelly/cli/command/RdfFromJellySpec.scala +++ b/src/test/scala/eu/neverblink/jelly/cli/command/RdfFromJellySpec.scala @@ -32,7 +32,7 @@ class RdfFromJellySpec extends AnyWordSpec with Matchers with TestFixtureHelper: RdfFromJelly.setStdIn(input) val nQuadString = DataGenHelper.generateNQuadString(testCardinality) val (out, err) = RdfFromJelly.runTestCommand( - List("rdf", "from-jelly", "--out-format", RdfFormatOption.NQuads.cliOptions.head), + List("rdf", "from-jelly", "--out-format", RdfFormat.NQuads.cliOptions.head), ) val sortedOut = out.split("\n").map(_.trim).sorted val sortedQuads = nQuadString.split("\n").map(_.trim).sorted @@ -53,6 +53,21 @@ class RdfFromJellySpec extends AnyWordSpec with Matchers with TestFixtureHelper: out.length should be(0) } } + "a file to file when defaulting to nQuads" in withFullJellyFile { j => + withEmptyRandomFile { q => + val nQuadString = DataGenHelper.generateNQuadString(testCardinality) + val (out, err) = + RdfFromJelly.runTestCommand( + List("rdf", "from-jelly", j, "--to", q), + ) + val sortedOut = Using.resource(Source.fromFile(q)) { content => + content.getLines().toList.map(_.trim).sorted + } + val sortedQuads = nQuadString.split("\n").map(_.trim).sorted + sortedOut should contain theSameElementsAs sortedQuads + out.length should be(0) + } + } "an input stream to file" in withEmptyQuadFile { q => val input = DataGenHelper.generateJellyInputStream(testCardinality) RdfFromJelly.setStdIn(input) @@ -76,7 +91,7 @@ class RdfFromJellySpec extends AnyWordSpec with Matchers with TestFixtureHelper: "from-jelly", j, "--out-format", - RdfFormatOption.JellyText.cliOptions.head, + RdfFormat.JellyText.cliOptions.head, ), ) val outString = """# Frame 0 @@ -97,6 +112,42 @@ class RdfFromJellySpec extends AnyWordSpec with Matchers with TestFixtureHelper: "rows".r.findAllIn(out).length should be(70) "http://example.org/predicate/".r.findAllIn(out).length should be(1) } + "a file to file when inferred type" in withFullJellyFile { j => + withEmptyJellyTextFile { t => + val (out, err) = + RdfFromJelly.runTestCommand( + List( + "rdf", + "from-jelly", + j, + "--to", + t, + ), + ) + val inTxt = Using.resource(Source.fromFile(t)) { content => + content.getLines().mkString("\n") + } + val outString = + """# Frame 0 + |rows { + | options { + | stream_name: "" + | physical_type: PHYSICAL_STREAM_TYPE_TRIPLES + | generalized_statements: true + | rdf_star: true + | max_name_table_size: 128 + | max_prefix_table_size: 16 + | max_datatype_table_size: 16 + | logical_type: LOGICAL_STREAM_TYPE_FLAT_TRIPLES + | version: 1 + | } + |}""".stripMargin + inTxt should include(outString) + "rows".r.findAllIn(inTxt).length should be(70) + "http://example.org/predicate/".r.findAllIn(inTxt).length should be(1) + } + + } } "throw proper exception" when { "input file is not found" in { @@ -191,5 +242,29 @@ class RdfFromJellySpec extends AnyWordSpec with Matchers with TestFixtureHelper: exception.code should be(1) } } + "invalid but known output format supplied" in withFullJellyFile { j => + withEmptyJellyFile { q => + val exception = + intercept[ExitException] { + RdfFromJelly.runTestCommand( + List( + "rdf", + "from-jelly", + j, + "--to", + q, + "--out-format", + RdfFormat.JellyBinary.cliOptions.head, + ), + ) + } + val msg = InvalidFormatSpecified( + RdfFormat.JellyBinary.cliOptions.head, + RdfFromJellyPrint.validFormatsString, + ) + RdfFromJelly.getErrString should include(msg.getMessage) + exception.code should be(1) + } + } } } diff --git a/src/test/scala/eu/neverblink/jelly/cli/command/RdfToJellySpec.scala b/src/test/scala/eu/neverblink/jelly/cli/command/RdfToJellySpec.scala index 5437ec2..3409902 100644 --- a/src/test/scala/eu/neverblink/jelly/cli/command/RdfToJellySpec.scala +++ b/src/test/scala/eu/neverblink/jelly/cli/command/RdfToJellySpec.scala @@ -2,7 +2,7 @@ package eu.neverblink.jelly.cli.command import eu.neverblink.jelly.cli.{ExitException, InvalidFormatSpecified} import eu.neverblink.jelly.cli.command.helpers.{DataGenHelper, TestFixtureHelper} -import eu.neverblink.jelly.cli.command.rdf.{RdfFormatOption, RdfToJelly, RdfToJellyPrint} +import eu.neverblink.jelly.cli.command.rdf.{RdfFormat, RdfToJelly, RdfToJellyPrint} import eu.ostrzyciel.jelly.convert.jena.riot.JellyLanguage import org.apache.jena.rdf.model.{Model, ModelFactory} import org.scalatest.matchers.should.Matchers @@ -49,7 +49,7 @@ class RdfToJellySpec extends AnyWordSpec with TestFixtureHelper with Matchers: RdfToJelly.setStdIn(input) val tripleModel = DataGenHelper.generateTripleModel(testCardinality) val (out, err) = RdfToJelly.runTestCommand( - List("rdf", "to-jelly", "--in-format", RdfFormatOption.NQuads.cliOptions.head), + List("rdf", "to-jelly", "--in-format", RdfFormat.NQuads.cliOptions.head), ) val newIn = new ByteArrayInputStream(RdfToJelly.getOutBytes) val content = translateJellyBack(newIn) @@ -64,16 +64,25 @@ class RdfToJellySpec extends AnyWordSpec with TestFixtureHelper with Matchers: content.containsAll(tripleModel.listStatements()) } } - } - "throw proper exception" when { - "invalid format is specified" in withFullQuadFile { f => - val exception = - intercept[ExitException] { - RdfToJelly.runTestCommand(List("rdf", "to-jelly", f, "--in-format", "invalid")) - } - val msg = InvalidFormatSpecified("invalid", RdfToJellyPrint.validFormatsString) - RdfToJelly.getErrString should include(msg.getMessage) - exception.code should be(1) - } + "throw proper exception" when { + "invalid format is specified" in withFullQuadFile { f => + val exception = + intercept[ExitException] { + RdfToJelly.runTestCommand(List("rdf", "to-jelly", f, "--in-format", "invalid")) + } + val msg = InvalidFormatSpecified("invalid", RdfToJellyPrint.validFormatsString) + RdfToJelly.getErrString should include(msg.getMessage) + exception.code should be(1) + } + "invalid format out of existing is specified" in withFullQuadFile { f => + val exception = + intercept[ExitException] { + RdfToJelly.runTestCommand(List("rdf", "to-jelly", f, "--in-format", "jelly-text")) + } + val msg = InvalidFormatSpecified("jelly-text", RdfToJellyPrint.validFormatsString) + RdfToJelly.getErrString should include(msg.getMessage) + exception.code should be(1) + } + } } diff --git a/src/test/scala/eu/neverblink/jelly/cli/command/helpers/TestFixtureHelper.scala b/src/test/scala/eu/neverblink/jelly/cli/command/helpers/TestFixtureHelper.scala index 1fa1b17..897b770 100644 --- a/src/test/scala/eu/neverblink/jelly/cli/command/helpers/TestFixtureHelper.scala +++ b/src/test/scala/eu/neverblink/jelly/cli/command/helpers/TestFixtureHelper.scala @@ -30,7 +30,7 @@ trait TestFixtureHelper extends BeforeAndAfterAll: def withFullQuadFile(testCode: (String) => Any): Unit = val extension = getFileExtension(RDFLanguages.NQUADS) - val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, extension) + val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, f".${extension}") val model = DataGenHelper.generateTripleModel(testCardinality) RDFDataMgr.write(new FileOutputStream(tempFile.toFile), model, RDFLanguages.NQUADS) try { @@ -39,14 +39,26 @@ trait TestFixtureHelper extends BeforeAndAfterAll: def withEmptyJellyFile(testCode: (String) => Any): Unit = val extension = getFileExtension(JellyLanguage.JELLY) - val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, extension) + val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, f".${extension}") + try { + testCode(tempFile.toString) + } finally { tempFile.toFile.delete() } + + def withEmptyJellyTextFile(testCode: (String) => Any): Unit = + val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, ".jelly.txt") + try { + testCode(tempFile.toString) + } finally { tempFile.toFile.delete() } + + def withEmptyRandomFile(testCode: (String) => Any): Unit = + val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, ".random") try { testCode(tempFile.toString) } finally { tempFile.toFile.delete() } def withFullJellyFile(testCode: (String) => Any): Unit = val extension = getFileExtension(JellyLanguage.JELLY) - val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, extension) + val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, f".${extension}") val model = DataGenHelper.generateTripleModel(testCardinality) RDFDataMgr.write(new FileOutputStream(tempFile.toFile), model, JellyLanguage.JELLY) try { @@ -55,7 +67,7 @@ trait TestFixtureHelper extends BeforeAndAfterAll: def withEmptyQuadFile(testCode: (String) => Any): Unit = val extension = getFileExtension(RDFLanguages.NQUADS) - val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, extension) + val tempFile = Files.createTempFile(tmpDir, randomUUID.toString, f".${extension}") try { testCode(tempFile.toString) } finally { tempFile.toFile.delete() }