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