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.betwixt.introspection;
19  
20  import java.util.List;
21  
22  import org.apache.commons.betwixt.AbstractTestCase;
23  import org.apache.commons.betwixt.ElementDescriptor;
24  import org.apache.commons.betwixt.XMLBeanInfo;
25  import org.apache.commons.betwixt.XMLIntrospector;
26  import org.apache.commons.betwixt.examples.rss.Channel;
27  
28  /**
29   * Tests for the new, more declarative style of introspection.
30   * @author <a href='http://commons.apache.org/'>Apache Commons Team</a>
31   * @version $Revision: 561314 $
32   */
33  public class TestDeclarativeIntrospection extends AbstractTestCase{
34      public TestDeclarativeIntrospection(String name) {
35          super(name);
36      }
37      
38      /** Tests whether a standard property's ElementDescriptor is hollow (as expected) */
39      public void testStandardPropertyIsHollow() throws Exception {
40          XMLIntrospector introspector = new XMLIntrospector();
41          introspector.getConfiguration().setAttributesForPrimitives(true);
42          XMLBeanInfo out = introspector.introspect(CompanyBean.class);
43          
44          ElementDescriptor companyBeanDescriptor = out.getElementDescriptor();
45          ElementDescriptor[] childDescriptors = companyBeanDescriptor.getElementDescriptors();
46          assertEquals("Correct number of child descriptors", 1, childDescriptors.length);
47          
48          ElementDescriptor addressDescriptor = childDescriptors[0];
49          assertEquals("standard property is hollow", true, addressDescriptor.isHollow());
50      }
51      
52  
53      /** Tests whether a simple element's ElementDescriptor is hollow */
54      public void testSimpleElementIsHollow() throws Exception {
55          XMLIntrospector introspector = new XMLIntrospector();
56          introspector.getConfiguration().setAttributesForPrimitives(false);
57          XMLBeanInfo out = introspector.introspect(CompanyBean.class);
58          
59          ElementDescriptor companyBeanDescriptor = out.getElementDescriptor();
60          ElementDescriptor[] childDescriptors = companyBeanDescriptor.getElementDescriptors();
61          assertEquals("Correct number of child descriptors", 2, childDescriptors.length);
62          
63          ElementDescriptor nameDescriptor = null;
64          for (int i=0, size=childDescriptors.length; i<size; i++)
65          {
66              if ("name".equals(childDescriptors[i].getLocalName())) {
67                  nameDescriptor = childDescriptors[i];
68              }
69          }
70          
71          assertNotNull("Expected to find an element descriptor for 'name'", nameDescriptor);
72          assertFalse("Expected simple element not to be hollow", nameDescriptor.isHollow());
73      }
74      
75      public void testWrappedCollective() throws Exception {
76          XMLIntrospector introspector = new XMLIntrospector();
77          introspector.getConfiguration().setWrapCollectionsInElement(true);
78          introspector.getConfiguration().setAttributesForPrimitives(true);
79          XMLBeanInfo out = introspector.introspect(PhoneBookBean.class);
80          
81          // with wrapped collective, we expect a spacer element descriptor 
82          // (for the collective) containing a single collective descriptor
83          ElementDescriptor phoneBookBeanDescriptor = out.getElementDescriptor();
84          ElementDescriptor[] phoneBookChildDescriptors = phoneBookBeanDescriptor.getElementDescriptors();
85          assertEquals("Expected single wrapping descriptor", 1, phoneBookChildDescriptors.length);
86          
87          ElementDescriptor wrappingDescriptor = phoneBookChildDescriptors[0];
88          assertNull("Spacer should not have an updater", wrappingDescriptor.getUpdater());
89          assertEquals("Wrapper element name should match getter", "numbers" , wrappingDescriptor.getQualifiedName());
90          
91          ElementDescriptor[] wrappingChildDescriptors = wrappingDescriptor.getElementDescriptors();
92          assertEquals("Expected single child for wrapping descriptor", 1, wrappingChildDescriptors.length);
93          
94          ElementDescriptor hollowPhoneNumberDescriptor = wrappingChildDescriptors[0];
95          assertTrue("Expected wrapped descriptor to be hollow", hollowPhoneNumberDescriptor.isHollow());
96          assertEquals("Expected the collective property type to be a list", 
97                      List.class, 
98                      hollowPhoneNumberDescriptor.getPropertyType());
99          assertEquals("Expected the singular property type to be the phone number", 
100                     PhoneNumberBean.class, 
101                     hollowPhoneNumberDescriptor.getSingularPropertyType());
102         
103         assertEquals("Collective element name should match adder", "number" , hollowPhoneNumberDescriptor.getQualifiedName());
104 
105     }
106     
107     public void testUnwrappedCollective() throws Exception {
108         XMLIntrospector introspector = new XMLIntrospector();
109         introspector.getConfiguration().setWrapCollectionsInElement(false);
110         introspector.getConfiguration().setAttributesForPrimitives(true);
111         XMLBeanInfo out = introspector.introspect(PhoneBookBean.class);
112         
113         // with wrapped collective, we expect a spacer element descriptor 
114         // (for the collective) containing a single collective descriptor
115         ElementDescriptor phoneBookBeanDescriptor = out.getElementDescriptor();
116         ElementDescriptor[] phoneBookChildDescriptors = phoneBookBeanDescriptor.getElementDescriptors();
117         assertEquals("Expected single child descriptor", 1, phoneBookChildDescriptors.length);
118         
119         ElementDescriptor hollowPhoneNumberDescriptor = phoneBookChildDescriptors[0];
120 
121         assertTrue("Expected collective element descriptor to be hollow", hollowPhoneNumberDescriptor.isHollow());
122         assertEquals("Expected the collective property type to be a list", 
123                     List.class, 
124                     hollowPhoneNumberDescriptor.getPropertyType());
125         assertEquals("Expected the singular property type to be the phone number", 
126                     PhoneNumberBean.class, 
127                     hollowPhoneNumberDescriptor.getSingularPropertyType());
128         assertEquals("Collective element name should match adder", "number" , hollowPhoneNumberDescriptor.getQualifiedName());
129     }
130     
131     public void testUnwrappedMap() throws Exception {
132         XMLIntrospector introspector = new XMLIntrospector();
133         introspector.getConfiguration().setWrapCollectionsInElement(false);
134         introspector.getConfiguration().setAttributesForPrimitives(true);
135         XMLBeanInfo out = introspector.introspect(DateFormatterBean.class);
136         
137         ElementDescriptor formatterDescriptor = out.getElementDescriptor();
138         ElementDescriptor[] formatterChildDescriptors = formatterDescriptor.getElementDescriptors();
139         
140         assertEquals("Only one top level child", 1, formatterChildDescriptors.length);
141         
142         ElementDescriptor entryDescriptor = formatterChildDescriptors[0];
143         assertEquals("Must be called entry", "entry" , entryDescriptor.getLocalName());
144         assertFalse("Is not hollow",  entryDescriptor.isHollow());
145         assertNull("No updater for entry spacer",  entryDescriptor.getUpdater());
146         
147         ElementDescriptor[] entryChildDesciptors = entryDescriptor.getElementDescriptors();
148         assertEquals("Entry has two children", 2, entryChildDesciptors.length);
149         
150         ElementDescriptor keyDescriptor = entryChildDesciptors[0];
151         assertEquals("Must be called key", "key", keyDescriptor.getLocalName());
152         assertTrue("Is not simple therefore hollow",  keyDescriptor.isHollow());
153         assertNotNull("Key should have an updater", keyDescriptor.getUpdater());
154         
155         ElementDescriptor valueDescriptor = entryChildDesciptors[1];
156         assertEquals("Must be called key", "value", valueDescriptor.getLocalName());
157         assertTrue("Is not simple therefore hollow",  valueDescriptor.isHollow());
158         assertNotNull("Value should have an updater", valueDescriptor.getUpdater());
159     }
160     
161     public void testWrappedMap() throws Exception {
162         XMLIntrospector introspector = new XMLIntrospector();
163         introspector.getConfiguration().setWrapCollectionsInElement(true);
164         introspector.getConfiguration().setAttributesForPrimitives(true);
165         XMLBeanInfo out = introspector.introspect(DateFormatterBean.class);
166         
167         ElementDescriptor formatterDescriptor = out.getElementDescriptor();
168         ElementDescriptor[] formatterChildDescriptors = formatterDescriptor.getElementDescriptors();
169         
170         assertEquals("Only one top level child", 1, formatterChildDescriptors.length);
171         
172         ElementDescriptor spacerDescriptor = formatterChildDescriptors[0];
173         assertEquals("Spacer must be called formats", "formats" , spacerDescriptor.getLocalName());
174         assertFalse("Is not hollow",  spacerDescriptor.isHollow());
175         assertNull("No updater for entry spacer",  spacerDescriptor.getUpdater());       
176         
177         ElementDescriptor[] spacerChildDescriptors = spacerDescriptor.getElementDescriptors();
178         assertEquals("Only one top level child", 1, spacerChildDescriptors.length);
179         
180         ElementDescriptor entryDescriptor = spacerChildDescriptors[0];
181         assertEquals("Must be called entry", "entry" , entryDescriptor.getLocalName());
182         assertFalse("Is not hollow",  entryDescriptor.isHollow());
183         assertNull("No updater for entry spacer",  entryDescriptor.getUpdater());
184         
185         ElementDescriptor[] entryChildDesciptors = entryDescriptor.getElementDescriptors();
186         assertEquals("Entry has two children", 2, entryChildDesciptors.length);
187         
188         ElementDescriptor keyDescriptor = entryChildDesciptors[0];
189         assertEquals("Must be called key", "key", keyDescriptor.getLocalName());
190         assertTrue("Is not simple therefore hollow",  keyDescriptor.isHollow());
191         assertNotNull("Key should have an updater", keyDescriptor.getUpdater());
192         
193         ElementDescriptor valueDescriptor = entryChildDesciptors[1];
194         assertEquals("Must be called key", "value", valueDescriptor.getLocalName());
195         assertTrue("Is not simple therefore hollow",  valueDescriptor.isHollow());
196         assertNotNull("Value should have an updater", valueDescriptor.getUpdater());
197     }
198     
199     public void testIsSimpleForPrimitives() throws Exception {
200         XMLIntrospector introspector = new XMLIntrospector();
201         introspector.getConfiguration().setWrapCollectionsInElement(true);
202         introspector.getConfiguration().setAttributesForPrimitives(false);
203         XMLBeanInfo out = introspector.introspect(PhoneNumberBean.class);
204         
205         // the bean is mapped to a complex type structure and so should not be simple
206         ElementDescriptor phoneNumberDescriptor = out.getElementDescriptor();
207         
208         assertFalse("Phone number descriptor is complex", phoneNumberDescriptor.isSimple());
209         
210         ElementDescriptor[] phoneNumberChildDescriptors = phoneNumberDescriptor.getElementDescriptors();
211         assertEquals("Expected three child elements", 3, phoneNumberChildDescriptors.length);
212          
213         // all children should be simple
214         assertTrue("Descriptor " + phoneNumberChildDescriptors[0] + " should be simple", 
215                     phoneNumberChildDescriptors[0].isSimple());
216         assertTrue("Descriptor " + phoneNumberChildDescriptors[1] + " should be simple", 
217                     phoneNumberChildDescriptors[1].isSimple());
218         assertTrue("Descriptor " + phoneNumberChildDescriptors[2] + " should be simple", 
219                     phoneNumberChildDescriptors[2].isSimple());
220     }
221     
222     public void testSimpleForRSS() throws Exception {
223         XMLIntrospector introspector = new XMLIntrospector();
224         introspector.getConfiguration().setWrapCollectionsInElement(true);
225         introspector.getConfiguration().setAttributesForPrimitives(false);
226         XMLBeanInfo out = introspector.introspect(Channel.class);
227         
228         ElementDescriptor channelDescriptor = out.getElementDescriptor();
229         ElementDescriptor[] childNodesOfRSS = channelDescriptor.getElementDescriptors();
230         assertEquals("RSS has only one child, channel", 1, childNodesOfRSS.length);
231         ElementDescriptor[] childNodesOfChannel = childNodesOfRSS[0].getElementDescriptors();
232         
233         boolean matched = false;
234         for (int i=0, size=childNodesOfChannel.length; i<size; i++) {
235             if ("item".equals(childNodesOfChannel[i].getLocalName())) {
236                 matched = true;   
237             }   
238         }
239         assertTrue("Local element named item", matched);
240         
241         for (int i=0, size=childNodesOfChannel.length; i<size; i++) {
242             if ("title".equals(childNodesOfChannel[i].getLocalName())) {
243                 assertFalse("Title is not hollow", childNodesOfChannel[i].isHollow());
244             } else if ("item".equals(childNodesOfChannel[i].getLocalName())) {
245                 assertTrue("Item is hollow", childNodesOfChannel[i].isHollow());
246             } else if ("textinput".equals(childNodesOfChannel[i].getLocalName())) {
247                 assertTrue("TextInput is hollow", childNodesOfChannel[i].isHollow());
248             } else if ("skipDays".equals(childNodesOfChannel[i].getLocalName())) {
249                 assertFalse("skipDays is not hollow", childNodesOfChannel[i].isHollow());
250                 assertFalse("day is not hollow", childNodesOfChannel[i].getElementDescriptors()[0].isHollow());
251             } else if ("skipHours".equals(childNodesOfChannel[i].getLocalName())) {
252                 assertFalse("skipHours is not hollow", childNodesOfChannel[i].isHollow());
253                 assertFalse("hour is not hollow", childNodesOfChannel[i].getElementDescriptors()[0].isHollow());
254             }    
255         }
256     }
257     
258     /** Tests for setting for map with a simple key */
259     public void testMapWithSimpleKey() throws Exception {
260         XMLIntrospector introspector = new XMLIntrospector();
261         introspector.getConfiguration().setWrapCollectionsInElement(false);
262         introspector.getConfiguration().setAttributesForPrimitives(true);
263         XMLBeanInfo out = introspector.introspect(AddressBook.class);
264         
265         ElementDescriptor formatterDescriptor = out.getElementDescriptor();
266         ElementDescriptor[] formatterChildDescriptors = formatterDescriptor.getElementDescriptors();
267         
268         assertEquals("Two top level children", 2, formatterChildDescriptors.length);
269         
270         ElementDescriptor entryDescriptor = formatterChildDescriptors[0];
271         assertEquals("Must be called entry", "entry" , entryDescriptor.getLocalName());
272         assertFalse("Is not hollow",  entryDescriptor.isHollow());
273         assertNull("No updater for entry spacer",  entryDescriptor.getUpdater());
274         
275         ElementDescriptor[] entryChildDesciptors = entryDescriptor.getElementDescriptors();
276         assertEquals("Entry has two children", 2, entryChildDesciptors.length);
277         
278         ElementDescriptor keyDescriptor = entryChildDesciptors[0];
279         assertEquals("Must be called key", "key", keyDescriptor.getLocalName());
280         assertFalse("Is simple therefore not hollow",  keyDescriptor.isHollow());
281         assertNotNull("Key should have an updater", keyDescriptor.getUpdater());
282         
283         ElementDescriptor valueDescriptor = entryChildDesciptors[1];
284         assertEquals("Must be called key", "value", valueDescriptor.getLocalName());
285         assertTrue("Is not simple therefore hollow",  valueDescriptor.isHollow());
286         assertNotNull("Value should have an updater", valueDescriptor.getUpdater());
287     }
288     
289     /** Tests introspector of map with simple entries */
290     public void testMapWithSimpleEntry() throws Exception {
291         XMLIntrospector introspector = new XMLIntrospector();
292         introspector.getConfiguration().setWrapCollectionsInElement(false);
293         introspector.getConfiguration().setAttributesForPrimitives(true);
294         XMLBeanInfo out = introspector.introspect(AddressBook.class);
295         
296         ElementDescriptor formatterDescriptor = out.getElementDescriptor();
297         ElementDescriptor[] formatterChildDescriptors = formatterDescriptor.getElementDescriptors();
298         
299         assertEquals("Two top level children", 2, formatterChildDescriptors.length);
300         
301         ElementDescriptor entryDescriptor = formatterChildDescriptors[1];
302         assertEquals("Must be called entry", "entry" , entryDescriptor.getLocalName());
303         assertFalse("Is not hollow",  entryDescriptor.isHollow());
304         assertNull("No updater for entry spacer",  entryDescriptor.getUpdater());
305         
306         ElementDescriptor[] entryChildDesciptors = entryDescriptor.getElementDescriptors();
307         assertEquals("Entry has two children", 2, entryChildDesciptors.length);
308         
309         ElementDescriptor keyDescriptor = entryChildDesciptors[0];
310         assertEquals("Must be called key", "key", keyDescriptor.getLocalName());
311         assertTrue("Is not simple therefore hollow",  keyDescriptor.isHollow());
312         assertNotNull("Key should have an updater", keyDescriptor.getUpdater());
313         
314         ElementDescriptor valueDescriptor = entryChildDesciptors[1];
315         assertEquals("Must be called key", "value", valueDescriptor.getLocalName());
316         assertFalse("Is simple therefore not hollow",  valueDescriptor.isHollow());
317         assertNotNull("Value should have an updater", valueDescriptor.getUpdater());
318     }
319     
320     public void testConcreteMapNoWrap() throws Exception {
321         XMLIntrospector introspector = new XMLIntrospector();
322         introspector.getConfiguration().setWrapCollectionsInElement(false);
323         XMLBeanInfo beanInfo = introspector.introspect(BeanWithConcreteMap.class);
324         ElementDescriptor beanDescriptor = beanInfo.getElementDescriptor();
325         
326         ElementDescriptor[] beanChildDescriptors = beanDescriptor.getElementDescriptors();
327         assertEquals("One Entry element", 1, beanChildDescriptors.length);
328         
329         ElementDescriptor entry = beanChildDescriptors[0];
330         ElementDescriptor[] entryChildren = entry.getElementDescriptors();
331         assertEquals("Expected key and entry elements", 2 , entryChildren.length);        
332     }
333     
334     public void testConcreteMapWithWrap() throws Exception {
335         XMLIntrospector introspector = new XMLIntrospector();
336         introspector.getConfiguration().setWrapCollectionsInElement(true);
337         XMLBeanInfo beanInfo = introspector.introspect(BeanWithConcreteMap.class);
338         
339         ElementDescriptor beanDescriptor = beanInfo.getElementDescriptor();
340         
341         ElementDescriptor[] beanChildDescriptors = beanDescriptor.getElementDescriptors();
342         assertEquals("One wrapper element", 1, beanChildDescriptors.length);
343         
344         ElementDescriptor wrapper = beanChildDescriptors[0];
345         ElementDescriptor[] wrapperChildren = wrapper.getElementDescriptors();
346         assertEquals("One Entry element", 1, wrapperChildren.length);
347         
348         ElementDescriptor entry = wrapperChildren[0];
349         ElementDescriptor[] entryChildren = entry.getElementDescriptors();
350         assertEquals("Expected key and entry elements", 2 , entryChildren.length);
351         
352         
353     }
354 }