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