diff --git a/qendpoint-backend/pom.xml b/qendpoint-backend/pom.xml index 6b75e331..2686d2fb 100644 --- a/qendpoint-backend/pom.xml +++ b/qendpoint-backend/pom.xml @@ -46,7 +46,7 @@ 5.0.2 3.4.0 1.5.6 - + 2.11.0 UTF-8 UTF-8 @@ -112,6 +112,11 @@ + + com.google.code.gson + gson + ${gson.version} + commons-codec diff --git a/qendpoint-backend/src/main/java/com/the_qa_company/qendpoint/controller/Sparql.java b/qendpoint-backend/src/main/java/com/the_qa_company/qendpoint/controller/Sparql.java index 7b25ce0c..ed9223ee 100644 --- a/qendpoint-backend/src/main/java/com/the_qa_company/qendpoint/controller/Sparql.java +++ b/qendpoint-backend/src/main/java/com/the_qa_company/qendpoint/controller/Sparql.java @@ -12,6 +12,8 @@ import com.the_qa_company.qendpoint.store.EndpointStoreUtils; import com.the_qa_company.qendpoint.utils.FileUtils; import com.the_qa_company.qendpoint.utils.RDFStreamUtils; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.util.Values; import org.eclipse.rdf4j.repository.RepositoryConnection; @@ -34,8 +36,6 @@ import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebInputException; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; diff --git a/qendpoint-core/pom.xml b/qendpoint-core/pom.xml index d0522ca2..46dde950 100644 --- a/qendpoint-core/pom.xml +++ b/qendpoint-core/pom.xml @@ -48,7 +48,7 @@ 1.5.6 0.9.44 - 4.3.2 + 4.9.0 1.7.30 UTF-8 @@ -75,7 +75,7 @@ org.apache.commons commons-compress - 1.21 + 1.26.0 org.apache.jena diff --git a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/iterator/utils/GraphFilteringTripleId.java b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/iterator/utils/GraphFilteringTripleId.java index a1b597c0..3894787a 100644 --- a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/iterator/utils/GraphFilteringTripleId.java +++ b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/iterator/utils/GraphFilteringTripleId.java @@ -16,7 +16,6 @@ public GraphFilteringTripleId(IteratorTripleID iterator, long[] graphIds) { this.graphIds = graphIds; } - @Override public void goToStart() { throw new NotImplementedException(); diff --git a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/IteratorTripleID.java b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/IteratorTripleID.java index 0c57074d..0fe04b12 100644 --- a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/IteratorTripleID.java +++ b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/IteratorTripleID.java @@ -92,9 +92,11 @@ default boolean isLastTriplePositionBoundToOrder() { /** * goto the next subject >= id + * * @param id id * @return true if the next subject == id - * @see #canGoToSubject() if can goto returns false, this function is not available + * @see #canGoToSubject() if can goto returns false, this function is not + * available */ default boolean gotoSubject(long id) { return false; @@ -102,9 +104,11 @@ default boolean gotoSubject(long id) { /** * goto the next predicate >= id + * * @param id id * @return true if the next predicate == id - * @see #canGoToPredicate() if can goto returns false, this function is not available + * @see #canGoToPredicate() if can goto returns false, this function is not + * available */ default boolean gotoPredicate(long id) { return false; @@ -112,9 +116,11 @@ default boolean gotoPredicate(long id) { /** * goto the next object >= id + * * @param id id * @return true if the next object == id - * @see #canGoToObject() if can goto returns false, this function is not available + * @see #canGoToObject() if can goto returns false, this function is not + * available */ default boolean gotoObject(long id) { return false; @@ -126,12 +132,14 @@ default boolean gotoObject(long id) { default boolean canGoToSubject() { return false; } + /** * @return true if {@link #gotoPredicate(long)} can be used, false otherwise */ default boolean canGoToPredicate() { return false; } + /** * @return true if {@link #gotoObject(long)} can be used, false otherwise */ diff --git a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIterator.java b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIterator.java index e62df132..d5b465d1 100644 --- a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIterator.java +++ b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIterator.java @@ -272,39 +272,50 @@ public boolean isLastTriplePositionBoundToOrder() { private boolean gotoOrder(long id, TripleComponentRole role) { switch (role) { - case SUBJECT -> { - if (patX != 0) { - return id == patX; // can't jump or already on the right element - } - - patX = id; - findRange(); - patX = 0; + case SUBJECT -> { + if (patX != 0) { + return id == patX; // can't jump or already on the right element + } - return true; // we know x exists because we are using + if (x >= id) { + return id == x; } - case PREDICATE -> { - if (patY != 0) { - return id == patY; // can't jump or already on the right element - } - if (posY == nextY) { - return false; // no next element - } + x = id; + posY = adjY.find(x - 1); + posZ = adjZ.find(posY); + y = adjY.get(posY); + nextY = adjY.last(x - 1) + 1; + nextZ = adjZ.find(posY + 1); - long curr = this.adjY.get(posY); + return true; // we know x exists + } + case PREDICATE -> { + if (patY != 0) { + return id == patY; // can't jump or already on the right element + } - if (curr >= id) { - return curr == id; - } - if (posY + 1 == nextY) { - return false; // no next element - } + if (posY == nextY) { + return false; // no next element + } - long last = this.adjY.get(nextY - 1); + long curr = this.adjY.get(posY); + if (curr >= id) { + return curr == id; + } - boolean res; + boolean res; + if (posY + 1 == nextY) { + // no next element, go next X + x++; + posY = nextY; + nextY = adjY.findNext(posY) + 1; + y = adjY.get(posY); + + res = false; + } else { + long last = this.adjY.get(nextY - 1); if (last > id) { // binary search between curr <-> last id @@ -319,77 +330,79 @@ private boolean gotoOrder(long id, TripleComponentRole role) { posY = -loc - 1; y = adjY.get(posY); } - } else if (last != id) { - // last < id - GOTO end + 1 - posY = nextY; - res = false; } else { - // last == id - GOTO last - posY = nextY - 1; - y = adjY.get(posY); - res = true; + if (last != id) { + // last < id - GOTO end + 1 + posY = nextY; + res = false; + } else { + // last == id - GOTO last + posY = nextY - 1; + y = adjY.get(posY); + res = true; + } + nextY = adjY.findNext(posY) + 1; } + } - nextY = adjY.findNext(posY) + 1; - - // down to z/posZ/nextZ? - posZ = adjZ.find(posY, patZ); - nextZ = adjZ.findNext(posZ) + 1; + // down to z/posZ/nextZ? + posZ = adjZ.find(posY); // assert patZ != 0 + nextZ = adjZ.findNext(posZ) + 1; - return res; + return res; + } + case OBJECT -> { + if (patZ != 0) { + return id == patZ; // can't jump or already on the right element } - case OBJECT -> { - if (patZ != 0) { - return id == patZ; // can't jump or already on the right element - } - if (posZ == nextZ) { - return false; // no next element - } - - long curr = this.adjZ.get(posZ); + if (posZ == nextZ) { + return false; // no next element + } - if (curr >= id) { - return curr == id; - } - if (posZ + 1 == nextZ) { - return false; // no next element - } + long curr = this.adjZ.get(posZ); - long last = this.adjZ.get(nextZ - 1); + if (curr >= id) { + return curr == id; + } + if (posZ + 1 == nextZ) { + return false; // no next element + } + long last = this.adjZ.get(nextZ - 1); - boolean res; + boolean res; - if (last > id) { - // binary search between curr <-> last id - long loc = this.adjZ.searchLoc(id, posZ + 1, nextZ - 2); + if (last > id) { + // binary search between curr <-> last id + long loc = this.adjZ.searchLoc(id, posZ + 1, nextZ - 2); - if (loc >= 0) { //match - res = true; - posZ = loc; - //z = id; // no need to compute the z, it is only used in next() - } else { - res = false; - posZ = -loc - 1; - //z = adjZ.get(posZ); - } - } else if (last != id) { - // last < id - GOTO end - posZ = nextZ; - res = false; - } else { - // last == id - GOTO last - posZ = nextZ - 1; - //z = adjZ.get(posZ); + if (loc >= 0) { // match res = true; + posZ = loc; + // z = id; // no need to compute the z, it is only used in + // next() + } else { + res = false; + posZ = -loc - 1; + // z = adjZ.get(posZ); } + } else if (last != id) { + // last < id - GOTO end + posZ = nextZ; + res = false; + } else { + // last == id - GOTO last + posZ = nextZ - 1; + // z = adjZ.get(posZ); + res = true; + } - nextZ = adjZ.findNext(posZ) + 1; + nextZ = adjZ.findNext(posZ) + 1; - return res; - } - default -> throw new NotImplementedException("goto " + role); + return res; + } + default -> throw new NotImplementedException("goto " + role); } } @@ -402,6 +415,7 @@ public boolean gotoSubject(long id) { public boolean gotoPredicate(long id) { return gotoOrder(id, idx.getOrder().getPredicateMapping()); } + @Override public boolean gotoObject(long id) { return gotoOrder(id, idx.getOrder().getObjectMapping()); @@ -411,10 +425,12 @@ public boolean gotoObject(long id) { public boolean canGoToSubject() { return true; } + @Override public boolean canGoToPredicate() { return true; } + @Override public boolean canGoToObject() { return true; diff --git a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/TriplesList.java b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/TriplesList.java index bc0c7f2e..4b6f522e 100644 --- a/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/TriplesList.java +++ b/qendpoint-core/src/main/java/com/the_qa_company/qendpoint/core/triples/impl/TriplesList.java @@ -448,7 +448,6 @@ public TripleID next() { return triplesList.arrayOfTriples.get(pos++).asTripleID(); } - /* * (non-Javadoc) * @see hdt.iterator.IteratorTripleID#goToStart() diff --git a/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapQuadTriplesTest.java b/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapQuadTriplesTest.java index 09344fdf..6d18a20a 100644 --- a/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapQuadTriplesTest.java +++ b/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapQuadTriplesTest.java @@ -34,7 +34,6 @@ private static IteratorTripleID fromList(List lst) { private int current; private int lastLoc; - @Override public void goToStart() { current = 0; diff --git a/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIteratorTest.java b/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIteratorTest.java index 4842866c..53c412b3 100644 --- a/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIteratorTest.java +++ b/qendpoint-core/src/test/java/com/the_qa_company/qendpoint/core/triples/impl/BitmapTriplesIteratorTest.java @@ -1,27 +1,34 @@ package com.the_qa_company.qendpoint.core.triples.impl; -import java.io.IOException; -import java.nio.file.Path; - -import com.the_qa_company.qendpoint.core.exceptions.NotFoundException; +import com.the_qa_company.qendpoint.core.enums.RDFNotation; +import com.the_qa_company.qendpoint.core.enums.TripleComponentOrder; import com.the_qa_company.qendpoint.core.exceptions.ParserException; import com.the_qa_company.qendpoint.core.hdt.HDT; import com.the_qa_company.qendpoint.core.hdt.HDTManager; +import com.the_qa_company.qendpoint.core.listener.ProgressListener; import com.the_qa_company.qendpoint.core.options.HDTOptions; +import com.the_qa_company.qendpoint.core.options.HDTOptionsKeys; import com.the_qa_company.qendpoint.core.triples.IteratorTripleID; -import com.the_qa_company.qendpoint.core.triples.IteratorTripleString; import com.the_qa_company.qendpoint.core.triples.TripleID; import com.the_qa_company.qendpoint.core.util.LargeFakeDataSetStreamSupplier; import org.apache.commons.io.file.PathUtils; -import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.Random; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class BitmapTriplesIteratorTest { @@ -32,18 +39,6 @@ public class BitmapTriplesIteratorTest { public void setUp() throws Exception { } - @Test - public void test() throws IOException { -// HDT hdt = HDTManager.mapHDT("/Users/mck/hdt/swdf.hdt", null); -// -// int t = (int) hdt.getTriples().getNumberOfElements(); -// BitmapTriplesIterator it = new BitmapTriplesIterator((BitmapTriples) hdt.getTriples(), t-10, t); -// -// while(it.hasNext()) { -// System.out.println(it.next()); -// } - } - @Test public void jumpTest() throws IOException, ParserException { Path root = tempDir.newFolder().toPath(); @@ -60,13 +55,11 @@ public void jumpTest() throws IOException, ParserException { TripleID start = it.next().clone(); - for (int i = 0; i < 458; i++) { assertTrue(it.hasNext()); it.next(); } - TripleID lastTest = it.next().clone(); assertNotEquals(start, lastTest); @@ -88,7 +81,274 @@ public void jumpTest() throws IOException, ParserException { PathUtils.deleteDirectory(root); } + } + + private static final String JUMP_XYZ_DATASET = """ + @prefix ex: . + + ex:s1 ex:p1 ex:o0000, ex:o0001, ex:o0002, ex:o0003, ex:o0004, ex:o0005 ; + ex:p2 ex:o0000, ex:o0002, ex:o0003, ex:o0004, ex:o0005 ; + ex:p3 ex:o0000, ex:o0001, ex:o0002, ex:o0003, ex:o0004, ex:o0005 ; + ex:p4 ex:o0000, ex:o0001, ex:o0002, ex:o0004, ex:o0005 ; + ex:p5 ex:o0000, ex:o0001, ex:o0002, ex:o0003, ex:o0004, ex:o0005 . + + + ex:s2 ex:p1 ex:o0006, ex:o0007, ex:o0008, ex:o0009, ex:o0010, ex:o0011 ; + ex:p2 ex:o0008, ex:o0009, ex:o0010, ex:o0011 ; + ex:p3 ex:o0007, ex:o0008, ex:o0009, ex:o0010, ex:o0011 ; + ex:p4 ex:o0006, ex:o0007, ex:o0008, ex:o0009, ex:o0010, ex:o0011 . + + + ex:s3 ex:p1 ex:o0003, ex:o0005, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p2 ex:o0003, ex:o0005, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p3 ex:o0003, ex:o0005, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p4 ex:o0003, ex:o0005, ex:o0007 ; + ex:p5 ex:o0003, ex:o0005, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p6 ex:o0003, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p7 ex:o0003, ex:o0005, ex:o0009, ex:o0011, ex:o0015 . + + + ex:s4 ex:p1 ex:o0003, ex:o0005, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p2 ex:o0005, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p3 ex:o0003, ex:o0005, ex:o0009, ex:o0011, ex:o0015 ; + ex:p4 ex:o0003, ex:o0005, ex:o0007, ex:o0009, ex:o0011, ex:o0015 ; + ex:p5 ex:o0003, ex:o0005, ex:o0007, ex:o0009 . + + """; + private static final long JUMP_XYZ_DATASET_X = 4; + private static final long JUMP_XYZ_DATASET_Y = 4; + + @Test + public void jumpXTest() throws IOException, ParserException { + Path root = tempDir.newFolder().toPath(); + + try { + + Path hdtPath = root.resolve("test.hdt"); + + HDTOptions spec = HDTOptions.of(HDTOptionsKeys.BITMAPTRIPLES_INDEX_OTHERS, "spo,sop,pos,pso,ops,osp", + HDTOptionsKeys.BITMAPTRIPLES_INDEX_NO_FOQ, true); + + try (HDT hdt = HDTManager.generateHDT( + new ByteArrayInputStream(JUMP_XYZ_DATASET.getBytes(StandardCharsets.UTF_8)), + LargeFakeDataSetStreamSupplier.BASE_URI, RDFNotation.TURTLE, spec, ProgressListener.ignore())) { + hdt.saveToHDT(hdtPath); + } + + try (HDT hdt = HDTManager.mapIndexedHDT(hdtPath, spec, ProgressListener.ignore())) { + + IteratorTripleID ittt = hdt.getTriples().searchAll(); + assertTrue("bad class: " + ittt.getClass(), ittt instanceof BitmapTriplesIterator); + + for (int sid = 1; sid <= JUMP_XYZ_DATASET_X; sid++) { + IteratorTripleID it = hdt.getTriples().searchAll(); + IteratorTripleID itex = hdt.getTriples().searchAll(); + + assertTrue(it.gotoSubject(sid)); + + assertEquals(sid, it.next().getSubject()); + + long s; + do { + assertTrue(itex.hasNext()); + s = itex.next().getSubject(); + } while (s < sid); + assertEquals(sid, s); + + assertTrue(it.hasNext()); + do { + TripleID ac = it.next(); + assertTrue(itex.hasNext()); + TripleID ex = itex.next(); + assertEquals(itex.getLastTriplePosition(), it.getLastTriplePosition()); + + assertEquals(ex, ac); + } while (it.hasNext()); + + assertFalse(itex.hasNext()); + } + } + } finally { + PathUtils.deleteDirectory(root); + } + } + + @Test + public void jumpYTest() throws IOException, ParserException { + Path root = tempDir.newFolder().toPath(); + + try { + + Path hdtPath = root.resolve("test.hdt"); + + HDTOptions spec = HDTOptions.of(HDTOptionsKeys.BITMAPTRIPLES_INDEX_OTHERS, "spo,sop,pos,pso,ops,osp", + HDTOptionsKeys.BITMAPTRIPLES_INDEX_NO_FOQ, true); + + try (HDT hdt = HDTManager.generateHDT( + new ByteArrayInputStream(JUMP_XYZ_DATASET.getBytes(StandardCharsets.UTF_8)), + LargeFakeDataSetStreamSupplier.BASE_URI, RDFNotation.TURTLE, spec, ProgressListener.ignore())) { + hdt.saveToHDT(hdtPath); + } + + try (HDT hdt = HDTManager.mapIndexedHDT(hdtPath, spec, ProgressListener.ignore())) { + + IteratorTripleID ittt = hdt.getTriples().searchAll(); + assertTrue("bad class: " + ittt.getClass(), ittt instanceof BitmapTriplesIterator); + + String lastPosData; + + for (int sid = 1; sid <= JUMP_XYZ_DATASET_X; sid++) { + for (int pid = 1; pid <= JUMP_XYZ_DATASET_Y; pid++) { + IteratorTripleID it = hdt.getTriples().searchAll(); + IteratorTripleID itex = hdt.getTriples().searchAll(); + + assertTrue(it.gotoSubject(sid)); + assertTrue(it.gotoPredicate(pid)); + + TripleID next = it.next(); + lastPosData = "[sid:" + sid + "/pid:" + pid + "][ac:" + it.getLastTriplePosition() + "/ex" + + itex.getLastTriplePosition() + "]" + next; + assertEquals("invalid pos: " + lastPosData, sid, next.getSubject()); + assertEquals("invalid pos: " + lastPosData, pid, next.getPredicate()); + + long s; + long p; + do { + assertTrue(itex.hasNext()); + TripleID next1 = itex.next(); + s = next1.getSubject(); + p = next1.getPredicate(); + lastPosData = "[sid:" + sid + "/pid:" + pid + "][ac:" + it.getLastTriplePosition() + "/ex" + + itex.getLastTriplePosition() + "]" + next1; + } while (s < sid || p < pid); + assertEquals(lastPosData, sid, s); + assertEquals(lastPosData, pid, p); + + assertTrue(it.hasNext()); + do { + TripleID ac = it.next(); + assertTrue(itex.hasNext()); + TripleID ex = itex.next(); + lastPosData = "[sid:" + sid + "/pid:" + pid + "][ac:" + it.getLastTriplePosition() + "/ex" + + itex.getLastTriplePosition() + "]" + ac + "/" + ex; + assertEquals(lastPosData, itex.getLastTriplePosition(), it.getLastTriplePosition()); + + assertEquals(lastPosData, ex, ac); + } while (it.hasNext()); + + assertFalse(itex.hasNext()); + } + } + } + } finally { + PathUtils.deleteDirectory(root); + } } + @Test + public void jumpXYZTest() throws IOException, ParserException { + Path root = tempDir.newFolder().toPath(); + + try { + Path hdtPath = root.resolve("test.hdt"); + + HDTOptions spec = HDTOptions.of(HDTOptionsKeys.BITMAPTRIPLES_INDEX_OTHERS, "spo,sop,pos,pso,ops,osp", + HDTOptionsKeys.BITMAPTRIPLES_INDEX_NO_FOQ, true); + final int count = 100_000; + LargeFakeDataSetStreamSupplier supplier = LargeFakeDataSetStreamSupplier + .createSupplierWithMaxTriples(count, 567890987).withMaxElementSplit(50).withMaxLiteralSize(20); + + supplier.createAndSaveFakeHDT(spec, hdtPath); + + Random rnd = new Random(34567); + + try (HDT hdt = HDTManager.mapIndexedHDT(hdtPath, spec, ProgressListener.ignore())) { + int elements = (int) hdt.getTriples().getNumberOfElements(); + + for (int i = 0; i < count; i++) { + int idx = rnd.nextInt(elements); + + IteratorTripleID it = hdt.getTriples().searchAll(); + + assertTrue(it.canGoTo()); + + it.goTo(idx); + + TripleID current = it.next().clone(); + assertEquals(idx, it.getLastTriplePosition()); + + for (int member = 0; member < 3; member++) { + IteratorTripleID itac = hdt.getTriples().searchAll(TripleComponentOrder.SPO.mask); + assertSame("invalid order (" + member + "/" + i + ")", itac.getOrder(), + TripleComponentOrder.SPO); + + // test subject + assertTrue("Can't jump to subject " + current + " (" + member + "/" + i + ")", + itac.canGoToSubject() && itac.gotoSubject(current.getSubject())); + + if (member >= 1) { + // test predicate + assertTrue("Can't jump to predicate " + current + " (" + member + "/" + i + ")", + itac.canGoToPredicate() && itac.gotoPredicate(current.getPredicate())); + + if (member >= 2) { + // test object + assertTrue("Can't jump to object " + current + " (" + member + "/" + i + ")", + itac.canGoToObject() && itac.gotoObject(current.getObject())); + } + } + + assertTrue("for " + current + " (" + member + "/" + i + ")", itac.hasNext()); + TripleID next = itac.next(); + String err = "invalid next " + next + " != " + current + " (" + member + "/" + i + ")"; + switch (member) { + case 2: // object + assertEquals("object err " + err, current.getObject(), next.getObject()); + case 1: // predicate + assertEquals("predicate err " + err, current.getPredicate(), next.getPredicate()); + case 0: // subject only + assertEquals("subject err " + err, current.getSubject(), next.getSubject()); + break; + default: + fail("bad member: " + member); + break; + } + if (member == 2) { + assertEquals("idx err " + err, idx, itac.getLastTriplePosition()); + TripleID newCurrent = itac.next(); + assertTrue("idx err " + err, idx < itac.getLastTriplePosition()); + + if (current.getSubject() == newCurrent.getSubject()) { + // no jump on X, we should have the sam + assertTrue("Can't jump to subject " + current + " (" + member + "/" + i + ")", + itac.gotoSubject(current.getSubject())); + + if (current.getPredicate() == newCurrent.getPredicate()) { + // no jump on Y, we should have the same + assertTrue("Can't jump to subject " + current + " (" + member + "/" + i + ")", + itac.gotoPredicate(current.getPredicate())); + + assertFalse("Can't jump to subject " + current + " (" + member + "/" + i + ")", + itac.gotoObject(current.getObject())); + } else { + assertFalse("Can't jump to subject " + current + " (" + member + "/" + i + ")", + itac.gotoPredicate(current.getPredicate())); + } + + } else { + assertFalse("Can't jump to subject " + current + " (" + member + "/" + i + ")", + itac.gotoSubject(current.getSubject())); + } + + } else { + assertTrue("idx err " + err, idx >= itac.getLastTriplePosition()); + } + } + } + } + } finally { + PathUtils.deleteDirectory(root); + } + } }