1
2
3
4 package fit;
5
6 import java.util.*;
7
8 abstract public class RowFixture extends ColumnFixture {
9
10 public Object results[];
11 public List missing = new LinkedList();
12 public List surplus = new LinkedList();
13
14
15 public void doRows(Parse rows) {
16 try {
17 bind(rows.parts);
18 results = query();
19 match(list(rows.more), list(results), 0);
20 Parse last = rows.last();
21 last.more = buildRows(surplus.toArray());
22 mark(last.more, "surplus");
23 mark(missing.iterator(), "missing");
24 } catch (Exception e) {
25 exception (rows.leaf(), e);
26 }
27 }
28
29 abstract public Object[] query() throws Exception;
30 abstract public Class getTargetClass();
31
32 protected void match(List expected, List computed, int col) {
33 if (col >= columnBindings.length) {
34 check (expected, computed);
35 } else if (columnBindings[col] == null) {
36 match (expected, computed, col+1);
37 } else {
38 Map eMap = eSort(expected, col);
39 Map cMap = cSort(computed, col);
40 Set keys = union(eMap.keySet(),cMap.keySet());
41 for (Iterator i=keys.iterator(); i.hasNext(); ) {
42 Object key = i.next();
43 List eList = (List)eMap.get(key);
44 List cList = (List)cMap.get(key);
45 if (eList == null) {
46 surplus.addAll(cList);
47 } else if (cList == null) {
48 missing.addAll(eList);
49 } else if (eList.size()==1 && cList.size()==1) {
50 check(eList, cList);
51 } else {
52 match(eList, cList, col+1);
53 }
54 }
55 }
56 }
57
58 protected List list (Parse rows) {
59 List result = new LinkedList();
60 while (rows != null) {
61 result.add(rows);
62 rows = rows.more;
63 }
64 return result;
65 }
66
67 protected List list (Object[] rows) {
68 List result = new LinkedList();
69 for (int i=0; i<rows.length; i++) {
70 result.add(rows[i]);
71 }
72 return result;
73 }
74
75 protected Map eSort(List list, int col) {
76 TypeAdapter a = columnBindings[col];
77 Map result = new HashMap(list.size());
78 for (Iterator i=list.iterator(); i.hasNext(); ) {
79 Parse row = (Parse) i.next();
80 Parse cell = row.parts.at(col);
81 try {
82 Object key = a.parse(cell.text());
83 bin(result, key, row);
84 } catch (Exception e) {
85 exception(cell, e);
86 for (Parse rest=cell.more; rest!=null; rest=rest.more) {
87 ignore(rest);
88 }
89 }
90 }
91 return result;
92 }
93
94 protected Map cSort(List list, int col) {
95 TypeAdapter a = columnBindings[col];
96 Map result = new HashMap(list.size());
97 for (Iterator i=list.iterator(); i.hasNext(); ) {
98 Object row = i.next();
99 try {
100 a.target = row;
101 Object key = a.get();
102 bin(result, key, row);
103 } catch (Exception e) {
104
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 Parse row = (Parse)rows.next();
167 wrong(row.parts);
168 row.parts.addToBody(annotation);
169 }
170 }
171
172 protected Parse buildRows(Object[] rows) {
173 Parse root = new Parse(null ,null, null, null);
174 Parse next = root;
175 for (int i=0; i<rows.length; i++) {
176 next = next.more = new Parse("tr", null, buildCells(rows[i]), null);
177 }
178 return root.more;
179 }
180
181 protected Parse buildCells(Object row) {
182 if (row == null) {
183 Parse nil = new Parse("td", "null", null, null);
184 nil.addToTag(" colspan="+columnBindings.length);
185 return nil;
186 }
187 Parse root = new Parse(null, null, null, null);
188 Parse next = root;
189 for (int i=0; i<columnBindings.length; i++) {
190 next = next.more = new Parse("td", " ", null, null);
191 TypeAdapter a = columnBindings[i];
192 if (a == null) {
193 ignore (next);
194 } else {
195 try {
196 a.target = row;
197 info(next, a.toString(a.get()));
198 } catch (Exception e) {
199 exception(next, e);
200 }
201 }
202 }
203 return root.more;
204 }
205 }