1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration.tree.xpath;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertSame;
22 import static org.junit.Assert.assertTrue;
23
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.commons.configuration.tree.ConfigurationNode;
29 import org.apache.commons.configuration.tree.DefaultConfigurationNode;
30 import org.apache.commons.configuration.tree.NodeAddData;
31 import org.apache.commons.jxpath.JXPathContext;
32 import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
33 import org.apache.commons.jxpath.ri.model.NodePointerFactory;
34 import org.junit.Before;
35 import org.junit.Test;
36
37
38
39
40
41
42
43
44
45 public class TestXPathExpressionEngine
46 {
47
48 static final ConfigurationNode ROOT = new DefaultConfigurationNode(
49 "testRoot");
50
51
52 static final String TEST_KEY = "TESTKEY";
53
54
55 XPathExpressionEngine engine;
56
57 @Before
58 public void setUp() throws Exception
59 {
60 engine = new MockJXPathContextExpressionEngine();
61 }
62
63
64
65
66 @Test
67 public void testQueryExpression()
68 {
69 List<ConfigurationNode> nodes = engine.query(ROOT, TEST_KEY);
70 assertEquals("Incorrect number of results", 1, nodes.size());
71 assertSame("Wrong result node", ROOT, nodes.get(0));
72 checkSelectCalls(1);
73 }
74
75
76
77
78 @Test
79 public void testQueryWithoutResult()
80 {
81 List<ConfigurationNode> nodes = engine.query(ROOT, "a non existing key");
82 assertTrue("Result list is not empty", nodes.isEmpty());
83 checkSelectCalls(1);
84 }
85
86
87
88
89
90 @Test
91 public void testQueryWithEmptyKey()
92 {
93 checkEmptyKey("");
94 }
95
96
97
98
99 @Test
100 public void testQueryWithNullKey()
101 {
102 checkEmptyKey(null);
103 }
104
105
106
107
108
109
110 private void checkEmptyKey(String key)
111 {
112 List<ConfigurationNode> nodes = engine.query(ROOT, key);
113 assertEquals("Incorrect number of results", 1, nodes.size());
114 assertSame("Wrong result node", ROOT, nodes.get(0));
115 checkSelectCalls(0);
116 }
117
118
119
120
121 @Test
122 public void testCreateContext()
123 {
124 JXPathContext ctx = new XPathExpressionEngine().createContext(ROOT,
125 TEST_KEY);
126 assertNotNull("Context is null", ctx);
127 assertTrue("Lenient mode is not set", ctx.isLenient());
128 assertSame("Incorrect context bean set", ROOT, ctx.getContextBean());
129
130 NodePointerFactory[] factories = JXPathContextReferenceImpl
131 .getNodePointerFactories();
132 boolean found = false;
133 for (int i = 0; i < factories.length; i++)
134 {
135 if (factories[i] instanceof ConfigurationNodePointerFactory)
136 {
137 found = true;
138 }
139 }
140 assertTrue("No configuration pointer factory found", found);
141 }
142
143
144
145
146 @Test
147 public void testNodeKeyNormal()
148 {
149 assertEquals("Wrong node key", "parent/child", engine.nodeKey(
150 new DefaultConfigurationNode("child"), "parent"));
151 }
152
153
154
155
156 @Test
157 public void testNodeKeyAttribute()
158 {
159 ConfigurationNode node = new DefaultConfigurationNode("attr");
160 node.setAttribute(true);
161 assertEquals("Wrong attribute key", "node/@attr", engine.nodeKey(node,
162 "node"));
163 }
164
165
166
167
168 @Test
169 public void testNodeKeyForRootNode()
170 {
171 assertEquals("Wrong key for root node", "", engine.nodeKey(ROOT, null));
172 assertEquals("Null name not detected", "test", engine.nodeKey(
173 new DefaultConfigurationNode(), "test"));
174 }
175
176
177
178
179 @Test
180 public void testNodeKeyForRootChild()
181 {
182 ConfigurationNode node = new DefaultConfigurationNode("child");
183 assertEquals("Wrong key for root child node", "child", engine.nodeKey(
184 node, ""));
185 node.setAttribute(true);
186 assertEquals("Wrong key for root attribute", "@child", engine.nodeKey(
187 node, ""));
188 }
189
190
191
192
193 @Test
194 public void testPrepareAddNode()
195 {
196 NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY + " newNode");
197 checkAddPath(data, new String[]
198 { "newNode" }, false);
199 checkSelectCalls(1);
200 }
201
202
203
204
205 @Test
206 public void testPrepareAddAttribute()
207 {
208 NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY + "\t@newAttr");
209 checkAddPath(data, new String[]
210 { "newAttr" }, true);
211 checkSelectCalls(1);
212 }
213
214
215
216
217 @Test
218 public void testPrepareAddPath()
219 {
220 NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY
221 + " \t a/full/path/node");
222 checkAddPath(data, new String[]
223 { "a", "full", "path", "node" }, false);
224 checkSelectCalls(1);
225 }
226
227
228
229
230 @Test
231 public void testPrepareAddAttributePath()
232 {
233 NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY
234 + " a/full/path@attr");
235 checkAddPath(data, new String[]
236 { "a", "full", "path", "attr" }, true);
237 checkSelectCalls(1);
238 }
239
240
241
242
243 @Test
244 public void testPrepareAddRootChild()
245 {
246 NodeAddData data = engine.prepareAdd(ROOT, " newNode");
247 checkAddPath(data, new String[]
248 { "newNode" }, false);
249 checkSelectCalls(0);
250 }
251
252
253
254
255 @Test
256 public void testPrepareAddRootAttribute()
257 {
258 NodeAddData data = engine.prepareAdd(ROOT, " @attr");
259 checkAddPath(data, new String[]
260 { "attr" }, true);
261 checkSelectCalls(0);
262 }
263
264
265
266
267 @Test(expected = IllegalArgumentException.class)
268 public void testPrepareAddInvalidParent()
269 {
270 engine.prepareAdd(ROOT, "invalidKey newNode");
271 }
272
273
274
275
276 @Test(expected = IllegalArgumentException.class)
277 public void testPrepareAddEmptyPath()
278 {
279 engine.prepareAdd(ROOT, TEST_KEY + " ");
280 }
281
282
283
284
285 @Test(expected = IllegalArgumentException.class)
286 public void testPrepareAddNullKey()
287 {
288 engine.prepareAdd(ROOT, null);
289 }
290
291
292
293
294 @Test(expected = IllegalArgumentException.class)
295 public void testPrepareAddEmptyKey()
296 {
297 engine.prepareAdd(ROOT, "");
298 }
299
300
301
302
303 @Test(expected = IllegalArgumentException.class)
304 public void testPrepareAddInvalidPath()
305 {
306 engine.prepareAdd(ROOT, TEST_KEY + " an/invalid//path");
307 }
308
309
310
311
312
313 @Test(expected = IllegalArgumentException.class)
314 public void testPrepareAddInvalidAttributePath()
315 {
316 engine.prepareAdd(ROOT, TEST_KEY + " a/path/with@an/attribute");
317 }
318
319
320
321
322
323 @Test(expected = IllegalArgumentException.class)
324 public void testPrepareAddInvalidAttributePath2()
325 {
326 engine.prepareAdd(ROOT, TEST_KEY + " a/path/with/@attribute");
327 }
328
329
330
331
332 @Test(expected = IllegalArgumentException.class)
333 public void testPrepareAddInvalidPathWithSlash()
334 {
335 engine.prepareAdd(ROOT, TEST_KEY + " /a/path/node");
336 }
337
338
339
340
341
342 @Test(expected = IllegalArgumentException.class)
343 public void testPrepareAddInvalidPathMultipleAttributes()
344 {
345 engine.prepareAdd(ROOT, TEST_KEY + " an@attribute@path");
346 }
347
348
349
350
351
352
353
354
355 private void checkAddPath(NodeAddData data, String[] expected, boolean attr)
356 {
357 assertSame("Wrong parent node", ROOT, data.getParent());
358 List<String> path = data.getPathNodes();
359 assertEquals("Incorrect number of path nodes", expected.length - 1,
360 path.size());
361 Iterator<String> it = path.iterator();
362 for (int idx = 0; idx < expected.length - 1; idx++)
363 {
364 assertEquals("Wrong node at position " + idx, expected[idx], it
365 .next());
366 }
367 assertEquals("Wrong name of new node", expected[expected.length - 1],
368 data.getNewNodeName());
369 assertEquals("Incorrect attribute flag", attr, data.isAttribute());
370 }
371
372
373
374
375
376
377
378 protected void checkSelectCalls(int expected)
379 {
380 MockJXPathContext ctx = ((MockJXPathContextExpressionEngine) engine).getContext();
381 int calls = (ctx == null) ? 0 : ctx.selectInvocations;
382 assertEquals("Incorrect number of select calls", expected, calls);
383 }
384
385
386
387
388
389
390
391 static class MockJXPathContext extends JXPathContextReferenceImpl
392 {
393 int selectInvocations;
394
395 public MockJXPathContext(Object bean)
396 {
397 super(null, bean);
398 }
399
400
401
402
403
404
405 @Override
406 public List<?> selectNodes(String xpath)
407 {
408 selectInvocations++;
409 if (TEST_KEY.equals(xpath))
410 {
411 List<ConfigurationNode> result = new ArrayList<ConfigurationNode>(1);
412 result.add(ROOT);
413 return result;
414 }
415 else
416 {
417 return null;
418 }
419 }
420 }
421
422
423
424
425
426 static class MockJXPathContextExpressionEngine extends
427 XPathExpressionEngine
428 {
429
430 private MockJXPathContext context;
431
432 @Override
433 protected JXPathContext createContext(ConfigurationNode root, String key)
434 {
435 context = new MockJXPathContext(root);
436 return context;
437 }
438
439
440
441
442
443
444 public MockJXPathContext getContext()
445 {
446 return context;
447 }
448 }
449 }