1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration2.tree.xpath;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertSame;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.when;
27
28 import java.util.Arrays;
29 import java.util.List;
30
31 import org.apache.commons.configuration2.tree.ImmutableNode;
32 import org.apache.commons.configuration2.tree.InMemoryNodeModel;
33 import org.apache.commons.configuration2.tree.NodeAddData;
34 import org.apache.commons.configuration2.tree.NodeHandler;
35 import org.apache.commons.configuration2.tree.QueryResult;
36 import org.apache.commons.jxpath.JXPathContext;
37 import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
38 import org.apache.commons.jxpath.ri.model.NodePointerFactory;
39 import org.junit.jupiter.api.BeforeAll;
40 import org.junit.jupiter.api.Test;
41
42
43
44
45 public class TestXPathExpressionEngine {
46
47 private static final String TEST_KEY = "TESTKEY";
48
49
50 private static final String ROOT_NAME = "testRoot";
51
52
53 private static ImmutableNode root;
54
55
56 private static NodeHandler<ImmutableNode> handler;
57
58
59
60
61
62
63
64
65 private static void checkAddPath(final NodeAddData<ImmutableNode> data, final boolean attr, final String... expected) {
66 assertSame(root, data.getParent());
67 final List<String> path = data.getPathNodes();
68 assertEquals(Arrays.asList(expected).subList(0, expected.length - 1), path);
69 assertEquals(expected[expected.length - 1], data.getNewNodeName());
70 assertEquals(attr, data.isAttribute());
71 }
72
73 @BeforeAll
74 public static void setUpBeforeClass() throws Exception {
75 root = new ImmutableNode.Builder().name(ROOT_NAME).create();
76 handler = new InMemoryNodeModel(root).getNodeHandler();
77 }
78
79
80
81
82
83
84 private void checkEmptyKey(final String key) {
85 final XPathContextFactory factory = mock(XPathContextFactory.class);
86 final XPathExpressionEngine engine = new XPathExpressionEngine(factory);
87 final List<QueryResult<ImmutableNode>> results = engine.query(root, key, handler);
88 assertEquals(1, results.size());
89 assertSame(root, results.get(0).getNode());
90 }
91
92
93
94
95
96
97
98 private void checkInvalidAddPath(final String path) {
99 final XPathExpressionEngine engine = new XPathExpressionEngine();
100 final QueryResult<ImmutableNode> res = QueryResult.createNodeResult(root);
101 assertThrows(IllegalArgumentException.class, () -> engine.createNodeAddData(path, res));
102 }
103
104
105
106
107
108
109
110 private JXPathContext expectSelect(final Object... results) {
111 final JXPathContext ctx = mock(JXPathContext.class);
112
113 when(ctx.selectNodes(TEST_KEY)).thenReturn(Arrays.asList(results));
114
115 return ctx;
116 }
117
118
119
120
121
122
123
124 private XPathExpressionEngine setUpEngine(final JXPathContext ctx) {
125 final XPathContextFactory factory = mock(XPathContextFactory.class);
126
127 when(factory.createContext(root, handler)).thenReturn(ctx);
128
129 return new XPathExpressionEngine(factory);
130 }
131
132
133
134
135 @Test
136 public void testAttributeKeyOfRootNode() {
137 final XPathExpressionEngine engine = new XPathExpressionEngine();
138 assertEquals("@child", engine.attributeKey(null, "child"));
139 }
140
141
142
143
144 @Test
145 public void testCanonicalKeyNoDuplicates() {
146 final ImmutableNode.Builder parentBuilder = new ImmutableNode.Builder(2);
147 final ImmutableNode c1 = new ImmutableNode.Builder().name("child").create();
148 final ImmutableNode c2 = new ImmutableNode.Builder().name("child_other").create();
149 parentBuilder.addChildren(Arrays.asList(c2, c1));
150 final ImmutableNode parent = parentBuilder.create();
151 final NodeHandler<ImmutableNode> testHandler = new InMemoryNodeModel(parent).getNodeHandler();
152 final XPathExpressionEngine engine = new XPathExpressionEngine();
153 assertEquals("parent/child[1]", engine.canonicalKey(c1, "parent", testHandler));
154 }
155
156
157
158
159 @Test
160 public void testCanonicalKeyNoParentKey() {
161 final ImmutableNode.Builder parentBuilder = new ImmutableNode.Builder(1);
162 final ImmutableNode c1 = new ImmutableNode.Builder().name("child").create();
163 final ImmutableNode parent = parentBuilder.addChild(c1).create();
164 final NodeHandler<ImmutableNode> testHandler = new InMemoryNodeModel(parent).getNodeHandler();
165 final XPathExpressionEngine engine = new XPathExpressionEngine();
166 assertEquals("child[1]", engine.canonicalKey(c1, null, testHandler));
167 }
168
169
170
171
172 @Test
173 public void testCanonicalKeyRootNoParentKey() {
174 final XPathExpressionEngine engine = new XPathExpressionEngine();
175 assertEquals("", engine.canonicalKey(root, null, handler));
176 }
177
178
179
180
181 @Test
182 public void testCanonicalKeyRootWithParentKey() {
183 final XPathExpressionEngine engine = new XPathExpressionEngine();
184 assertEquals("parent", engine.canonicalKey(root, "parent", handler));
185 }
186
187
188
189
190 @Test
191 public void testCanonicalKeyWithDuplicates() {
192 final ImmutableNode.Builder parentBuilder = new ImmutableNode.Builder(3);
193 final ImmutableNode c1 = new ImmutableNode.Builder().name("child").create();
194 final ImmutableNode c2 = new ImmutableNode.Builder().name("child").create();
195 final ImmutableNode c3 = new ImmutableNode.Builder().name("child_other").create();
196 parentBuilder.addChildren(Arrays.asList(c1, c2, c3));
197 final ImmutableNode parent = parentBuilder.create();
198 final NodeHandler<ImmutableNode> testHandler = new InMemoryNodeModel(parent).getNodeHandler();
199 final XPathExpressionEngine engine = new XPathExpressionEngine();
200 assertEquals("parent/child[1]", engine.canonicalKey(c1, "parent", testHandler));
201 assertEquals("parent/child[2]", engine.canonicalKey(c2, "parent", testHandler));
202 }
203
204
205
206
207 @Test
208 public void testDefaultContextFactory() {
209 final XPathExpressionEngine engine = new XPathExpressionEngine();
210 assertNotNull(engine.getContextFactory());
211 }
212
213
214
215
216 @Test
217 public void testNodeKeyAttribute() {
218 final XPathExpressionEngine engine = new XPathExpressionEngine();
219 assertEquals("node/@attr", engine.attributeKey("node", "attr"));
220 }
221
222
223
224
225 @Test
226 public void testNodeKeyForRootChild() {
227 final XPathExpressionEngine engine = new XPathExpressionEngine();
228 assertEquals(ROOT_NAME, engine.nodeKey(root, "", handler));
229 }
230
231
232
233
234 @Test
235 public void testNodeKeyForRootNode() {
236 final XPathExpressionEngine engine = new XPathExpressionEngine();
237 assertEquals("", engine.nodeKey(root, null, handler));
238 }
239
240
241
242
243 @Test
244 public void testNodeKeyNoNodeName() {
245 final XPathExpressionEngine engine = new XPathExpressionEngine();
246 assertEquals("test", engine.nodeKey(new ImmutableNode.Builder().create(), "test", handler));
247 }
248
249
250
251
252 @Test
253 public void testNodeKeyNormal() {
254 final XPathExpressionEngine engine = new XPathExpressionEngine();
255 assertEquals("parent/" + ROOT_NAME, engine.nodeKey(root, "parent", handler));
256 }
257
258
259
260
261 @Test
262 public void testNodePointerFactory() {
263 JXPathContext.newContext(this);
264 final NodePointerFactory[] factories = JXPathContextReferenceImpl.getNodePointerFactories();
265 boolean found = false;
266 for (final NodePointerFactory factory : factories) {
267 if (factory instanceof ConfigurationNodePointerFactory) {
268 found = true;
269 break;
270 }
271 }
272 assertTrue(found);
273 }
274
275
276
277
278 @Test
279 public void testPrepareAddAttribute() {
280 final JXPathContext ctx = expectSelect(root);
281 final XPathExpressionEngine engine = setUpEngine(ctx);
282 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + "\t@newAttr", handler);
283 checkAddPath(data, true, "newAttr");
284 }
285
286
287
288
289 @Test
290 public void testPrepareAddAttributePath() {
291 final JXPathContext ctx = expectSelect(root);
292 final XPathExpressionEngine engine = setUpEngine(ctx);
293 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + " a/full/path@attr", handler);
294 checkAddPath(data, true, "a", "full", "path", "attr");
295 }
296
297
298
299
300 @Test
301 public void testPrepareAddEmptyKey() {
302 final XPathExpressionEngine engine = new XPathExpressionEngine();
303 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, "", handler));
304 }
305
306
307
308
309 @Test
310 public void testPrepareAddEmptyPath() {
311 final XPathExpressionEngine engine = new XPathExpressionEngine();
312 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, TEST_KEY + " ", handler));
313 }
314
315
316
317
318 @Test
319 public void testPrepareAddInvalidAttributePath() {
320 checkInvalidAddPath("a/path/with@an/attribute");
321 }
322
323
324
325
326 @Test
327 public void testPrepareAddInvalidAttributePath2() {
328 checkInvalidAddPath("a/path/with/@attribute");
329 }
330
331
332
333
334 @Test
335 public void testPrepareAddInvalidParent() {
336 final JXPathContext ctx = expectSelect();
337 final XPathExpressionEngine engine = setUpEngine(ctx);
338 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, TEST_KEY + " test", handler));
339 }
340
341
342
343
344 @Test
345 public void testPrepareAddInvalidPath() {
346 checkInvalidAddPath("an/invalid//path");
347 }
348
349
350
351
352 @Test
353 public void testPrepareAddInvalidPathMultipleAttributes() {
354 checkInvalidAddPath("an@attribute@path");
355 }
356
357
358
359
360 @Test
361 public void testPrepareAddInvalidPathWithSlash() {
362 checkInvalidAddPath("/a/path/node");
363 }
364
365
366
367
368 @Test
369 public void testPrepareAddNode() {
370 final JXPathContext ctx = expectSelect(root);
371 final XPathExpressionEngine engine = setUpEngine(ctx);
372 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + " newNode", handler);
373 checkAddPath(data, false, "newNode");
374 }
375
376
377
378
379 @Test
380 public void testPrepareAddNullKey() {
381 final XPathExpressionEngine engine = new XPathExpressionEngine();
382 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, null, handler));
383 }
384
385
386
387
388 @Test
389 public void testPrepareAddPath() {
390 final JXPathContext ctx = expectSelect(root);
391 final XPathExpressionEngine engine = setUpEngine(ctx);
392 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + " \t a/full/path/node", handler);
393 checkAddPath(data, false, "a", "full", "path", "node");
394 }
395
396
397
398
399 @Test
400 public void testPrepareAddRootAttribute() {
401 final JXPathContext ctx = expectSelect(root);
402 final XPathExpressionEngine engine = setUpEngine(ctx);
403 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, " @attr", handler);
404 checkAddPath(data, true, "attr");
405 }
406
407
408
409
410 @Test
411 public void testPrepareAddRootChild() {
412 final JXPathContext ctx = expectSelect(root);
413 final XPathExpressionEngine engine = setUpEngine(ctx);
414 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, " newNode", handler);
415 checkAddPath(data, false, "newNode");
416 }
417
418
419
420
421 @Test
422 public void testPrepareAddToAttributeResult() {
423 final XPathExpressionEngine engine = new XPathExpressionEngine();
424 final QueryResult<ImmutableNode> result = QueryResult.createAttributeResult(root, TEST_KEY);
425 assertThrows(IllegalArgumentException.class, () -> engine.createNodeAddData("path", result));
426 }
427
428
429
430
431 @Test
432 public void testQueryAttributeExpression() {
433 final QueryResult<ImmutableNode> attrResult = QueryResult.createAttributeResult(root, "attr");
434 final JXPathContext ctx = expectSelect(attrResult);
435 final XPathExpressionEngine engine = setUpEngine(ctx);
436 final List<QueryResult<ImmutableNode>> result = engine.query(root, TEST_KEY, handler);
437 assertEquals(1, result.size());
438 assertSame(attrResult, result.get(0));
439 }
440
441
442
443
444 @Test
445 public void testQueryNodeExpression() {
446 final JXPathContext ctx = expectSelect(root);
447 final XPathExpressionEngine engine = setUpEngine(ctx);
448 final List<QueryResult<ImmutableNode>> result = engine.query(root, TEST_KEY, handler);
449 assertEquals(1, result.size());
450 assertSame(root, result.get(0).getNode());
451 assertFalse(result.get(0).isAttributeResult());
452 }
453
454
455
456
457 @Test
458 public void testQueryWithEmptyKey() {
459 checkEmptyKey("");
460 }
461
462
463
464
465 @Test
466 public void testQueryWithNullKey() {
467 checkEmptyKey(null);
468 }
469
470
471
472
473 @Test
474 public void testQueryWithoutResult() {
475 final JXPathContext ctx = expectSelect();
476 final XPathExpressionEngine engine = setUpEngine(ctx);
477 assertTrue(engine.query(root, TEST_KEY, handler).isEmpty());
478 }
479 }