diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java
index 0a002d40973..dc608162e6a 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,8 @@
package org.springframework.test.context.support;
-import java.io.IOException;
-import java.io.StringReader;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -34,12 +29,8 @@ import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration;
@@ -64,7 +55,6 @@ import org.springframework.util.ResourceUtils;
*
* @author Sam Brannen
* @author Juergen Hoeller
- * @author Dave Syer
* @since 2.5
* @see #generateDefaultLocations
* @see #getResourceSuffixes
@@ -74,8 +64,6 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
- private static final String LINE_SEPARATOR = System.getProperty("line.separator");
-
private static final Log logger = LogFactory.getLog(AbstractContextLoader.class);
@@ -137,74 +125,11 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
*/
protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
- addResourcePropertySourcesToEnvironment(context, mergedConfig);
- addInlinedPropertiesToEnvironment(context, mergedConfig);
+ TestPropertySourceUtils.addResourcePropertySourcesToEnvironment(context, mergedConfig.getPropertySourceLocations());
+ TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context, mergedConfig.getPropertySourceProperties());
invokeApplicationContextInitializers(context, mergedConfig);
}
- /**
- * @since 4.1
- */
- private void addResourcePropertySourcesToEnvironment(ConfigurableApplicationContext context,
- MergedContextConfiguration mergedConfig) {
- try {
- ConfigurableEnvironment environment = context.getEnvironment();
- String[] locations = mergedConfig.getPropertySourceLocations();
- for (String location : locations) {
- String resolvedLocation = environment.resolveRequiredPlaceholders(location);
- Resource resource = context.getResource(resolvedLocation);
- ResourcePropertySource ps = new ResourcePropertySource(resource);
- environment.getPropertySources().addFirst(ps);
- }
- }
- catch (IOException e) {
- throw new IllegalStateException("Failed to add PropertySource to Environment", e);
- }
- }
-
- /**
- * @since 4.1
- */
- private void addInlinedPropertiesToEnvironment(ConfigurableApplicationContext context,
- MergedContextConfiguration mergedConfig) {
- String[] keyValuePairs = mergedConfig.getPropertySourceProperties();
- if (!ObjectUtils.isEmpty(keyValuePairs)) {
- String name = "test properties " + ObjectUtils.nullSafeToString(keyValuePairs);
- MapPropertySource ps = new MapPropertySource(name, extractEnvironmentProperties(keyValuePairs));
- context.getEnvironment().getPropertySources().addFirst(ps);
- }
- }
-
- /**
- * Extract environment properties from the supplied key/value pairs.
- *
Parsing of the key/value pairs is achieved by converting all pairs
- * into a single virtual properties file in memory and delegating
- * to {@link Properties#load(java.io.Reader)} to parse that virtual file.
- *
This code has been adapted from Spring Boot's
- * {@link org.springframework.boot.test.SpringApplicationContextLoader SpringApplicationContextLoader}.
- * @since 4.1
- */
- private Map extractEnvironmentProperties(String[] keyValuePairs) {
- StringBuilder sb = new StringBuilder();
- for (String keyValuePair : keyValuePairs) {
- sb.append(keyValuePair).append(LINE_SEPARATOR);
- }
- String content = sb.toString();
- Properties props = new Properties();
- try {
- props.load(new StringReader(content));
- }
- catch (IOException e) {
- throw new IllegalStateException("Failed to load test environment properties from: " + content, e);
- }
-
- Map properties = new HashMap();
- for (String name : props.stringPropertyNames()) {
- properties.put(name, props.getProperty(name));
- }
- return properties;
- }
-
@SuppressWarnings("unchecked")
private void invokeApplicationContextInitializers(ConfigurableApplicationContext context,
MergedContextConfiguration mergedConfig) {
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java
index c77ec1cb528..90b8002d24e 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,24 +16,39 @@
package org.springframework.test.context.support;
+import java.io.IOException;
+import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationAttributes;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.util.TestContextResourceUtils;
-import org.springframework.test.util.MetaAnnotationUtils.*;
+import org.springframework.test.util.MetaAnnotationUtils.AnnotationDescriptor;
import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import static org.springframework.test.util.MetaAnnotationUtils.*;
/**
- * Utility methods for working with {@link TestPropertySource @TestPropertySource}.
+ * Utility methods for working with {@link TestPropertySource @TestPropertySource}
+ * and adding test {@link PropertySource PropertySources} to the {@code Environment}.
+ *
+ * Primarily intended for use within the framework.
*
* @author Sam Brannen
* @since 4.1
@@ -131,4 +146,76 @@ abstract class TestPropertySourceUtils {
return StringUtils.toStringArray(properties);
}
+ /**
+ * @since 4.1.5
+ */
+ static void addResourcePropertySourcesToEnvironment(ConfigurableApplicationContext context,
+ String[] propertySourceLocations) {
+ try {
+ ConfigurableEnvironment environment = context.getEnvironment();
+ String[] locations = propertySourceLocations;
+ for (String location : locations) {
+ String resolvedLocation = environment.resolveRequiredPlaceholders(location);
+ Resource resource = context.getResource(resolvedLocation);
+ ResourcePropertySource ps = new ResourcePropertySource(resource);
+ environment.getPropertySources().addFirst(ps);
+ }
+ }
+ catch (IOException e) {
+ throw new IllegalStateException("Failed to add PropertySource to Environment", e);
+ }
+ }
+
+ /**
+ * @since 4.1.5
+ */
+ static void addInlinedPropertiesToEnvironment(ConfigurableApplicationContext context,
+ String[] propertySourceProperties) {
+ addInlinedPropertiesToEnvironment(context.getEnvironment(), propertySourceProperties);
+ }
+
+ /**
+ * @since 4.1.5
+ */
+ static void addInlinedPropertiesToEnvironment(ConfigurableEnvironment environment, String[] propertySourceProperties) {
+ if (!ObjectUtils.isEmpty(propertySourceProperties)) {
+ String name = "test properties " + ObjectUtils.nullSafeToString(propertySourceProperties);
+ MapPropertySource ps = new MapPropertySource(name, extractEnvironmentProperties(propertySourceProperties));
+ environment.getPropertySources().addFirst(ps);
+ }
+ }
+
+ /**
+ * Extract environment properties from the supplied key/value pairs,
+ * preserving the ordering of property names in the returned map.
+ *
Parsing of the key/value pairs is achieved by converting all pairs
+ * into virtual properties files in memory and delegating to
+ * {@link Properties#load(java.io.Reader)} to parse each virtual file.
+ */
+ private static Map extractEnvironmentProperties(String[] keyValuePairs) {
+ Map map = new LinkedHashMap();
+
+ Properties props = new Properties();
+ for (String pair : keyValuePairs) {
+ if (!StringUtils.hasText(pair)) {
+ continue;
+ }
+
+ try {
+ props.load(new StringReader(pair));
+ }
+ catch (Exception e) {
+ throw new IllegalStateException("Failed to load test environment property from [" + pair + "].", e);
+ }
+ Assert.state(props.size() == 1, "Failed to load exactly one test environment property from [" + pair + "].");
+
+ for (String name : props.stringPropertyNames()) {
+ map.put(name, props.getProperty(name));
+ }
+ props.clear();
+ }
+
+ return map;
+ }
+
}
diff --git a/spring-test/src/test/java/org/springframework/test/context/env/InlinedPropertiesTestPropertySourceTests.java b/spring-test/src/test/java/org/springframework/test/context/env/InlinedPropertiesTestPropertySourceTests.java
index a1721e854a8..fa4a04ec177 100644
--- a/spring-test/src/test/java/org/springframework/test/context/env/InlinedPropertiesTestPropertySourceTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/env/InlinedPropertiesTestPropertySourceTests.java
@@ -21,7 +21,10 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
+import org.springframework.core.env.PropertySource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -29,28 +32,31 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
/**
- * Integration tests for {@link TestPropertySource @TestPropertySource}
- * support with an inlined properties.
+ * Integration tests for {@link TestPropertySource @TestPropertySource} support with
+ * inlined properties.
*
* @author Sam Brannen
* @since 4.1
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
-@TestPropertySource(properties = { "foo = bar", "baz quux", "enigma: 42",
- "x.y.z = a=b=c", "server.url = http://example.com", "key.value.1: key=value",
- "key.value.2 key=value", "key.value.3 key:value" })
+@TestPropertySource(properties = { "", "foo = bar", "baz quux", "enigma: 42", "x.y.z = a=b=c",
+ "server.url = http://example.com", "key.value.1: key=value", "key.value.2 key=value", "key.value.3 key:value" })
public class InlinedPropertiesTestPropertySourceTests {
@Autowired
- protected Environment env;
+ private Environment env;
@Test
- public void verifyPropertiesAreAvailableInEnvironment() {
+ public void propertiesAreAvailableInEnvironment() {
+
+ // Simple key/value pairs
assertEquals("bar", env.getProperty("foo"));
assertEquals("quux", env.getProperty("baz"));
assertEquals(42, env.getProperty("enigma", Integer.class).intValue());
+
+ // Values containing key/value delimiters (":", "=", " ")
assertEquals("a=b=c", env.getProperty("x.y.z"));
assertEquals("http://example.com", env.getProperty("server.url"));
assertEquals("key=value", env.getProperty("key.value.1"));
@@ -58,6 +64,28 @@ public class InlinedPropertiesTestPropertySourceTests {
assertEquals("key:value", env.getProperty("key.value.3"));
}
+ @Test
+ @SuppressWarnings("rawtypes")
+ public void propertyNameOrderingIsPreservedInEnvironment() {
+ String[] propertyNames = null;
+
+ ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) env;
+ for (PropertySource> propertySource : configurableEnvironment.getPropertySources()) {
+ if (propertySource instanceof EnumerablePropertySource) {
+ EnumerablePropertySource eps = (EnumerablePropertySource) propertySource;
+ if (eps.getName().startsWith("test properties")) {
+ propertyNames = eps.getPropertyNames();
+ break;
+ }
+ }
+ }
+
+ final String[] expectedPropertyNames = new String[] { "foo", "baz", "enigma", "x.y.z", "server.url",
+ "key.value.1", "key.value.2", "key.value.3" };
+
+ assertArrayEquals(expectedPropertyNames, propertyNames);
+ }
+
// -------------------------------------------------------------------
diff --git a/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java b/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java
index 8d4769ec732..9a300628caa 100644
--- a/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/support/TestPropertySourceUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +16,16 @@
package org.springframework.test.context.support;
+import java.util.Map;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.mock.env.MockEnvironment;
+import org.springframework.mock.env.MockPropertySource;
import org.springframework.test.context.TestPropertySource;
import static org.hamcrest.CoreMatchers.*;
@@ -113,6 +119,41 @@ public class TestPropertySourceUtilsTests {
new String[] { "classpath:/baz.properties" }, new String[] { "key = value" });
}
+ /**
+ * @since 4.1.5
+ */
+ @Test
+ @SuppressWarnings("rawtypes")
+ public void emptyInlinedProperty() {
+ ConfigurableEnvironment environment = new MockEnvironment();
+ MutablePropertySources propertySources = environment.getPropertySources();
+ propertySources.remove(MockPropertySource.MOCK_PROPERTIES_PROPERTY_SOURCE_NAME);
+ assertEquals(0, propertySources.size());
+ addInlinedPropertiesToEnvironment(environment, new String[] { " " });
+ assertEquals(1, propertySources.size());
+ assertEquals(0, ((Map) propertySources.iterator().next().getSource()).size());
+ }
+
+ /**
+ * @since 4.1.5
+ */
+ @Test
+ public void inlinedPropertyWithMalformedUnicodeInValue() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Failed to load test environment property");
+ addInlinedPropertiesToEnvironment(new MockEnvironment(), new String[] { "key = \\uZZZZ" });
+ }
+
+ /**
+ * @since 4.1.5
+ */
+ @Test
+ public void inlinedPropertyWithMultipleKeyValuePairs() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Failed to load exactly one test environment property");
+ addInlinedPropertiesToEnvironment(new MockEnvironment(), new String[] { "a=b\nx=y" });
+ }
+
// -------------------------------------------------------------------