/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Jun 19, 2008
*/
package com.bigdata.bop.bindingSet;
import java.util.Iterator;
import java.util.Map;
import junit.framework.TestCase2;
import com.bigdata.bop.Constant;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IConstant;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.Var;
import com.bigdata.io.SerializerUtil;
/**
* Unit tests for {@link IBindingSet}.
* <p>
* Note:
* <ul>
* <li>a) these tests assume that the values held for a given key are not
* cloned, i.e. comparison is done by '==' and not '.equals' (this is true
* except for the Serializatoin tests, where the {@link Var} references will be
* preserved but the {@link IConstant}s will be distinct).</li>
* <li>b) keys with the same 'name' are a unique object.</li>
* </ul>
*
* @author <a href="mailto:dmacgbr@users.sourceforge.net">David MacMillan</a>
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public abstract class TestIBindingSet extends TestCase2 {
/**
*
*/
public TestIBindingSet () {}
/**
* @param name
*/
public TestIBindingSet ( String name ) { super ( name ) ; }
/**
* Unit test for {@link IBindingSet#isBound(IVariable)}
*/
public void testIsBound ()
{
Var<?> a = Var.var ( "a" ) ;
Var<?> b = Var.var ( "b" ) ;
Var<?> c = Var.var ( "a" ) ;
IBindingSet bs = newBindingSet ( new IVariable [] { a }, new IConstant [] { new Constant<Integer> ( 1 ) } ) ;
assertTrue ( "bound expected, same variable", bs.isBound ( a ) ) ;
assertFalse ( "not bound expected", bs.isBound ( b ) ) ;
assertTrue ( "bound expected, equivalent variable", bs.isBound ( c ) ) ;
}
/**
* Unit test for {@link IBindingSet#set(IVariable,IConstant)}
*/
public void testSet ()
{
Var<?> var = Var.var ( "a" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
IBindingSet bs = newBindingSet ( 2 ) ;
try { bs.set ( null, val1 ) ; fail ( "IllegalArgumentException expected, var was null" ) ; }
catch ( IllegalArgumentException e ) {}
try { bs.set ( var, null ) ; fail ( "IllegalArgumentException expected, val was null" ) ; }
catch ( IllegalArgumentException e ) {}
bs.set ( var, val1 ) ;
assertTrue ( val1 == bs.get ( var ) ) ;
bs.set ( var, val2 ) ;
assertTrue ( val2 == bs.get ( var ) ) ;
}
/**
* Unit test for {@link IBindingSet#get(IVariable)}
*/
public void testGet ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
IBindingSet bs = newBindingSet ( new IVariable [] { var1 }, new IConstant [] { val1 } ) ;
try { bs.get ( null ) ; fail ( "IllegalArgumentException expected, var was null" ) ; }
catch ( IllegalArgumentException e ) {}
assertTrue ( val1 == bs.get ( var1 ) ) ;
assertTrue ( null == bs.get ( var2 ) ) ;
}
/**
* Unit test for {@link IBindingSet#clear(IVariable)}
*/
public void testClear ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
IBindingSet bs = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val2 } ) ;
try { bs.clear ( null ) ; fail ( "IllegalArgumentException expected, var was null" ) ; }
catch ( IllegalArgumentException e ) {}
bs.clear ( var1 ) ;
assertTrue ( null == bs.get ( var1 ) ) ;
assertTrue ( val2 == bs.get ( var2 ) ) ;
bs.clear ( var2 ) ;
assertTrue ( null == bs.get ( var2 ) ) ;
assertTrue ( 0 == bs.size () ) ;
}
/**
* Unit test for {@link IBindingSet#clearAll()}
*/
public void testClearAll ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
IBindingSet bs = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val2 } ) ;
bs.clearAll () ;
assertTrue ( null == bs.get ( var1 ) ) ;
assertTrue ( null == bs.get ( var2 ) ) ;
assertTrue ( 0 == bs.size () ) ;
}
/**
* Unit test for {@link IBindingSet#size()}
*/
public void testSize ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
IBindingSet bs = newBindingSet ( 2 ) ;
assertTrue ( 0 == bs.size () ) ;
bs.set ( var1, val1 ) ;
bs.set ( var2, val2 ) ;
assertTrue ( 2 == bs.size () ) ;
bs.clear ( var2 ) ;
assertTrue ( 1 == bs.size () ) ;
}
/**
* Unit test for {@link IBindingSet#iterator()}
*/
public void testIterator ()
{
final Var<?> var1 = Var.var("a");
final Var<?> var2 = Var.var("b");
final Constant<Integer> val1 = new Constant<Integer>(1);
final Constant<Integer> val2 = new Constant<Integer>(2);
final IBindingSet bs = newBindingSet(//
new IVariable[] { var1, var2 },//
new IConstant[] { val1, val2 }//
);
int nvisited = 0 ;
for (Iterator<Map.Entry<IVariable, IConstant>> i = bs.iterator(); i
.hasNext();) {
final Map.Entry<IVariable, IConstant> e = i.next();
final IVariable<?> var = e.getKey();
if ( var1 == var ) assertTrue ( "wrong value", val1 == e.getValue () ) ;
else if ( var2 == var ) assertTrue ( "wrong value", val2 == e.getValue () ) ;
else fail ( "unexpected variable: " + var ) ;
// try {
// i.remove();
// fail("UnsupportedOperationException expected, iterator remove");
// } catch (UnsupportedOperationException ex) {
// }
i.remove();
nvisited++;
}
assertEquals("size", 2, nvisited);
// Should be empty afterwards.
assertEquals(newBindingSet(//
new IVariable[] {},//
new IConstant[] {}//
), bs);
}
/**
* Unit test for {@link IBindingSet#vars()}
*/
public void testVars ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
IBindingSet bs = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val2 } ) ;
int n = 0 ;
for ( Iterator<IVariable> i = bs.vars (); i.hasNext (); )
{
IVariable<?> var = i.next () ;
if ( var1 != var && var2 != var )
fail ( "unexpected variable: " + var ) ;
try { i.remove () ; fail ( "UnsupportedOperationException expected, iterator remove" ) ; }
catch ( UnsupportedOperationException e ) {}
n++ ;
}
assertTrue ( "wrong count", 2 == n ) ;
}
/**
* Unit test for {@link IBindingSet#copy(IVariable[])}
*/
public void testCopy ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Var<?> var3 = Var.var ( "c" ) ;
Var<?> var4 = Var.var ( "d" ) ;
Var<?> var5 = Var.var ( "e" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
Constant<Integer> val3 = new Constant<Integer> ( 3 ) ;
Constant<Integer> val4 = new Constant<Integer> ( 4 ) ;
Constant<Integer> val5 = new Constant<Integer> ( 5 ) ;
IBindingSet bs = newBindingSet ( new IVariable [] { var1, var2, var3, var4, var5 }
, new IConstant [] { val1, val2, val3, val4, val5 }
) ;
assertEqual(
bs.copy(null/* variablesToKeep */), //
new IVariable[] { var1, var2, var3, var4, var5 },
new IConstant[] { val1, val2, val3, val4, val5 }//
);
IBindingSet bs2 = bs.copy ( new IVariable [] { var1, var3, var5 } ) ;
assertTrue ( 3 == bs2.size () ) ;
for ( IVariable<?> v : new IVariable [] { var1, var3, var5 } )
assertTrue ( bs2.get ( v ).equals ( bs.get ( v ) ) ) ;
}
/**
* Unit test for {@link IBindingSet#equals(Object)}
*/
public void testEquals ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Var<?> var3 = Var.var ( "c" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
Constant<Integer> val3 = new Constant<Integer> ( 3 ) ;
IBindingSet bs1 = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val2 } ) ;
IBindingSet bs2 = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val2 } ) ;
IBindingSet bs3 = newBindingSet ( new IVariable [] { var2, var1 }, new IConstant [] { val2, val1 } ) ;
IBindingSet bs4 = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val3 } ) ;
IBindingSet bs5 = newBindingSet ( new IVariable [] { var1, var3 }, new IConstant [] { val1, val3 } ) ;
IBindingSet bs6 = newBindingSet ( new IVariable [] { var1, var2, var3 }, new IConstant [] { val1, val2, val3 } ) ;
IBindingSet bs7 = newBindingSet ( new IVariable [] { var1 }, new IConstant [] { val1 } ) ;
assertTrue ( "expected equal: same bindings, same order", bs1.equals ( bs2 ) ) ;
assertTrue ( "expected equal: same bindings, different order", bs1.equals ( bs3 ) ) ;
assertTrue ( "expected not equal: different value", !bs1.equals ( bs4 ) ) ;
assertTrue ( "expected not equal: different variable", !bs1.equals ( bs5 ) ) ;
assertTrue ( "expected not equal: subsetOf ( this, that )", !bs1.equals ( bs6 ) ) ;
assertTrue ( "expected not equal: subsetOf ( that, this )", !bs1.equals ( bs7 ) ) ;
}
/**
* Unit test for {@link IBindingSet#hashCode()}
*/
public void testHashCode ()
{
Var<?> var1 = Var.var ( "a" ) ;
Var<?> var2 = Var.var ( "b" ) ;
Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
IBindingSet bs1 = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val2 } ) ;
IBindingSet bs2 = newBindingSet ( new IVariable [] { var1, var2 }, new IConstant [] { val1, val2 } ) ;
IBindingSet bs3 = newBindingSet ( new IVariable [] { var2, var1 }, new IConstant [] { val2, val1 } ) ;
IBindingSet bs4 = newBindingSet ( new IVariable [] { var2 }, new IConstant [] { val2 } ) ;
assertTrue ( "expected equal: same bindings, same order", bs1.hashCode () == bs2.hashCode () ) ;
assertTrue ( "expected equal: same bindings, different order", bs1.hashCode () == bs3.hashCode () ) ;
//
// After mutation. Not sure that this really proves anything, although in most cases I guess that
// the original value of bs1.hasCode () will not equal the subsequent value or that of bs4.hashCode ()
//
bs1.clear ( var1 ) ;
assertTrue ( "expected equal: same bindings after mutation", bs1.hashCode () == bs4.hashCode () ) ;
}
// /*
// * push()/pop() tests.
// *
// * In addition to testing push() and pop(), we have to test that copy() and
// * clone() operate correctly in the presence of nested symbol tables, and
// * that the visitation patterns for the bindings operate correctly when
// * there are nested symbol tables. For example, if there "y" is bound at
// * level zero, a push() is executed, and then "x" is bound at level one. The
// * visitation pattern must visit both "x" and "y".
// */
//
// public void test_pushPop1() {
//
// final Var<?> var1 = Var.var("var1"); // visible and bound in query and subquery.
// final Var<?> var2 = Var.var("var2"); // visible only in subquery and not projected.
// final Var<?> var3 = Var.var("var3"); // visible in query and subquery; bound in subquery.
// final Var<?> var4 = Var.var("var4"); // visible and bound only in query
//
// final Constant<Integer> val1 = new Constant<Integer>(1);
// final Constant<Integer> val2 = new Constant<Integer>(2);
// final Constant<Integer> val3 = new Constant<Integer>(3);
// final Constant<Integer> val4 = new Constant<Integer>(4);
// final Constant<Integer> val4a = new Constant<Integer>(40);
//
// // the "projected" variables.
// final IVariable<?>[] vars = new IVariable[] { var1, var3 };
//
// final IBindingSet bs1 = newBindingSet(4/* size */);
//
// /*
// * bind var1 in the base symbol table.
// */
// bs1.set(var1, val1);
// bs1.set(var4, val4);
// assertEqual(bs1, new IVariable[] { var1, var4 }, new IConstant[] { val1, val4 });
//
// /*
// * push a symbol table onto the stack
// */
// bs1.push(vars);
//
// // verify initial symbol table for subquery.
// assertEqual(bs1, new IVariable[] { var1 }, new IConstant[] { val1 });
//
// // bind an unbound variables.
// bs1.set(var2, val2);
// bs1.set(var3, val3);
// bs1.set(var4, val4a); // note: variable and binding are distinct in this scope.
// assertEqual(bs1, new IVariable[] { var1, var2, var3, var4 }, new IConstant[] {
// val1, val2, val3, val4a });
//
// // verify clone shows the same symbol table.
// final IBindingSet copy = bs1.clone();
// assertEqual(copy, new IVariable[] { var1, var2, var3, var4 }, new IConstant[] {
// val1, val2, val3, val4a });
// assertEquals(bs1, copy);
//
// // pop the stack.
// bs1.pop(vars);
//
// // verify projected variables were copied and local vars discarded.
// assertEqual(bs1, new IVariable[] { var1, var3, var4 }, new IConstant[] {
// val1, val3, val4 });
//
// // verify copy was not effected.
// assertEqual(copy, new IVariable[] { var1, var2, var3, var4 }, new IConstant[] {
// val1, val2, val3, val4a });
//
// copy.pop(vars);
//
// // verify projected variables were copied and local vars discarded.
// assertEqual(bs1, new IVariable[] { var1, var3, var4 }, new IConstant[] {
// val1, val3, val4 });
//
// // copy and original should now be equal again.
// assertEquals(bs1, copy);
//
// /*
// * Verify that we can not pop() off the last symbol table in the stack.
// */
// try {
// bs1.pop(vars);
// fail("Expecting: " + IllegalStateException.class);
// } catch (IllegalStateException ex) {
// if (log.isInfoEnabled())
// log.info("Ignoring expected exception: " + ex);
// }
//
// }
public void test_serialization() {
final Var<?> var1 = Var.var ( "a" ) ;
final Var<?> var2 = Var.var ( "b" ) ;
final Constant<Integer> val1 = new Constant<Integer> ( 1 ) ;
final Constant<Integer> val2 = new Constant<Integer> ( 2 ) ;
final IBindingSet bs1 = newBindingSet(2/* size */);
bs1.set(var1, val1);
bs1.set(var2, val2);
assertEqual(bs1, new IVariable[] { var1, var2 }, new IConstant[] {
val1, val2 });
final IBindingSet bs2 = (IBindingSet) SerializerUtil
.deserialize(SerializerUtil.serialize(bs1));
assertEquals(bs1, bs2);
}
/*
* Hooks for testing specific implementations.
*/
protected abstract IBindingSet newBindingSet ( IVariable<?> vars [], IConstant<?> vals [] ) ;
protected abstract IBindingSet newBindingSet ( int size ) ;
/**
* Compare actual and expected, where the latter is expressed using
* (vars,vals).
* <p>
* Note: This does not follow the junit pattern for asserts, which puts the
* expected data first.
*
* @param actual
* @param vars
* @param vals
*/
protected void assertEqual(final IBindingSet actual,
final IVariable<?> vars[], final IConstant<?> vals[]) {
assertEquals("size", actual.size(), vars.length);
for (int i = 0; i < vars.length; i++) {
if (vals[i] != actual.get(vars[i])) {
assertEquals(vars[i].toString(), vals[i], actual.get(vars[i]));
}
}
}
protected void assertEquals(IBindingSet expected, IBindingSet actual) {
// expected variables in some order.
final Iterator<IVariable> evars = expected.vars();
// actual variables in some order (the order MAY be different).
final Iterator<IVariable> avars = actual.vars();
while(evars.hasNext()) {
// Some variable for which we expect a binding.
final IVariable evar = evars.next();
if(!avars.hasNext()) {
fail("actual does not bind enough variables.");
}
// consume and ignore actual variable since the order may differ
avars.next();
// The expected binding for some variable.
final IConstant eval = expected.get(evar);
// The actual binding for the same variable.
final IConstant aval = actual.get(evar);
// Verify that the bound values compare as equals.
assertEquals(evar.getName(), eval, aval);
}
if(avars.hasNext()) {
fail("actual binds more variables than expected.");
}
}
}