package org.gbif.checklistbank.neo.traverse; import org.gbif.api.vocabulary.Rank; import org.gbif.checklistbank.neo.Labels; import org.gbif.checklistbank.neo.NeoProperties; import org.gbif.checklistbank.neo.RelType; import org.gbif.utils.text.StringUtils; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.assertj.core.util.Files; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.factory.GraphDatabaseFactory; import org.neo4j.graphdb.traversal.TraversalDescription; import org.neo4j.helpers.collection.Iterators; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; public class TraversalsTest { private File dbf; private GraphDatabaseService db; private Node root; private Node child1; private Node child2; private Node child1Syn; private Node child2Syn; private Node bas; @Before public void init() throws IOException { dbf = Files.newTemporaryFolder(); db = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(dbf).newGraphDatabase(); } @After public void cleanup() { db.shutdown(); FileUtils.deleteQuietly(dbf); } private Node createNode(Rank rank, Labels ... label) { Node n = db.createNode(label); n.setProperty(NeoProperties.RANK, rank.ordinal()); n.setProperty(NeoProperties.SCIENTIFIC_NAME, StringUtils.randomSpecies()); return n; } @Test public void testFindParents() { // SETUP NODES AND RELATIONS try (Transaction tx = db.beginTx()) { // single root root = createNode(Rank.KINGDOM, Labels.ROOT); // add children of all ranks Node p = root; for (Rank r : Rank.values()) { if (Rank.KINGDOM.higherThan(r) && r.higherThan(Rank.FORM)) { Node child = createNode(r, Labels.TAXON); p.createRelationshipTo(child, RelType.PARENT_OF); p = child; if (r == Rank.ORDER) { child1 = child; } else if (r == Rank.VARIETY) { child2 = child; } // second child not further related Node child2 = createNode(r, Labels.TAXON); p.createRelationshipTo(child2, RelType.PARENT_OF); } } tx.success(); } try (Transaction tx = db.beginTx()) { assertNull(Traversals.findParentWithRank(child1, Rank.SPECIES)); assertNull(Traversals.findParentWithRank(child1, Rank.FAMILY)); assertNull(Traversals.findParentWithRank(child1, Rank.ORDER)); assertEquals(root, Traversals.findParentWithRank(child1, Rank.KINGDOM)); assertEquals(Rank.SUBCLASS.ordinal(), Traversals.findParentWithRank(child1, Rank.SUBCLASS).getProperty(NeoProperties.RANK)); assertNull(Traversals.findParentWithRank(child2, Rank.UNRANKED)); assertNull(Traversals.findParentWithRank(child1, Rank.ORDER)); assertEquals(root, Traversals.findParentWithRank(child2, Rank.KINGDOM)); } } @Test public void testTraversals() { // SETUP NODES AND RELATIONS try (Transaction tx = db.beginTx()) { // single root root = db.createNode(Labels.ROOT); // chain up 10 children Node p = root; for (int idx = 1; idx <= 10; idx++) { Node child = db.createNode(Labels.TAXON); p.createRelationshipTo(child, RelType.PARENT_OF); p = child; } child1 = p; // 5 other nodes downward from root p = root; for (int idx = 1; idx <= 5; idx++) { Node child = db.createNode(Labels.TAXON); p.createRelationshipTo(child, RelType.PARENT_OF); p = child; } child2 = p; // synonyms child2Syn = db.createNode(Labels.SYNONYM); child2Syn.createRelationshipTo(child2, RelType.SYNONYM_OF); child1Syn = db.createNode(Labels.SYNONYM); child1Syn.createRelationshipTo(child1, RelType.SYNONYM_OF); child1Syn.createRelationshipTo(child2, RelType.PROPARTE_SYNONYM_OF); // one basionym with 3 rels Node n = db.createNode(Labels.TAXON); root.createRelationshipTo(n, RelType.PARENT_OF); bas = db.createNode(Labels.SYNONYM); bas.createRelationshipTo(n, RelType.SYNONYM_OF); bas.createRelationshipTo(n, RelType.BASIONYM_OF); bas.createRelationshipTo(child2, RelType.BASIONYM_OF); bas.createRelationshipTo(child2Syn, RelType.BASIONYM_OF); tx.success(); } try (Transaction tx = db.beginTx()) { // child1, child1Syn, child2, child2Syn, root, bas assertTraversalSizes(Traversals.PARENT, 1, 0, 1, 0, 0, 0); assertTraversalSizes(Traversals.PARENTS, 10, 0, 5, 0, 0, 0); assertTraversalSizes(Traversals.CHILDREN, 0, 0, 0, 0, 3, 0); // descendants are synonyms (incl pro parte) and children assertTraversalSizes(Traversals.DESCENDANTS, 1, 0, 2, 0, 20, 0); assertTraversalSizes(Traversals.SYNONYMS, 1, 0, 2, 0, 0, 0); assertTraversalSizes(Traversals.ACCEPTED, 0, 2, 0, 1, 0, 1); assertTraversalSizes(Traversals.BASIONYM_GROUP, 1, 1, 4, 4, 1, 4); // numbers just as descendants +1 for the start node assertTraversalSizes(Traversals.SORTED_TREE, 2, 1, 3, 1, 21, 1); assertTraversalSizes(Traversals.SORTED_ACCEPTED_TREE, 1, 0, 1, 0, 17, 0); } } private void assertTraversalSizes(TraversalDescription td, int child1, int child1Syn, int child2, int child2Syn, int root, int bas) { assertEquals("child1 traversal wrong", child1, Iterators.count(td.traverse(this.child1).iterator())); assertEquals("child1Syn traversal wrong", child1Syn, Iterators.count(td.traverse(this.child1Syn).iterator())); assertEquals("child2 traversal wrong", child2, Iterators.count(td.traverse(this.child2).iterator())); assertEquals("child2Syn traversal wrong", child2Syn, Iterators.count(td.traverse(this.child2Syn).iterator())); assertEquals("root traversal wrong", root, Iterators.count(td.traverse(this.root).iterator())); assertEquals("bas traversal wrong", bas, Iterators.count(td.traverse(this.bas).iterator())); } }