001: // Copyright (c) 2002 Cunningham & Cunningham, Inc.
002: // Released under the terms of the GNU General Public License version 2 or later.
003:
004: package fit;
005:
006: import java.util.*;
007:
008: abstract public class RowFixture extends ColumnFixture {
009:
010: public Object results[];
011: public List missing = new LinkedList();
012: public List surplus = new LinkedList();
013:
014: public void doRows(Parse rows) {
015: try {
016: bind(rows.parts);
017: results = query();
018: match(list(rows.more), list(results), 0);
019: Parse last = rows.last();
020: last.more = buildRows(surplus.toArray());
021: mark(last.more, "surplus");
022: mark(missing.iterator(), "missing");
023: } catch (Exception e) {
024: exception(rows.leaf(), e);
025: }
026: }
027:
028: abstract public Object[] query() throws Exception; // get rows to be compared
029:
030: abstract public Class getTargetClass(); // get expected type of row
031:
032: protected void match(List expected, List computed, int col) {
033: if (col >= columnBindings.length) {
034: check(expected, computed);
035: } else if (columnBindings[col] == null) {
036: match(expected, computed, col + 1);
037: } else {
038: Map eMap = eSort(expected, col);
039: Map cMap = cSort(computed, col);
040: Set keys = union(eMap.keySet(), cMap.keySet());
041: for (Iterator i = keys.iterator(); i.hasNext();) {
042: Object key = i.next();
043: List eList = (List) eMap.get(key);
044: List cList = (List) cMap.get(key);
045: if (eList == null) {
046: surplus.addAll(cList);
047: } else if (cList == null) {
048: missing.addAll(eList);
049: } else if (eList.size() == 1 && cList.size() == 1) {
050: check(eList, cList);
051: } else {
052: match(eList, cList, col + 1);
053: }
054: }
055: }
056: }
057:
058: protected List list(Parse rows) {
059: List result = new LinkedList();
060: while (rows != null) {
061: result.add(rows);
062: rows = rows.more;
063: }
064: return result;
065: }
066:
067: protected List list(Object[] rows) {
068: List result = new LinkedList();
069: for (int i = 0; i < rows.length; i++) {
070: result.add(rows[i]);
071: }
072: return result;
073: }
074:
075: protected Map eSort(List list, int col) {
076: TypeAdapter a = columnBindings[col];
077: Map result = new HashMap(list.size());
078: for (Iterator i = list.iterator(); i.hasNext();) {
079: Parse row = (Parse) i.next();
080: Parse cell = row.parts.at(col);
081: try {
082: Object key = a.parse(cell.text());
083: bin(result, key, row);
084: } catch (Exception e) {
085: exception(cell, e);
086: for (Parse rest = cell.more; rest != null; rest = rest.more) {
087: ignore(rest);
088: }
089: }
090: }
091: return result;
092: }
093:
094: protected Map cSort(List list, int col) {
095: TypeAdapter a = columnBindings[col];
096: Map result = new HashMap(list.size());
097: for (Iterator i = list.iterator(); i.hasNext();) {
098: Object row = i.next();
099: try {
100: a.target = row;
101: Object key = a.get();
102: bin(result, key, row);
103: } catch (Exception e) {
104: // surplus anything with bad keys, including null
105: surplus.add(row);
106: }
107: }
108: return result;
109: }
110:
111: protected void bin(Map map, Object key, Object row) {
112: if (key.getClass().isArray()) {
113: key = Arrays.asList((Object[]) key);
114: }
115: if (map.containsKey(key)) {
116: ((List) map.get(key)).add(row);
117: } else {
118: List list = new LinkedList();
119: list.add(row);
120: map.put(key, list);
121: }
122: }
123:
124: protected Set union(Set a, Set b) {
125: Set result = new HashSet();
126: result.addAll(a);
127: result.addAll(b);
128: return result;
129: }
130:
131: protected void check(List eList, List cList) {
132: if (eList.size() == 0) {
133: surplus.addAll(cList);
134: return;
135: }
136: if (cList.size() == 0) {
137: missing.addAll(eList);
138: return;
139: }
140: Parse row = (Parse) eList.remove(0);
141: Parse cell = row.parts;
142: Object obj = cList.remove(0);
143: for (int i = 0; i < columnBindings.length && cell != null; i++) {
144: TypeAdapter a = columnBindings[i];
145: if (a != null) {
146: a.target = obj;
147: }
148: check(cell, a);
149: cell = cell.more;
150: }
151: check(eList, cList);
152: }
153:
154: protected void mark(Parse rows, String message) {
155: String annotation = label(message);
156: while (rows != null) {
157: wrong(rows.parts);
158: rows.parts.addToBody(annotation);
159: rows = rows.more;
160: }
161: }
162:
163: protected void mark(Iterator rows, String message) {
164: String annotation = label(message);
165: while (rows.hasNext()) {
166: ;
167: Parse row = (Parse) rows.next();
168: wrong(row.parts);
169: row.parts.addToBody(annotation);
170: }
171: }
172:
173: protected Parse buildRows(Object[] rows) {
174: Parse root = new Parse(null, null, null, null);
175: Parse next = root;
176: for (int i = 0; i < rows.length; i++) {
177: next = next.more = new Parse("tr", null,
178: buildCells(rows[i]), null);
179: }
180: return root.more;
181: }
182:
183: protected Parse buildCells(Object row) {
184: if (row == null) {
185: Parse nil = new Parse("td", "null", null, null);
186: nil.addToTag(" colspan=" + columnBindings.length);
187: return nil;
188: }
189: Parse root = new Parse(null, null, null, null);
190: Parse next = root;
191: for (int i = 0; i < columnBindings.length; i++) {
192: next = next.more = new Parse("td", " ", null, null);
193: TypeAdapter a = columnBindings[i];
194: if (a == null) {
195: ignore(next);
196: } else {
197: try {
198: a.target = row;
199: info(next, a.toString(a.get()));
200: } catch (Exception e) {
201: exception(next, e);
202: }
203: }
204: }
205: return root.more;
206: }
207: }
|