diff options
Diffstat (limited to 'src/test/scala')
3 files changed, 192 insertions, 33 deletions
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/CanonicalModelSpec.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/CanonicalModelSpec.scala index 3070ce3..0d07923 100644 --- a/src/test/scala/uk/ac/ox/cs/rsacomb/CanonicalModelSpec.scala +++ b/src/test/scala/uk/ac/ox/cs/rsacomb/CanonicalModelSpec.scala | |||
| @@ -15,6 +15,8 @@ import tech.oxfordsemantic.jrdfox.logic.expression.Variable | |||
| 15 | import scala.collection.JavaConverters._ | 15 | import scala.collection.JavaConverters._ |
| 16 | 16 | ||
| 17 | import uk.ac.ox.cs.rsacomb.RSAOntology | 17 | import uk.ac.ox.cs.rsacomb.RSAOntology |
| 18 | import uk.ac.ox.cs.rsacomb.converter.SkolemStrategy | ||
| 19 | import uk.ac.ox.cs.rsacomb.suffix.Empty | ||
| 18 | import uk.ac.ox.cs.rsacomb.util.{RDFoxUtil, RSA} | 20 | import uk.ac.ox.cs.rsacomb.util.{RDFoxUtil, RSA} |
| 19 | 21 | ||
| 20 | object Ontology1_CanonicalModelSpec { | 22 | object Ontology1_CanonicalModelSpec { |
| @@ -28,6 +30,7 @@ object Ontology1_CanonicalModelSpec { | |||
| 28 | val ontology_path: File = new File("examples/example1.ttl") | 30 | val ontology_path: File = new File("examples/example1.ttl") |
| 29 | val ontology = RSAOntology(ontology_path) | 31 | val ontology = RSAOntology(ontology_path) |
| 30 | val program = ontology.canonicalModel | 32 | val program = ontology.canonicalModel |
| 33 | val converter = program.CanonicalModelConverter | ||
| 31 | 34 | ||
| 32 | val roleR = new OWLObjectPropertyImpl(base("R")) | 35 | val roleR = new OWLObjectPropertyImpl(base("R")) |
| 33 | val roleS = new OWLObjectPropertyImpl(base("S")) | 36 | val roleS = new OWLObjectPropertyImpl(base("S")) |
| @@ -89,9 +92,13 @@ class Ontology1_CanonicalModelSpec | |||
| 89 | } | 92 | } |
| 90 | 93 | ||
| 91 | renderer.render(AsubClassOfD) should "be converted into a single Rule" in { | 94 | renderer.render(AsubClassOfD) should "be converted into a single Rule" in { |
| 92 | val varX = Variable.create("X") | 95 | val term = Variable.create("X") |
| 93 | val visitor = program.RuleGenerator | 96 | val unsafe = ontology.unsafeRoles |
| 94 | val rules = AsubClassOfD.accept(visitor) | 97 | val skolem = SkolemStrategy.None |
| 98 | val suffix = Empty | ||
| 99 | val (facts, rules) = | ||
| 100 | converter.convert(AsubClassOfD, term, unsafe, skolem, suffix) | ||
| 101 | facts shouldBe empty | ||
| 95 | rules.loneElement shouldBe a[Rule] | 102 | rules.loneElement shouldBe a[Rule] |
| 96 | } | 103 | } |
| 97 | 104 | ||
| @@ -154,10 +161,14 @@ class Ontology1_CanonicalModelSpec | |||
| 154 | renderer.render( | 161 | renderer.render( |
| 155 | AsomeValuesFromSiC | 162 | AsomeValuesFromSiC |
| 156 | ) should "produce 1 rule" in { | 163 | ) should "produce 1 rule" in { |
| 157 | val varX = Variable.create("X") | 164 | val term = Variable.create("X") |
| 158 | val visitor = program.RuleGenerator | 165 | val unsafe = ontology.unsafeRoles |
| 159 | val rules = AsomeValuesFromSiC.accept(visitor) | 166 | val skolem = SkolemStrategy.None |
| 160 | rules should have length 1 | 167 | val suffix = Empty |
| 168 | val (facts, rules) = | ||
| 169 | converter.convert(AsomeValuesFromSiC, term, unsafe, skolem, suffix) | ||
| 170 | facts shouldBe empty | ||
| 171 | rules.loneElement shouldBe a[Rule] | ||
| 161 | } | 172 | } |
| 162 | 173 | ||
| 163 | renderer.render( | 174 | renderer.render( |
| @@ -172,15 +183,18 @@ class Ontology1_CanonicalModelSpec | |||
| 172 | ontology.cycle(DsomeValuesFromRB) should have size 48 | 183 | ontology.cycle(DsomeValuesFromRB) should have size 48 |
| 173 | } | 184 | } |
| 174 | 185 | ||
| 175 | it should "produce 5 rules" in { | 186 | it should "produce 48 facts and 98 rules" in { |
| 176 | // Rule 1 provides 1 rule (split in 2) + 48 fact | 187 | // Rule 1 provides 1 rule (split in 2) + 48 fact |
| 177 | // Rule 2 provides 0 rules | 188 | // Rule 2 provides 0 rules |
| 178 | // Rule 3 provides 48 rule (split in 2) | 189 | // Rule 3 provides 48 rule (split in 2) |
| 179 | // Then (1*2 + 48) + (0) + (48*2) = 146 | 190 | val term = Variable.create("X") |
| 180 | val varX = Variable.create("X") | 191 | val unsafe = ontology.unsafeRoles |
| 181 | val visitor = program.RuleGenerator | 192 | val skolem = SkolemStrategy.None |
| 182 | val rules = DsomeValuesFromRB.accept(visitor) | 193 | val suffix = Empty |
| 183 | rules should have length 146 | 194 | val (facts, rules) = |
| 195 | converter.convert(DsomeValuesFromRB, term, unsafe, skolem, suffix) | ||
| 196 | facts should have length 48 | ||
| 197 | rules should have length 98 | ||
| 184 | } | 198 | } |
| 185 | 199 | ||
| 186 | renderer.render( | 200 | renderer.render( |
| @@ -200,18 +214,26 @@ class Ontology1_CanonicalModelSpec | |||
| 200 | // Rule 2 provides 0 rules | 214 | // Rule 2 provides 0 rules |
| 201 | // Rule 3 provides 32 rule (split in 2) | 215 | // Rule 3 provides 32 rule (split in 2) |
| 202 | // Then (1*2 + 32) + (0) + (32*2) = 98 | 216 | // Then (1*2 + 32) + (0) + (32*2) = 98 |
| 203 | val varX = Variable.create("X") | 217 | val term = Variable.create("X") |
| 204 | val visitor = program.RuleGenerator | 218 | val unsafe = ontology.unsafeRoles |
| 205 | val rules = DsomeValuesFromRB.accept(visitor) | 219 | val skolem = SkolemStrategy.None |
| 206 | rules should have length 146 | 220 | val suffix = Empty |
| 221 | val (facts, rules) = | ||
| 222 | converter.convert(BsomeValuesFromSD, term, unsafe, skolem, suffix) | ||
| 223 | facts should have length 32 | ||
| 224 | rules should have length 66 | ||
| 207 | } | 225 | } |
| 208 | 226 | ||
| 209 | renderer.render( | 227 | renderer.render( |
| 210 | SsubPropertyOfT | 228 | SsubPropertyOfT |
| 211 | ) should "produce 2 rules" in { | 229 | ) should "produce 2 rules" in { |
| 212 | val varX = Variable.create("X") | 230 | val term = Variable.create("X") |
| 213 | val visitor = program.RuleGenerator | 231 | val unsafe = ontology.unsafeRoles |
| 214 | val rules = SsubPropertyOfT.accept(visitor) | 232 | val skolem = SkolemStrategy.None |
| 233 | val suffix = Empty | ||
| 234 | val (facts, rules) = | ||
| 235 | converter.convert(SsubPropertyOfT, term, unsafe, skolem, suffix) | ||
| 236 | facts shouldBe empty | ||
| 215 | rules should have length 2 | 237 | rules should have length 2 |
| 216 | } | 238 | } |
| 217 | 239 | ||
| @@ -228,6 +250,7 @@ object Ontology2_CanonicalModelSpec { | |||
| 228 | val ontology_path: File = new File("examples/example2.owl") | 250 | val ontology_path: File = new File("examples/example2.owl") |
| 229 | val ontology = RSAOntology(ontology_path) | 251 | val ontology = RSAOntology(ontology_path) |
| 230 | val program = ontology.canonicalModel | 252 | val program = ontology.canonicalModel |
| 253 | val converter = program.CanonicalModelConverter | ||
| 231 | 254 | ||
| 232 | val roleR = new OWLObjectPropertyImpl(base("R")) | 255 | val roleR = new OWLObjectPropertyImpl(base("R")) |
| 233 | val roleS = new OWLObjectPropertyImpl(base("S")) | 256 | val roleS = new OWLObjectPropertyImpl(base("S")) |
| @@ -332,8 +355,13 @@ class Ontology2_CanonicalModelSpec | |||
| 332 | renderer.render( | 355 | renderer.render( |
| 333 | AsomeValuesFromRB | 356 | AsomeValuesFromRB |
| 334 | ) should "produce 1 rule" in { | 357 | ) should "produce 1 rule" in { |
| 335 | val visitor = program.RuleGenerator | 358 | val term = Variable.create("X") |
| 336 | val rules = AsomeValuesFromRB.accept(visitor) | 359 | val unsafe = ontology.unsafeRoles |
| 360 | val skolem = SkolemStrategy.None | ||
| 361 | val suffix = Empty | ||
| 362 | val (facts, rules) = | ||
| 363 | converter.convert(AsomeValuesFromRB, term, unsafe, skolem, suffix) | ||
| 364 | facts shouldBe empty | ||
| 337 | rules should have length 1 | 365 | rules should have length 1 |
| 338 | } | 366 | } |
| 339 | 367 | ||
| @@ -342,8 +370,13 @@ class Ontology2_CanonicalModelSpec | |||
| 342 | renderer.render( | 370 | renderer.render( |
| 343 | BsomeValuesFromSC | 371 | BsomeValuesFromSC |
| 344 | ) should "produce 1 rule" in { | 372 | ) should "produce 1 rule" in { |
| 345 | val visitor = program.RuleGenerator | 373 | val term = Variable.create("X") |
| 346 | val rules = BsomeValuesFromSC.accept(visitor) | 374 | val unsafe = ontology.unsafeRoles |
| 375 | val skolem = SkolemStrategy.None | ||
| 376 | val suffix = Empty | ||
| 377 | val (facts, rules) = | ||
| 378 | converter.convert(BsomeValuesFromSC, term, unsafe, skolem, suffix) | ||
| 379 | facts shouldBe empty | ||
| 347 | rules should have length 1 | 380 | rules should have length 1 |
| 348 | } | 381 | } |
| 349 | 382 | ||
| @@ -352,8 +385,13 @@ class Ontology2_CanonicalModelSpec | |||
| 352 | renderer.render( | 385 | renderer.render( |
| 353 | CsomeValuesFromTD | 386 | CsomeValuesFromTD |
| 354 | ) should "produce 1 rule" in { | 387 | ) should "produce 1 rule" in { |
| 355 | val visitor = program.RuleGenerator | 388 | val term = Variable.create("X") |
| 356 | val rules = CsomeValuesFromTD.accept(visitor) | 389 | val unsafe = ontology.unsafeRoles |
| 390 | val skolem = SkolemStrategy.None | ||
| 391 | val suffix = Empty | ||
| 392 | val (facts, rules) = | ||
| 393 | converter.convert(CsomeValuesFromTD, term, unsafe, skolem, suffix) | ||
| 394 | facts shouldBe empty | ||
| 357 | rules should have length 1 | 395 | rules should have length 1 |
| 358 | } | 396 | } |
| 359 | 397 | ||
| @@ -362,8 +400,13 @@ class Ontology2_CanonicalModelSpec | |||
| 362 | renderer.render( | 400 | renderer.render( |
| 363 | DsomeValuesFromPA | 401 | DsomeValuesFromPA |
| 364 | ) should "produce 1 rule" in { | 402 | ) should "produce 1 rule" in { |
| 365 | val visitor = program.RuleGenerator | 403 | val term = Variable.create("X") |
| 366 | val rules = DsomeValuesFromPA.accept(visitor) | 404 | val unsafe = ontology.unsafeRoles |
| 405 | val skolem = SkolemStrategy.None | ||
| 406 | val suffix = Empty | ||
| 407 | val (facts, rules) = | ||
| 408 | converter.convert(DsomeValuesFromPA, term, unsafe, skolem, suffix) | ||
| 409 | facts shouldBe empty | ||
| 367 | rules should have length 1 | 410 | rules should have length 1 |
| 368 | } | 411 | } |
| 369 | 412 | ||
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala index 71c9a99..86e0253 100644 --- a/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala +++ b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala | |||
| @@ -65,24 +65,32 @@ class FilteringProgramSpec extends AnyFlatSpec with Matchers { | |||
| 65 | 65 | ||
| 66 | import FilteringProgramSpec._ | 66 | import FilteringProgramSpec._ |
| 67 | 67 | ||
| 68 | "CQ 0" should "generate 30 rules" in { | 68 | "CQ 0" should "generate 27 rules and 3 facts" in { |
| 69 | val cq = ConjunctiveQuery(cq0).get | 69 | val cq = ConjunctiveQuery(cq0).get |
| 70 | FilteringProgram(cq, constants).rules should have length 30 | 70 | val filter = FilteringProgram(cq, constants) |
| 71 | filter.facts should have length 3 | ||
| 72 | filter.rules should have length 27 | ||
| 71 | } | 73 | } |
| 72 | 74 | ||
| 73 | "CQ 1" should "generate 15 rules" in { | 75 | "CQ 1" should "generate 15 rules" in { |
| 74 | val cq = ConjunctiveQuery(cq1).get | 76 | val cq = ConjunctiveQuery(cq1).get |
| 75 | FilteringProgram(cq, List()).rules should have length 15 | 77 | val filter = FilteringProgram(cq, List()) |
| 78 | filter.facts shouldBe empty | ||
| 79 | filter.rules should have length 15 | ||
| 76 | } | 80 | } |
| 77 | 81 | ||
| 78 | "CQ 2" should "generate 51 rules" in { | 82 | "CQ 2" should "generate 51 rules" in { |
| 79 | val cq = ConjunctiveQuery(cq2).get | 83 | val cq = ConjunctiveQuery(cq2).get |
| 80 | FilteringProgram(cq, List()).rules should have length 51 | 84 | val filter = FilteringProgram(cq, List()) |
| 85 | filter.facts shouldBe empty | ||
| 86 | filter.rules should have length 51 | ||
| 81 | } | 87 | } |
| 82 | 88 | ||
| 83 | "BCQ 0" should "generate 46 rules" in { | 89 | "BCQ 0" should "generate 46 rules" in { |
| 84 | val cq = ConjunctiveQuery(bcq0).get | 90 | val cq = ConjunctiveQuery(bcq0).get |
| 85 | FilteringProgram(cq, constants).rules should have length 46 | 91 | val filter = FilteringProgram(cq, constants) |
| 92 | filter.facts should have length 3 | ||
| 93 | filter.rules should have length 43 | ||
| 86 | } | 94 | } |
| 87 | 95 | ||
| 88 | } | 96 | } |
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/RDFoxConverterSpec.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/RDFoxConverterSpec.scala new file mode 100644 index 0000000..e2da6e4 --- /dev/null +++ b/src/test/scala/uk/ac/ox/cs/rsacomb/RDFoxConverterSpec.scala | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | package rsacomb | ||
| 2 | |||
| 3 | import org.scalatest.LoneElement | ||
| 4 | import org.scalatest.flatspec.AnyFlatSpec | ||
| 5 | import org.scalatest.matchers.should.Matchers | ||
| 6 | import org.semanticweb.owlapi.apibinding.OWLManager | ||
| 7 | import org.semanticweb.owlapi.model.OWLOntologyManager | ||
| 8 | |||
| 9 | import tech.oxfordsemantic.jrdfox.logic.datalog.TupleTableAtom | ||
| 10 | import tech.oxfordsemantic.jrdfox.logic.expression.{Variable, IRI} | ||
| 11 | import uk.ac.ox.cs.rsacomb.converter.RDFoxConverter | ||
| 12 | import uk.ac.ox.cs.rsacomb.suffix.{Empty, Forward, Backward, Inverse} | ||
| 13 | import uk.ac.ox.cs.rsacomb.converter.SkolemStrategy | ||
| 14 | |||
| 15 | object RDFoxConverterSpec { | ||
| 16 | |||
| 17 | val manager = OWLManager.createOWLOntologyManager() | ||
| 18 | val factory = manager.getOWLDataFactory | ||
| 19 | |||
| 20 | val term0 = Variable.create("X") | ||
| 21 | val term1 = Variable.create("Y") | ||
| 22 | val iriString0 = "http://example.com/rsacomb/iri0" | ||
| 23 | val iriString1 = "http://example.com/rsacomb/iri1" | ||
| 24 | val iriString2 = "http://example.com/rsacomb/iri2" | ||
| 25 | val suffixes = Seq( | ||
| 26 | Empty, | ||
| 27 | Forward, | ||
| 28 | Backward, | ||
| 29 | Inverse, | ||
| 30 | Forward + Inverse, | ||
| 31 | Backward + Inverse | ||
| 32 | ) | ||
| 33 | } | ||
| 34 | |||
| 35 | class RDFoxConverterSpec | ||
| 36 | extends AnyFlatSpec | ||
| 37 | with Matchers | ||
| 38 | with LoneElement | ||
| 39 | with RDFoxConverter { | ||
| 40 | |||
| 41 | import RDFoxConverterSpec._ | ||
| 42 | |||
| 43 | "A class name" should "be converted into a single atom" in { | ||
| 44 | val cls = factory.getOWLClass(iriString0) | ||
| 45 | val atom = TupleTableAtom.rdf(term0, IRI.RDF_TYPE, IRI.create(iriString0)) | ||
| 46 | val (res, ext) = | ||
| 47 | convert(cls, term0, List(), SkolemStrategy.None, Empty) | ||
| 48 | res.loneElement shouldEqual atom | ||
| 49 | ext shouldBe empty | ||
| 50 | } | ||
| 51 | |||
| 52 | "A intersection of classes" should "be converted into the union of the conversion of the classes" in { | ||
| 53 | val cls0 = factory.getOWLClass(iriString0) | ||
| 54 | val cls1 = factory.getOWLClass(iriString1) | ||
| 55 | val cls2 = factory.getOWLClass(iriString2) | ||
| 56 | val conj = factory.getOWLObjectIntersectionOf(cls0, cls1, cls2) | ||
| 57 | val (res0, ext0) = | ||
| 58 | convert(cls0, term0, List(), SkolemStrategy.None, Empty) | ||
| 59 | val (res1, ext1) = | ||
| 60 | convert(cls1, term0, List(), SkolemStrategy.None, Empty) | ||
| 61 | val (res2, ext2) = | ||
| 62 | convert(cls2, term0, List(), SkolemStrategy.None, Empty) | ||
| 63 | val (res, ext) = | ||
| 64 | convert(conj, term0, List(), SkolemStrategy.None, Empty) | ||
| 65 | res should contain theSameElementsAs (res0 ::: res1 ::: res2) | ||
| 66 | ext should contain theSameElementsAs (ext0 ::: ext1 ::: ext2) | ||
| 67 | } | ||
| 68 | |||
| 69 | "A singleton intersection" should "correspond to the conversion of the internal class" in { | ||
| 70 | val cls0 = factory.getOWLClass(iriString0) | ||
| 71 | val conj = factory.getOWLObjectIntersectionOf(cls0) | ||
| 72 | val (res0, ext0) = | ||
| 73 | convert(cls0, term0, List(), SkolemStrategy.None, Empty) | ||
| 74 | val (res, ext) = | ||
| 75 | convert(conj, term0, List(), SkolemStrategy.None, Empty) | ||
| 76 | res should contain theSameElementsAs res0 | ||
| 77 | ext should contain theSameElementsAs ext0 | ||
| 78 | } | ||
| 79 | |||
| 80 | "An object property" should "be converted into an atom with matching predicate" in { | ||
| 81 | val prop = factory.getOWLObjectProperty(iriString0) | ||
| 82 | for (sx <- suffixes) { | ||
| 83 | val atom = | ||
| 84 | TupleTableAtom.rdf(term0, IRI.create(iriString0 :: sx), term1) | ||
| 85 | convert(prop, term0, term1, sx) shouldEqual atom | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | "The inverse of an object property" should "be converted into an atom with matching negated predicate" in { | ||
| 90 | val prop = factory.getOWLObjectProperty(iriString0) | ||
| 91 | val inv = factory.getOWLObjectInverseOf(prop) | ||
| 92 | for (sx <- Seq(Empty, Forward, Backward)) { | ||
| 93 | val atom = | ||
| 94 | TupleTableAtom.rdf(term0, IRI.create(iriString0 :: sx + Inverse), term1) | ||
| 95 | convert(inv, term0, term1, sx) shouldEqual atom | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | "A data property" should "be converted into an atom with matching predicate" in { | ||
| 100 | val prop = factory.getOWLDataProperty(iriString0) | ||
| 101 | for (suffix <- suffixes) { | ||
| 102 | val atom = | ||
| 103 | TupleTableAtom.rdf(term0, IRI.create(iriString0 :: suffix), term1) | ||
| 104 | convert(prop, term0, term1, suffix) shouldEqual atom | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | } | ||
