package org.openbel.framework.core.protonetwork; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import java.util.Arrays; import org.junit.Test; import org.openbel.framework.common.bel.parser.BELParser; import org.openbel.framework.common.model.Document; import org.openbel.framework.common.model.Header; import org.openbel.framework.common.model.NamespaceGroup; import org.openbel.framework.common.model.Statement; import org.openbel.framework.common.model.StatementGroup; import org.openbel.framework.common.protonetwork.model.ProtoNetwork; import org.openbel.framework.core.compiler.expansion.ExpansionService; import org.openbel.framework.core.compiler.expansion.ExpansionServiceImpl; /** * Unit test for {@link ProtoNetworkMerger}. This unit test's purpose is to * exercise the merge routines for completeness and correctness. * * <p> * Created to assert the commutative property of network merges holds true. * </p> * * @see https://github.com/OpenBEL/openbel-framework/issues/49 */ public class ProtoNetworkMerge_CommutativeTest { private static final String URL = "http://resource.belframework.org/" + "belframework/1.0/namespace/hgnc-approved-symbols.belns"; @Test /** * Tests that statement triples in two {@link Document documents} will * produce the same merged result regardless of document sequence. */ public void commutative_simple() { Document a = make_document(new Header("Doc 1", "Doc 1", "1.0"), new NamespaceGroup(URL, null), parse("g(AKT2) -> r(AKT3)"), parse("p(AKT1) => complex(p(DUSP1), p(WRN))")); Document b = make_document(new Header("Doc 2", "Doc 2", "1.0"), new NamespaceGroup(URL, null), parse("m(AKT1) =| p(AKT2)"), parse("cat(g(AKT2)) -| p(PARP1)")); // merge in different orders ProtoNetwork ab = merge(a, b); ProtoNetwork ba = merge(b, a); network_asserts(ab, ba); } @Test /** * Tests that subject-only statements in two {@link Document documents} * will produce the same merged result regardless of document sequence. */ public void commutative_subject_only() { Document a = make_document(new Header("Doc 1", "Doc 1", "1.0"), new NamespaceGroup(URL, null), parse("r(AKT3)"), parse("p(AKT1)")); Document b = make_document(new Header("Doc 2", "Doc 2", "1.0"), new NamespaceGroup(URL, null), parse("m(AKT1)"), parse("g(AKT2)")); // merge in different orders ProtoNetwork ab = merge(a, b); ProtoNetwork ba = merge(b, a); network_asserts(ab, ba); } @Test /** * Tests that nested statements in two {@link Document documents} will * produce the same merged result regardless of document sequence. */ public void commutative_nested() { Document a = make_document(new Header("Doc 1", "Doc 1", "1.0"), new NamespaceGroup(URL, null), parse("r(AKT3) => (g(PARP1) -| cat(p(AKT2)))"), parse("p(AKT1) -> (kin(p(PARP1)) -| p(AKT3))")); Document b = make_document(new Header("Doc 2", "Doc 2", "1.0"), new NamespaceGroup(URL, null), parse("m(AKT1) => (g(PARP1) -| p(AKT2))"), parse("g(AKT2) -> (r(AKT1) => p(PARP1))")); // merge in different orders ProtoNetwork ab = merge(a, b); ProtoNetwork ba = merge(b, a); network_asserts(ab, ba); } /** * Asserts equal table counts. The {@link ProtoNetwork} objects cannot be * compared directly because {@link ProtoNetwork#equals(Object)} relies on * collection ordering which will not be consistent when {@link Document}s * are merged in different sequences. * * @param ab {@link ProtoNetwork} * @param ba {@link ProtoNetwork} */ private void network_asserts(ProtoNetwork ab, ProtoNetwork ba) { assertThat(ab.getProtoEdgeTable().getProtoEdges().size(), is(ba .getProtoEdgeTable().getProtoEdges().size())); assertThat(ab.getProtoNodeTable().getProtoNodes().size(), is(ba .getProtoNodeTable().getProtoNodes().size())); assertThat(ab.getStatementTable().getStatements().size(), is(ba .getStatementTable().getStatements().size())); assertThat(ab.getTermTable().getTermValues().size(), is(ba .getTermTable().getTermValues().size())); assertThat(ab.getParameterTable().getTableParameterArray().length, is(ba.getParameterTable().getTableParameterArray().length)); } /** * Merges two {@link Document}s together after each has been compiled. * The compilation step builds the {@link ProtoNetwork} and expands * additional knowledge. * * @param a {@link Document} * @param b {@link Document} * @return merged {@link ProtoNetwork} */ private ProtoNetwork merge(Document a, Document b) { ExpansionService es = new ExpansionServiceImpl(); ProtoNetworkBuilder builder = new ProtoNetworkBuilder(a); ProtoNetwork networkA = builder.buildProtoNetwork(); es.expandTerms(a, networkA); builder = new ProtoNetworkBuilder(b); ProtoNetwork n2 = builder.buildProtoNetwork(); es.expandTerms(b, n2); ProtoNetworkMerger merger = new ProtoNetworkMerger(); merger.merge(networkA, n2); return networkA; } /** * Build a {@link Document} for testing. * * @param h {@link Header}; document header * @param n {@link NamespaceGroup}; namespace group * @param statements {@link Statement}; bel statements * @return {@link Document} */ private Document make_document(Header h, NamespaceGroup n, Statement... statements) { StatementGroup g = new StatementGroup(); g.setStatements(Arrays.asList(statements)); return new Document(h, Arrays.asList(g), n, null); } /** * Parses a {@link String string} into a {@link Statement bel statement}. * * @param statement {@link String} * @return {@link Statement} */ private Statement parse(String statement) { return BELParser.parseStatement(statement); } }