/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.store.tuples;
// Third party packages
import junit.framework.*; // JUnit
import org.apache.log4j.Logger; // Log4J
// Locally written packages
import org.mulgara.query.Variable;
/**
* Test case for {@link UnboundJoin}.
*
* @created 2003-09-04
*
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
*
* @version $Revision: 1.12 $
*
* @modified $Date: 2005/03/07 19:42:40 $
*
* @maintenanceAuthor $Author: newmana $
*
* @company <A href="mailto:info@PIsoftware.com">Plugged In Software</A>
*
* @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In
* Software Pty Ltd</A>
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class UnboundJoinUnitTest extends TestCase {
/**
* Logger.
*/
private static final Logger logger = Logger.getLogger(UnboundJoinUnitTest.class);
/**
* Description of the Field
*/
final Variable x = new Variable("x");
/**
* Description of the Field
*/
final Variable y = new Variable("y");
/**
* Description of the Field
*/
final Variable z = new Variable("z");
/**
* Description of the Field
*/
final Variable w = new Variable("w");
/**
* Description of the Field
*/
final Variable u = new Variable("u");
/**
* Description of the Field
*/
final Variable v = new Variable("v");
/**
* Constructs a new test with the given name.
*
* @param name the name of the test
*/
public UnboundJoinUnitTest(String name) {
super(name);
}
/**
* Hook for test runner to obtain a test suite from.
*
* @return The test suite
*/
public static Test suite() {
TestSuite testSuite = new TestSuite();
testSuite.addTest(new UnboundJoinUnitTest("testZeroOperands"));
testSuite.addTest(new UnboundJoinUnitTest("testOneOperand"));
testSuite.addTest(new UnboundJoinUnitTest("testCartesianDyad"));
testSuite.addTest(new UnboundJoinUnitTest("testCartesianTriad"));
testSuite.addTest(new UnboundJoinUnitTest("testTwoOperands"));
testSuite.addTest(new UnboundJoinUnitTest("testSuffixJoin"));
testSuite.addTest(new UnboundJoinUnitTest("testSuffixJoin2"));
testSuite.addTest(new UnboundJoinUnitTest("testNullJoin"));
testSuite.addTest(new UnboundJoinUnitTest("testNullPrefixBoundInSuffix"));
testSuite.addTest(new UnboundJoinUnitTest("testNullPropagation"));
testSuite.addTest(new UnboundJoinUnitTest("testLeadingPrefixNull"));
testSuite.addTest(new UnboundJoinUnitTest("testPartialMGR36"));
return testSuite;
//return new TestSuite(UnboundJoinTest.class);
}
/**
* Default text runner.
*
* @param args The command line arguments
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
/**
* Create test instance.
*
* @throws Exception EXCEPTION TO DO
*/
public void setUp() throws Exception {
// null implementation
}
/**
* The teardown method for JUnit
*
* @throws Exception EXCEPTION TO DO
*/
public void tearDown() throws Exception {
// null implementation
}
//
// Test cases
//
/**
* Test {@link UnboundJoin}. When passed a list of zero arguments, the result
* of a join should be unconstrained.
*
* @throws Exception if query fails when it should have succeeded
*/
public void testZeroOperands() throws Exception {
Tuples joinedTuples = new UnboundJoin(new Tuples[] {});
assertTrue(joinedTuples.isUnconstrained());
assertEquals(0, ((UnboundJoin)joinedTuples).getNrGroups());
}
/**
* Test {@link UnboundJoin}. When passed a single argument, the result should
* be identical to that argument.
*
* @throws Exception if query fails when it should have succeeded
*/
public void testOneOperand() throws Exception {
Tuples operand =
TuplesFactory.newInstance().newTuples(new MemoryTuples(x, 1).and(y, 2)
.or(x, 3).and(y, 4));
assert operand != null;
Tuples joinedTuples = new UnboundJoin(new Tuples[] {operand});
assertEquals(1, ((UnboundJoin)joinedTuples).getNrGroups());
joinedTuples.beforeFirst();
TuplesTestingUtil.testTuplesRow(joinedTuples, new long[] { 1, 2 } );
TuplesTestingUtil.testTuplesRow(joinedTuples, new long[] { 3, 4 } );
assertTrue(!joinedTuples.next());
TuplesTestingUtil.closeTuples(new Tuples[] { joinedTuples, operand } );
}
/**
* Test {@link UnboundJoin}. When passed two arguments without common
* variables, the result should be a cartesian product.
*
* @throws Exception if query fails when it should have succeeded
*/
public void testCartesianDyad() throws Exception {
Tuples lhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(x, 1).and(y, 2)
.or(x, 3).and(y, 4));
Tuples rhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(z, 5).and(w, 6)
.or(z, 7).and(w, 8));
Tuples joined = new UnboundJoin(new Tuples[] {lhs, rhs});
assertEquals(2, ((UnboundJoin)joined).getNrGroups());
Variable[] variables = joined.getVariables();
TuplesTestingUtil.testVariables(new Variable[] { x, y, z, w }, variables);
TuplesTestingUtil.testTuplesRow(joined, new Variable[] { x, y, z, w } );
TuplesTestingUtil.checkBeforeFirst(joined);
joined.beforeFirst();
TuplesTestingUtil.testTuplesRow(joined, new long[] { 1, 2, 5, 6 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 1, 2, 7, 8 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 3, 4, 5, 6 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 3, 4, 7, 8 } );
assertTrue(!joined.next());
TuplesTestingUtil.closeTuples(new Tuples[] { joined, lhs, rhs });
}
/**
* Test {@link UnboundJoin}. When passed three arguments without common
* variables, the result should be a cartesian product.
*
* @throws Exception if query fails when it should have succeeded
*/
public void testCartesianTriad() throws Exception {
Tuples lhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(x, 1).and(y, 2)
.or(x, 3).and(y, 4));
Tuples mhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(z, 5).and(w, 6)
.or(z, 7).and(w, 8));
Tuples rhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(u, 9).and(v, 10)
.or(u, 11).and(v, 12));
Tuples joined = new UnboundJoin(new Tuples[] {lhs, mhs, rhs});
assertEquals(3, ((UnboundJoin)joined).getNrGroups());
Variable[] variables = joined.getVariables();
assertEquals(6, variables.length);
assertEquals(x, variables[0]);
assertEquals(y, variables[1]);
assertEquals(z, variables[2]);
assertEquals(w, variables[3]);
assertEquals(u, variables[4]);
assertEquals(v, variables[5]);
assertEquals(0, joined.getColumnIndex(x));
assertEquals(1, joined.getColumnIndex(y));
assertEquals(2, joined.getColumnIndex(z));
assertEquals(3, joined.getColumnIndex(w));
assertEquals(4, joined.getColumnIndex(u));
assertEquals(5, joined.getColumnIndex(v));
TuplesTestingUtil.checkBeforeFirst(joined);
joined.beforeFirst();
TuplesTestingUtil.testTuplesRow(joined, new long[] { 1, 2, 5, 6, 9, 10 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 1, 2, 5, 6, 11, 12 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 1, 2, 7, 8, 9, 10 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 1, 2, 7, 8, 11, 12 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 3, 4, 5, 6, 9, 10 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 3, 4, 5, 6, 11, 12 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 3, 4, 7, 8, 9, 10 } );
TuplesTestingUtil.testTuplesRow(joined, new long[] { 3, 4, 7, 8, 11, 12 } );
assertTrue(!joined.next());
TuplesTestingUtil.closeTuples(new Tuples[] { joined, lhs, rhs, mhs } );
}
/**
* Test {@link UnboundJoin}. When passed two arguments with common variables,
* the result should be a natural join.
*
* @throws Exception if query fails when it should have succeeded
*/
public void testTwoOperands() throws Exception {
String[] lvars = new String[] {"x", "y"};
String[] rvars = new String[] {"y", "z"};
LiteralTuples lhs = new LiteralTuples(lvars);
lhs.appendTuple(new long[] {1, 2});
lhs.appendTuple(new long[] {3, 4});
LiteralTuples rhs = new LiteralTuples(rvars);
rhs.appendTuple(new long[] {2, 5});
rhs.appendTuple(new long[] {4, 6});
TuplesFactory.newInstance().newTuples(new MemoryTuples(y, 2).and(z, 5)
.or(y, 4).and(z, 6));
UnboundJoin joined = new UnboundJoin(new Tuples[] {lhs, rhs});
assertEquals(1, joined.getNrGroups());
Tuples actual = TuplesOperations.sort(joined);
// First, try a straightforward iteration through all rows
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 2, 5 } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 3, 4, 6 } );
assertTrue(!actual.next());
// Second, try prefix searches
actual.beforeFirst(new long[] { 3 }, 0);
TuplesTestingUtil.testTuplesRow(actual, new long[] { 3, 4, 6 } );
assertTrue(!actual.next());
// Third, try more prefix searches
actual.beforeFirst(new long[] { 3, 4, 6 }, 0);
TuplesTestingUtil.testTuplesRow(actual, new long[] { 3, 4, 6 } );
assertTrue(!actual.next());
actual.close();
// Try joining in the opposite order (RHS to LHS)
actual = new UnboundJoin(new Tuples[] {
rhs, lhs});
Variable[] variables = actual.getVariables();
assertEquals(3, variables.length);
assertEquals(y, variables[0]);
assertEquals(z, variables[1]);
assertEquals(x, variables[2]);
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 5, 1 } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 4, 6, 3 } );
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs} );
}
/**
* Test {@link UnboundJoin}. Perform a join with conditions which requires
* iterative rather than indexed resolution
*
* @throws Exception if query fails when it should have succeeded
*/
public void testSuffixJoin() throws Exception {
Tuples lhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(x, 1).and(y, 4)
.or(x, 1)
.and(y, 5)
.or(x, 2)
.and(y, 6)
.or(x, 3).and(y,
7));
Tuples rhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(y, 4).and(x, 1)
.or(y, 6).and(x,
2));
Tuples actual = new UnboundJoin(new Tuples[] {
lhs, rhs});
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 4 } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 6 } );
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { lhs, rhs, actual } );
}
/**
* Test {@link UnboundJoin}. Perform another join with conditions which
* requires iterative rather than indexed resolution
*
* @throws Exception if query fails when it should have succeeded
*/
public void testSuffixJoin2() throws Exception {
Variable e = new Variable("e");
Variable v = new Variable("vcard");
Variable f = new Variable("_from");
Tuples lhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(e, 62).and(v, 37)
.and(f, 36)
.or(e, 89)
.and(v, 78)
.and(f, 36)
.or(e, 106)
.and(v, 97)
.and(f, 36)
.or(e, 121)
.and(v, 113)
.and(f, 36));
Tuples rhs =
TuplesFactory.newInstance().newTuples(new MemoryTuples(e, 89).and(f, 36));
Tuples actual = new UnboundJoin(new Tuples[] {
lhs, rhs});
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 89, 78, 36 } );
// assertTrue(actual.next());
// assertEquals(89, actual.getColumnValue(0));
// assertEquals(78, actual.getColumnValue(1));
// assertEquals(36, actual.getColumnValue(2));
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { actual, rhs, lhs } );
}
/**
* Test {@link UnboundJoin}.n the presence of unconstrained elements.
*/
public void testNullJoin() throws Exception {
String[] vars = new String[] {"x", "y"};
LiteralTuples lhs = new LiteralTuples(vars);
lhs.appendTuple(new long[] {Tuples.UNBOUND, 2});
lhs.appendTuple(new long[] {1, Tuples.UNBOUND});
LiteralTuples rhs = new LiteralTuples(vars);
rhs.appendTuple(new long[] {1, 1});
rhs.appendTuple(new long[] {2, 2});
Tuples actual = TuplesOperations.sort(new UnboundJoin(new Tuples[] {lhs,
rhs}));
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 1 } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 2 } );
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs } );
}
/**
* Test {@link UnboundJoin}.n correctly binds a variable from a rhs operand when
* unbound in the lhs.
*/
public void testNullPrefixBoundInSuffix() throws Exception {
String[] lvars = new String[] { "x", "z" };
final long[][] lhsValues = new long[][] {
new long[] { Tuples.UNBOUND, 1 },
new long[] { 2, Tuples.UNBOUND },
};
LiteralTuples lhs = LiteralTuples.create(lvars, lhsValues);
String[] rvars = new String[] { "x", "y", "z" };
final long[][] rhsValues = new long[][] {
new long[] { 2, 3, 1 }
};
LiteralTuples rhs = LiteralTuples.create(rvars, rhsValues);
Tuples actual = TuplesOperations.sort(new UnboundJoin(new Tuples[] {lhs, rhs}));
actual.beforeFirst();
// Note: If only one row is returned this is *NOT* a bug, but currently planned
// implementation should return a duplicate row.
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 1, 3} );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 1, 3} );
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs } );
}
/**
* Test {@link UnboundJoin}.n the presence of unconstrained elements.
* <pre>
* x y z x z x y z
* | 5 6 7 | | * 1 | | 2 3 1 |
* | 2 3 1 | join | 2 * | = | 2 3 1 |
* | 2 4 * | | 2 4 * |
* | 2 4 1 |
* </pre>
*/
public void testNullPropagation() throws Exception {
String[] lvars = new String[] { "x", "y", "z" };
final long[][] lhsValues = new long[][] {
new long[] { 2, 3, 1 },
new long[] { 2, 4, Tuples.UNBOUND } };
LiteralTuples lhs = LiteralTuples.create(lvars, lhsValues);
String[] rvars = new String[] { "x", "z" };
final long[][] rhsValues = new long[][] {
new long[] { Tuples.UNBOUND, 1 },
new long[] { 2, Tuples.UNBOUND } };
LiteralTuples rhs = LiteralTuples.create(rvars, rhsValues);
Tuples actual = TuplesOperations.sort(new UnboundJoin(new Tuples[] {lhs, rhs}));
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 3, 1 } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 3, 1 } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 4, Tuples.UNBOUND } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 2, 4, 1} );
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs });
}
/**
* Test {@link UnboundJoin}.n the presence of unconstrained elements.
* <pre>
* x y x y x y
* | * 2 | | * 3 | | 1 3 |
* | 1 * | join | 4 * | = | 4 2 |
* </pre>
*/
public void testLeadingPrefixNull() throws Exception {
String[] vars = new String[] { "x", "y" };
final long[][] lhsValues = new long[][] {
new long[] { Tuples.UNBOUND, 2 },
new long[] { 1, Tuples.UNBOUND } };
final long[][] rhsValues = new long[][] {
new long[] { Tuples.UNBOUND, 3 },
new long[] { 4, Tuples.UNBOUND } };
LiteralTuples lhs = LiteralTuples.create(vars, lhsValues);
LiteralTuples rhs = LiteralTuples.create(vars, rhsValues);
Tuples actual = TuplesOperations.sort(new UnboundJoin(new Tuples[] {lhs, rhs}));
// logger.warn("testLeadingPrefixNull result = " + actual);
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 3} );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 4, 2} );
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs });
}
/**
* Test {@link UnboundJoin}.n the expected final join of MGR-36 case 2.
* <pre>
* s s p o x s p o x
* | 1 | join | 1 2 3 * | = | 1 2 3 * |
* | 2 4 5 * | | 1 5 3 2 |
* | 2 4 6 * | | 1 6 3 2 |
* | 1 5 3 2 |
* | 1 6 3 2 |
* </pre>
*/
public void testPartialMGR36() throws Exception {
String[] lvars = new String[] { "s" };
final long[][] lhsValues = new long[][] {
new long[] { 1 } };
String[] rvars = new String[] { "s", "p", "o", "x" };
final long[][] rhsValues = new long[][] {
new long[] { 1, 2, 3, Tuples.UNBOUND },
new long[] { 1, 5, 3, 2 },
new long[] { 1, 6, 3, 2 },
new long[] { 2, 4, 5, Tuples.UNBOUND },
new long[] { 2, 4, 6, Tuples.UNBOUND } };
LiteralTuples lhs = LiteralTuples.create(lvars, lhsValues);
LiteralTuples rhs = LiteralTuples.create(rvars, rhsValues);
UnboundJoin joined = new UnboundJoin(new Tuples[] {lhs, rhs});
assertEquals(1, joined.getNrGroups());
Tuples actual = TuplesOperations.sort(joined);
logger.warn("testPartialMGR36 result = " + actual);
actual.beforeFirst();
TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 2, 3, Tuples.UNBOUND } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 5, 3, 2 } );
TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 6, 3, 2 } );
assertTrue(!actual.next());
TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs });
}
}