/*
 * Copyright 2010-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.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.context.config;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.config.ConfigFileApplicationListener.ConfigurationPropertySources;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.env.EnumerableCompositePropertySource;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

/**
 * Tests for {@link ConfigFileApplicationListener}.
 *
 * @author Phillip Webb
 * @author Dave Syer
 */
public class ConfigFileApplicationListenerTests {

	private final StandardEnvironment environment = new StandardEnvironment();

	private final ApplicationEnvironmentPreparedEvent event = new ApplicationEnvironmentPreparedEvent(
			new SpringApplication(), new String[0], this.environment);

	private final ConfigFileApplicationListener initializer = new ConfigFileApplicationListener();

	@Rule
	public ExpectedException expected = ExpectedException.none();

	@After
	public void cleanup() {
		System.clearProperty("the.property");
		System.clearProperty("spring.config.location");
		System.clearProperty("spring.main.showBanner");
	}

	@Test
	public void loadCustomResource() throws Exception {
		this.event.getSpringApplication().setResourceLoader(new ResourceLoader() {
			@Override
			public Resource getResource(final String location) {
				if (location.equals("classpath:/custom.properties")) {
					return new ByteArrayResource("the.property: fromcustom".getBytes(),
							location) {
						@Override
						public String getFilename() {
							return location;
						}
					};
				}
				return null;
			}

			@Override
			public ClassLoader getClassLoader() {
				return getClass().getClassLoader();
			}
		});
		this.initializer.setSearchNames("custom");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("fromcustom"));
	}

	@Test
	public void loadPropertiesFile() throws Exception {
		this.initializer.setSearchNames("testproperties");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("frompropertiesfile"));
	}

	@Test
	public void loadTwoPropertiesFile() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ "classpath:application.properties,classpath:testproperties.properties");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("frompropertiesfile"));
	}

	@Test
	public void loadTwoPropertiesFilesWithProfiles() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ "classpath:enableprofile.properties,classpath:enableother.properties");
		this.initializer.onApplicationEvent(this.event);
		assertEquals("other", StringUtils.arrayToCommaDelimitedString(this.environment
				.getActiveProfiles()));
		String property = this.environment.getProperty("my.property");
		assertThat(property, equalTo("fromotherpropertiesfile"));
	}

	@Test
	public void loadTwoPropertiesFilesWithProfilesAndSwitchOneOff() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ "classpath:enabletwoprofiles.properties,"
				+ "classpath:enableprofile.properties");
		this.initializer.onApplicationEvent(this.event);
		assertEquals("myprofile",
				StringUtils.arrayToCommaDelimitedString(this.environment
						.getActiveProfiles()));
		String property = this.environment.getProperty("the.property");
		// The value from the second file wins (no profile specific configuration is
		// actually loaded)
		assertThat(property, equalTo("frompropertiesfile"));
	}

	@Test
	public void loadTwoPropertiesFilesWithProfilesAndSwitchOneOffFromSpecificLocation()
			throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment,
				"spring.config.name:enabletwoprofiles",
				"spring.config.location:classpath:enableprofile.properties");
		this.initializer.onApplicationEvent(this.event);
		assertEquals("myprofile",
				StringUtils.arrayToCommaDelimitedString(this.environment
						.getActiveProfiles()));
		String property = this.environment.getProperty("the.property");
		// The value from the second file wins (no profile specific configuration is
		// actually loaded)
		assertThat(property, equalTo("frompropertiesfile"));
	}

	@Test
	public void localFileTakesPrecedenceOverClasspath() throws Exception {
		File localFile = new File(new File("."), "application.properties");
		assertThat(localFile.exists(), equalTo(false));
		try {
			Properties properties = new Properties();
			properties.put("the.property", "fromlocalfile");
			OutputStream out = new FileOutputStream(localFile);
			try {
				properties.store(out, "");
			}
			finally {
				out.close();
			}
			this.initializer.onApplicationEvent(this.event);
			String property = this.environment.getProperty("the.property");
			assertThat(property, equalTo("fromlocalfile"));
		}
		finally {
			localFile.delete();
		}
	}

	@Test
	public void moreSpecificLocationTakesPrecedenceOverRoot() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment,
				"spring.config.name:specific");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.property");
		assertThat(property, equalTo("specific"));
	}

	@Test
	public void loadTwoOfThreePropertiesFile() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ "classpath:application.properties,"
				+ "classpath:testproperties.properties,"
				+ "classpath:nonexistent.properties");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("frompropertiesfile"));
	}

	@Test
	public void randomValue() throws Exception {
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("random.value");
		assertThat(property, notNullValue());
	}

	@Test
	public void loadTwoPropertiesFiles() throws Exception {
		this.initializer.setSearchNames("moreproperties,testproperties");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		// The search order has highest precedence last (like merging a map)
		assertThat(property, equalTo("frompropertiesfile"));
	}

	@Test
	public void loadYamlFile() throws Exception {
		this.initializer.setSearchNames("testyaml");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.property");
		assertThat(property, equalTo("fromyamlfile"));
		assertThat(this.environment.getProperty("my.array[0]"), equalTo("1"));
		assertThat(this.environment.getProperty("my.array"), nullValue(String.class));
	}

	@Test
	public void commandLineWins() throws Exception {
		this.environment.getPropertySources().addFirst(
				new SimpleCommandLinePropertySource("--the.property=fromcommandline"));
		this.initializer.setSearchNames("testproperties");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("fromcommandline"));
	}

	@Test
	public void systemPropertyWins() throws Exception {
		System.setProperty("the.property", "fromsystem");
		this.initializer.setSearchNames("testproperties");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("fromsystem"));
	}

	@Test
	public void defaultPropertyAsFallback() throws Exception {
		this.event
				.getEnvironment()
				.getPropertySources()
				.addLast(
						new MapPropertySource("defaultProperties", Collections
								.singletonMap("my.fallback", (Object) "foo")));
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.fallback");
		assertThat(property, equalTo("foo"));
	}

	@Test
	public void defaultPropertyAsFallbackDuringFileParsing() throws Exception {
		this.event
				.getEnvironment()
				.getPropertySources()
				.addLast(
						new MapPropertySource("defaultProperties", Collections
								.singletonMap("spring.config.name",
										(Object) "testproperties")));
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("frompropertiesfile"));
	}

	@Test
	public void loadPropertiesThenProfilePropertiesActivatedInSpringApplication()
			throws Exception {
		// This should be the effect of calling
		// SpringApplication.setAdditionalProfiles("other")
		this.environment.setActiveProfiles("other");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.property");
		// The "other" profile is activated in SpringApplication so it should take
		// precedence over the default profile
		assertThat(property, equalTo("fromotherpropertiesfile"));
	}

	@Test
	public void twoProfilesFromProperties() throws Exception {
		// This should be the effect of calling
		// SpringApplication.setAdditionalProfiles("other", "dev")
		this.environment.setActiveProfiles("other", "dev");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.property");
		// The "dev" profile is activated in SpringApplication so it should take
		// precedence over the default profile
		assertThat(property, equalTo("fromdevpropertiesfile"));
	}

	@Test
	public void loadPropertiesThenProfilePropertiesActivatedInFirst() throws Exception {
		this.initializer.setSearchNames("enableprofile");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		// The "myprofile" profile is activated in enableprofile.properties so its value
		// should show up here
		assertThat(property, equalTo("fromprofilepropertiesfile"));
	}

	@Test
	public void loadPropertiesThenProfilePropertiesWithOverride() throws Exception {
		this.environment.setActiveProfiles("other");
		// EnvironmentTestUtils.addEnvironment(this.environment,
		// "spring.profiles.active:other");
		this.initializer.setSearchNames("enableprofile");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("other.property");
		// The "other" profile is activated before any processing starts
		assertThat(property, equalTo("fromotherpropertiesfile"));
		property = this.environment.getProperty("the.property");
		// The "myprofile" profile is activated in enableprofile.properties and "other"
		// was not activated by setting spring.profiles.active so "myprofile" should still
		// be activated
		assertThat(property, equalTo("fromprofilepropertiesfile"));
	}

	@Test
	public void profilePropertiesUsedInPlaceholders() throws Exception {
		this.initializer.setSearchNames("enableprofile");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("one.more");
		assertThat(property, equalTo("fromprofilepropertiesfile"));
	}

	@Test
	public void yamlProfiles() throws Exception {
		this.initializer.setSearchNames("testprofiles");
		this.environment.setActiveProfiles("dev");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.property");
		assertThat(property, equalTo("fromdevprofile"));
		property = this.environment.getProperty("my.other");
		assertThat(property, equalTo("notempty"));
	}

	@Test
	public void yamlTwoProfiles() throws Exception {
		this.initializer.setSearchNames("testprofiles");
		this.environment.setActiveProfiles("other", "dev");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.property");
		assertThat(property, equalTo("fromdevprofile"));
		property = this.environment.getProperty("my.other");
		assertThat(property, equalTo("notempty"));
	}

	@Test
	public void yamlSetsProfiles() throws Exception {
		this.initializer.setSearchNames("testsetprofiles");
		this.initializer.onApplicationEvent(this.event);
		assertEquals("dev", StringUtils.arrayToCommaDelimitedString(this.environment
				.getActiveProfiles()));
		String property = this.environment.getProperty("my.property");
		assertThat(Arrays.asList(this.environment.getActiveProfiles()), contains("dev"));
		assertThat(property, equalTo("fromdevprofile"));
		ConfigurationPropertySources propertySource = (ConfigurationPropertySources) this.environment
				.getPropertySources().get("applicationConfigurationProperties");
		Collection<org.springframework.core.env.PropertySource<?>> sources = propertySource
				.getSource();
		assertEquals(2, sources.size());
		List<String> names = new ArrayList<String>();
		for (org.springframework.core.env.PropertySource<?> source : sources) {
			if (source instanceof EnumerableCompositePropertySource) {
				for (org.springframework.core.env.PropertySource<?> nested : ((EnumerableCompositePropertySource) source)
						.getSource()) {
					names.add(nested.getName());
				}
			}
			else {
				names.add(source.getName());
			}
		}
		assertThat(
				names,
				contains("applicationConfig: [classpath:/testsetprofiles.yml]#dev",
						"applicationConfig: [classpath:/testsetprofiles.yml]"));
	}

	@Test
	public void yamlProfileCanBeChanged() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment,
				"spring.profiles.active:prod");
		this.initializer.setSearchNames("testsetprofiles");
		this.initializer.onApplicationEvent(this.event);
		assertThat(this.environment.getActiveProfiles(), equalTo(new String[] { "prod" }));
	}

	@Test
	public void specificNameAndProfileFromExistingSource() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment,
				"spring.profiles.active=specificprofile",
				"spring.config.name=specificfile");
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("my.property");
		assertThat(property, equalTo("fromspecificpropertiesfile"));
	}

	@Test
	public void specificResource() throws Exception {
		String location = "classpath:specificlocation.properties";
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ location);
		this.initializer.onApplicationEvent(this.event);
		String property = this.environment.getProperty("the.property");
		assertThat(property, equalTo("fromspecificlocation"));
		assertThat(this.environment, containsPropertySource("applicationConfig: "
				+ "[classpath:specificlocation.properties]"));
		// The default property source is still there
		assertThat(this.environment, containsPropertySource("applicationConfig: "
				+ "[classpath:/application.properties]"));
		assertThat(this.environment.getProperty("foo"), equalTo("bucket"));
	}

	@Test
	public void specificResourceAsFile() throws Exception {
		String location = "file:src/test/resources/specificlocation.properties";
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ location);
		this.initializer.onApplicationEvent(this.event);
		assertThat(this.environment, containsPropertySource("applicationConfig: ["
				+ location + "]"));
	}

	@Test
	public void specificResourceDefaultsToFile() throws Exception {
		String location = "src/test/resources/specificlocation.properties";
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ location);
		this.initializer.onApplicationEvent(this.event);
		assertThat(this.environment, containsPropertySource("applicationConfig: [file:"
				+ location + "]"));
	}

	@Test
	public void absoluteResourceDefaultsToFile() throws Exception {
		String location = new File("src/test/resources/specificlocation.properties")
				.getAbsolutePath();
		EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
				+ location);
		this.initializer.onApplicationEvent(this.event);
		assertThat(this.environment, containsPropertySource("applicationConfig: [file:"
				+ location.replace(File.separatorChar, '/') + "]"));
	}

	@Test
	public void propertySourceAnnotation() throws Exception {
		SpringApplication application = new SpringApplication(WithPropertySource.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application.run();
		String property = context.getEnvironment().getProperty("the.property");
		assertThat(property, equalTo("fromspecificlocation"));
		assertThat(context.getEnvironment(),
				containsPropertySource("class path resource "
						+ "[specificlocation.properties]"));
		context.close();
	}

	@Test
	public void propertySourceAnnotationWithPlaceholder() throws Exception {
		EnvironmentTestUtils.addEnvironment(this.environment,
				"source.location:specificlocation");
		SpringApplication application = new SpringApplication(
				WithPropertySourcePlaceholders.class);
		application.setEnvironment(this.environment);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application.run();
		String property = context.getEnvironment().getProperty("the.property");
		assertThat(property, equalTo("fromspecificlocation"));
		assertThat(context.getEnvironment(),
				containsPropertySource("class path resource "
						+ "[specificlocation.properties]"));
		context.close();
	}

	@Test
	public void propertySourceAnnotationWithName() throws Exception {
		SpringApplication application = new SpringApplication(
				WithPropertySourceAndName.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application.run();
		String property = context.getEnvironment().getProperty("the.property");
		assertThat(property, equalTo("fromspecificlocation"));
		assertThat(context.getEnvironment(), containsPropertySource("foo"));
		context.close();
	}

	@Test
	public void propertySourceAnnotationInProfile() throws Exception {
		SpringApplication application = new SpringApplication(
				WithPropertySourceInProfile.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application
				.run("--spring.profiles.active=myprofile");
		String property = context.getEnvironment().getProperty("the.property");
		assertThat(property, equalTo("frompropertiesfile"));
		assertThat(context.getEnvironment(),
				containsPropertySource("class path resource "
						+ "[enableprofile.properties]"));
		assertThat(context.getEnvironment(), not(containsPropertySource("classpath:/"
				+ "enableprofile-myprofile.properties")));
		context.close();
	}

	@Test
	public void propertySourceAnnotationAndNonActiveProfile() throws Exception {
		SpringApplication application = new SpringApplication(
				WithPropertySourceAndProfile.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application.run();
		String property = context.getEnvironment().getProperty("my.property");
		assertThat(property, equalTo("fromapplicationproperties"));
		assertThat(context.getEnvironment(), not(containsPropertySource("classpath:"
				+ "/enableprofile-myprofile.properties")));
		context.close();
	}

	@Test
	public void propertySourceAnnotationMultipleLocations() throws Exception {
		SpringApplication application = new SpringApplication(
				WithPropertySourceMultipleLocations.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application.run();
		String property = context.getEnvironment().getProperty("the.property");
		assertThat(property, equalTo("frommorepropertiesfile"));
		assertThat(context.getEnvironment(),
				containsPropertySource("class path resource "
						+ "[specificlocation.properties]"));
		context.close();
	}

	@Test
	public void propertySourceAnnotationMultipleLocationsAndName() throws Exception {
		SpringApplication application = new SpringApplication(
				WithPropertySourceMultipleLocationsAndName.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application.run();
		String property = context.getEnvironment().getProperty("the.property");
		assertThat(property, equalTo("frommorepropertiesfile"));
		assertThat(context.getEnvironment(), containsPropertySource("foo"));
		context.close();
	}

	@Test
	public void activateProfileFromProfileSpecificProperties() throws Exception {
		SpringApplication application = new SpringApplication(Config.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application
				.run("--spring.profiles.active=includeprofile");
		assertThat(context.getEnvironment(), acceptsProfiles("includeprofile"));
		assertThat(context.getEnvironment(), acceptsProfiles("specific"));
		assertThat(context.getEnvironment(), acceptsProfiles("morespecific"));
		assertThat(context.getEnvironment(), acceptsProfiles("yetmorespecific"));
		assertThat(context.getEnvironment(), not(acceptsProfiles("missing")));
	}

	@Test
	public void profileSubDocumentInProfileSpecificFile() throws Exception {
		// gh-340
		SpringApplication application = new SpringApplication(Config.class);
		application.setWebEnvironment(false);
		ConfigurableApplicationContext context = application
				.run("--spring.profiles.active=activeprofilewithsubdoc");
		String property = context.getEnvironment().getProperty("foobar");
		assertThat(property, equalTo("baz"));
	}

	@Test
	public void bindsToSpringApplication() throws Exception {
		// gh-346
		this.initializer.setSearchNames("bindtoapplication");
		this.initializer.onApplicationEvent(this.event);
		SpringApplication application = this.event.getSpringApplication();
		Field field = ReflectionUtils.findField(SpringApplication.class, "showBanner");
		field.setAccessible(true);
		assertThat((Boolean) field.get(application), equalTo(false));
	}

	@Test
	public void bindsSystemPropertyToSpringApplication() throws Exception {
		// gh-951
		System.setProperty("spring.main.showBanner", "false");
		this.initializer.onApplicationEvent(this.event);
		SpringApplication application = this.event.getSpringApplication();
		Field field = ReflectionUtils.findField(SpringApplication.class, "showBanner");
		field.setAccessible(true);
		assertThat((Boolean) field.get(application), equalTo(false));
	}

	private static Matcher<? super ConfigurableEnvironment> containsPropertySource(
			final String sourceName) {
		return new TypeSafeDiagnosingMatcher<ConfigurableEnvironment>() {
			@Override
			public void describeTo(Description description) {
				description.appendText("environment containing property source ")
						.appendValue(sourceName);
			}

			@Override
			protected boolean matchesSafely(ConfigurableEnvironment item,
					Description mismatchDescription) {
				MutablePropertySources sources = new MutablePropertySources(
						item.getPropertySources());
				ConfigurationPropertySources.finishAndRelocate(sources);
				mismatchDescription.appendText("Not matched against: ").appendValue(
						sources);
				return sources.contains(sourceName);
			}
		};
	}

	private static Matcher<? super ConfigurableEnvironment> acceptsProfiles(
			final String... profiles) {
		return new TypeSafeDiagnosingMatcher<ConfigurableEnvironment>() {
			@Override
			public void describeTo(Description description) {
				description.appendText("environment accepting profiles ").appendValue(
						profiles);
			}

			@Override
			protected boolean matchesSafely(ConfigurableEnvironment item,
					Description mismatchDescription) {
				mismatchDescription.appendText("Not matched against: ").appendValue(
						item.getActiveProfiles());
				return item.acceptsProfiles(profiles);
			}
		};
	}

	@Configuration
	protected static class Config {

	}

	@Configuration
	@PropertySource("classpath:/specificlocation.properties")
	protected static class WithPropertySource {

	}

	@Configuration
	@PropertySource("classpath:/${source.location}.properties")
	protected static class WithPropertySourcePlaceholders {

	}

	@Configuration
	@PropertySource(value = "classpath:/specificlocation.properties", name = "foo")
	protected static class WithPropertySourceAndName {

	}

	@Configuration
	@PropertySource("classpath:/enableprofile.properties")
	protected static class WithPropertySourceInProfile {

	}

	@Configuration
	@PropertySource("classpath:/enableprofile-myprofile.properties")
	@Profile("myprofile")
	protected static class WithPropertySourceAndProfile {

	}

	@Configuration
	@PropertySource({ "classpath:/specificlocation.properties",
			"classpath:/moreproperties.properties" })
	protected static class WithPropertySourceMultipleLocations {

	}

	@Configuration
	@PropertySource(value = { "classpath:/specificlocation.properties",
			"classpath:/moreproperties.properties" }, name = "foo")
	protected static class WithPropertySourceMultipleLocationsAndName {

	}

}
