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 }
270 }
271 assertTrue(found);
272 }
273
274
275
276
277 @Test
278 public void testPrepareAddAttribute() {
279 final JXPathContext ctx = expectSelect(root);
280 final XPathExpressionEngine engine = setUpEngine(ctx);
281 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + "\t@newAttr", handler);
282 checkAddPath(data, true, "newAttr");
283 }
284
285
286
287
288 @Test
289 public void testPrepareAddAttributePath() {
290 final JXPathContext ctx = expectSelect(root);
291 final XPathExpressionEngine engine = setUpEngine(ctx);
292 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + " a/full/path@attr", handler);
293 checkAddPath(data, true, "a", "full", "path", "attr");
294 }
295
296
297
298
299 @Test
300 public void testPrepareAddEmptyKey() {
301 final XPathExpressionEngine engine = new XPathExpressionEngine();
302 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, "", handler));
303 }
304
305
306
307
308 @Test
309 public void testPrepareAddEmptyPath() {
310 final XPathExpressionEngine engine = new XPathExpressionEngine();
311 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, TEST_KEY + " ", handler));
312 }
313
314
315
316
317 @Test
318 public void testPrepareAddInvalidAttributePath() {
319 checkInvalidAddPath("a/path/with@an/attribute");
320 }
321
322
323
324
325 @Test
326 public void testPrepareAddInvalidAttributePath2() {
327 checkInvalidAddPath("a/path/with/@attribute");
328 }
329
330
331
332
333 @Test
334 public void testPrepareAddInvalidParent() {
335 final JXPathContext ctx = expectSelect();
336 final XPathExpressionEngine engine = setUpEngine(ctx);
337 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, TEST_KEY + " test", handler));
338 }
339
340
341
342
343 @Test
344 public void testPrepareAddInvalidPath() {
345 checkInvalidAddPath("an/invalid//path");
346 }
347
348
349
350
351 @Test
352 public void testPrepareAddInvalidPathMultipleAttributes() {
353 checkInvalidAddPath("an@attribute@path");
354 }
355
356
357
358
359 @Test
360 public void testPrepareAddInvalidPathWithSlash() {
361 checkInvalidAddPath("/a/path/node");
362 }
363
364
365
366
367 @Test
368 public void testPrepareAddNode() {
369 final JXPathContext ctx = expectSelect(root);
370 final XPathExpressionEngine engine = setUpEngine(ctx);
371 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + " newNode", handler);
372 checkAddPath(data, false, "newNode");
373 }
374
375
376
377
378 @Test
379 public void testPrepareAddNullKey() {
380 final XPathExpressionEngine engine = new XPathExpressionEngine();
381 assertThrows(IllegalArgumentException.class, () -> engine.prepareAdd(root, null, handler));
382 }
383
384
385
386
387 @Test
388 public void testPrepareAddPath() {
389 final JXPathContext ctx = expectSelect(root);
390 final XPathExpressionEngine engine = setUpEngine(ctx);
391 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, TEST_KEY + " \t a/full/path/node", handler);
392 checkAddPath(data, false, "a", "full", "path", "node");
393 }
394
395
396
397
398 @Test
399 public void testPrepareAddRootAttribute() {
400 final JXPathContext ctx = expectSelect(root);
401 final XPathExpressionEngine engine = setUpEngine(ctx);
402 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, " @attr", handler);
403 checkAddPath(data, true, "attr");
404 }
405
406
407
408
409 @Test
410 public void testPrepareAddRootChild() {
411 final JXPathContext ctx = expectSelect(root);
412 final XPathExpressionEngine engine = setUpEngine(ctx);
413 final NodeAddData<ImmutableNode> data = engine.prepareAdd(root, " newNode", handler);
414 checkAddPath(data, false, "newNode");
415 }
416
417
418
419
420 @Test
421 public void testPrepareAddToAttributeResult() {
422 final XPathExpressionEngine engine = new XPathExpressionEngine();
423 final QueryResult<ImmutableNode> result = QueryResult.createAttributeResult(root, TEST_KEY);
424 assertThrows(IllegalArgumentException.class, () -> engine.createNodeAddData("path", result));
425 }
426
427
428
429
430 @Test
431 public void testQueryAttributeExpression() {
432 final QueryResult<ImmutableNode> attrResult = QueryResult.createAttributeResult(root, "attr");
433 final JXPathContext ctx = expectSelect(attrResult);
434 final XPathExpressionEngine engine = setUpEngine(ctx);
435 final List<QueryResult<ImmutableNode>> result = engine.query(root, TEST_KEY, handler);
436 assertEquals(1, result.size());
437 assertSame(attrResult, result.get(0));
438 }
439
440
441
442
443 @Test
444 public void testQueryNodeExpression() {
445 final JXPathContext ctx = expectSelect(root);
446 final XPathExpressionEngine engine = setUpEngine(ctx);
447 final List<QueryResult<ImmutableNode>> result = engine.query(root, TEST_KEY, handler);
448 assertEquals(1, result.size());
449 assertSame(root, result.get(0).getNode());
450 assertFalse(result.get(0).isAttributeResult());
451 }
452
453
454
455
456 @Test
457 public void testQueryWithEmptyKey() {
458 checkEmptyKey("");
459 }
460
461
462
463
464 @Test
465 public void testQueryWithNullKey() {
466 checkEmptyKey(null);
467 }
468
469
470
471
472 @Test
473 public void testQueryWithoutResult() {
474 final JXPathContext ctx = expectSelect();
475 final XPathExpressionEngine engine = setUpEngine(ctx);
476 assertTrue(engine.query(root, TEST_KEY, handler).isEmpty());
477 }
478 }