1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration2;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
21 import static org.junit.jupiter.api.Assertions.assertNotSame;
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.verify;
27 import static org.mockito.Mockito.verifyNoMoreInteractions;
28 import static org.mockito.Mockito.when;
29
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.NoSuchElementException;
36 import java.util.Set;
37
38 import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
39 import org.apache.commons.configuration2.convert.DisabledListDelimiterHandler;
40 import org.apache.commons.configuration2.convert.ListDelimiterHandler;
41 import org.apache.commons.configuration2.interpol.ConfigurationInterpolator;
42 import org.apache.commons.configuration2.tree.ImmutableNode;
43 import org.apache.commons.configuration2.tree.InMemoryNodeModel;
44 import org.apache.commons.configuration2.tree.NodeSelector;
45 import org.apache.commons.configuration2.tree.NodeStructureHelper;
46 import org.apache.commons.configuration2.tree.TrackedNodeModel;
47 import org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine;
48 import org.junit.jupiter.api.BeforeEach;
49 import org.junit.jupiter.api.Test;
50
51
52
53
54 public class TestSubnodeConfiguration {
55
56 private static final String SUB_KEY = "tables.table(0)";
57
58
59 private static final NodeSelector SELECTOR = new NodeSelector(SUB_KEY);
60
61
62
63
64
65
66
67 private static void appendTree(final BaseHierarchicalConfiguration configuration, final ImmutableNode root) {
68 configuration.addNodes(null, Collections.singleton(root));
69 }
70
71
72
73
74
75
76 private static BaseHierarchicalConfiguration setUpParentConfig() {
77 final BaseHierarchicalConfiguration conf = new BaseHierarchicalConfiguration();
78 appendTree(conf, NodeStructureHelper.ROOT_TABLES_TREE);
79 return conf;
80 }
81
82
83 private BaseHierarchicalConfiguration parent;
84
85
86 private SubnodeConfiguration config;
87
88
89
90
91
92
93 private void checkInterpolationFromConfigurationAt(final boolean withUpdates) {
94 parent.addProperty("base.dir", "/home/foo");
95 parent.addProperty("test.absolute.dir.dir1", "${base.dir}/path1");
96 parent.addProperty("test.absolute.dir.dir2", "${base.dir}/path2");
97 parent.addProperty("test.absolute.dir.dir3", "${base.dir}/path3");
98
99 final Configuration sub = parent.configurationAt("test.absolute.dir", withUpdates);
100 for (int i = 1; i < 4; i++) {
101 assertEquals("/home/foo/path" + i, parent.getString("test.absolute.dir.dir" + i));
102 assertEquals("/home/foo/path" + i, sub.getString("dir" + i));
103 }
104 }
105
106
107
108
109 private void checkSubConfigContent() {
110 assertEquals(NodeStructureHelper.table(0), config.getString("name"));
111 final List<Object> fields = config.getList("fields.field.name");
112
113 final List<String> expected = new ArrayList<>();
114 for (int i = 0; i < NodeStructureHelper.fieldsLength(0); i++) {
115 expected.add(NodeStructureHelper.field(0, i));
116 }
117 assertEquals(expected, fields);
118 }
119
120 @BeforeEach
121 public void setUp() throws Exception {
122 parent = setUpParentConfig();
123 }
124
125
126
127
128 private void setUpSubnodeConfig() {
129 setUpSubnodeConfig(SUB_KEY);
130 }
131
132
133
134
135
136
137 private void setUpSubnodeConfig(final String key) {
138 config = (SubnodeConfiguration) parent.configurationAt(key, true);
139 }
140
141
142
143
144
145
146
147 private TrackedNodeModel setUpTrackedModel(final NodeSelector selector) {
148 final InMemoryNodeModel parentModel = (InMemoryNodeModel) parent.getModel();
149 parentModel.trackNode(selector, parent);
150 return new TrackedNodeModel(parent, selector, true);
151 }
152
153
154
155
156 @Test
157 public void testAddProperty() {
158 setUpSubnodeConfig();
159 config.addProperty("[@table-type]", "test");
160 assertEquals("test", parent.getString("tables.table(0)[@table-type]"));
161
162 parent.addProperty("tables.table(0).fields.field(-1).name", "newField");
163 final List<Object> fields = config.getList("fields.field.name");
164 assertEquals(NodeStructureHelper.fieldsLength(0) + 1, fields.size());
165 assertEquals("newField", fields.get(fields.size() - 1));
166 }
167
168
169
170
171 @Test
172 public void testClone() {
173 setUpSubnodeConfig();
174 final SubnodeConfiguration copy = (SubnodeConfiguration) config.clone();
175 assertNotSame(config.getModel(), copy.getModel());
176 final TrackedNodeModel subModel = (TrackedNodeModel) copy.getModel();
177 assertEquals(SELECTOR, subModel.getSelector());
178 final InMemoryNodeModel parentModel = (InMemoryNodeModel) parent.getModel();
179 assertEquals(parentModel, subModel.getParentModel());
180
181
182 parentModel.untrackNode(SELECTOR);
183 parentModel.untrackNode(SELECTOR);
184 assertTrue(subModel.isReleaseTrackedNodeOnFinalize());
185 }
186
187
188
189
190 @Test
191 public void testClose() {
192 final TrackedNodeModel model = mock(TrackedNodeModel.class);
193
194 when(model.getSelector()).thenReturn(SELECTOR);
195
196 final SubnodeConfiguration config = new SubnodeConfiguration(parent, model);
197 config.close();
198
199 verify(model).getSelector();
200 verify(model).close();
201 verifyNoMoreInteractions(model);
202 }
203
204
205
206
207 @Test
208 public void testConfiguarationAtNoUpdates() {
209 setUpSubnodeConfig();
210 final HierarchicalConfiguration<ImmutableNode> sub2 = config.configurationAt("fields.field(1)");
211 assertEquals(NodeStructureHelper.field(0, 1), sub2.getString("name"));
212 parent.setProperty("tables.table(0).fields.field(1).name", "otherName");
213 assertEquals(NodeStructureHelper.field(0, 1), sub2.getString("name"));
214 }
215
216
217
218
219 @Test
220 public void testConfigurationAtWithUpdateSupport() {
221 setUpSubnodeConfig();
222 final SubnodeConfiguration sub2 = (SubnodeConfiguration) config.configurationAt("fields.field(1)", true);
223 assertEquals(NodeStructureHelper.field(0, 1), sub2.getString("name"));
224 assertEquals(config, sub2.getParent());
225 }
226
227
228
229
230 @Test
231 public void testGetKeys() {
232 setUpSubnodeConfig();
233 final Set<String> keys = new HashSet<>(ConfigurationAssert.keysToList(config));
234 assertEquals(new HashSet<>(Arrays.asList("name", "fields.field.name")), keys);
235 }
236
237
238
239
240 @Test
241 public void testGetNodeModel() {
242 setUpSubnodeConfig();
243 final InMemoryNodeModel nodeModel = config.getNodeModel();
244
245 assertEquals("table", nodeModel.getNodeHandler().getRootNode().getNodeName());
246 }
247
248
249
250
251 @Test
252 public void testGetProperties() {
253 setUpSubnodeConfig();
254 checkSubConfigContent();
255 }
256
257
258
259
260 @Test
261 public void testInitSubNodeConfig() {
262 setUpSubnodeConfig();
263 assertSame(NodeStructureHelper.nodeForKey(parent.getModel().getNodeHandler().getRootNode(), "tables/table(0)"),
264 config.getModel().getNodeHandler().getRootNode());
265 assertSame(parent, config.getParent());
266 }
267
268
269
270
271 @Test
272 public void testInitSubNodeConfigWithNullNode() {
273 assertThrows(IllegalArgumentException.class, () -> new SubnodeConfiguration(parent, null));
274 }
275
276
277
278
279 @Test
280 public void testInitSubNodeConfigWithNullParent() {
281 final TrackedNodeModel model = setUpTrackedModel(SELECTOR);
282 assertThrows(IllegalArgumentException.class, () -> new SubnodeConfiguration(null, model));
283 }
284
285
286
287
288 @Test
289 public void testInterpolation() {
290 parent.addProperty("tablespaces.tablespace.name", "default");
291 parent.addProperty("tablespaces.tablespace(-1).name", "test");
292 parent.addProperty("tables.table(0).tablespace", "${tablespaces.tablespace(0).name}");
293 assertEquals("default", parent.getString("tables.table(0).tablespace"));
294
295 setUpSubnodeConfig();
296 assertEquals("default", config.getString("tablespace"));
297 }
298
299
300
301
302
303 @Test
304 public void testInterpolationFromConfigurationAtNoUpdateSupport() {
305 checkInterpolationFromConfigurationAt(false);
306 }
307
308
309
310
311 @Test
312 public void testInterpolationFromConfigurationAtWithUpdateSupport() {
313 checkInterpolationFromConfigurationAt(true);
314 }
315
316
317
318
319 @Test
320 public void testInterpolator() {
321 parent.addProperty("tablespaces.tablespace.name", "default");
322 parent.addProperty("tablespaces.tablespace(-1).name", "test");
323
324 setUpSubnodeConfig();
325 InterpolationTestHelper.testGetInterpolator(config);
326 }
327
328
329
330
331 @Test
332 public void testLocalInterpolationFromConfigurationAt() {
333 parent.addProperty("base.dir", "/home/foo");
334 parent.addProperty("test.absolute.dir.dir1", "${base.dir}/path1");
335 parent.addProperty("test.absolute.dir.dir2", "${dir1}");
336
337 final Configuration sub = parent.configurationAt("test.absolute.dir");
338 assertEquals("/home/foo/path1", sub.getString("dir1"));
339 assertEquals("/home/foo/path1", sub.getString("dir2"));
340 }
341
342 @Test
343 public void testLocalLookupsInInterpolatorAreInherited() {
344 parent.addProperty("tablespaces.tablespace.name", "default");
345 parent.addProperty("tablespaces.tablespace(-1).name", "test");
346 parent.addProperty("tables.table(0).var", "${brackets:x}");
347
348 final ConfigurationInterpolator interpolator = parent.getInterpolator();
349 interpolator.registerLookup("brackets", key -> "(" + key + ")");
350 setUpSubnodeConfig();
351 assertEquals("(x)", config.getString("var", ""));
352 }
353
354
355
356
357
358 @Test
359 public void testParentChangeDetach() {
360 setUpSubnodeConfig();
361 parent.clear();
362 checkSubConfigContent();
363 }
364
365
366
367
368
369 @Test
370 public void testParentChangeDetatchException() {
371 setUpSubnodeConfig();
372 parent.setExpressionEngine(new XPathExpressionEngine());
373 parent.addProperty("newProp", "value");
374 checkSubConfigContent();
375 }
376
377
378
379
380 @Test
381 public void testSetExpressionEngine() {
382 parent.setExpressionEngine(new XPathExpressionEngine());
383 setUpSubnodeConfig("tables/table[1]");
384 assertEquals(NodeStructureHelper.field(0, 1), config.getString("fields/field[2]/name"));
385 final Set<String> keys = ConfigurationAssert.keysToSet(config);
386 assertEquals(new HashSet<>(Arrays.asList("name", "fields/field/name")), keys);
387 config.setExpressionEngine(null);
388 assertInstanceOf(XPathExpressionEngine.class, parent.getExpressionEngine());
389 }
390
391
392
393
394 @Test
395 public void testSetListDelimiterHandler() {
396 final ListDelimiterHandler handler1 = new DefaultListDelimiterHandler('/');
397 final ListDelimiterHandler handler2 = new DefaultListDelimiterHandler(';');
398 parent.setListDelimiterHandler(handler1);
399 setUpSubnodeConfig();
400 parent.setListDelimiterHandler(handler2);
401 assertEquals(handler1, config.getListDelimiterHandler());
402 config.addProperty("newProp", "test1,test2/test3");
403 assertEquals("test1,test2", parent.getString("tables.table(0).newProp"));
404 config.setListDelimiterHandler(DisabledListDelimiterHandler.INSTANCE);
405 assertEquals(handler2, parent.getListDelimiterHandler());
406 }
407
408
409
410
411
412 @Test
413 public void testSetProperty() {
414 setUpSubnodeConfig();
415 config.setProperty(null, "testTable");
416 config.setProperty("name", NodeStructureHelper.table(0) + "_tested");
417 assertEquals("testTable", parent.getString("tables.table(0)"));
418 assertEquals(NodeStructureHelper.table(0) + "_tested", parent.getString("tables.table(0).name"));
419
420 parent.setProperty("tables.table(0).fields.field(1).name", "testField");
421 assertEquals("testField", config.getString("fields.field(1).name"));
422 }
423
424
425
426
427 @Test
428 public void testSetThrowExceptionOnMissing() {
429 parent.setThrowExceptionOnMissing(true);
430 setUpSubnodeConfig();
431 assertTrue(config.isThrowExceptionOnMissing());
432 assertThrows(NoSuchElementException.class, () -> config.getString("non existing key"));
433 }
434
435
436
437
438 @Test
439 public void testSetThrowExceptionOnMissingAffectsParent() {
440 parent.setThrowExceptionOnMissing(true);
441 setUpSubnodeConfig();
442 config.setThrowExceptionOnMissing(false);
443 assertTrue(parent.isThrowExceptionOnMissing());
444 }
445 }