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  
18  package org.apache.commons.jxpath.ri.model.dynamic;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.apache.commons.jxpath.AbstractJXPathTest;
29  import org.apache.commons.jxpath.JXPathContext;
30  import org.apache.commons.jxpath.TestBean;
31  import org.junit.jupiter.api.BeforeEach;
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   * TODO more iterator testing with maps
36   */
37  public class DynamicPropertiesModelTest extends AbstractJXPathTest {
38  
39      private JXPathContext context;
40  
41      @Override
42      @BeforeEach
43      public void setUp() {
44          if (context == null) {
45              context = JXPathContext.newContext(new TestBean());
46              context.setFactory(new TestDynamicPropertyFactory());
47          }
48      }
49  
50      /**
51       * Testing the pseudo-attribute "name" that dynamic property objects appear to have.
52       */
53      @Test
54      public void testAttributeName() {
55          assertXPathValue(context, "map[@name = 'Key1']", "Value 1");
56          assertXPathPointer(context, "map[@name = 'Key1']", "/map[@name='Key1']");
57          assertXPathPointerLenient(context, "map[@name = 'Key"'"'1']", "/map[@name='Key"'"'1']");
58          assertXPathValue(context, "/.[@name='map']/Key2/name", "Name 6");
59          assertXPathPointer(context, "/.[@name='map']/Key2/name", "/map[@name='Key2']/name");
60          // Bean in a map
61          assertXPathValue(context, "/map[@name='Key2'][@name='name']", "Name 6");
62          assertXPathPointer(context, "/map[@name='Key2'][@name='name']", "/map[@name='Key2']/name");
63          // Map in a bean in a map
64          assertXPathValue(context, "/.[@name='map'][@name='Key2'][@name='name']", "Name 6");
65          assertXPathPointer(context, "/.[@name='map'][@name='Key2'][@name='name']", "/map[@name='Key2']/name");
66          ((Map) context.getValue("map")).put("Key:3", "value3");
67          assertXPathValueAndPointer(context, "/map[@name='Key:3']", "value3", "/map[@name='Key:3']");
68          assertXPathValueAndPointer(context, "/map[@name='Key:4:5']", null, "/map[@name='Key:4:5']");
69      }
70  
71      @Test
72      public void testAxisChild() {
73          assertXPathValue(context, "map/Key1", "Value 1");
74          assertXPathPointer(context, "map/Key1", "/map[@name='Key1']");
75          assertXPathValue(context, "map/Key2/name", "Name 6");
76          assertXPathPointer(context, "map/Key2/name", "/map[@name='Key2']/name");
77      }
78  
79      @Test
80      public void testAxisDescendant() {
81          assertXPathValue(context, "//Key1", "Value 1");
82      }
83  
84      @Test
85      public void testCollectionOfMaps() {
86          final TestBean bean = (TestBean) context.getContextBean();
87          final List list = new ArrayList();
88          bean.getMap().put("stuff", list);
89          Map m = new HashMap();
90          m.put("fruit", "apple");
91          list.add(m);
92          m = new HashMap();
93          m.put("berry", "watermelon");
94          list.add(m);
95          m = new HashMap();
96          m.put("fruit", "banana");
97          list.add(m);
98          assertXPathValueIterator(context, "/map/stuff/fruit", list("apple", "banana"));
99          assertXPathValueIterator(context, "/map/stuff[@name='fruit']", list("apple", "banana"));
100     }
101 
102     @Test
103     public void testCreatePath() {
104         final TestBean bean = (TestBean) context.getContextBean();
105         bean.setMap(null);
106         // Calls factory.createObject(..., testBean, "map"), then
107         // sets the value
108         assertXPathCreatePath(context, "/map[@name='TestKey1']", "", "/map[@name='TestKey1']");
109     }
110 
111     @Test
112     public void testCreatePathAndSetValue() {
113         final TestBean bean = (TestBean) context.getContextBean();
114         bean.setMap(null);
115         // Calls factory.createObject(..., testBean, "map"), then
116         // sets the value
117         assertXPathCreatePathAndSetValue(context, "/map[@name='TestKey1']", "Test", "/map[@name='TestKey1']");
118     }
119 
120     @Test
121     public void testCreatePathAndSetValueCollectionElement() {
122         final TestBean bean = (TestBean) context.getContextBean();
123         bean.setMap(null);
124         assertXPathCreatePathAndSetValue(context, "/map/TestKey3[2]", "Test1", "/map[@name='TestKey3'][2]");
125         // Should be the same as the one before
126         assertXPathCreatePathAndSetValue(context, "/map[@name='TestKey3'][3]", "Test2", "/map[@name='TestKey3'][3]");
127     }
128 
129     @Test
130     public void testCreatePathAndSetValueCreateBean() {
131         final TestBean bean = (TestBean) context.getContextBean();
132         bean.setMap(null);
133         // Calls factory.createObject(..., testBean, "map"), then
134         // then factory.createObject(..., map, "TestKey2"), then
135         // sets the value
136         assertXPathCreatePathAndSetValue(context, "/map[@name='TestKey2']/int", Integer.valueOf(4), "/map[@name='TestKey2']/int");
137     }
138 
139     @Test
140     public void testCreatePathAndSetValueNewCollectionElement() {
141         final TestBean bean = (TestBean) context.getContextBean();
142         bean.setMap(null);
143         // Create an element of a dynamic map element, which is a collection
144         assertXPathCreatePathAndSetValue(context, "/map/TestKey4[1]/int", Integer.valueOf(2), "/map[@name='TestKey4'][1]/int");
145         bean.getMap().remove("TestKey4");
146         // Should be the same as the one before
147         assertXPathCreatePathAndSetValue(context, "/map/TestKey4[1]/int", Integer.valueOf(3), "/map[@name='TestKey4'][1]/int");
148     }
149 
150     @Test
151     public void testCreatePathCollectionElement() {
152         final TestBean bean = (TestBean) context.getContextBean();
153         bean.setMap(null);
154         assertXPathCreatePath(context, "/map/TestKey3[2]", null, "/map[@name='TestKey3'][2]");
155         // Should be the same as the one before
156         assertXPathCreatePath(context, "/map[@name='TestKey3'][3]", null, "/map[@name='TestKey3'][3]");
157     }
158 
159     @Test
160     public void testCreatePathCreateBean() {
161         final TestBean bean = (TestBean) context.getContextBean();
162         bean.setMap(null);
163         // Calls factory.createObject(..., testBean, "map"), then
164         // then factory.createObject(..., map, "TestKey2"), then
165         // sets the value
166         assertXPathCreatePath(context, "/map[@name='TestKey2']/int", Integer.valueOf(1), "/map[@name='TestKey2']/int");
167     }
168 
169     @Test
170     public void testCreatePathNewCollectionElement() {
171         final TestBean bean = (TestBean) context.getContextBean();
172         bean.setMap(null);
173         // Create an element of a dynamic map element, which is a collection
174         assertXPathCreatePath(context, "/map/TestKey4[1]/int", Integer.valueOf(1), "/map[@name='TestKey4'][1]/int");
175         bean.getMap().remove("TestKey4");
176         // Should be the same as the one before
177         assertXPathCreatePath(context, "/map/TestKey4[1]/int", Integer.valueOf(1), "/map[@name='TestKey4'][1]/int");
178     }
179 
180     @Test
181     public void testMapOfMaps() {
182         final TestBean bean = (TestBean) context.getContextBean();
183         final Map fruit = new HashMap();
184         fruit.put("apple", "green");
185         fruit.put("orange", "red");
186         final Map meat = new HashMap();
187         meat.put("pork", "pig");
188         meat.put("beef", "cow");
189         bean.getMap().put("fruit", fruit);
190         bean.getMap().put("meat", meat);
191         assertXPathPointer(context, "//beef", "/map[@name='meat'][@name='beef']");
192         assertXPathPointer(context, "map//apple", "/map[@name='fruit'][@name='apple']");
193         // Ambiguous search - will return nothing
194         assertXPathPointerLenient(context, "map//banana", "null()");
195         // Unambiguous, even though the particular key is missing
196         assertXPathPointerLenient(context, "//fruit/pear", "/map[@name='fruit']/pear");
197     }
198 
199     @Test
200     public void testRemovePath() {
201         final TestBean bean = (TestBean) context.getContextBean();
202         bean.getMap().put("TestKey1", "test");
203         // Remove dynamic property
204         context.removePath("map[@name = 'TestKey1']");
205         assertNull(context.getValue("map[@name = 'TestKey1']"), "Remove dynamic property value");
206     }
207 
208     @Test
209     public void testRemovePathArrayElement() {
210         final TestBean bean = (TestBean) context.getContextBean();
211         bean.getMap().put("TestKey2", new String[] { "temp1", "temp2" });
212         context.removePath("map[@name = 'TestKey2'][1]");
213         assertEquals("temp2", context.getValue("map[@name = 'TestKey2'][1]"), "Remove dynamic property collection element");
214     }
215 
216     @Test
217     public void testSetCollection() {
218         // See if we can assign a whole collection
219         context.setValue("map/Key1", new Integer[] { Integer.valueOf(7), Integer.valueOf(8) });
220         // And then an element in that collection
221         assertXPathSetValue(context, "map/Key1[1]", Integer.valueOf(9));
222     }
223 
224     /**
225      * The key does not exist, but the assignment should succeed anyway, because you should always be able to store anything in a Map.
226      */
227     @Test
228     public void testSetNewKey() {
229         // Using a "simple" path
230         assertXPathSetValue(context, "map/Key4", Integer.valueOf(7));
231         // Using a "non-simple" path
232         assertXPathPointerLenient(context, "//map/Key5", "/map/Key5");
233         assertXPathSetValue(context, "//map/Key5", Integer.valueOf(8));
234     }
235 
236     @Test
237     public void testSetPrimitiveValue() {
238         assertXPathSetValue(context, "map/Key1", Integer.valueOf(6));
239     }
240 }