package org.test4j.module.dbfit.fixture.fit; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import org.test4j.module.database.environment.normalise.NameNormaliser; import org.test4j.module.dbfit.exception.NoMatchingRowFoundException; import org.test4j.module.dbfit.model.DataColumn; import org.test4j.module.dbfit.model.DataRow; import org.test4j.module.dbfit.model.DataTable; import org.test4j.module.dbfit.model.DbTypeAdapter; import org.test4j.module.dbfit.model.SymbolAccessQueryBinding; import org.test4j.module.dbfit.utility.ParseArg; import org.test4j.tools.commons.PrimitiveHelper; import fit.Binding; import fit.ColumnFixture; import fit.Fixture; import fit.Parse; @SuppressWarnings({ "rawtypes" }) public abstract class RowSetFixture extends ColumnFixture { private DataTable dt; private DataRow currentRow; private class CurrentDataRowTypeAdapter extends DbTypeAdapter { public String key; public CurrentDataRowTypeAdapter(String key, Class type) throws NoSuchMethodException { target = null; method = CurrentDataRowTypeAdapter.class.getMethod("get", new Class[] {}); fixture = RowSetFixture.this; this.type = type; this.key = key; } public Object get() { return currentRow.get(key); } public Object invoke() throws IllegalAccessException { return get(); } @Override public boolean equals(Object a, Object b) { if (a instanceof Number && b instanceof Number) { boolean isEqual = PrimitiveHelper.doesEqual((Number) a, (Number) b); return isEqual; } else { return super.equals(a, b); } } } private int findColumn(String name) throws Exception { // todo: implement non-key String normalisedName = NameNormaliser.normaliseName(name); for (int i = 0; i < dt.getColumns().size(); i++) { String colName = dt.getColumns().get(i).getName(); if (normalisedName.equals(NameNormaliser.normaliseName(colName))) return i; } throw new Exception("Unknown column " + normalisedName); } // if element not 0, fixture column -> result set column index private String[] keyColumns; protected void bind(Parse heads) { try { columnBindings = new Binding[heads.size()]; keyColumns = new String[heads.size()]; for (int i = 0; heads != null; i++, heads = heads.more) { String name = heads.text(); columnBindings[i] = new SymbolAccessQueryBinding(); int idx = findColumn(name); String columnName = dt.getColumns().get(idx).getName(); if (!name.endsWith("?")) keyColumns[i] = columnName; columnBindings[i].adapter = new CurrentDataRowTypeAdapter(columnName, getJavaClassForColumn(dt .getColumns().get(idx))); } } catch (Throwable sqle) { exception(heads, sqle); } } protected abstract DataTable getDataTable() throws Exception; protected abstract boolean isOrdered(); public void doRows(Parse rows) { try { dt = getDataTable(); super.doRows(rows); addSurplusRows(rows.last()); } catch (Exception sqle) { sqle.printStackTrace(); exception(rows, sqle); } } public void doRow(Parse row) { try { if (isOrdered()) { currentRow = dt.findFirstUnprocessedRow(); } else { currentRow = findMatchingRow(row); } super.doRow(row); currentRow.markProcessed(); } catch (NoMatchingRowFoundException e) { row.parts.addToBody(Fixture.gray(" missing")); // super.doRow(row); wrong(row); } } /** * 覆盖父方法,是因为数据中含有变量的话,需要回显<br> * 例如: @{name} = your value */ @Override public void wrong(Parse row) { if (row != null && row.parts != null) { Parse cells = row.parts; try { for (; cells != null;) { ParseArg.parseCellValue(cells); cells = cells.more; } } catch (Throwable e) { exception(cells, e); } } super.wrong(row); } public DataRow findMatchingRow(Parse row) throws NoMatchingRowFoundException { Parse columns = row.parts; Map<String, Object> keyMap = new HashMap<String, Object>(); for (int i = 0; i < keyColumns.length; i++, columns = columns.more) { if (keyColumns[i] != null) { try { Object value = columnBindings[i].adapter.parse(columns.text()); if (value instanceof InputStream) { value = columns.text(); } keyMap.put(keyColumns[i], value); } catch (Throwable e) { exception(columns, e); } } } return dt.findMatching(keyMap); } private void addSurplusRows(Parse rows) { Parse lastRow = rows; for (DataRow dr : dt.getUnprocessedRows()) { Parse newRow = new Parse("tr", null, null, null); lastRow.more = newRow; lastRow = newRow; try { currentRow = dr; // for getting Parse firstCell = new Parse("td", String.valueOf(columnBindings[0].adapter.invoke()), null, null); newRow.parts = firstCell; firstCell.addToBody(Fixture.gray(" surplus")); wrong(firstCell); for (int i = 1; i < columnBindings.length; i++) { Parse nextCell = new Parse("td", String.valueOf(columnBindings[i].adapter.invoke()), null, null); firstCell.more = nextCell; firstCell = nextCell; } } catch (Throwable e) { exception(newRow, e); } } } protected Class getJavaClassForColumn(DataColumn col) { try { return Class.forName(col.getJavaClassName()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } }