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