1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration.tree;
18
19 import java.util.Iterator;
20 import java.util.List;
21
22 import junit.framework.TestCase;
23
24 /***
25 * Test class for DefaultExpressionEngine.
26 *
27 * @author Oliver Heger
28 */
29 public class TestDefaultExpressionEngine extends TestCase
30 {
31 /*** Stores the names of the test nodes representing tables. */
32 private static String[] tables =
33 { "users", "documents"};
34
35 /*** Stores the types of the test table nodes. */
36 private static String[] tabTypes =
37 { "system", "application"};
38
39 /*** Test data fields for the node hierarchy. */
40 private static String[][] fields =
41 {
42 { "uid", "uname", "firstName", "lastName", "email"},
43 { "docid", "name", "creationDate", "authorID", "version"}};
44
45 /*** The object to be tested. */
46 DefaultExpressionEngine engine;
47
48 /*** The root of a hierarchy with configuration nodes. */
49 ConfigurationNode root;
50
51 protected void setUp() throws Exception
52 {
53 super.setUp();
54 root = setUpNodes();
55 engine = new DefaultExpressionEngine();
56 }
57
58 /***
59 * Tests some simple queries.
60 */
61 public void testQueryKeys()
62 {
63 checkKey("tables.table.name", "name", 2);
64 checkKey("tables.table.fields.field.name", "name", 10);
65 checkKey("tables.table[@type]", "type", 2);
66 checkKey("tables.table(0).fields.field.name", "name", 5);
67 checkKey("tables.table(1).fields.field.name", "name", 5);
68 checkKey("tables.table.fields.field(1).name", "name", 2);
69 }
70
71 /***
72 * Performs some queries and evaluates the values of the result nodes.
73 */
74 public void testQueryNodes()
75 {
76 for (int i = 0; i < tables.length; i++)
77 {
78 checkKeyValue("tables.table(" + i + ").name", "name", tables[i]);
79 checkKeyValue("tables.table(" + i + ")[@type]", "type", tabTypes[i]);
80
81 for (int j = 0; j < fields[i].length; j++)
82 {
83 checkKeyValue("tables.table(" + i + ").fields.field(" + j
84 + ").name", "name", fields[i][j]);
85 }
86 }
87 }
88
89 /***
90 * Tests querying keys that do not exist.
91 */
92 public void testQueryNonExistingKeys()
93 {
94 checkKey("tables.tablespace.name", null, 0);
95 checkKey("tables.table(2).name", null, 0);
96 checkKey("a complete unknown key", null, 0);
97 checkKey("tables.table(0).fields.field(-1).name", null, 0);
98 checkKey("tables.table(0).fields.field(28).name", null, 0);
99 checkKey("tables.table(0).fields.field().name", null, 0);
100 checkKey("connection.settings.usr.name", null, 0);
101 }
102
103 /***
104 * Tests querying nodes whose names contain a delimiter.
105 */
106 public void testQueryEscapedKeys()
107 {
108 checkKeyValue("connection..settings.usr..name", "usr.name", "scott");
109 checkKeyValue("connection..settings.usr..pwd", "usr.pwd", "tiger");
110 }
111
112 /***
113 * Tests some queries when the same delimiter is used for properties and
114 * attributes.
115 */
116 public void testQueryAttributeEmulation()
117 {
118 engine.setAttributeEnd(null);
119 engine.setAttributeStart(engine.getPropertyDelimiter());
120 checkKeyValue("tables.table(0).name", "name", tables[0]);
121 checkKeyValue("tables.table(0).type", "type", tabTypes[0]);
122 checkKey("tables.table.type", "type", 2);
123 }
124
125 /***
126 * Tests accessing the root node.
127 */
128 public void testQueryRootNode()
129 {
130 List nodes = checkKey(null, null, 1);
131 assertSame("Root node not found", root, nodes.get(0));
132 nodes = checkKey("", null, 1);
133 assertSame("Root node not found", root, nodes.get(0));
134 checkKeyValue("[@test]", "test", "true");
135 }
136
137 /***
138 * Tests a different query snytax. Sets other strings for the typical tokens
139 * used by the expression engine.
140 */
141 public void testQueryAlternativeSyntax()
142 {
143 setUpAlternativeSyntax();
144 checkKeyValue("tables/table[1]/name", "name", tables[1]);
145 checkKeyValue("tables/table[0]@type", "type", tabTypes[0]);
146 checkKeyValue("@test", "test", "true");
147 checkKeyValue("connection.settings/usr.name", "usr.name", "scott");
148 }
149
150 /***
151 * Tests obtaining keys for nodes.
152 */
153 public void testNodeKey()
154 {
155 ConfigurationNode node = root.getChild(0);
156 assertEquals("Invalid name for descendant of root", "tables", engine
157 .nodeKey(node, ""));
158 assertEquals("Parent key not respected", "test.tables", engine.nodeKey(
159 node, "test"));
160 assertEquals("Full parent key not taken into account",
161 "a.full.parent.key.tables", engine.nodeKey(node,
162 "a.full.parent.key"));
163 }
164
165 /***
166 * Tests obtaining keys when the root node is involved.
167 */
168 public void testNodeKeyWithRoot()
169 {
170 assertEquals("Wrong name for root noot", "", engine.nodeKey(root, null));
171 assertEquals("Null name not detected", "test", engine.nodeKey(root,
172 "test"));
173 }
174
175 /***
176 * Tests obtaining keys for attribute nodes.
177 */
178 public void testNodeKeyWithAttribute()
179 {
180 ConfigurationNode node = root.getChild(0).getChild(0).getAttribute(0);
181 assertEquals("Wrong attribute node", "type", node.getName());
182 assertEquals("Wrong attribute key", "tables.table[@type]", engine
183 .nodeKey(node, "tables.table"));
184 assertEquals("Wrong key for root attribute", "[@test]", engine.nodeKey(
185 root.getAttribute(0), ""));
186 }
187
188 /***
189 * Tests obtaining keys for nodes that contain the delimiter character.
190 */
191 public void testNodeKeyWithEscapedDelimiters()
192 {
193 ConfigurationNode node = root.getChild(1);
194 assertEquals("Wrong escaped key", "connection..settings", engine
195 .nodeKey(node, ""));
196 assertEquals("Wrong complex escaped key",
197 "connection..settings.usr..name", engine.nodeKey(node
198 .getChild(0), engine.nodeKey(node, "")));
199 }
200
201 /***
202 * Tests obtaining node keys when a different syntax is set.
203 */
204 public void testNodeKeyWithAlternativeSyntax()
205 {
206 setUpAlternativeSyntax();
207 assertEquals("Wrong child key", "tables/table", engine.nodeKey(root
208 .getChild(0).getChild(0), "tables"));
209 assertEquals("Wrong attribute key", "@test", engine.nodeKey(root
210 .getAttribute(0), ""));
211
212 engine.setAttributeStart(engine.getPropertyDelimiter());
213 assertEquals("Wrong attribute key", "/test", engine.nodeKey(root
214 .getAttribute(0), ""));
215 }
216
217 /***
218 * Tests adding direct child nodes to the existing hierarchy.
219 */
220 public void testPrepareAddDirectly()
221 {
222 NodeAddData data = engine.prepareAdd(root, "newNode");
223 assertSame("Wrong parent node", root, data.getParent());
224 assertTrue("Path nodes available", data.getPathNodes().isEmpty());
225 assertEquals("Wrong name of new node", "newNode", data.getNewNodeName());
226 assertFalse("New node is an attribute", data.isAttribute());
227
228 data = engine.prepareAdd(root, "tables.table.fields.field.name");
229 assertEquals("Wrong name of new node", "name", data.getNewNodeName());
230 assertTrue("Path nodes available", data.getPathNodes().isEmpty());
231 assertEquals("Wrong parent node", "field", data.getParent().getName());
232 ConfigurationNode nd = data.getParent().getChild(0);
233 assertEquals("Field has no name node", "name", nd.getName());
234 assertEquals("Incorrect name", "version", nd.getValue());
235 }
236
237 /***
238 * Tests adding when indices are involved.
239 */
240 public void testPrepareAddWithIndex()
241 {
242 NodeAddData data = engine
243 .prepareAdd(root, "tables.table(0).tableSpace");
244 assertEquals("Wrong name of new node", "tableSpace", data
245 .getNewNodeName());
246 assertTrue("Path nodes available", data.getPathNodes().isEmpty());
247 assertEquals("Wrong type of parent node", "table", data.getParent()
248 .getName());
249 ConfigurationNode node = data.getParent().getChild(0);
250 assertEquals("Wrong table", tables[0], node.getValue());
251
252 data = engine.prepareAdd(root, "tables.table(1).fields.field(2).alias");
253 assertEquals("Wrong name of new node", "alias", data.getNewNodeName());
254 assertEquals("Wrong type of parent node", "field", data.getParent()
255 .getName());
256 assertEquals("Wrong field node", "creationDate", data.getParent()
257 .getChild(0).getValue());
258 }
259
260 /***
261 * Tests adding new attributes.
262 */
263 public void testPrepareAddAttribute()
264 {
265 NodeAddData data = engine.prepareAdd(root,
266 "tables.table(0)[@tableSpace]");
267 assertEquals("Wrong table node", tables[0], data.getParent()
268 .getChild(0).getValue());
269 assertEquals("Wrong name of new node", "tableSpace", data
270 .getNewNodeName());
271 assertTrue("Attribute not detected", data.isAttribute());
272 assertTrue("Path nodes available", data.getPathNodes().isEmpty());
273
274 data = engine.prepareAdd(root, "[@newAttr]");
275 assertSame("Root node is not parent", root, data.getParent());
276 assertEquals("Wrong name of new node", "newAttr", data.getNewNodeName());
277 assertTrue("Attribute not detected", data.isAttribute());
278 }
279
280 /***
281 * Tests add operations where complete pathes are added.
282 */
283 public void testPrepareAddWithPath()
284 {
285 NodeAddData data = engine.prepareAdd(root,
286 "tables.table(1).fields.field(-1).name");
287 assertEquals("Wrong name of new node", "name", data.getNewNodeName());
288 checkNodePath(data, new String[]
289 { "field"});
290 assertEquals("Wrong type of parent node", "fields", data.getParent()
291 .getName());
292
293 data = engine.prepareAdd(root, "tables.table(-1).name");
294 assertEquals("Wrong name of new node", "name", data.getNewNodeName());
295 checkNodePath(data, new String[]
296 { "table"});
297 assertEquals("Wrong type of parent node", "tables", data.getParent()
298 .getName());
299
300 data = engine.prepareAdd(root, "a.complete.new.path");
301 assertEquals("Wrong name of new node", "path", data.getNewNodeName());
302 checkNodePath(data, new String[]
303 { "a", "complete", "new"});
304 assertSame("Root is not parent", root, data.getParent());
305 }
306
307 /***
308 * Tests add operations when property and attribute delimiters are equal.
309 * Then it is not possible to add new attribute nodes.
310 */
311 public void testPrepareAddWithSameAttributeDelimiter()
312 {
313 engine.setAttributeEnd(null);
314 engine.setAttributeStart(engine.getPropertyDelimiter());
315
316 NodeAddData data = engine.prepareAdd(root, "tables.table(0).test");
317 assertEquals("Wrong name of new node", "test", data.getNewNodeName());
318 assertFalse("New node is an attribute", data.isAttribute());
319 assertEquals("Wrong type of parent node", "table", data.getParent()
320 .getName());
321
322 data = engine.prepareAdd(root, "a.complete.new.path");
323 assertFalse("New node is an attribute", data.isAttribute());
324 checkNodePath(data, new String[]
325 { "a", "complete", "new"});
326 }
327
328 /***
329 * Tests add operations when an alternative syntax is set.
330 */
331 public void testPrepareAddWithAlternativeSyntax()
332 {
333 setUpAlternativeSyntax();
334 NodeAddData data = engine.prepareAdd(root, "tables/table[0]/test");
335 assertEquals("Wrong name of new node", "test", data.getNewNodeName());
336 assertFalse("New node is attribute", data.isAttribute());
337 assertEquals("Wrong parent node", tables[0], data.getParent().getChild(
338 0).getValue());
339
340 data = engine.prepareAdd(root, "a/complete/new/path@attr");
341 assertEquals("Wrong name of new attribute", "attr", data
342 .getNewNodeName());
343 checkNodePath(data, new String[]
344 { "a", "complete", "new", "path"});
345 assertSame("Root is not parent", root, data.getParent());
346 }
347
348 /***
349 * Tests using invalid keys, e.g. if something should be added to
350 * attributes.
351 */
352 public void testPrepareAddInvalidKeys()
353 {
354 try
355 {
356 engine.prepareAdd(root, "tables.table(0)[@type].new");
357 fail("Could add node to existing attribute!");
358 }
359 catch (IllegalArgumentException iex)
360 {
361
362 }
363
364 try
365 {
366 engine
367 .prepareAdd(root,
368 "a.complete.new.path.with.an[@attribute].at.a.non.allowed[@position]");
369 fail("Could add invalid path!");
370 }
371 catch (IllegalArgumentException iex)
372 {
373
374 }
375
376 try
377 {
378 engine.prepareAdd(root, null);
379 fail("Could add null key!");
380 }
381 catch (IllegalArgumentException iex)
382 {
383
384 }
385
386 try
387 {
388 engine.prepareAdd(root, "");
389 fail("Could add undefined key!");
390 }
391 catch (IllegalArgumentException iex)
392 {
393
394 }
395 }
396
397 /***
398 * Creates a node hierarchy for testing that consists of tables, their
399 * fields, and some additional data:
400 *
401 * <pre>
402 * tables
403 * table
404 * name
405 * fields
406 * field
407 * name
408 * field
409 * name
410 * </pre>
411 *
412 * @return the root of the test node hierarchy
413 */
414 protected ConfigurationNode setUpNodes()
415 {
416 DefaultConfigurationNode rootNode = new DefaultConfigurationNode();
417
418 DefaultConfigurationNode nodeTables = new DefaultConfigurationNode(
419 "tables");
420 rootNode.addChild(nodeTables);
421 for (int i = 0; i < tables.length; i++)
422 {
423 DefaultConfigurationNode nodeTable = new DefaultConfigurationNode(
424 "table");
425 nodeTables.addChild(nodeTable);
426 nodeTable.addChild(new DefaultConfigurationNode("name", tables[i]));
427 nodeTable.addAttribute(new DefaultConfigurationNode("type",
428 tabTypes[i]));
429 DefaultConfigurationNode nodeFields = new DefaultConfigurationNode(
430 "fields");
431 nodeTable.addChild(nodeFields);
432
433 for (int j = 0; j < fields[i].length; j++)
434 {
435 nodeFields.addChild(createFieldNode(fields[i][j]));
436 }
437 }
438
439 DefaultConfigurationNode nodeConn = new DefaultConfigurationNode(
440 "connection.settings");
441 rootNode.addChild(nodeConn);
442 nodeConn.addChild(new DefaultConfigurationNode("usr.name", "scott"));
443 nodeConn.addChild(new DefaultConfigurationNode("usr.pwd", "tiger"));
444 rootNode.addAttribute(new DefaultConfigurationNode("test", "true"));
445
446 return rootNode;
447 }
448
449 /***
450 * Configures the expression engine to use a different syntax.
451 */
452 private void setUpAlternativeSyntax()
453 {
454 engine.setAttributeEnd(null);
455 engine.setAttributeStart("@");
456 engine.setPropertyDelimiter("/");
457 engine.setEscapedDelimiter(null);
458 engine.setIndexStart("[");
459 engine.setIndexEnd("]");
460 }
461
462 /***
463 * Helper method for checking the evaluation of a key. Queries the
464 * expression engine and tests if the expected results are returned.
465 *
466 * @param key the key
467 * @param name the name of the nodes to be returned
468 * @param count the number of expected result nodes
469 * @return the list with the results of the query
470 */
471 private List checkKey(String key, String name, int count)
472 {
473 List nodes = engine.query(root, key);
474 assertEquals("Wrong number of result nodes for key " + key, count,
475 nodes.size());
476 for (Iterator it = nodes.iterator(); it.hasNext();)
477 {
478 assertEquals("Wrong result node for key " + key, name,
479 ((ConfigurationNode) it.next()).getName());
480 }
481 return nodes;
482 }
483
484 /***
485 * Helper method for checking the value of a node specified by the given
486 * key. This method evaluates the key and checks whether the resulting node
487 * has the expected value.
488 *
489 * @param key the key
490 * @param name the expected name of the result node
491 * @param value the expected value of the result node
492 */
493 private void checkKeyValue(String key, String name, String value)
494 {
495 List nodes = checkKey(key, name, 1);
496 assertEquals("Wrong value for key " + key, value,
497 ((ConfigurationNode) nodes.get(0)).getValue());
498 }
499
500 /***
501 * Helper method for checking the path of an add operation.
502 *
503 * @param data the add data object
504 * @param expected the expected path nodes
505 */
506 private void checkNodePath(NodeAddData data, String[] expected)
507 {
508 assertEquals("Wrong number of path nodes", expected.length, data
509 .getPathNodes().size());
510 Iterator it = data.getPathNodes().iterator();
511 for (int i = 0; i < expected.length; i++)
512 {
513 assertEquals("Wrong path node " + i, expected[i], it.next());
514 }
515 }
516
517 /***
518 * Helper method for creating a field node with its children for the test
519 * node hierarchy.
520 *
521 * @param name the name of the field
522 * @return the field node
523 */
524 private static ConfigurationNode createFieldNode(String name)
525 {
526 DefaultConfigurationNode nodeField = new DefaultConfigurationNode(
527 "field");
528 nodeField.addChild(new DefaultConfigurationNode("name", name));
529 return nodeField;
530 }
531 }