001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.configuration.beanutils; 018 019 import static org.junit.Assert.assertEquals; 020 import static org.junit.Assert.assertNotNull; 021 import static org.junit.Assert.assertNull; 022 import static org.junit.Assert.assertTrue; 023 024 import java.util.Map; 025 026 import org.apache.commons.configuration.HierarchicalConfiguration; 027 import org.apache.commons.configuration.SubnodeConfiguration; 028 import org.apache.commons.configuration.tree.ConfigurationNode; 029 import org.junit.Test; 030 031 /** 032 * Test class for XMLBeanDeclaration. 033 * 034 * @since 1.3 035 * @author <a 036 * href="http://commons.apache.org/configuration/team-list.html">Commons 037 * Configuration team</a> 038 * @version $Id: TestXMLBeanDeclaration.java 1225643 2011-12-29 20:37:36Z oheger $ 039 */ 040 public class TestXMLBeanDeclaration 041 { 042 /** An array with some test properties. */ 043 static final String[] TEST_PROPS = 044 { "firstName", "lastName", "department", "age", "hobby"}; 045 046 /** An array with the values for the test properties. */ 047 static final String[] TEST_VALUES = 048 { "John", "Smith", "Engineering", "42", "TV"}; 049 050 /** An array with the names of nested (complex) properties. */ 051 static final String[] COMPLEX_PROPS = 052 { "address", "car"}; 053 054 /** An array with the names of the classes of the complex properties. */ 055 static final String[] COMPLEX_CLASSES = 056 { "org.apache.commons.configuration.test.AddressTest", 057 "org.apache.commons.configuration.test.CarTest"}; 058 059 /** An array with the property names of the complex properties. */ 060 static final String[][] COMPLEX_ATTRIBUTES = 061 { 062 { "street", "zip", "city", "country"}, 063 { "brand", "color"}}; 064 065 /** An array with the values of the complex properties. */ 066 static final String[][] COMPLEX_VALUES = 067 { 068 { "Baker Street", "12354", "London", "UK"}, 069 { "Bentley", "silver"}}; 070 071 /** Constant for the key with the bean declaration. */ 072 static final String KEY = "myBean"; 073 074 /** Constant for the section with the variables.*/ 075 static final String VARS = "variables."; 076 077 /** Stores the object to be tested. */ 078 XMLBeanDeclaration decl; 079 080 /** 081 * Tests creating a declaration from a null node. This should cause an 082 * exception. 083 */ 084 @Test(expected = IllegalArgumentException.class) 085 public void testInitFromNullNode() 086 { 087 decl = new XMLBeanDeclaration(new HierarchicalConfiguration().configurationAt(null), 088 (ConfigurationNode) null); 089 } 090 091 /** 092 * Tests creating a declaration from a null configuration. This should cause 093 * an exception. 094 */ 095 @Test(expected = IllegalArgumentException.class) 096 public void testInitFromNullConfiguration() 097 { 098 decl = new XMLBeanDeclaration((HierarchicalConfiguration) null); 099 } 100 101 /** 102 * Tests creating a declaration from a null configuration with a key. This 103 * should cause an exception. 104 */ 105 @Test(expected = IllegalArgumentException.class) 106 public void testInitFromNullConfigurationAndKey() 107 { 108 decl = new XMLBeanDeclaration(null, KEY); 109 } 110 111 /** 112 * Tests creating a declaration from a null configuration with a node. This 113 * should cause an exception. 114 */ 115 @Test(expected = IllegalArgumentException.class) 116 public void testInitFromNullConfigurationAndNode() 117 { 118 decl = new XMLBeanDeclaration(null, new HierarchicalConfiguration() 119 .getRoot()); 120 } 121 122 /** 123 * Tests fetching the bean's class name. 124 */ 125 @Test 126 public void testGetBeanClassName() 127 { 128 HierarchicalConfiguration config = new HierarchicalConfiguration(); 129 config.addProperty(KEY + "[@config-class]", getClass().getName()); 130 decl = new XMLBeanDeclaration(config, KEY); 131 assertEquals("Wrong class name", getClass().getName(), decl 132 .getBeanClassName()); 133 } 134 135 /** 136 * Tests fetching the bean's class name if it is undefined. 137 */ 138 @Test 139 public void testGetBeanClassNameUndefined() 140 { 141 decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); 142 assertNull(decl.getBeanClassName()); 143 } 144 145 /** 146 * Tests fetching the name of the bean factory. 147 */ 148 @Test 149 public void testGetBeanFactoryName() 150 { 151 HierarchicalConfiguration config = new HierarchicalConfiguration(); 152 config.addProperty(KEY + "[@config-factory]", "myFactory"); 153 decl = new XMLBeanDeclaration(config, KEY); 154 assertEquals("Wrong factory name", "myFactory", decl 155 .getBeanFactoryName()); 156 } 157 158 /** 159 * Tests fetching the name of the bean factory if it is undefined. 160 */ 161 @Test 162 public void testGetBeanFactoryNameUndefined() 163 { 164 decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); 165 assertNull(decl.getBeanFactoryName()); 166 } 167 168 /** 169 * Tests fetching the parameter for the bean factory. 170 */ 171 @Test 172 public void testGetBeanFactoryParameter() 173 { 174 HierarchicalConfiguration config = new HierarchicalConfiguration(); 175 config 176 .addProperty(KEY + "[@config-factoryParam]", 177 "myFactoryParameter"); 178 decl = new XMLBeanDeclaration(config, KEY); 179 assertEquals("Wrong factory parameter", "myFactoryParameter", decl 180 .getBeanFactoryParameter()); 181 } 182 183 /** 184 * Tests fetching the parameter for the bean factory if it is undefined. 185 */ 186 @Test 187 public void testGetBeanFactoryParameterUndefined() 188 { 189 decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); 190 assertNull(decl.getBeanFactoryParameter()); 191 } 192 193 /** 194 * Tests if the bean's properties are correctly extracted from the 195 * configuration object. 196 */ 197 @Test 198 public void testGetBeanProperties() 199 { 200 HierarchicalConfiguration config = new HierarchicalConfiguration(); 201 setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); 202 decl = new XMLBeanDeclaration(config, KEY); 203 checkProperties(decl, TEST_PROPS, TEST_VALUES); 204 } 205 206 /** 207 * Tests obtaining the bean's properties when reserved attributes are 208 * involved. These should be ignored. 209 */ 210 @Test 211 public void testGetBeanPropertiesWithReservedAttributes() 212 { 213 HierarchicalConfiguration config = new HierarchicalConfiguration(); 214 setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); 215 config.addProperty(KEY + "[@config-testattr]", "yes"); 216 config.addProperty(KEY + "[@config-anothertest]", "this, too"); 217 decl = new XMLBeanDeclaration(config, KEY); 218 checkProperties(decl, TEST_PROPS, TEST_VALUES); 219 } 220 221 /** 222 * Tests fetching properties if none are defined. 223 */ 224 @Test 225 public void testGetBeanPropertiesEmpty() 226 { 227 decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); 228 Map<String, Object> props = decl.getBeanProperties(); 229 assertTrue("Properties found", props == null || props.isEmpty()); 230 } 231 232 /** 233 * Creates a configuration with data for testing nested bean declarations. 234 * @return the initialized test configuration 235 */ 236 private HierarchicalConfiguration prepareNestedBeanDeclarations() 237 { 238 HierarchicalConfiguration config = new HierarchicalConfiguration(); 239 setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); 240 for (int i = 0; i < COMPLEX_PROPS.length; i++) 241 { 242 setupBeanDeclaration(config, KEY + '.' + COMPLEX_PROPS[i], 243 COMPLEX_ATTRIBUTES[i], COMPLEX_VALUES[i]); 244 config.addProperty( 245 KEY + '.' + COMPLEX_PROPS[i] + "[@config-class]", 246 COMPLEX_CLASSES[i]); 247 } 248 return config; 249 } 250 251 /** 252 * Tests fetching nested bean declarations. 253 */ 254 @Test 255 public void testGetNestedBeanDeclarations() 256 { 257 HierarchicalConfiguration config = prepareNestedBeanDeclarations(); 258 decl = new XMLBeanDeclaration(config, KEY); 259 checkProperties(decl, TEST_PROPS, TEST_VALUES); 260 261 Map<String, Object> nested = decl.getNestedBeanDeclarations(); 262 assertEquals("Wrong number of nested declarations", 263 COMPLEX_PROPS.length, nested.size()); 264 for (int i = 0; i < COMPLEX_PROPS.length; i++) 265 { 266 XMLBeanDeclaration d = (XMLBeanDeclaration) nested 267 .get(COMPLEX_PROPS[i]); 268 assertNotNull("No declaration found for " + COMPLEX_PROPS[i], d); 269 checkProperties(d, COMPLEX_ATTRIBUTES[i], COMPLEX_VALUES[i]); 270 assertEquals("Wrong bean class", COMPLEX_CLASSES[i], d 271 .getBeanClassName()); 272 } 273 } 274 275 /** 276 * Tests whether the factory method for creating nested bean declarations 277 * gets called. 278 */ 279 @Test 280 public void testGetNestedBeanDeclarationsFactoryMethod() 281 { 282 HierarchicalConfiguration config = prepareNestedBeanDeclarations(); 283 decl = new XMLBeanDeclaration(config, KEY) 284 { 285 @Override 286 protected BeanDeclaration createBeanDeclaration( 287 ConfigurationNode node) 288 { 289 return new XMLBeanDeclarationTestImpl(getConfiguration() 290 .configurationAt(node.getName()), node); 291 } 292 }; 293 Map<String, Object> nested = decl.getNestedBeanDeclarations(); 294 for (int i = 0; i < COMPLEX_PROPS.length; i++) 295 { 296 Object d = nested.get(COMPLEX_PROPS[i]); 297 assertTrue("Wrong class for bean declaration: " + d, 298 d instanceof XMLBeanDeclarationTestImpl); 299 } 300 } 301 302 /** 303 * Tests fetching nested bean declarations if none are defined. 304 */ 305 @Test 306 public void testGetNestedBeanDeclarationsEmpty() 307 { 308 HierarchicalConfiguration config = new HierarchicalConfiguration(); 309 setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); 310 decl = new XMLBeanDeclaration(config, KEY); 311 Map<String, Object> nested = decl.getNestedBeanDeclarations(); 312 assertTrue("Found nested declarations", nested == null 313 || nested.isEmpty()); 314 } 315 316 /** 317 * Tests whether interpolation of bean properties works. 318 */ 319 @Test 320 public void testGetInterpolatedBeanProperties() 321 { 322 HierarchicalConfiguration config = new HierarchicalConfiguration(); 323 String[] varValues = new String[TEST_PROPS.length]; 324 for(int i = 0; i < TEST_PROPS.length; i++) 325 { 326 varValues[i] = "${" + VARS + TEST_PROPS[i] + "}"; 327 config.addProperty(VARS + TEST_PROPS[i], TEST_VALUES[i]); 328 } 329 setupBeanDeclaration(config, KEY, TEST_PROPS, varValues); 330 decl = new XMLBeanDeclaration(config, KEY); 331 checkProperties(decl, TEST_PROPS, TEST_VALUES); 332 } 333 334 /** 335 * Tests constructing a bean declaration from an undefined key. This should 336 * cause an exception. 337 */ 338 @Test(expected = IllegalArgumentException.class) 339 public void testInitFromUndefinedKey() 340 { 341 HierarchicalConfiguration config = new HierarchicalConfiguration(); 342 setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); 343 decl = new XMLBeanDeclaration(config, "undefined_key"); 344 } 345 346 /** 347 * Tests constructing a bean declaration from a key, which is undefined when 348 * the optional flag is set. In this case an empty declaration should be 349 * created, which can be used for creating beans as long as a default class 350 * is provided. 351 */ 352 @Test 353 public void testInitFromUndefinedKeyOptional() 354 { 355 HierarchicalConfiguration config = new HierarchicalConfiguration(); 356 setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); 357 decl = new XMLBeanDeclaration(config, "undefined_key", true); 358 assertNull("Found a bean class", decl.getBeanClassName()); 359 } 360 361 /** 362 * Tests constructing a bean declaration from a key with multiple values. 363 * This should cause an exception because keys must be unique. 364 */ 365 @Test(expected = IllegalArgumentException.class) 366 public void testInitFromMultiValueKey() 367 { 368 HierarchicalConfiguration config = new HierarchicalConfiguration(); 369 config.addProperty(KEY, "myFirstKey"); 370 config.addProperty(KEY, "mySecondKey"); 371 decl = new XMLBeanDeclaration(config, KEY); 372 } 373 374 /** 375 * Initializes a configuration object with a bean declaration. Under the 376 * specified key the given properties will be added. 377 * 378 * @param config the configuration to initialize 379 * @param key the key of the bean declaration 380 * @param names an array with the names of the properties 381 * @param values an array with the corresponding values 382 */ 383 private void setupBeanDeclaration(HierarchicalConfiguration config, 384 String key, String[] names, String[] values) 385 { 386 for (int i = 0; i < names.length; i++) 387 { 388 config.addProperty(key + "[@" + names[i] + "]", values[i]); 389 } 390 } 391 392 /** 393 * Checks the properties returned by a bean declaration. 394 * 395 * @param beanDecl the bean declaration 396 * @param names an array with the expected property names 397 * @param values an array with the expected property values 398 */ 399 private void checkProperties(BeanDeclaration beanDecl, String[] names, 400 String[] values) 401 { 402 Map<String, Object> props = beanDecl.getBeanProperties(); 403 assertEquals("Wrong number of properties", names.length, props.size()); 404 for (int i = 0; i < names.length; i++) 405 { 406 assertTrue("Property " + names[i] + " not contained", props 407 .containsKey(names[i])); 408 assertEquals("Wrong value for property " + names[i], values[i], 409 props.get(names[i])); 410 } 411 } 412 413 /** 414 * A helper class used for testing the createBeanDeclaration() factory 415 * method. 416 */ 417 private static class XMLBeanDeclarationTestImpl extends XMLBeanDeclaration 418 { 419 public XMLBeanDeclarationTestImpl(SubnodeConfiguration config, 420 ConfigurationNode node) 421 { 422 super(config, node); 423 } 424 } 425 }