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; 018 019 import static org.junit.Assert.assertEquals; 020 import static org.junit.Assert.assertFalse; 021 import static org.junit.Assert.assertTrue; 022 023 import java.util.ArrayList; 024 import java.util.Arrays; 025 import java.util.Collection; 026 import java.util.HashMap; 027 import java.util.Iterator; 028 import java.util.List; 029 import java.util.Map; 030 031 import org.apache.commons.collections.CollectionUtils; 032 import org.apache.commons.configuration.event.ConfigurationEvent; 033 import org.apache.commons.configuration.event.ConfigurationListener; 034 import org.junit.Test; 035 036 /** 037 * A test class for some of the basic functionality implemented by 038 * AbstractConfiguration. 039 * 040 * @version $Id: TestAbstractConfigurationBasicFeatures.java 1222823 2011-12-23 20:03:10Z oheger $ 041 */ 042 public class TestAbstractConfigurationBasicFeatures 043 { 044 /** Constant for the prefix of test keys.*/ 045 private static final String KEY_PREFIX = "key"; 046 047 /** Constant for the number of properties in tests for copy operations.*/ 048 private static final int PROP_COUNT = 12; 049 050 /** 051 * Tests the clear() implementation of AbstractConfiguration if the iterator 052 * returned by getKeys() does not support the remove() operation. 053 */ 054 @Test 055 public void testClearIteratorNoRemove() 056 { 057 AbstractConfiguration config = new TestConfigurationImpl( 058 new BaseConfiguration()) 059 { 060 // return an iterator that does not support remove operations 061 @Override 062 public Iterator<String> getKeys() 063 { 064 Collection<String> keyCol = new ArrayList<String>(); 065 CollectionUtils.addAll(keyCol, getUnderlyingConfiguration() 066 .getKeys()); 067 String[] keys = keyCol.toArray(new String[keyCol.size()]); 068 return Arrays.asList(keys).iterator(); 069 } 070 }; 071 for (int i = 0; i < 20; i++) 072 { 073 config.addProperty("key" + i, "value" + i); 074 } 075 config.clear(); 076 assertTrue("Configuration not empty", config.isEmpty()); 077 } 078 079 /** 080 * Tests escaping the variable marker, so that no interpolation will be 081 * performed. 082 */ 083 @Test 084 public void testInterpolateEscape() 085 { 086 AbstractConfiguration config = new TestConfigurationImpl( 087 new PropertiesConfiguration()); 088 config 089 .addProperty( 090 "mypath", 091 "$${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc.jar\\,$${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc_license_cu.jar"); 092 assertEquals( 093 "Wrong interpolated value", 094 "${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc.jar,${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc_license_cu.jar", 095 config.getString("mypath")); 096 } 097 098 /** 099 * Tests adding list properties. The single elements of the list should be 100 * added. 101 */ 102 @Test 103 public void testAddPropertyList() 104 { 105 checkAddListProperty(new TestConfigurationImpl( 106 new PropertiesConfiguration())); 107 } 108 109 /** 110 * Tests adding list properties when delimiter parsing is disabled. 111 */ 112 @Test 113 public void testAddPropertyListNoDelimiterParsing() 114 { 115 AbstractConfiguration config = new TestConfigurationImpl( 116 new PropertiesConfiguration()); 117 config.setDelimiterParsingDisabled(true); 118 checkAddListProperty(config); 119 } 120 121 /** 122 * Helper method for adding properties with multiple values. 123 * 124 * @param config the configuration to be used for testing 125 */ 126 private void checkAddListProperty(AbstractConfiguration config) 127 { 128 config.addProperty("test", "value1"); 129 Object[] lstValues1 = new Object[] 130 { "value2", "value3" }; 131 Object[] lstValues2 = new Object[] 132 { "value4", "value5", "value6" }; 133 config.addProperty("test", lstValues1); 134 config.addProperty("test", Arrays.asList(lstValues2)); 135 List<Object> lst = config.getList("test"); 136 assertEquals("Wrong number of list elements", 6, lst.size()); 137 for (int i = 0; i < lst.size(); i++) 138 { 139 assertEquals("Wrong list element at " + i, "value" + (i + 1), lst 140 .get(i)); 141 } 142 } 143 144 /** 145 * Tests the copy() method. 146 */ 147 @Test 148 public void testCopy() 149 { 150 AbstractConfiguration config = setUpDestConfig(); 151 Configuration srcConfig = setUpSourceConfig(); 152 config.copy(srcConfig); 153 for (int i = 0; i < PROP_COUNT; i++) 154 { 155 String key = KEY_PREFIX + i; 156 if (srcConfig.containsKey(key)) 157 { 158 assertEquals("Value not replaced: " + key, srcConfig 159 .getProperty(key), config.getProperty(key)); 160 } 161 else 162 { 163 assertEquals("Value modified: " + key, "value" + i, config 164 .getProperty(key)); 165 } 166 } 167 } 168 169 /** 170 * Tests the copy() method when properties with multiple values and escaped 171 * list delimiters are involved. 172 */ 173 @Test 174 public void testCopyWithLists() 175 { 176 Configuration srcConfig = setUpSourceConfig(); 177 AbstractConfiguration config = setUpDestConfig(); 178 config.copy(srcConfig); 179 checkListProperties(config); 180 } 181 182 /** 183 * Tests the events generated by a copy() operation. 184 */ 185 @Test 186 public void testCopyEvents() 187 { 188 AbstractConfiguration config = setUpDestConfig(); 189 Configuration srcConfig = setUpSourceConfig(); 190 CollectingConfigurationListener l = new CollectingConfigurationListener(); 191 config.addConfigurationListener(l); 192 config.copy(srcConfig); 193 checkCopyEvents(l, srcConfig, AbstractConfiguration.EVENT_SET_PROPERTY); 194 } 195 196 /** 197 * Tests copying a null configuration. This should be a noop. 198 */ 199 @Test 200 public void testCopyNull() 201 { 202 AbstractConfiguration config = setUpDestConfig(); 203 config.copy(null); 204 ConfigurationAssert.assertEquals(setUpDestConfig(), config); 205 } 206 207 /** 208 * Tests the append() method. 209 */ 210 @Test 211 public void testAppend() 212 { 213 AbstractConfiguration config = setUpDestConfig(); 214 Configuration srcConfig = setUpSourceConfig(); 215 config.append(srcConfig); 216 for (int i = 0; i < PROP_COUNT; i++) 217 { 218 String key = KEY_PREFIX + i; 219 if (srcConfig.containsKey(key)) 220 { 221 List<Object> values = config.getList(key); 222 assertEquals("Value not added: " + key, 2, values.size()); 223 assertEquals("Wrong value 1 for " + key, "value" + i, values 224 .get(0)); 225 assertEquals("Wrong value 2 for " + key, "src" + i, values 226 .get(1)); 227 } 228 else 229 { 230 assertEquals("Value modified: " + key, "value" + i, config 231 .getProperty(key)); 232 } 233 } 234 } 235 236 /** 237 * Tests the append() method when properties with multiple values and 238 * escaped list delimiters are involved. 239 */ 240 @Test 241 public void testAppendWithLists() 242 { 243 AbstractConfiguration config = setUpDestConfig(); 244 config.append(setUpSourceConfig()); 245 checkListProperties(config); 246 } 247 248 /** 249 * Tests the events generated by an append() operation. 250 */ 251 @Test 252 public void testAppendEvents() 253 { 254 AbstractConfiguration config = setUpDestConfig(); 255 Configuration srcConfig = setUpSourceConfig(); 256 CollectingConfigurationListener l = new CollectingConfigurationListener(); 257 config.addConfigurationListener(l); 258 config.append(srcConfig); 259 checkCopyEvents(l, srcConfig, AbstractConfiguration.EVENT_ADD_PROPERTY); 260 } 261 262 /** 263 * Tests appending a null configuration. This should be a noop. 264 */ 265 @Test 266 public void testAppendNull() 267 { 268 AbstractConfiguration config = setUpDestConfig(); 269 config.append(null); 270 ConfigurationAssert.assertEquals(setUpDestConfig(), config); 271 } 272 273 /** 274 * Tests whether environment variables can be interpolated. 275 */ 276 @Test 277 public void testInterpolateEnvironmentVariables() 278 { 279 AbstractConfiguration config = new TestConfigurationImpl( 280 new PropertiesConfiguration()); 281 EnvironmentConfiguration envConfig = new EnvironmentConfiguration(); 282 Map<String, Object> env = new HashMap<String, Object>(); 283 for (Iterator<String> it = envConfig.getKeys(); it.hasNext();) 284 { 285 String key = it.next(); 286 String propKey = "envtest." + key; 287 env.put(propKey, envConfig.getString(key)); 288 config.addProperty(propKey, "${env:" + key + "}"); 289 } 290 assertFalse("No environment properties", env.isEmpty()); 291 for (Map.Entry<String, Object> e : env.entrySet()) 292 { 293 assertEquals("Wrong value for " + e.getKey(), e.getValue(), config 294 .getString(e.getKey())); 295 } 296 } 297 298 /** 299 * Tests getList() for single non-string values. 300 */ 301 @Test 302 public void testGetListNonString() 303 { 304 checkGetListScalar(Integer.valueOf(42)); 305 checkGetListScalar(Long.valueOf(42)); 306 checkGetListScalar(Short.valueOf((short) 42)); 307 checkGetListScalar(Byte.valueOf((byte) 42)); 308 checkGetListScalar(Float.valueOf(42)); 309 checkGetListScalar(Double.valueOf(42)); 310 checkGetListScalar(Boolean.TRUE); 311 } 312 313 /** 314 * Tests getStringArray() for single son-string values. 315 */ 316 @Test 317 public void testGetStringArrayNonString() 318 { 319 checkGetStringArrayScalar(Integer.valueOf(42)); 320 checkGetStringArrayScalar(Long.valueOf(42)); 321 checkGetStringArrayScalar(Short.valueOf((short) 42)); 322 checkGetStringArrayScalar(Byte.valueOf((byte) 42)); 323 checkGetStringArrayScalar(Float.valueOf(42)); 324 checkGetStringArrayScalar(Double.valueOf(42)); 325 checkGetStringArrayScalar(Boolean.TRUE); 326 } 327 328 /** 329 * Helper method for checking getList() if the property value is a scalar. 330 * @param value the value of the property 331 */ 332 private void checkGetListScalar(Object value) 333 { 334 BaseConfiguration config = new BaseConfiguration(); 335 config.addProperty(KEY_PREFIX, value); 336 List<Object> lst = config.getList(KEY_PREFIX); 337 assertEquals("Wrong number of values", 1, lst.size()); 338 assertEquals("Wrong value", value.toString(), lst.get(0)); 339 } 340 341 /** 342 * Helper method for checking getStringArray() if the property value is a 343 * scalar. 344 * 345 * @param value the value of the property 346 */ 347 private void checkGetStringArrayScalar(Object value) 348 { 349 BaseConfiguration config = new BaseConfiguration(); 350 config.addProperty(KEY_PREFIX, value); 351 String[] array = config.getStringArray(KEY_PREFIX); 352 assertEquals("Weong number of elements", 1, array.length); 353 assertEquals("Wrong value", value.toString(), array[0]); 354 } 355 356 /** 357 * Tests whether interpolation works in variable names. 358 */ 359 @Test 360 public void testNestedVariableInterpolation() 361 { 362 BaseConfiguration config = new BaseConfiguration(); 363 config.getSubstitutor().setEnableSubstitutionInVariables(true); 364 config.addProperty("java.version", "1.4"); 365 config.addProperty("jre-1.4", "C:\\java\\1.4"); 366 config.addProperty("jre.path", "${jre-${java.version}}"); 367 assertEquals("Wrong path", "C:\\java\\1.4", 368 config.getString("jre.path")); 369 } 370 371 /** 372 * Creates the source configuration for testing the copy() and append() 373 * methods. This configuration contains keys with an odd index and values 374 * starting with the prefix "src". There are also some list properties. 375 * 376 * @return the source configuration for copy operations 377 */ 378 private Configuration setUpSourceConfig() 379 { 380 BaseConfiguration config = new BaseConfiguration(); 381 for (int i = 1; i < PROP_COUNT; i += 2) 382 { 383 config.addProperty(KEY_PREFIX + i, "src" + i); 384 } 385 config.addProperty("list1", "1,2,3"); 386 config.addProperty("list2", "3\\,1415,9\\,81"); 387 return config; 388 } 389 390 /** 391 * Creates the destination configuration for testing the copy() and append() 392 * methods. This configuration contains keys with a running index and 393 * corresponding values starting with the prefix "value". 394 * 395 * @return the destination configuration for copy operations 396 */ 397 private AbstractConfiguration setUpDestConfig() 398 { 399 AbstractConfiguration config = new TestConfigurationImpl( 400 new PropertiesConfiguration()); 401 for (int i = 0; i < PROP_COUNT; i++) 402 { 403 config.addProperty(KEY_PREFIX + i, "value" + i); 404 } 405 return config; 406 } 407 408 /** 409 * Tests the values of list properties after a copy operation. 410 * 411 * @param config the configuration to test 412 */ 413 private void checkListProperties(Configuration config) 414 { 415 List<Object> values = config.getList("list1"); 416 assertEquals("Wrong number of elements in list 1", 3, values.size()); 417 values = config.getList("list2"); 418 assertEquals("Wrong number of elements in list 2", 2, values.size()); 419 assertEquals("Wrong value 1", "3,1415", values.get(0)); 420 assertEquals("Wrong value 2", "9,81", values.get(1)); 421 } 422 423 /** 424 * Tests whether the correct events are received for a copy operation. 425 * 426 * @param l the event listener 427 * @param src the configuration that was copied 428 * @param eventType the expected event type 429 */ 430 private void checkCopyEvents(CollectingConfigurationListener l, 431 Configuration src, int eventType) 432 { 433 Map<String, ConfigurationEvent> events = new HashMap<String, ConfigurationEvent>(); 434 for (ConfigurationEvent e : l.events) 435 { 436 assertEquals("Wrong event type", eventType, e.getType()); 437 assertTrue("Unknown property: " + e.getPropertyName(), src 438 .containsKey(e.getPropertyName())); 439 assertEquals("Wrong property value for " + e.getPropertyName(), e 440 .getPropertyValue(), src.getProperty(e.getPropertyName())); 441 if (!e.isBeforeUpdate()) 442 { 443 assertTrue("After event without before event", events 444 .containsKey(e.getPropertyName())); 445 } 446 else 447 { 448 events.put(e.getPropertyName(), e); 449 } 450 } 451 452 for (Iterator<String> it = src.getKeys(); it.hasNext();) 453 { 454 String key = it.next(); 455 assertTrue("No event received for key " + key, events 456 .containsKey(key)); 457 } 458 } 459 460 /** 461 * A test configuration implementation. This implementation inherits 462 * directly from AbstractConfiguration. For implementing the required 463 * functionality another implementation of AbstractConfiguration is used; 464 * all methods that need to be implemented delegate to this wrapped 465 * configuration. 466 */ 467 static class TestConfigurationImpl extends AbstractConfiguration 468 { 469 /** Stores the underlying configuration. */ 470 private AbstractConfiguration config; 471 472 public AbstractConfiguration getUnderlyingConfiguration() 473 { 474 return config; 475 } 476 477 public TestConfigurationImpl(AbstractConfiguration wrappedConfig) 478 { 479 config = wrappedConfig; 480 } 481 482 @Override 483 protected void addPropertyDirect(String key, Object value) 484 { 485 config.addPropertyDirect(key, value); 486 } 487 488 public boolean containsKey(String key) 489 { 490 return config.containsKey(key); 491 } 492 493 public Iterator<String> getKeys() 494 { 495 return config.getKeys(); 496 } 497 498 public Object getProperty(String key) 499 { 500 return config.getProperty(key); 501 } 502 503 public boolean isEmpty() 504 { 505 return config.isEmpty(); 506 } 507 508 @Override 509 protected void clearPropertyDirect(String key) 510 { 511 config.clearPropertyDirect(key); 512 } 513 } 514 515 /** 516 * An event listener implementation that simply collects all received 517 * configuration events. 518 */ 519 static class CollectingConfigurationListener implements 520 ConfigurationListener 521 { 522 List<ConfigurationEvent> events = new ArrayList<ConfigurationEvent>(); 523 524 public void configurationChanged(ConfigurationEvent event) 525 { 526 events.add(event); 527 } 528 } 529 }