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