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