View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration2.tree;
18  
19  import static org.apache.commons.configuration2.tree.NodeStructureHelper.ROOT_AUTHORS_TREE;
20  import static org.apache.commons.configuration2.tree.NodeStructureHelper.ROOT_PERSONAE_TREE;
21  import static org.apache.commons.configuration2.tree.NodeStructureHelper.nodeForKey;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertSame;
26  import static org.junit.jupiter.api.Assertions.assertThrows;
27  import static org.junit.jupiter.api.Assertions.assertTrue;
28  
29  import java.util.HashSet;
30  import java.util.List;
31  import java.util.Set;
32  
33  import org.junit.jupiter.api.Test;
34  
35  /**
36   * A base test class for {@code NodeHandler} implementations for immutable nodes. Concrete sub classes have to implement
37   * a method which creates a new handler object for a given nodes structure.
38   */
39  public abstract class AbstractImmutableNodeHandlerTest {
40      /**
41       * A dummy NodeMatcher implementation that will simply accept all passed in nodes.
42       */
43      private static final class DummyNodeMatcher implements NodeMatcher<Object> {
44          @Override
45          public <T> boolean matches(final T node, final NodeHandler<T> handler, final Object criterion) {
46              return true;
47          }
48      }
49  
50      /**
51       * Creates a new {@code NodeHandler} object for the specified nodes structure.
52       *
53       * @param root the root of the nodes structure
54       * @return the handler object
55       */
56      protected abstract NodeHandler<ImmutableNode> createHandler(ImmutableNode root);
57  
58      /**
59       * Tests whether the correct parent for the root node is returned.
60       */
61      @Test
62      public void testGetParentForRoot() {
63          final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
64          assertNull(handler.getParent(ROOT_AUTHORS_TREE));
65      }
66  
67      /**
68       * Tries to query the parent node for a node which does not belong to the managed tree.
69       */
70      @Test
71      public void testGetParentInvalidNode() {
72          final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
73          final ImmutableNode node = new ImmutableNode.Builder().name("unknown").create();
74          assertThrows(IllegalArgumentException.class, () -> handler.getParent(node));
75      }
76  
77      /**
78       * Tests whether the correct parent nodes are returned. All nodes in the tree are checked.
79       */
80      @Test
81      public void testGetParentNode() {
82          final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
83          for (int authorIdx = 0; authorIdx < NodeStructureHelper.authorsLength(); authorIdx++) {
84              final ImmutableNode authorNode = nodeForKey(handler.getRootNode(), NodeStructureHelper.author(authorIdx));
85              assertSame(handler.getRootNode(), handler.getParent(authorNode), "Wrong parent for " + NodeStructureHelper.author(authorIdx));
86              for (int workIdx = 0; workIdx < NodeStructureHelper.worksLength(authorIdx); workIdx++) {
87                  final String workKey = NodeStructureHelper.appendPath(NodeStructureHelper.author(authorIdx), NodeStructureHelper.work(authorIdx, workIdx));
88                  final ImmutableNode workNode = nodeForKey(handler.getRootNode(), workKey);
89                  assertSame(authorNode, handler.getParent(workNode), "Wrong parent for " + workKey);
90                  for (int personaIdx = 0; personaIdx < NodeStructureHelper.personaeLength(authorIdx, workIdx); personaIdx++) {
91                      final String personKey = NodeStructureHelper.appendPath(workKey, NodeStructureHelper.persona(authorIdx, workIdx, personaIdx));
92                      final ImmutableNode personNode = nodeForKey(handler.getRootNode(), personKey);
93                      assertSame(workNode, handler.getParent(personNode), "Wrong parent for " + personKey);
94                  }
95              }
96          }
97      }
98  
99      /**
100      * Tests whether a node's attributes can be queried.
101      */
102     @Test
103     public void testNodeHandlerGetAttributes() {
104         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
105         final ImmutableNode node = nodeForKey(handler, "Puck");
106         assertEquals(node.getAttributes().keySet(), handler.getAttributes(node));
107     }
108 
109     /**
110      * Tests that the keys of attributes cannot be modified.
111      */
112     @Test
113     public void testNodeHandlerGetAttributesImmutable() {
114         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
115         final ImmutableNode node = nodeForKey(handler, "Puck");
116         final Set<String> attributes = handler.getAttributes(node);
117         assertThrows(UnsupportedOperationException.class, () -> attributes.add("test"));
118     }
119 
120     /**
121      * Tests whether the value of an attribute can be queried.
122      */
123     @Test
124     public void testNodeHandlerGetAttributeValue() {
125         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
126         final ImmutableNode node = nodeForKey(handler, "Prospero");
127         assertEquals("Shakespeare", handler.getAttributeValue(node, NodeStructureHelper.ATTR_AUTHOR));
128     }
129 
130     /**
131      * Tests whether a child at a given index can be accessed.
132      */
133     @Test
134     public void testNodeHandlerGetChildAtIndex() {
135         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
136         final ImmutableNode node = nodeForKey(handler, NodeStructureHelper.author(0));
137         assertSame(node.getChildren().get(1), handler.getChild(node, 1));
138     }
139 
140     /**
141      * Tests whether the children of a node can be queried.
142      */
143     @Test
144     public void testNodeHandlerGetChildren() {
145         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
146         final ImmutableNode node = nodeForKey(handler, NodeStructureHelper.author(0));
147         assertSame(node.getChildren(), handler.getChildren(node));
148     }
149 
150     /**
151      * Tests whether all children of a specific name can be queried.
152      */
153     @Test
154     public void testNodeHandlerGetChildrenByName() {
155         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
156         final String name = "Achilles";
157         final Set<ImmutableNode> children = new HashSet<>(handler.getChildren(ROOT_PERSONAE_TREE, name));
158         assertEquals(3, children.size());
159         for (final ImmutableNode c : children) {
160             assertEquals(name, c.getNodeName());
161         }
162     }
163 
164     /**
165      * Tests whether the collection of children cannot be modified.
166      */
167     @Test
168     public void testNodeHandlerGetChildrenByNameImmutable() {
169         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
170         final List<ImmutableNode> children = handler.getChildren(ROOT_PERSONAE_TREE, "Ajax");
171         assertThrows(UnsupportedOperationException.class, () -> children.add(null));
172     }
173 
174     /**
175      * Tests whether the number of all children can be queried.
176      */
177     @Test
178     public void testNodeHandlerGetChildrenCountAll() {
179         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
180         final ImmutableNode node = nodeForKey(handler, NodeStructureHelper.author(0));
181         assertEquals(NodeStructureHelper.worksLength(0), handler.getChildrenCount(node, null));
182     }
183 
184     /**
185      * Tests whether the number of all children with a given name can be queried.
186      */
187     @Test
188     public void testNodeHandlerGetChildrenCountSpecific() {
189         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
190         assertEquals(3, handler.getChildrenCount(ROOT_PERSONAE_TREE, "Achilles"));
191     }
192 
193     /**
194      * Tests a filter operation on child nodes.
195      */
196     @Test
197     public void testNodeHandlerGetMatchingChildren() {
198         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
199         final ImmutableNode target = NodeStructureHelper.nodeForKey(ROOT_AUTHORS_TREE, NodeStructureHelper.author(1));
200         final Set<String> encounteredAuthors = new HashSet<>();
201 
202         final NodeMatcher<ImmutableNode> matcher = new NodeMatcher<ImmutableNode>() {
203             @Override
204             public <T> boolean matches(final T node, final NodeHandler<T> paramHandler, final ImmutableNode criterion) {
205                 encounteredAuthors.add(paramHandler.nodeName(node));
206                 return node == target;
207             }
208         };
209 
210         final List<ImmutableNode> result = handler.getMatchingChildren(handler.getRootNode(), matcher, target);
211         assertEquals(1, result.size());
212         assertSame(target, result.get(0));
213 
214         final Set<String> expectedAuthors = new HashSet<>();
215         for (int i = 0; i < NodeStructureHelper.authorsLength(); i++) {
216             expectedAuthors.add(NodeStructureHelper.author(i));
217         }
218         assertEquals(expectedAuthors, encounteredAuthors);
219     }
220 
221     /**
222      * Tests whether filtered nodes can be counted.
223      */
224     @Test
225     public void testNodeHandlerGetMatchingChildrenCount() {
226         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
227         assertEquals(NodeStructureHelper.authorsLength(), handler.getMatchingChildrenCount(handler.getRootNode(), new DummyNodeMatcher(), this));
228     }
229 
230     /**
231      * Tests that the list returned by getMatchingChildren() cannot be modified.
232      */
233     @Test
234     public void testNodeHandlerGetMatchingChildrenImmutable() {
235         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
236         final List<ImmutableNode> result = handler.getMatchingChildren(handler.getRootNode(), new DummyNodeMatcher(), this);
237         assertThrows(UnsupportedOperationException.class, result::clear);
238     }
239 
240     /**
241      * Tests a negative check whether a node has attributes.
242      */
243     @Test
244     public void testNodeHandlerHasAttributesFalse() {
245         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
246         assertFalse(handler.hasAttributes(ROOT_PERSONAE_TREE));
247     }
248 
249     /**
250      * Tests a positive check whether a node has attributes.
251      */
252     @Test
253     public void testNodeHandlerHasAttributesTrue() {
254         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
255         final ImmutableNode node = nodeForKey(handler, "Puck");
256         assertTrue(handler.hasAttributes(node));
257     }
258 
259     /**
260      * Tests whether the index of a given child can be queried.
261      */
262     @Test
263     public void testNodeHandlerIndexOfChild() {
264         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
265         final String key = "Simmons/Hyperion";
266         final ImmutableNode parent = nodeForKey(handler, key);
267         final ImmutableNode child = nodeForKey(handler, key + "/Weintraub");
268         assertEquals(3, handler.indexOfChild(parent, child));
269     }
270 
271     /**
272      * Tests the indexOfChild() method for an unknown child node.
273      */
274     @Test
275     public void testNodeHandlerIndexOfUnknownChild() {
276         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
277         final ImmutableNode parent = nodeForKey(handler, "Homer/Ilias");
278         final ImmutableNode child = nodeForKey(handler, "Shakespeare/Troilus and Cressida/Achilles");
279         assertEquals(-1, handler.indexOfChild(parent, child));
280     }
281 
282     /**
283      * Tests whether a node with attributes is defined.
284      */
285     @Test
286     public void testNodeHandlerIsDefinedAttributes() {
287         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
288         final ImmutableNode node = new ImmutableNode.Builder().addAttribute(NodeStructureHelper.ATTR_AUTHOR, NodeStructureHelper.author(0)).create();
289         assertTrue(handler.isDefined(node));
290     }
291 
292     /**
293      * Tests whether a node with children is defined.
294      */
295     @Test
296     public void testNodeHandlerIsDefinedChildren() {
297         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
298         final ImmutableNode node = nodeForKey(handler, NodeStructureHelper.author(2));
299         assertTrue(handler.isDefined(node));
300     }
301 
302     /**
303      * Tests whether an undefined node is correctly detected.
304      */
305     @Test
306     public void testNodeHandlerIsDefinedFalse() {
307         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
308         final ImmutableNode node = new ImmutableNode.Builder().name(NodeStructureHelper.author(1)).create();
309         assertFalse(handler.isDefined(node));
310     }
311 
312     /**
313      * Tests whether a node with a value is defined.
314      */
315     @Test
316     public void testNodeHandlerIsDefinedValue() {
317         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_PERSONAE_TREE);
318         final ImmutableNode node = new ImmutableNode.Builder().value(42).create();
319         assertTrue(handler.isDefined(node));
320     }
321 
322     /**
323      * Tests whether the name of a node can be queried.
324      */
325     @Test
326     public void testNodeHandlerName() {
327         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
328         final ImmutableNode author = nodeForKey(handler, NodeStructureHelper.author(0));
329         assertEquals(NodeStructureHelper.author(0), handler.nodeName(author));
330     }
331 
332     /**
333      * Tests whether the value of a node can be queried.
334      */
335     @Test
336     public void testNodeHandlerValue() {
337         final NodeHandler<ImmutableNode> handler = createHandler(ROOT_AUTHORS_TREE);
338         ImmutableNode work = nodeForKey(handler, "Shakespeare/The Tempest");
339         final int year = 1611;
340         work = work.setValue(year);
341         assertEquals(year, handler.getValue(work));
342     }
343 }