1   /*
2    * Copyright 1999-2004 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.jxpath.ri.model.dynamic;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.jxpath.JXPathContext;
24  import org.apache.commons.jxpath.JXPathTestCase;
25  import org.apache.commons.jxpath.TestBean;
26  
27  /***
28   * @todo more iterator testing with maps
29   *
30   * @author Dmitri Plotnikov
31   * @version $Revision: 1.8 $ $Date: 2004/02/29 14:17:45 $
32   */
33  
34  public class DynamicPropertiesModelTest extends JXPathTestCase {
35      private static boolean enabled = true;
36      private JXPathContext context;
37  
38      /***
39       * Construct a new instance of this test case.
40       *
41       * @param name Name of the test case
42       */
43      public DynamicPropertiesModelTest(String name) {
44          super(name);
45      }
46  
47      public void setUp() {
48          if (context == null) {
49              context = JXPathContext.newContext(new TestBean());
50              context.setFactory(new TestDynamicPropertyFactory());
51          }
52      }
53  
54      public void testAxisChild() {
55          assertXPathValue(context, "map/Key1", "Value 1");
56  
57          assertXPathPointer(context, "map/Key1", "/map[@name='Key1']");
58  
59          assertXPathValue(context, "map/Key2/name", "Name 6");
60  
61          assertXPathPointer(context, "map/Key2/name", "/map[@name='Key2']/name");
62      }
63  
64      public void testAxisDescendant() {
65          assertXPathValue(context, "//Key1", "Value 1");
66      }
67  
68      /***
69       * Testing the pseudo-attribute "name" that dynamic property
70       * objects appear to have.
71       */
72      public void testAttributeName() {
73          assertXPathValue(context, "map[@name = 'Key1']", "Value 1");
74  
75          assertXPathPointer(
76              context,
77              "map[@name = 'Key1']",
78              "/map[@name='Key1']");
79  
80          assertXPathPointerLenient(
81              context,
82              "map[@name = 'Key"'"'1']",
83              "/map[@name='Key"'"'1']");
84  
85          assertXPathValue(context, "/.[@name='map']/Key2/name", "Name 6");
86  
87          assertXPathPointer(
88              context,
89              "/.[@name='map']/Key2/name",
90              "/map[@name='Key2']/name");
91  
92          // Bean in a map
93          assertXPathValue(context, "/map[@name='Key2'][@name='name']", "Name 6");
94  
95          assertXPathPointer(
96              context,
97              "/map[@name='Key2'][@name='name']",
98              "/map[@name='Key2']/name");
99  
100         // Map in a bean in a map
101         assertXPathValue(
102             context,
103             "/.[@name='map'][@name='Key2'][@name='name']",
104             "Name 6");
105 
106         assertXPathPointer(
107             context,
108             "/.[@name='map'][@name='Key2'][@name='name']",
109             "/map[@name='Key2']/name");
110                         
111         ((Map)context.getValue("map")).put("Key:3", "value3");
112         
113         assertXPathValueAndPointer(
114             context,
115             "/map[@name='Key:3']",
116             "value3",
117             "/map[@name='Key:3']");
118 
119         assertXPathValueAndPointer(
120             context,
121             "/map[@name='Key:4:5']",
122             null,
123             "/map[@name='Key:4:5']");
124     }
125 
126     public void testSetPrimitiveValue() {
127         assertXPathSetValue(context, "map/Key1", new Integer(6));
128     }
129 
130     public void testSetCollection() {
131         // See if we can assign a whole collection        
132         context.setValue(
133             "map/Key1",
134             new Integer[] { new Integer(7), new Integer(8)});
135 
136         // And then an element in that collection
137         assertXPathSetValue(context, "map/Key1[1]", new Integer(9));
138     }
139 
140     /***
141      * The key does not exist, but the assignment should succeed anyway,
142      * because you should always be able to store anything in a Map.
143      */
144     public void testSetNewKey() {
145         // Using a "simple" path
146         assertXPathSetValue(context, "map/Key4", new Integer(7));
147         
148         // Using a "non-simple" path
149         assertXPathPointerLenient(context, "//map/Key5", "/map/Key5");
150         
151         assertXPathSetValue(context, "//map/Key5", new Integer(8));
152     }
153 
154     public void testCreatePath() {
155         TestBean bean = (TestBean) context.getContextBean();
156         bean.setMap(null);
157 
158         // Calls factory.createObject(..., testBean, "map"), then
159         // sets the value
160         assertXPathCreatePath(
161             context,
162             "/map[@name='TestKey1']",
163             "",
164             "/map[@name='TestKey1']");
165     }
166 
167     public void testCreatePathAndSetValue() {
168         TestBean bean = (TestBean) context.getContextBean();
169         bean.setMap(null);
170 
171         // Calls factory.createObject(..., testBean, "map"), then
172         // sets the value
173         assertXPathCreatePathAndSetValue(
174             context,
175             "/map[@name='TestKey1']",
176             "Test",
177             "/map[@name='TestKey1']");
178     }
179 
180     public void testCreatePathCreateBean() {
181         TestBean bean = (TestBean) context.getContextBean();
182         bean.setMap(null);
183 
184         // Calls factory.createObject(..., testBean, "map"), then
185         // then factory.createObject(..., map, "TestKey2"), then
186         // sets the value
187         assertXPathCreatePath(
188             context,
189             "/map[@name='TestKey2']/int",
190             new Integer(1),
191             "/map[@name='TestKey2']/int");
192     }
193 
194     public void testCreatePathAndSetValueCreateBean() {
195         TestBean bean = (TestBean) context.getContextBean();
196         bean.setMap(null);
197 
198         // Calls factory.createObject(..., testBean, "map"), then
199         // then factory.createObject(..., map, "TestKey2"), then
200         // sets the value
201         assertXPathCreatePathAndSetValue(
202             context,
203             "/map[@name='TestKey2']/int",
204             new Integer(4),
205             "/map[@name='TestKey2']/int");
206     }
207 
208     public void testCreatePathCollectionElement() {
209         TestBean bean = (TestBean) context.getContextBean();
210         bean.setMap(null);
211 
212         assertXPathCreatePath(
213             context,
214             "/map/TestKey3[2]",
215             null,
216             "/map[@name='TestKey3'][2]");
217 
218         // Should be the same as the one before
219         assertXPathCreatePath(
220             context,
221             "/map[@name='TestKey3'][3]",
222             null,
223             "/map[@name='TestKey3'][3]");
224     }
225 
226     public void testCreatePathAndSetValueCollectionElement() {
227         TestBean bean = (TestBean) context.getContextBean();
228         bean.setMap(null);
229 
230         assertXPathCreatePathAndSetValue(
231             context,
232             "/map/TestKey3[2]",
233             "Test1",
234             "/map[@name='TestKey3'][2]");
235 
236         // Should be the same as the one before
237         assertXPathCreatePathAndSetValue(
238             context,
239             "/map[@name='TestKey3'][3]",
240             "Test2",
241             "/map[@name='TestKey3'][3]");
242     }
243 
244     public void testCreatePathNewCollectionElement() {
245         TestBean bean = (TestBean) context.getContextBean();
246         bean.setMap(null);
247 
248         // Create an element of a dynamic map element, which is a collection
249         assertXPathCreatePath(
250             context,
251             "/map/TestKey4[1]/int",
252             new Integer(1),
253             "/map[@name='TestKey4'][1]/int");
254 
255         bean.getMap().remove("TestKey4");
256 
257         // Should be the same as the one before
258         assertXPathCreatePath(
259             context,
260             "/map/TestKey4[1]/int",
261             new Integer(1),
262             "/map[@name='TestKey4'][1]/int");
263     }
264 
265     public void testCreatePathAndSetValueNewCollectionElement() {
266         TestBean bean = (TestBean) context.getContextBean();
267         bean.setMap(null);
268 
269         // Create an element of a dynamic map element, which is a collection
270         assertXPathCreatePathAndSetValue(
271             context,
272             "/map/TestKey4[1]/int",
273             new Integer(2),
274             "/map[@name='TestKey4'][1]/int");
275 
276         bean.getMap().remove("TestKey4");
277 
278         // Should be the same as the one before
279         assertXPathCreatePathAndSetValue(
280             context,
281             "/map/TestKey4[1]/int",
282             new Integer(3),
283             "/map[@name='TestKey4'][1]/int");
284     }
285 
286     public void testRemovePath() {
287         TestBean bean = (TestBean) context.getContextBean();
288         bean.getMap().put("TestKey1", "test");
289 
290         // Remove dynamic property
291         context.removePath("map[@name = 'TestKey1']");
292         assertEquals(
293             "Remove dynamic property value",
294             null,
295             context.getValue("map[@name = 'TestKey1']"));
296     }
297 
298     public void testRemovePathArrayElement() {
299         TestBean bean = (TestBean) context.getContextBean();
300 
301         bean.getMap().put("TestKey2", new String[] { "temp1", "temp2" });
302         context.removePath("map[@name = 'TestKey2'][1]");
303         assertEquals(
304             "Remove dynamic property collection element",
305             "temp2",
306             context.getValue("map[@name = 'TestKey2'][1]"));
307     }
308     
309     public void testCollectionOfMaps() {
310         TestBean bean = (TestBean) context.getContextBean();
311         List list = new ArrayList();
312 
313         bean.getMap().put("stuff", list);        
314 
315         Map m = new HashMap();
316         m.put("fruit", "apple");
317         list.add(m);
318 
319         m = new HashMap();
320         m.put("berry", "watermelon");
321         list.add(m);
322 
323         m = new HashMap();
324         m.put("fruit", "banana");
325         list.add(m);
326 
327         assertXPathValueIterator(
328             context,
329             "/map/stuff/fruit",
330             list("apple", "banana"));
331 
332         assertXPathValueIterator(
333             context,
334             "/map/stuff[@name='fruit']",
335             list("apple", "banana"));        
336     }
337 
338     public void testMapOfMaps() {
339         TestBean bean = (TestBean) context.getContextBean();
340 
341         Map fruit = new HashMap();
342         fruit.put("apple", "green");
343         fruit.put("orange", "red");
344         
345         Map meat = new HashMap();
346         meat.put("pork", "pig");
347         meat.put("beef", "cow");
348         
349         bean.getMap().put("fruit", fruit);        
350         bean.getMap().put("meat", meat);        
351                 
352         assertXPathPointer(
353             context,
354             "//beef",
355             "/map[@name='meat'][@name='beef']");
356         
357         assertXPathPointer(
358             context,
359             "map//apple",
360             "/map[@name='fruit'][@name='apple']");
361 
362         // Ambiguous search - will return nothing
363         assertXPathPointerLenient(context, "map//banana", "null()");
364         
365         // Unambiguous, even though the particular key is missing 
366         assertXPathPointerLenient(
367             context,
368             "//fruit/pear",
369             "/map[@name='fruit']/pear");
370     }
371 }