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.junit.jupiter.api.Assertions.assertSame;
20  import static org.junit.jupiter.api.Assertions.assertThrows;
21  import static org.mockito.Mockito.mock;
22  import static org.mockito.Mockito.verify;
23  import static org.mockito.Mockito.verifyNoMoreInteractions;
24  import static org.mockito.Mockito.when;
25  
26  import java.util.Arrays;
27  import java.util.Collections;
28  import java.util.List;
29  
30  import org.junit.jupiter.api.BeforeAll;
31  import org.junit.jupiter.api.BeforeEach;
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   * Test class for {@code TrackedNodeModel}.
36   */
37  public class TestTrackedNodeModel {
38      /** Constant for a test key. */
39      private static final String KEY = "aTestKey";
40  
41      /** A test node selector. */
42      private static NodeSelector selector;
43  
44      /** A mock resolver. */
45      private static NodeKeyResolver<ImmutableNode> resolver;
46  
47      @BeforeAll
48      public static void setUpBeforeClass() throws Exception {
49          selector = new NodeSelector("someKey");
50          @SuppressWarnings("unchecked")
51          final NodeKeyResolver<ImmutableNode> resolverMock = mock(NodeKeyResolver.class);
52          resolver = resolverMock;
53      }
54  
55      /** A mock for the underlying node model. */
56      private InMemoryNodeModel parentModel;
57  
58      /** A mock for the support object that provides the model. */
59      private InMemoryNodeModelSupport modelSupport;
60  
61      /**
62       * Creates a mock for a node handler and prepares the parent model to expect a request for the tracked node handler.
63       *
64       * @return the mock for the node handler
65       */
66      private NodeHandler<ImmutableNode> prepareGetNodeHandler() {
67          @SuppressWarnings("unchecked")
68          final NodeHandler<ImmutableNode> handler = mock(NodeHandler.class);
69          when(parentModel.getTrackedNodeHandler(selector)).thenReturn(handler);
70          return handler;
71      }
72  
73      @BeforeEach
74      public void setUp() throws Exception {
75          parentModel = mock(InMemoryNodeModel.class);
76          modelSupport = mock(InMemoryNodeModelSupport.class);
77  
78          when(modelSupport.getNodeModel()).thenReturn(parentModel);
79      }
80  
81      /**
82       * Creates a test model with default settings.
83       *
84       * @return the test model
85       */
86      private TrackedNodeModel setUpModel() {
87          return new TrackedNodeModel(modelSupport, selector, true);
88      }
89  
90      /**
91       * Tests whether nodes can be added.
92       */
93      @Test
94      public void testAddNodes() {
95          final List<ImmutableNode> nodes = Arrays.asList(NodeStructureHelper.createNode("n1", 1), NodeStructureHelper.createNode("n2", 2));
96  
97          setUpModel().addNodes(KEY, nodes, resolver);
98  
99          verify(parentModel).addNodes(KEY, selector, nodes, resolver);
100         verifyNoMoreInteractions(parentModel);
101     }
102 
103     /**
104      * Tests whether properties can be added.
105      */
106     @Test
107     public void testAddProperty() {
108         final Iterable<?> values = mock(Iterable.class);
109 
110         setUpModel().addProperty(KEY, values, resolver);
111 
112         verify(parentModel).addProperty(KEY, selector, values, resolver);
113         verifyNoMoreInteractions(parentModel);
114     }
115 
116     /**
117      * Tests whether the whole model can be cleared.
118      */
119     @Test
120     public void testClear() {
121         when(parentModel.clearTree(null, selector, resolver)).thenReturn(null);
122 
123         setUpModel().clear(resolver);
124 
125         verify(parentModel).clearTree(null, selector, resolver);
126         verifyNoMoreInteractions(parentModel);
127     }
128 
129     /**
130      * Tests whether a property can be cleared.
131      */
132     @Test
133     public void testClearProperty() {
134         setUpModel().clearProperty(KEY, resolver);
135 
136         verify(parentModel).clearProperty(KEY, selector, resolver);
137         verifyNoMoreInteractions(parentModel);
138     }
139 
140     /**
141      * Tests whether a sub tree can be cleared.
142      */
143     @Test
144     public void testClearTree() {
145         final QueryResult<ImmutableNode> result = QueryResult.createNodeResult(NodeStructureHelper.createNode("test", null));
146         final List<QueryResult<ImmutableNode>> removed = Collections.singletonList(result);
147 
148         when(parentModel.clearTree(KEY, selector, resolver)).thenReturn(removed);
149 
150         assertSame(removed, setUpModel().clearTree(KEY, resolver));
151 
152         verify(parentModel).clearTree(KEY, selector, resolver);
153         verifyNoMoreInteractions(parentModel);
154     }
155 
156     /**
157      * Tests whether the model can be closed.
158      */
159     @Test
160     public void testClose() {
161         setUpModel().close();
162 
163         verify(parentModel).untrackNode(selector);
164         verifyNoMoreInteractions(parentModel);
165     }
166 
167     /**
168      * Tests whether close can be called multiple times.
169      */
170     @Test
171     public void testCloseMultipleTimes() {
172         final TrackedNodeModel model = setUpModel();
173         model.close();
174         model.close();
175 
176         verify(parentModel).untrackNode(selector);
177         verifyNoMoreInteractions(parentModel);
178     }
179 
180     /**
181      * Tests whether the correct in-memory representation can be queried.
182      */
183     @Test
184     public void testGetInMemoryRepresentation() {
185         final NodeHandler<ImmutableNode> handler = prepareGetNodeHandler();
186         final ImmutableNode root = NodeStructureHelper.createNode("Root", null);
187 
188         when(handler.getRootNode()).thenReturn(root);
189 
190         final TrackedNodeModel model = setUpModel();
191         assertSame(root, model.getInMemoryRepresentation());
192     }
193 
194     /**
195      * Tests whether a node handler can be queried.
196      */
197     @Test
198     public void testGetNodeHandler() {
199         final NodeHandler<ImmutableNode> handler = prepareGetNodeHandler();
200 
201         assertSame(handler, setUpModel().getNodeHandler());
202 
203         verify(parentModel).getTrackedNodeHandler(selector);
204         verifyNoMoreInteractions(parentModel);
205     }
206 
207     /**
208      * Tries to create an instance without a parent model.
209      */
210     @Test
211     public void testInitNoParentModel() {
212         assertThrows(IllegalArgumentException.class, () -> new TrackedNodeModel(null, selector, true));
213     }
214 
215     /**
216      * Tries to create an instance without a selector.
217      */
218     @Test
219     public void testInitNoSelector() {
220         assertThrows(IllegalArgumentException.class, () -> new TrackedNodeModel(modelSupport, null, true));
221     }
222 
223     /**
224      * Tests whether a property can be set.
225      */
226     @Test
227     public void testSetProperty() {
228         final Object value = 42;
229 
230         setUpModel().setProperty(KEY, value, resolver);
231 
232         verify(parentModel).setProperty(KEY, selector, value, resolver);
233         verifyNoMoreInteractions(parentModel);
234     }
235 
236     /**
237      * Tests whether the root node can be changed.
238      */
239     @Test
240     public void testSetRootNode() {
241         final ImmutableNode root = NodeStructureHelper.createNode("root", null);
242 
243         final TrackedNodeModel model = setUpModel();
244         model.setRootNode(root);
245 
246         verify(parentModel).replaceTrackedNode(selector, root);
247         verifyNoMoreInteractions(parentModel);
248     }
249 }