package jeql.command.test;
import jeql.api.command.Command;
import jeql.api.error.JeqlException;
import jeql.api.row.Row;
import jeql.api.row.RowIterator;
import jeql.api.row.RowIteratorComparator;
import jeql.api.row.RowList;
import jeql.api.row.RowSchema;
import jeql.api.table.Table;
import jeql.engine.Scope;
import jeql.util.TypeUtil;
/**
* Tests objects/tables/columns for equality,
* and throws an exception on failure.
* If a single table is supplied, tests that it has two columns which
* contain equal values in each row.
*
* @author Martin Davis
*
*/
public class AssertEqualCommand
implements Command
{
private TableMatcher matcher = new TableMatcher();
//private Table tbl;
private Object val;
private Object expected;
public AssertEqualCommand() {
}
public void setMatchColumnNames(boolean matchColNames)
{
matcher.setMatchColumnNames(matchColNames);
}
public void setValue(Object val)
{
this.val = val;
}
public void setExpected(Object expected)
{
this.expected = expected;
}
/*
public void setTable(Table tbl)
{
this.tbl = tbl;
}
*/
public void setDefault(Object val)
{
this.val = val;
}
public void execute(Scope scope)
{
if (val instanceof Table && expected == null) {
checkEqual((Table) val);
return;
}
if (val instanceof Table) {
checkEqual((Table) val, (Table) expected);
}
else
checkEqual(val, expected);
}
private void checkEqual(Table t)
{
String msg = checkColumnsEqual(t);
if (msg == null) return;
reportNotEqualError(msg);
}
private String checkColumnsEqual(Table t)
{
RowList rs = t.getRows();
RowSchema schema = rs.getSchema();
if (schema.getType(0) != schema.getType(1)) {
return "Column types do not match";
}
RowIterator it = rs.iterator();
while (true) {
Row row = it.next();
if (row == null) break;
Object v0 = row.getValue(0);
Object v1 = row.getValue(1);
if (! TypeUtil.isEqual(v0, v1)) {
return "Values do not match (" + v0 + ", " + v1 + ")";
}
}
return null;
}
private void checkEqual(Table t1, Table t2)
{
boolean isEqual = matcher.match(t1, t2);
String msg = matcher.getErrorMsg();
if (isEqual) return;
reportNotEqualError(msg);
}
private void checkEqual(Object o1, Object o2)
{
if (o1 == null && o2 == null) return;
if (o1 != null && o2 != null) {
if (o1.getClass() == o2.getClass()) {
boolean isEqual = TypeUtil.isEqual(o1, o2);
if (isEqual) return;
}
}
reportNotEqualError("Values do not match (" + o1 + ", " + o2 + ")");
}
private void reportNotEqualError(String msg)
{
String baseMsg = "AssertEqual: Value does not equal Expected Value. ";
String errMsg = baseMsg;
if (msg != null && msg.length() > 0) {
errMsg = baseMsg + " [Cause: " + msg + "]";
}
throw new JeqlException(errMsg);
}
private static class TableMatcher
{
// default is to not match column names
private boolean matchColNames = false;
private String errorMsg = "";
private NormalizingValueComparator valueComp = new NormalizingValueComparator();
public TableMatcher()
{
}
public void setMatchColumnNames(boolean matchColNames)
{
this.matchColNames = matchColNames;
}
public String getErrorMsg() { return errorMsg; }
public boolean match(Table t1, Table t2)
{
if (t1.size() != t2.size()) {
errorMsg = "Table schema sizes are not equal";
return false;
}
if (matchColNames) {
for (int i = 0; i < t1.size(); i++) {
if (! t1.getColumnName(i).equals(t2.getColumnName(i))) {
errorMsg = "Column names are different "
+ "(t1." + t1.getColumnName(i)
+ " vs "
+ "t2." + t2.getColumnName(i)
+ ")";
return false;
}
}
}
if (! t1.getRows().getSchema().equals(t2.getRows().getSchema())) {
errorMsg = "Schemas are not equal";
return false;
}
RowIteratorComparator rowStrComp = new RowIteratorComparator(valueComp);
boolean isRowsEqual = rowStrComp.compare(
t1.getRows().iterator(),
t2.getRows().iterator()) == 0;
if (! isRowsEqual) {
errorMsg = "Rows are not equal";
}
return isRowsEqual;
}
}
}