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.checklistbank.neo.printer.TxtPrinter;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import com.google.common.io.Resources;
import org.apache.commons.io.Charsets;
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 static junit.framework.Assert.assertEquals;
/**
*
*/
public class TreeWalkerTest {
private File dbf;
private GraphDatabaseService db;
private Node root;
private Node phylum;
private Node order;
private Node family;
private Node genus;
private Node bas;
private Node ppSyn;
private int idx;
@Before
public void init() throws IOException {
dbf = Files.newTemporaryFolder();
db = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(dbf).newGraphDatabase();
setupNodesAndRels();
}
@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, rank.name().toLowerCase() + idx++);
return n;
}
private void setupNodesAndRels() {
// SETUP NODES AND RELATIONS
try (Transaction tx = db.beginTx()) {
// single root
root = createNode(Rank.KINGDOM, Labels.ROOT);
// chain up phylum child
phylum = createNode(Rank.PHYLUM, Labels.TAXON);
root.createRelationshipTo(phylum, RelType.PARENT_OF);
// phylum synonym
Node syn = createNode(Rank.PHYLUM, Labels.TAXON, Labels.SYNONYM);
syn.createRelationshipTo(phylum, RelType.SYNONYM_OF);
// phylum children of all ranks
Node p = phylum;
for (Rank r : Rank.values()) {
if (Rank.PHYLUM.higherThan(r) && r.higherThan(Rank.SUBGENUS)) {
Node child = createNode(r, Labels.TAXON);
p.createRelationshipTo(child, RelType.PARENT_OF);
p = child;
if (r == Rank.GENUS) {
genus = child;
} else if (r == Rank.FAMILY) {
family = child;
} else if (r == Rank.ORDER) {
order = child;
}
}
}
// chain up more orders, each with 3 families
for (int idx = 1; idx <= 3; idx++) {
Node n = createNode(Rank.ORDER, Labels.TAXON);
phylum.createRelationshipTo(n, RelType.PARENT_OF);
for (int idx2 = 1; idx2 <= 3; idx2++) {
Node f = createNode(Rank.FAMILY, Labels.TAXON);
n.createRelationshipTo(f, RelType.PARENT_OF);
}
}
// 3 species inside genus without a synonym
for (int idx = 1; idx <= 3; idx++) {
Node sp = createNode(Rank.SPECIES, Labels.TAXON);
genus.createRelationshipTo(sp, RelType.PARENT_OF);
}
// 1 basionym
bas = createNode(Rank.SPECIES, Labels.TAXON, Labels.BASIONYM);
genus.createRelationshipTo(bas, RelType.PARENT_OF);
// 5 more species inside genus
for (int idx = 1; idx <= 5; idx++) {
Node sp = createNode(Rank.SPECIES, Labels.TAXON);
genus.createRelationshipTo(sp, RelType.PARENT_OF);
Node spSyn = createNode(Rank.SPECIES, Labels.TAXON, Labels.SYNONYM);
spSyn.createRelationshipTo(sp, RelType.SYNONYM_OF);
bas.createRelationshipTo(spSyn, RelType.BASIONYM_OF);
if (idx % 3 == 0) {
// multiple synonyms and a basionym
for (int idx2 = 1; idx2 <= 6; idx2++) {
Node syn2 = createNode(idx2%2==0 ? Rank.SPECIES : Rank.SUBSPECIES, Labels.TAXON, Labels.SYNONYM);
syn2.createRelationshipTo(sp, RelType.SYNONYM_OF);
}
bas = createNode(Rank.SPECIES, Labels.TAXON, Labels.BASIONYM, Labels.SYNONYM);
bas.createRelationshipTo(sp, RelType.SYNONYM_OF);
bas.createRelationshipTo(sp, RelType.BASIONYM_OF);
}
}
// new genus with 4 species and a pro parte synonym for 3 of them
Node genus2 = createNode(Rank.GENUS, Labels.TAXON);
family.createRelationshipTo(genus2, RelType.PARENT_OF);
ppSyn = createNode(Rank.SPECIES, Labels.TAXON, Labels.SYNONYM);
for (int idx = 1; idx <= 4; idx++) {
Node sp = createNode(Rank.SPECIES, Labels.TAXON);
genus2.createRelationshipTo(sp, RelType.PARENT_OF);
if (idx == 2) {
ppSyn.createRelationshipTo(sp, RelType.SYNONYM_OF);
}else if (idx > 2) {
ppSyn.createRelationshipTo(sp, RelType.PROPARTE_SYNONYM_OF);
}
}
tx.success();
}
}
@Test
public void testWalkTree() throws Exception {
StringWriter writer = new StringWriter();
TreeWalker.walkTree(db, true, new TxtPrinter(writer));
System.out.println(writer.toString());
assertEquals(Resources.toString(Resources.getResource("traverse/tree.txt"), Charsets.UTF_8), writer.toString());
writer = new StringWriter();
TreeWalker.walkTree(db, true, phylum, null, null, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/treePhylum.txt"), Charsets.UTF_8), writer.toString());
writer = new StringWriter();
TreeWalker.walkTree(db, true, genus, null, null, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/treeGenus.txt"), Charsets.UTF_8), writer.toString());
writer = new StringWriter();
TreeWalker.walkTree(db, true, bas, null, null, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/treeBasionym.txt"), Charsets.UTF_8), writer.toString());
writer = new StringWriter();
TreeWalker.walkTree(db, true, phylum, Rank.ORDER, null, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/tree-order.txt"), Charsets.UTF_8), writer.toString());
}
@Test
public void testWalkAcceptedTree() throws Exception {
StringWriter writer = new StringWriter();
TreeWalker.walkAcceptedTree(db, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/treeAccepted.txt"), Charsets.UTF_8), writer.toString());
writer = new StringWriter();
TreeWalker.walkAcceptedTree(db, genus, null, null, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/treeAcceptedGenus.txt"), Charsets.UTF_8), writer.toString());
}
@Test
public void testChunkingHandler() throws Exception {
StringWriter writer = new StringWriter();
TreeWalker.walkAcceptedTree(db, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/treeAccepted.txt"), Charsets.UTF_8), writer.toString());
writer = new StringWriter();
TreeWalker.walkAcceptedTree(db, genus, null, null, new TxtPrinter(writer));
assertEquals(Resources.toString(Resources.getResource("traverse/treeAcceptedGenus.txt"), Charsets.UTF_8), writer.toString());
}
}