1 /*------------------------------------------------------------------------------
2 Name: Sql92SelectorTest.java
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 ------------------------------------------------------------------------------*/
6 package org.xmlBlaster.test.classtest;
7
8 import java.io.BufferedReader;
9 import java.io.InputStreamReader;
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.Map;
13
14 import junit.framework.TestCase;
15
16 import java.util.logging.Logger;
17 import java.util.logging.Level;
18 import org.xmlBlaster.util.Global;
19 import org.xmlBlaster.util.XmlBlasterException;
20 import org.xmlBlaster.util.lexical.LikeOpWrapper;
21 import org.xmlBlaster.util.lexical.Sql92Selector;
22 import org.xmlBlaster.util.qos.ClientProperty;
23
24 /**
25 * Test ClientProperty.
26 * <p />
27 * All methods starting with 'test' and without arguments are invoked automatically
28 * <p />
29 * Invoke: java -Djava.compiler= junit.textui.TestRunner -noloading org.xmlBlaster.test.classtest.Sql92SelectorTest
30 * @see org.xmlBlaster.util.qos.ClientProperty
31 * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/engine.qos.clientProperty.html">The client.qos.clientProperty requirement</a>
32 */
33 public class Sql92SelectorTest extends TestCase {
34
35 private final static String ME = "Sql92SelectorTest";
36 protected Global glob;
37 private static Logger log = Logger.getLogger(Sql92SelectorTest.class.getName());
38 private Map[] dataSet;
39 private boolean[][] resultSet;
40 private String[] querySet;
41
42 public Sql92SelectorTest(String name) {
43 this(null, name);
44 }
45
46 public Sql92SelectorTest(Global global, String name) {
47 super(name);
48 if (global == null) this.glob = Global.instance();
49 else this.glob = global;
50
51 }
52
53 protected void setUp() {
54 setupDataSets();
55 }
56
57 protected void tearDown() {
58 }
59
60 /**
61 * Change this method if you want to add a new data set to be checked
62 *
63 */
64 private void setupDataSets() {
65 ArrayList datas = new ArrayList();
66 Map map;
67 String encoding = null;
68 ClientProperty prop1, prop2, prop3;
69 prop1 = new ClientProperty("age" , "integer", encoding, "23" );
70 prop2 = new ClientProperty("city" , null, encoding, "London" );
71 prop3 = new ClientProperty("amount", "double", encoding, "100.1234567");
72
73 // set : 0 (0:0:0)
74 map = new HashMap();
75 datas.add(map);
76
77 // set : 1 (0:0:1)
78 map = new HashMap();
79 map.put("amount", prop3);
80 datas.add(map);
81
82 // set : 2 (0:1:0)
83 map = new HashMap();
84 map.put("city" , prop2);
85 datas.add(map);
86
87 // set : 3 (0:1:1)
88 map = new HashMap();
89 map.put("city" , prop2);
90 map.put("amount", prop3);
91 datas.add(map);
92
93 // set : 4 (1:0:0)
94 map = new HashMap();
95 map.put("age" , prop1);
96 datas.add(map);
97
98 // set : 5 (1:0:1)
99 map = new HashMap();
100 map.put("age" , prop1);
101 map.put("amount", prop3);
102 datas.add(map);
103
104 // set : 6 (1:1:0)
105 map = new HashMap();
106 map.put("age" , prop1);
107 map.put("city" , prop2);
108 datas.add(map);
109
110 // set : 7 (1:1:1)
111 map = new HashMap();
112 map.put("age" , prop1);
113 map.put("city" , prop2);
114 map.put("amount", prop3);
115 datas.add(map);
116 this.dataSet = (Map[])datas.toArray(new Map[datas.size()]);
117
118 }
119
120 /**
121 * Checks if the provided data sets, the queries and the results are
122 * consistent with eachother (this is invoked before starting the real testing)
123 */
124 private void consistencyCheck() {
125 int numData = this.dataSet.length;
126 int numQueries = this.querySet.length;
127 int numResults = this.resultSet.length;
128 assertEquals("The number of queries '" + numQueries + "' differes from the number of results '" + numResults + "'", numQueries, numResults);
129 for (int i=0; i < numResults; i++) {
130 assertEquals("The number of results for query '" + i + "' is wrong", numData, this.resultSet[i].length);
131 }
132 }
133
134 private String getDataAsText(int pos) {
135 Map map = this.dataSet[pos];
136 StringBuffer buffer = new StringBuffer("[");
137 Object[] keys = map.keySet().toArray();
138 for (int i=0; i < keys.length; i++) {
139 if (i != 0) buffer.append(";");
140 buffer.append(keys[i]).append("=");
141 ClientProperty cp = (ClientProperty)map.get(keys[i]);
142 String tmp = "null";
143 if (cp != null) tmp = cp.getStringValue();
144 buffer.append(tmp);
145 }
146 buffer.append("]");
147 return buffer.toString();
148 }
149
150 /**
151 * This is the fully automatized initial (general) test. Since it is
152 * difficult to predict all possible problems, additional tests should
153 * be added once a bug is encountered. For each such bug an own test
154 * method should be added.
155 */
156 private void selectorPerformTest() {
157 // for each data set one selector
158 consistencyCheck();
159 /*
160 Sql92Selector[] selectors = new Sql92Selector[this.dataSet.length];
161 for (int i=0; i < this.dataSet.length; i++) {
162 if (log.isLoggable(Level.FINE)) log.fine("testSelectorStandard: creating selector nr. " + i);
163 selectors[i] = new Sql92Selector(this.glob);
164 }
165 */
166 Sql92Selector selector = new Sql92Selector(this.glob);
167
168 for (int i=0; i < this.querySet.length; i++) {
169 String query = this.querySet[i];
170 log.info("testSelectorStandard: process query '" + query + "'");
171 boolean[] shouldAnswers = this.resultSet[i];
172 for (int j=0; j < this.dataSet.length; j++) {
173 if (log.isLoggable(Level.FINE)) log.fine("testSelectorStandard: query '" + query + "' on set '" + getDataAsText(j));
174 try {
175 boolean response = selector.select(query, this.dataSet[j]);
176 assertEquals("wrong answer for query '" + i + "'\"" + query + "\" on set '" + j + "' " + getDataAsText(j), shouldAnswers[j], response);
177 }
178 catch (XmlBlasterException ex) {
179 ex.printStackTrace();
180 assertTrue("An exception should not occur on query '" + i + "'\"" + query + "\" for dataset " + getDataAsText(j), false);
181 }
182 }
183 }
184 }
185
186
187 /**
188 *
189 * @return the milliseconds per request
190 */
191 private void performanceCheck() {
192 if (log.isLoggable(Level.FINER)) log.finer("performanceCheck");
193 // for each data set one selector
194 consistencyCheck();
195 /*
196 Sql92Selector[] selectors = new Sql92Selector[this.dataSet.length];
197 for (int i=0; i < this.dataSet.length; i++) {
198 selectors[i] = new Sql92Selector(this.glob);
199 }
200 */
201 Sql92Selector selector = new Sql92Selector(this.glob);
202 try {
203 int kmax = 100;
204 long t0 = System.currentTimeMillis();
205 for (int k=0; k < kmax; k++) {
206 for (int i=0; i < this.querySet.length; i++) {
207 String query = this.querySet[i];
208 for (int j=0; j < this.dataSet.length; j++) {
209 boolean response = selector.select(query, this.dataSet[j]);
210 }
211 }
212 }
213 long dt = System.currentTimeMillis() - t0;
214 int nmax = kmax * this.dataSet.length * this.querySet.length;
215 log.info("performance: '" + nmax + "' requests in '" + dt + "' ms");
216 double ret = 1.0 * dt / nmax;
217 log.info("performance: '" + ret + "' ms per request");
218 log.info("performance: '" + ((int)(1000.0 / ret)) + "' request per second (rps)");
219 }
220 catch (XmlBlasterException ex) {
221 ex.printStackTrace();
222 }
223 }
224
225
226
227 public void interactive() {
228 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
229 System.out.println("\n- input new query: ");
230 while (true) {
231 try {
232 String line = br.readLine();
233 if (line == null) break;
234 System.out.print("Result: ");
235 for (int i=0; i < this.dataSet.length; i++) {
236 Sql92Selector selector = new Sql92Selector(this.glob);
237 boolean ret = selector.select(line, this.dataSet[i]);
238 System.out.print(ret + "\t");
239 }
240 }
241 catch (Exception ex) {
242 ex.printStackTrace();
243 }
244 System.out.println("\n- input new query: ");
245 }
246 }
247
248
249 // THE TESTING METHODS COME HERE .....
250
251 /**
252 * Tests the outer logical operators AND, OR, NOT with and without brackets.
253 * For each data there must be a boolean value telling if the result is true or false
254 */
255 public void testLogicalOps() {
256 ArrayList queries = new ArrayList();
257 ArrayList results = new ArrayList();
258 boolean t = true;
259 boolean f = false;
260
261 // query 0
262 queries.add("age=23 AND city='London' AND amount<200.2");
263 /* helper 0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.0.1 1.1.0 1.1.1 */
264 results.add(new boolean[] {false, false, false, false, false, false, false, true });
265
266 // query 1
267 queries.add("age=23 OR city='London' OR amount < 200.2");
268 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
269 results.add(new boolean[] {f||f||f, f||f||t, f||t||f, f||t||t, t||f||f, t||f||t, t||t||f, t||t||t });
270
271 // query 2
272 queries.add("age=23 OR city='London' AND amount < 200.2");
273 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
274 results.add(new boolean[] {f||f&&f, f||f&&t, f||t&&f, f||t&&t, t||f&&f, t||f&&t, t||t&&f, t||t&&t });
275
276 // query 3
277 queries.add("age=23 OR city='London' AND amount < 200.2");
278 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
279 results.add(new boolean[] {f||f&&f, f||f&&t, f||t&&f, f||t&&t, t||f&&f, t||f&&t, t||t&&f, t||t&&t });
280
281 // query 4
282 queries.add("(age=23 AND city='London') OR amount < 200.2");
283 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
284 results.add(new boolean[] {f&&f||f, f&&f||t, f&&t||f, f&&t||t, t&&f||f, t&&f||t, t&&t||f, t&&t||t });
285
286 // query 5
287 queries.add("age=23 OR (city='London' AND amount < 200.2)");
288 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
289 results.add(new boolean[] {f||(f&&f), f||(f&&t), f||(t&&f), f||(t&&t), t||(f&&f), t||(f&&t), t||(t&&f), t||(t&&t) });
290
291 // query 6
292 queries.add("NOT age=23 OR (city='London' AND amount < 200.2)");
293 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0 , 1 0 1 , 1 1 0 , 1 1 1 */
294 results.add(new boolean[] {!f||(f&&f), !f||(f&&t), !f||(t&&f), !f||(t&&t), !t||(f&&f), !t||(f&&t), !t||(t&&f), !t||(t&&t) });
295
296 // query 7
297 queries.add("age=23 OR NOT (city='London' AND amount < 200.2)");
298 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
299 results.add(new boolean[] {f||!(f&&f), f||!(f&&t), f||!(t&&f), f||!(t&&t), t||!(f&&f), t||!(f&&t), t||!(t&&f), t||!(t&&t) });
300
301 // query 8
302 queries.add("(age=23 OR NOT (city='London' AND amount < 200.2))");
303 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
304 results.add(new boolean[] {f||!(f&&f), f||!(f&&t), f||!(t&&f), f||!(t&&t), t||!(f&&f), t||!(f&&t), t||!(t&&f), t||!(t&&t) });
305
306 // query 9
307 queries.add("NOT (age=23 OR NOT (city='London' AND amount < 200.2))");
308 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
309 results.add(new boolean[] {!(f||!(f&&f)), !(f||!(f&&t)), !(f||!(t&&f)), !(f||!(t&&t)), !(t||!(f&&f)), !(t||!(f&&t)), !(t||!(t&&f)), !(t||!(t&&t)) });
310
311 // query 10
312 queries.add("NOT (age=23 OR NOT (city='London' AND (amount < 200.2)))");
313 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
314 results.add(new boolean[] {!(f||!(f&&f)), !(f||!(f&&t)), !(f||!(t&&f)), !(f||!(t&&t)), !(t||!(f&&f)), !(t||!(f&&t)), !(t||!(t&&f)), !(t||!(t&&t)) });
315
316 // query 11
317 queries.add("age=23 OR NOT ((city='London') AND amount < 200.2)");
318 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
319 results.add(new boolean[] {f||!(f&&f), f||!(f&&t), f||!(t&&f), f||!(t&&t), t||!(f&&f), t||!(f&&t), t||!(t&&f), t||!(t&&t) });
320
321 // query 12
322 queries.add("age=23 OR NOT ((city='London') AND (amount < 200.2))");
323 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
324 results.add(new boolean[] {f||!(f&&f), f||!(f&&t), f||!(t&&f), f||!(t&&t), t||!(f&&f), t||!(f&&t), t||!(t&&f), t||!(t&&t) });
325
326 // query 13
327 queries.add("age=23 OR NOT ((city='London') AND NOT(amount < 200.2))");
328 /* helper 0 0 0 , 0 0 1 , 0 1 0 , 0 1 1 , 1 0 0, 1 0 1 , 1 1 0 , 1 1 1 */
329 results.add(new boolean[] {f||!(f&&!f), f||!(f&&!t), f||!(t&&!f), f||!(t&&!t), t||!(f&&!f), t||!(f&&!t), t||!(t&&!f), t||!(t&&!t) });
330
331 this.querySet = (String[])queries.toArray(new String[queries.size()]);
332 this.resultSet = (boolean[][])results.toArray(new boolean[results.size()][]);
333 // here the real testing is performed (the algorithm is the same for all tests)
334 selectorPerformTest();
335 }
336
337
338 /**
339 * Tests the NULL and NOT NULL statements.
340 * For each data there must be a boolean value telling if the result is true or false
341 */
342 public void testNullOps() {
343 ArrayList queries = new ArrayList();
344 ArrayList results = new ArrayList();
345 boolean t = true;
346 boolean f = false;
347
348 // query 0
349 queries.add("age IS NULL OR city IS NULL OR amount IS NULL");
350 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
351 results.add(new boolean[] {t||t||t, t||t||f, t||f||t, t||f||f, f||t||t, f||t||f, f||f||t, f||f||f });
352
353 // query 1
354 queries.add("age IS NULL AND city IS NULL AND amount IS NULL");
355 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
356 results.add(new boolean[] {t&&t&&t, t&&t&&f, t&&f&&t, t&&f&&f, f&&t&&t, f&&t&&f, f&&f&&t, f&&f&&f });
357
358 // query 2
359 queries.add("age IS NOT NULL OR city IS NOT NULL OR amount IS NOT NULL");
360 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
361 results.add(new boolean[] {f||f||f, f||f||t, f||t||f, f||t||t, t||f||f, t||f||t, t||t||f, t||t||t });
362
363 // query 3
364 queries.add("age IS NOT NULL AND city IS NOT NULL AND amount IS NOT NULL");
365 /* helper 0 0 0, 0 0 1, 0 1 0, 0 1 1, 1 0 0 1 0 1 1 1 0 1 1 1 */
366 results.add(new boolean[] {f&&f&&f, f&&f&&t, f&&t&&f, f&&t&&t, t&&f&&f, t&&f&&t, t&&t&&f, t&&t&&t });
367
368 this.querySet = (String[])queries.toArray(new String[queries.size()]);
369 this.resultSet = (boolean[][])results.toArray(new boolean[results.size()][]);
370 // here the real testing is performed (the algorithm is the same for all tests)
371 selectorPerformTest();
372 }
373
374 /**
375 * Tests the outer logical operators AND, OR, NOT with and without brackets.
376 * For each data there must be a boolean value telling if the result is true or false
377 */
378 public void testArithmeticOps() {
379 ArrayList queries = new ArrayList();
380 ArrayList results = new ArrayList();
381 boolean t = true;
382 boolean f = false;
383
384 // query 0
385 queries.add("age = 15+8 AND amount < 300.0+10.0");
386 /* helper 0 0, 0 1, 0 0, 0 1, 1 0 1 1 1 0 1 1 */
387 results.add(new boolean[] {f&&f, f&&t, f&&f, f&&t, t&&f, t&&t, t&&f, t&&t });
388
389 // query 1
390 queries.add("age = 26-3 AND amount < 300.0-10.0");
391 /* helper 0 0, 0 1, 0 0, 0 1, 1 0 1 1 1 0 1 1 */
392 results.add(new