Internal change
PiperOrigin-RevId: 230609148
diff --git a/pluginapi/src/main/java/org/robolectric/pluginapi/ConfigMerger.java b/pluginapi/src/main/java/org/robolectric/pluginapi/ConfigMerger.java
new file mode 100644
index 0000000..15e72ee
--- /dev/null
+++ b/pluginapi/src/main/java/org/robolectric/pluginapi/ConfigMerger.java
@@ -0,0 +1,10 @@
+package org.robolectric.pluginapi;
+
+import java.lang.reflect.Method;
+import org.robolectric.annotation.Config;
+
+public interface ConfigMerger {
+
+ Config getConfig(Class<?> testClass, Method method, Config globalConfig);
+
+}
diff --git a/pluginapi/src/main/java/org/robolectric/pluginapi/ConfigurationStrategy.java b/pluginapi/src/main/java/org/robolectric/pluginapi/ConfigurationStrategy.java
deleted file mode 100644
index b2e8402..0000000
--- a/pluginapi/src/main/java/org/robolectric/pluginapi/ConfigurationStrategy.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.robolectric.pluginapi;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-
-/**
- * Strategy for configuring individual tests.
- *
- * @since 4.2
- */
-public interface ConfigurationStrategy {
-
- /**
- * Determine the configuration for the given test class and method.
- *
- * Since a method may be run on multiple test subclasses, {@param testClass} indicates which
- * test case is currently being evaluated.
- *
- * @param testClass the test class being evaluated; this might be a subclass of the method's
- * declaring class.
- * @param method the test method to be evaluated
- * @return the set of configs
- */
- Configuration getConfig(Class<?> testClass, Method method);
-
- /**
- * Heterogeneous typesafe collection of configuration objects managed by their {@link Configurer}.
- *
- * @since 4.2
- */
- interface Configuration {
-
- /** Returns the configuration instance of the specified class for the current test. */
- <T> T get(Class<T> configClass);
-
- /** Returns the set of known configuration classes. */
- Collection<Class<?>> keySet();
- }
-}
diff --git a/pluginapi/src/main/java/org/robolectric/pluginapi/Configurer.java b/pluginapi/src/main/java/org/robolectric/pluginapi/Configurer.java
deleted file mode 100644
index 860c6e2..0000000
--- a/pluginapi/src/main/java/org/robolectric/pluginapi/Configurer.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.robolectric.pluginapi;
-
-import java.lang.reflect.Method;
-import javax.annotation.Nonnull;
-
-/**
- * Provides configuration data for tests.
- *
- * The test author can apply configuration data at a package, class, or method level, or any
- * combination of those. See [Configuring Robolectric](http://robolectric.org/configuring/) for
- * more details.
- *
- * The implementation of the configurer determines how config information is collected and merged
- * for each test.
- *
- * For a test:
- * ```java
- * class com.foo.MyTest extends com.foo.BaseTest {
- * {@literal @}Test void testMethod() {}
- * }
- * ```
- * the configuration is applied in the following order:
- *
- * * the {@link #defaultConfig()}.
- * * as specified in /robolectric.properties
- * * as specified in /com/robolectric.properties
- * * as specified in /com/foo/robolectric.properties
- * * as specified in BaseTest
- * * as specified in MyTest
- * * as specified in MyTest.testMethod
- *
- * Configuration objects can be accessed by shadows or tests via
- * {@link org.robolectric.config.ConfigRegistry.get(Class)}.
- *
- * @param <T> the configuration object's type
- */
-public interface Configurer<T> {
-
- /** Retrieve the class type for this Configurer */
- Class<T> getConfigClass();
-
- /**
- * Returns the default configuration for tests that do not specify a configuration of this type.
- */
- @Nonnull T defaultConfig();
-
- /**
- * Returns the configuration for a given package.
- *
- * This method will be called once for package in the hierarchy leading to the test class being
- * configured. For example, for `com.example.FooTest`, this method will be called three times
- * with `"com.example"`, `"com"`, and `""` (representing the top level package).
- *
- * @param packageName the name of the package, or the empty string representing the top level
- * unnamed package
- * @return a configuration object, or `null` if the given properties has no relevant data for this
- * configuration
- */
- T getConfigFor(@Nonnull String packageName);
-
- /**
- * Returns the configuration for the given class.
- *
- * This method will be called for each class in the test's class inheritance hierarchy.
- *
- * @return a configuration object, or `null` if the given class has no relevant data for this
- * configuration
- */
- T getConfigFor(@Nonnull Class<?> testClass);
-
- /**
- * Returns the configuration for the given method.
- *
- * @return a configuration object, or `null` if the given method has no relevant data for this
- * configuration
- */
- T getConfigFor(@Nonnull Method method);
-
- /**
- * Merges two configurations.
- *
- * This method will called whenever {@link #getConfigFor} returns a non-null configuration object.
- *
- * @param parentConfig a less specific configuration object
- * @param childConfig a more specific configuration object
- * @return the new configuration with merged parent and child data.
- */
- @Nonnull T merge(@Nonnull T parentConfig, @Nonnull T childConfig);
-
-}
diff --git a/pluginapi/src/main/java/org/robolectric/pluginapi/SdkPicker.java b/pluginapi/src/main/java/org/robolectric/pluginapi/SdkPicker.java
index 7e95a84..7954626 100644
--- a/pluginapi/src/main/java/org/robolectric/pluginapi/SdkPicker.java
+++ b/pluginapi/src/main/java/org/robolectric/pluginapi/SdkPicker.java
@@ -2,10 +2,10 @@
import java.util.List;
import javax.annotation.Nonnull;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
+import org.robolectric.annotation.Config;
public interface SdkPicker {
@Nonnull
- List<Sdk> selectSdks(Configuration configuration, UsesSdk usesSdk);
+ List<Sdk> selectSdks(Config config, UsesSdk usesSdk);
}
diff --git a/robolectric/src/main/java/org/robolectric/ConfigMerger.java b/robolectric/src/main/java/org/robolectric/ConfigMerger.java
index a90427c..0eeacf2 100644
--- a/robolectric/src/main/java/org/robolectric/ConfigMerger.java
+++ b/robolectric/src/main/java/org/robolectric/ConfigMerger.java
@@ -1,151 +1,7 @@
package org.robolectric;
-import static com.google.common.collect.Lists.reverse;
+import org.robolectric.plugins.DefaultConfigMerger;
-import com.google.common.annotations.VisibleForTesting;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Method;
-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 javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.Join;
-
-/**
- * Computes the effective Robolectric configuration for a given test method.
- *
- * This class is no longer used directly by Robolectric, but is left for convenience during
- * migration.
- *
- * @deprecated Provide an implementation of {@link javax.inject.Provider<Config>} instead. See
- * [Migration Notes](http://robolectric.org/migrating/#migrating-to-40) for details. This
- * class will be removed in Robolectric 4.3.
- */
+/** @deprecated use {@link org.robolectric.plugins.DefaultConfigMerger} instead. */
@Deprecated
-public class ConfigMerger {
- private final Map<String, Config> packageConfigCache = new LinkedHashMap<String, Config>() {
- @Override
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > 10;
- }
- };
-
- /**
- * Calculate the {@link Config} for the given test.
- *
- * @param testClass the class containing the test
- * @param method the test method
- * @param globalConfig global configuration values
- * @return the effective configuration
- * @since 3.2
- */
- public Config getConfig(Class<?> testClass, Method method, Config globalConfig) {
- Config config = Config.Builder.defaults().build();
- config = override(config, globalConfig);
-
- for (String packageName : reverse(packageHierarchyOf(testClass))) {
- Config packageConfig = cachedPackageConfig(packageName);
- config = override(config, packageConfig);
- }
-
- for (Class clazz : reverse(parentClassesFor(testClass))) {
- Config classConfig = (Config) clazz.getAnnotation(Config.class);
- config = override(config, classConfig);
- }
-
- Config methodConfig = method.getAnnotation(Config.class);
- config = override(config, methodConfig);
-
- return config;
- }
-
- /**
- * Generate {@link Config} for the specified package.
- *
- * More specific packages, test classes, and test method configurations
- * will override values provided here.
- *
- * The default implementation uses properties provided by {@link #getConfigProperties(String)}.
- *
- * The returned object is likely to be reused for many tests.
- *
- * @param packageName the name of the package, or empty string ({@code ""}) for the top level package
- * @return {@link Config} object for the specified package
- * @since 3.2
- */
- @Nullable
- private Config buildPackageConfig(String packageName) {
- return Config.Implementation.fromProperties(getConfigProperties(packageName));
- }
-
- /**
- * Return a {@link Properties} file for the given package name, or {@code null} if none is available.
- *
- * @since 3.2
- */
- protected Properties getConfigProperties(String packageName) {
- List<String> packageParts = new ArrayList<>(Arrays.asList(packageName.split("\\.")));
- packageParts.add(RobolectricTestRunner.CONFIG_PROPERTIES);
- final String resourceName = Join.join("/", packageParts);
- try (InputStream resourceAsStream = getResourceAsStream(resourceName)) {
- if (resourceAsStream == null) return null;
- Properties properties = new Properties();
- properties.load(resourceAsStream);
- return properties;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Nonnull @VisibleForTesting
- List<String> packageHierarchyOf(Class<?> javaClass) {
- Package aPackage = javaClass.getPackage();
- String testPackageName = aPackage == null ? "" : aPackage.getName();
- List<String> packageHierarchy = new ArrayList<>();
- while (!testPackageName.isEmpty()) {
- packageHierarchy.add(testPackageName);
- int lastDot = testPackageName.lastIndexOf('.');
- testPackageName = lastDot > 1 ? testPackageName.substring(0, lastDot) : "";
- }
- packageHierarchy.add("");
- return packageHierarchy;
- }
-
- @Nonnull
- private List<Class> parentClassesFor(Class testClass) {
- List<Class> testClassHierarchy = new ArrayList<>();
- while (testClass != null && !testClass.equals(Object.class)) {
- testClassHierarchy.add(testClass);
- testClass = testClass.getSuperclass();
- }
- return testClassHierarchy;
- }
-
- private Config override(Config config, Config classConfig) {
- return classConfig != null ? new Config.Builder(config).overlay(classConfig).build() : config;
- }
-
- @Nullable
- private Config cachedPackageConfig(String packageName) {
- synchronized (packageConfigCache) {
- Config config = packageConfigCache.get(packageName);
- if (config == null && !packageConfigCache.containsKey(packageName)) {
- config = buildPackageConfig(packageName);
- packageConfigCache.put(packageName, config);
- }
- return config;
- }
- }
-
- // visible for testing
- @SuppressWarnings("WeakerAccess")
- InputStream getResourceAsStream(String resourceName) {
- return getClass().getClassLoader().getResourceAsStream(resourceName);
- }
-}
+public class ConfigMerger extends DefaultConfigMerger {}
diff --git a/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java b/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java
index 347a457..b472ad4 100644
--- a/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java
+++ b/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java
@@ -2,7 +2,6 @@
import android.os.Build;
-import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
@@ -19,7 +18,6 @@
import java.util.Properties;
import java.util.ServiceLoader;
import javax.annotation.Nonnull;
-import javax.annotation.Priority;
import javax.inject.Inject;
import org.junit.AssumptionViolatedException;
import org.junit.Ignore;
@@ -49,12 +47,8 @@
import org.robolectric.internal.bytecode.ShadowMap;
import org.robolectric.internal.bytecode.ShadowWrangler;
import org.robolectric.manifest.AndroidManifest;
-import org.robolectric.pluginapi.ConfigurationStrategy;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
import org.robolectric.pluginapi.Sdk;
import org.robolectric.pluginapi.SdkPicker;
-import org.robolectric.plugins.ConfigConfigurer.DefaultConfigProvider;
-import org.robolectric.plugins.HierarchicalConfigurationStrategy.ConfigurationImpl;
import org.robolectric.util.PerfStatsCollector;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.util.inject.Injector;
@@ -95,15 +89,16 @@
final SandboxFactory sandboxFactory;
final ApkLoader apkLoader;
final SdkPicker sdkPicker;
- final ConfigurationStrategy configurationStrategy;
+ final org.robolectric.pluginapi.ConfigMerger configMerger;
@Inject
- public Ctx(SandboxFactory sandboxFactory, ApkLoader apkLoader, SdkPicker sdkPicker,
- ConfigurationStrategy configurationStrategy) {
+ public Ctx(SandboxFactory sandboxFactory, ApkLoader apkLoader,
+ SdkPicker sdkPicker,
+ org.robolectric.pluginapi.ConfigMerger configMerger) {
this.sandboxFactory = sandboxFactory;
this.apkLoader = apkLoader;
this.sdkPicker = sdkPicker;
- this.configurationStrategy = configurationStrategy;
+ this.configMerger = configMerger;
}
}
@@ -121,10 +116,6 @@
throws InitializationError {
super(testClass);
- if (DeprecatedTestRunnerDefaultConfigProvider.globalConfig == null) {
- DeprecatedTestRunnerDefaultConfigProvider.globalConfig = buildGlobalConfig();
- }
-
ctx = injector.getInstance(Ctx.class);
}
@@ -166,12 +157,9 @@
*/
@Override @Nonnull
protected InstrumentationConfiguration createClassLoaderConfig(final FrameworkMethod method) {
- Configuration configuration = ((RobolectricFrameworkMethod) method).config;
- Config config = configuration.get(Config.class);
-
Builder builder = new Builder(super.createClassLoaderConfig(method));
AndroidConfigurer.configure(builder, getInterceptors());
- AndroidConfigurer.withConfig(builder, config);
+ AndroidConfigurer.withConfig(builder, ((RobolectricFrameworkMethod) method).config);
return builder.build();
}
@@ -231,11 +219,10 @@
List<FrameworkMethod> children = new ArrayList<>();
for (FrameworkMethod frameworkMethod : super.getChildren()) {
try {
- Configuration configuration = getConfiguration(frameworkMethod.getMethod());
+ Config config = getConfig(frameworkMethod.getMethod());
+ AndroidManifest appManifest = getAppManifest(config);
- AndroidManifest appManifest = getAppManifest(configuration);
-
- List<Sdk> sdksToRun = ctx.sdkPicker.selectSdks(configuration, appManifest);
+ List<Sdk> sdksToRun = ctx.sdkPicker.selectSdks(config, appManifest);
RobolectricFrameworkMethod last = null;
for (Sdk sdk : sdksToRun) {
if (resourcesMode.includeLegacy(appManifest)) {
@@ -245,7 +232,7 @@
frameworkMethod.getMethod(),
appManifest,
sdk,
- configuration,
+ config,
ResourcesMode.legacy,
resourcesMode,
alwaysIncludeVariantMarkersInName));
@@ -257,7 +244,7 @@
frameworkMethod.getMethod(),
appManifest,
sdk,
- configuration,
+ config,
ResourcesMode.binary,
resourcesMode,
alwaysIncludeVariantMarkersInName));
@@ -411,27 +398,27 @@
}
protected Properties getBuildSystemApiProperties() {
- return staticGetBuildSystemApiProperties();
- }
+ InputStream resourceAsStream = getClass().getResourceAsStream("/com/android/tools/test_config.properties");
+ if (resourceAsStream == null) {
+ return null;
+ }
- protected static Properties staticGetBuildSystemApiProperties() {
- try (InputStream resourceAsStream =
- RobolectricTestRunner.class.getResourceAsStream(
- "/com/android/tools/test_config.properties")) {
- if (resourceAsStream == null) {
- return null;
- }
-
+ try {
Properties properties = new Properties();
properties.load(resourceAsStream);
return properties;
} catch (IOException e) {
return null;
+ } finally {
+ try {
+ resourceAsStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
}
}
- private AndroidManifest getAppManifest(Configuration configuration) {
- Config config = configuration.get(Config.class);
+ private AndroidManifest getAppManifest(Config config) {
ManifestFactory manifestFactory = getManifestFactory(config);
ManifestIdentifier identifier = manifestFactory.identify(config);
@@ -481,29 +468,10 @@
*
* @param method the test method
* @return the effective Robolectric configuration for the given test method
- * @deprecated Provide an implementation of {@link javax.inject.Provider<Config>} instead. See
- * [Migration Notes](http://robolectric.org/migrating/#migrating-to-40) for details. This
- * method will be removed in Robolectric 4.3.
* @since 2.0
*/
- @Deprecated
public Config getConfig(Method method) {
- throw new UnsupportedOperationException();
- }
-
- private Configuration getConfiguration(Method method) {
- Configuration configuration =
- ctx.configurationStrategy.getConfig(getTestClass().getJavaClass(), method);
-
- // in case #getConfig(Method) has been overridden...
- try {
- Config config = getConfig(method);
- ((ConfigurationImpl) configuration).put(Config.class, config);
- } catch (UnsupportedOperationException e) {
- // no problem
- }
-
- return configuration;
+ return ctx.configMerger.getConfig(getTestClass().getJavaClass(), method, buildGlobalConfig());
}
/**
@@ -518,31 +486,15 @@
* The default implementation has appropriate values for most use cases.
*
* @return global {@link Config} object
- * @deprecated Provide a service implementation of {@link DefaultConfigProvider} instead. See
- * [Migration Notes](http://robolectric.org/migrating/#migrating-to-40) for details. This
- * method will be removed in Robolectric 4.3.
* @since 3.1.3
*/
- @Deprecated
protected Config buildGlobalConfig() {
return new Config.Builder().build();
}
- @AutoService(DefaultConfigProvider.class)
- @Priority(Integer.MIN_VALUE)
- @Deprecated
- public static class DeprecatedTestRunnerDefaultConfigProvider implements DefaultConfigProvider {
- static Config globalConfig;
-
- @Override
- public Config get() {
- return globalConfig;
- }
- }
-
@Override @Nonnull
protected Class<?>[] getExtraShadows(FrameworkMethod frameworkMethod) {
- Config config = ((RobolectricFrameworkMethod) frameworkMethod).config.get(Config.class);
+ Config config = ((RobolectricFrameworkMethod) frameworkMethod).config;
return config.shadows();
}
@@ -617,7 +569,7 @@
private final @Nonnull AndroidManifest appManifest;
private final int apiLevel;
- final @Nonnull Configuration config;
+ final @Nonnull Config config;
final ResourcesMode resourcesMode;
private final ResourcesMode defaultResourcesMode;
private final boolean alwaysIncludeVariantMarkersInName;
@@ -630,7 +582,7 @@
@Nonnull Method method,
@Nonnull AndroidManifest appManifest,
@Nonnull Sdk sdk,
- @Nonnull Configuration config,
+ @Nonnull Config config,
ResourcesMode resourcesMode,
ResourcesMode defaultResourcesMode,
boolean alwaysIncludeVariantMarkersInName) {
diff --git a/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java b/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java
index cd9546a..25cb139 100755
--- a/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java
+++ b/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java
@@ -19,6 +19,7 @@
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.Package;
import android.content.res.AssetManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Build.VERSION_CODES;
@@ -40,13 +41,11 @@
import org.robolectric.android.Bootstrap;
import org.robolectric.android.fakes.RoboMonitoringInstrumentation;
import org.robolectric.annotation.Config;
-import org.robolectric.config.ConfigurationRegistry;
import org.robolectric.internal.ParallelUniverseInterface;
import org.robolectric.internal.SdkEnvironment;
import org.robolectric.manifest.AndroidManifest;
import org.robolectric.manifest.BroadcastReceiverData;
import org.robolectric.manifest.RoboNotFoundException;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
import org.robolectric.pluginapi.Sdk;
import org.robolectric.res.Fs;
import org.robolectric.res.PackageResourceTable;
@@ -94,12 +93,8 @@
}
@Override
- public void setUpApplicationState(ApkLoader apkLoader, Method method,
- Configuration configuration, AndroidManifest appManifest, SdkEnvironment sdkEnvironment) {
- Config config = configuration.get(Config.class);
-
- ConfigurationRegistry.instance = new ConfigurationRegistry(configuration);
-
+ public void setUpApplicationState(ApkLoader apkLoader, Method method, Config config,
+ AndroidManifest appManifest, SdkEnvironment sdkEnvironment) {
ReflectionHelpers.setStaticField(RuntimeEnvironment.class, "apiLevel", apiLevel);
RuntimeEnvironment.application = null;
@@ -117,16 +112,15 @@
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}
- android.content.res.Configuration androidConfiguration =
- new android.content.res.Configuration();
+ Configuration configuration = new Configuration();
DisplayMetrics displayMetrics = new DisplayMetrics();
- Bootstrap.applyQualifiers(config.qualifiers(), apiLevel, androidConfiguration,
+ Bootstrap.applyQualifiers(config.qualifiers(), apiLevel, configuration,
displayMetrics);
Locale locale = apiLevel >= VERSION_CODES.N
- ? androidConfiguration.getLocales().get(0)
- : androidConfiguration.locale;
+ ? configuration.getLocales().get(0)
+ : configuration.locale;
Locale.setDefault(locale);
// Looper needs to be prepared before the activity thread is created
@@ -159,15 +153,15 @@
// code in there that can be reusable, e.g: the XxxxIntentResolver code.
ShadowActivityThread.setApplicationInfo(applicationInfo);
- _activityThread_.setCompatConfiguration(androidConfiguration);
+ _activityThread_.setCompatConfiguration(configuration);
ReflectionHelpers
.setStaticField(ActivityThread.class, "sMainThreadHandler", new Handler(Looper.myLooper()));
- Bootstrap.setUpDisplay(androidConfiguration, displayMetrics);
- activityThread.applyConfigurationToResources(androidConfiguration);
+ Bootstrap.setUpDisplay(configuration, displayMetrics);
+ activityThread.applyConfigurationToResources(configuration);
Resources systemResources = Resources.getSystem();
- systemResources.updateConfiguration(androidConfiguration, displayMetrics);
+ systemResources.updateConfiguration(configuration, displayMetrics);
Context systemContextImpl = reflector(_ContextImpl_.class).createSystemContext(activityThread);
RuntimeEnvironment.systemContext = systemContextImpl;
@@ -225,7 +219,7 @@
}
registerBroadcastReceivers(application, appManifest);
- appResources.updateConfiguration(androidConfiguration, displayMetrics);
+ appResources.updateConfiguration(configuration, displayMetrics);
if (ShadowAssetManager.useLegacy()) {
populateAssetPaths(appResources.getAssets(), appManifest);
diff --git a/robolectric/src/main/java/org/robolectric/config/ConfigurationRegistry.java b/robolectric/src/main/java/org/robolectric/config/ConfigurationRegistry.java
deleted file mode 100644
index c7c3b89..0000000
--- a/robolectric/src/main/java/org/robolectric/config/ConfigurationRegistry.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.robolectric.config;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.HashMap;
-import java.util.Map;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
-
-/**
- * Holds configuration objects for the current test, computed using
- * {@link org.robolectric.pluginapi.Configurer}.
- *
- * Configuration is computed before tests run, outside of their sandboxes. If the configuration
- * is needed from within a sandbox (when a test is executing), we need to transfer it to a class
- * that the SandboxClassLoader recognizes. We do this by serializing and deserializing in
- * {@link #reloadInSandboxClassLoader(Object)}.
- */
-public class ConfigurationRegistry {
-
- public static ConfigurationRegistry instance;
-
- /**
- * Returns the configuration object of the specified class, computed using
- * {@link org.robolectric.pluginapi.Configurer}.
- */
- public static <T> T get(Class<T> configClass) {
- return instance.getInSandboxClassLoader(configClass);
- }
-
- private final Map<String, Object> configurations = new HashMap<>();
-
- public ConfigurationRegistry(Configuration configuration) {
- for (Class<?> classInParentLoader : configuration.keySet()) {
- Object configInParentLoader = configuration.get(classInParentLoader);
- configurations.put(classInParentLoader.getName(), configInParentLoader);
- }
- }
-
- private <T> T getInSandboxClassLoader(Class<T> someConfigClass) {
- Object configInParentLoader = configurations.get(someConfigClass.getName());
- Object configInSandboxLoader = reloadInSandboxClassLoader(configInParentLoader);
- return someConfigClass.cast(configInSandboxLoader);
- }
-
- private static Object reloadInSandboxClassLoader(Object configInParentLoader) {
- ByteArrayOutputStream buf = new ByteArrayOutputStream();
- try (ObjectOutputStream out = new ObjectOutputStream(buf)) {
- out.writeObject(configInParentLoader);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- byte[] bytes = buf.toByteArray();
-
- // ObjectInputStream loads classes in the current classloader by magic
- try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
- return in.readObject();
- } catch (IOException | ClassNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/robolectric/src/main/java/org/robolectric/internal/ParallelUniverseInterface.java b/robolectric/src/main/java/org/robolectric/internal/ParallelUniverseInterface.java
index f1167fa..e182401 100644
--- a/robolectric/src/main/java/org/robolectric/internal/ParallelUniverseInterface.java
+++ b/robolectric/src/main/java/org/robolectric/internal/ParallelUniverseInterface.java
@@ -2,8 +2,8 @@
import java.lang.reflect.Method;
import org.robolectric.ApkLoader;
+import org.robolectric.annotation.Config;
import org.robolectric.manifest.AndroidManifest;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
import org.robolectric.pluginapi.Sdk;
public interface ParallelUniverseInterface {
@@ -14,7 +14,7 @@
void setUpApplicationState(
ApkLoader apkLoader, Method method,
- Configuration config, AndroidManifest appManifest,
+ Config config, AndroidManifest appManifest,
SdkEnvironment sdkEnvironment);
Thread getMainThread();
diff --git a/robolectric/src/main/java/org/robolectric/plugins/ConfigConfigurer.java b/robolectric/src/main/java/org/robolectric/plugins/ConfigConfigurer.java
deleted file mode 100644
index de13373..0000000
--- a/robolectric/src/main/java/org/robolectric/plugins/ConfigConfigurer.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.robolectric.plugins;
-
-import com.google.auto.service.AutoService;
-import java.lang.reflect.Method;
-import java.util.Properties;
-import javax.annotation.Nonnull;
-import javax.inject.Provider;
-import org.robolectric.annotation.Config;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
-import org.robolectric.pluginapi.Configurer;
-
-/** Provides configuration to Robolectric for its `@`{@link Config} annotation. */
-@AutoService(Configurer.class)
-public class ConfigConfigurer implements Configurer<Config> {
-
- private final PackagePropertiesLoader packagePropertiesLoader;
- private final Config defaultConfig;
-
- public static Config get(Configuration testConfig) {
- return testConfig.get(Config.class);
- }
-
- protected ConfigConfigurer(PackagePropertiesLoader packagePropertiesLoader) {
- this(packagePropertiesLoader, () -> new Config.Builder().build());
- }
-
- public ConfigConfigurer(
- PackagePropertiesLoader packagePropertiesLoader,
- DefaultConfigProvider defaultConfigProvider) {
- this.packagePropertiesLoader = packagePropertiesLoader;
- this.defaultConfig = Config.Builder.defaults().overlay(defaultConfigProvider.get()).build();
- }
-
- @Override
- public Class<Config> getConfigClass() {
- return Config.class;
- }
-
- @Nonnull
- @Override
- public Config defaultConfig() {
- return defaultConfig;
- }
-
- @Override
- public Config getConfigFor(@Nonnull String packageName) {
- Properties properties = packagePropertiesLoader.getConfigProperties(packageName);
- return Config.Implementation.fromProperties(properties);
- }
-
- @Override
- public Config getConfigFor(@Nonnull Class<?> testClass) {
- return testClass.getAnnotation(Config.class);
- }
-
- @Override
- public Config getConfigFor(@Nonnull Method method) {
- return method.getAnnotation(Config.class);
- }
-
- @Nonnull
- @Override
- public Config merge(@Nonnull Config parentConfig, @Nonnull Config childConfig) {
- return new Config.Builder(parentConfig).overlay(childConfig).build();
- }
-
- /** Provides the default config for a test. */
- public interface DefaultConfigProvider extends Provider<Config> {
- @Override
- Config get();
- }
-}
diff --git a/robolectric/src/main/java/org/robolectric/plugins/DefaultConfigMerger.java b/robolectric/src/main/java/org/robolectric/plugins/DefaultConfigMerger.java
index 101fa73..99bf10c 100644
--- a/robolectric/src/main/java/org/robolectric/plugins/DefaultConfigMerger.java
+++ b/robolectric/src/main/java/org/robolectric/plugins/DefaultConfigMerger.java
@@ -1,7 +1,152 @@
package org.robolectric.plugins;
-import org.robolectric.ConfigMerger;
+import static com.google.common.collect.Lists.reverse;
-public class DefaultConfigMerger extends ConfigMerger {
+import com.google.auto.service.AutoService;
+import com.google.common.annotations.VisibleForTesting;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+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 javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.Priority;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.pluginapi.ConfigMerger;
+import org.robolectric.util.Join;
+/** Robolectric's default {@link ConfigMerger}. */
+@AutoService(ConfigMerger.class)
+@Priority(Integer.MIN_VALUE)
+public class DefaultConfigMerger implements ConfigMerger {
+ private final Map<String, Config> packageConfigCache =
+ new LinkedHashMap<String, Config>() {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > 10;
+ }
+ };
+
+ /**
+ * Calculate the {@link Config} for the given test.
+ *
+ * @param testClass the class containing the test
+ * @param method the test method
+ * @param globalConfig global configuration values
+ * @return the effective configuration
+ * @since 3.2
+ */
+ @Override
+ public Config getConfig(Class<?> testClass, Method method, Config globalConfig) {
+ Config config = Config.Builder.defaults().build();
+ config = override(config, globalConfig);
+
+ for (String packageName : reverse(packageHierarchyOf(testClass))) {
+ Config packageConfig = cachedPackageConfig(packageName);
+ config = override(config, packageConfig);
+ }
+
+ for (Class clazz : reverse(parentClassesFor(testClass))) {
+ Config classConfig = (Config) clazz.getAnnotation(Config.class);
+ config = override(config, classConfig);
+ }
+
+ Config methodConfig = method.getAnnotation(Config.class);
+ config = override(config, methodConfig);
+
+ return config;
+ }
+
+ /**
+ * Generate {@link Config} for the specified package.
+ *
+ * <p>More specific packages, test classes, and test method configurations will override values
+ * provided here.
+ *
+ * <p>The default implementation uses properties provided by {@link #getConfigProperties(String)}.
+ *
+ * <p>The returned object is likely to be reused for many tests.
+ *
+ * @param packageName the name of the package, or empty string ({@code ""}) for the top level
+ * package
+ * @return {@link Config} object for the specified package
+ * @since 3.2
+ */
+ @Nullable
+ private Config buildPackageConfig(String packageName) {
+ return Config.Implementation.fromProperties(getConfigProperties(packageName));
+ }
+
+ /**
+ * Return a {@link Properties} file for the given package name, or {@code null} if none is
+ * available.
+ *
+ * @since 3.2
+ */
+ protected Properties getConfigProperties(String packageName) {
+ List<String> packageParts = new ArrayList<>(Arrays.asList(packageName.split("\\.")));
+ packageParts.add(RobolectricTestRunner.CONFIG_PROPERTIES);
+ final String resourceName = Join.join("/", packageParts);
+ try (InputStream resourceAsStream = getResourceAsStream(resourceName)) {
+ if (resourceAsStream == null) return null;
+ Properties properties = new Properties();
+ properties.load(resourceAsStream);
+ return properties;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Nonnull
+ @VisibleForTesting
+ List<String> packageHierarchyOf(Class<?> javaClass) {
+ Package aPackage = javaClass.getPackage();
+ String testPackageName = aPackage == null ? "" : aPackage.getName();
+ List<String> packageHierarchy = new ArrayList<>();
+ while (!testPackageName.isEmpty()) {
+ packageHierarchy.add(testPackageName);
+ int lastDot = testPackageName.lastIndexOf('.');
+ testPackageName = lastDot > 1 ? testPackageName.substring(0, lastDot) : "";
+ }
+ packageHierarchy.add("");
+ return packageHierarchy;
+ }
+
+ @Nonnull
+ private List<Class> parentClassesFor(Class testClass) {
+ List<Class> testClassHierarchy = new ArrayList<>();
+ while (testClass != null && !testClass.equals(Object.class)) {
+ testClassHierarchy.add(testClass);
+ testClass = testClass.getSuperclass();
+ }
+ return testClassHierarchy;
+ }
+
+ private Config override(Config config, Config classConfig) {
+ return classConfig != null ? new Config.Builder(config).overlay(classConfig).build() : config;
+ }
+
+ @Nullable
+ private Config cachedPackageConfig(String packageName) {
+ synchronized (packageConfigCache) {
+ Config config = packageConfigCache.get(packageName);
+ if (config == null && !packageConfigCache.containsKey(packageName)) {
+ config = buildPackageConfig(packageName);
+ packageConfigCache.put(packageName, config);
+ }
+ return config;
+ }
+ }
+
+ // visible for testing
+ @SuppressWarnings("WeakerAccess")
+ InputStream getResourceAsStream(String resourceName) {
+ return getClass().getClassLoader().getResourceAsStream(resourceName);
+ }
}
diff --git a/robolectric/src/main/java/org/robolectric/plugins/DefaultSdkPicker.java b/robolectric/src/main/java/org/robolectric/plugins/DefaultSdkPicker.java
index 2447cdb..a96b206 100644
--- a/robolectric/src/main/java/org/robolectric/plugins/DefaultSdkPicker.java
+++ b/robolectric/src/main/java/org/robolectric/plugins/DefaultSdkPicker.java
@@ -18,7 +18,6 @@
import javax.inject.Inject;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.internal.ConfigUtils;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
import org.robolectric.pluginapi.Sdk;
import org.robolectric.pluginapi.SdkPicker;
import org.robolectric.pluginapi.UsesSdk;
@@ -57,15 +56,14 @@
/**
* Enumerate the SDKs to be used for this test.
*
- * @param configuration a collection of configuration objects, including {@link Config}
+ * @param config a {@link Config} specifying one or more SDKs
* @param usesSdk the {@link UsesSdk} for the test
* @return the list of candidate {@link Sdk}s.
* @since 3.9
*/
@Override
@Nonnull
- public List<Sdk> selectSdks(Configuration configuration, UsesSdk usesSdk) {
- Config config = configuration.get(Config.class);
+ public List<Sdk> selectSdks(Config config, UsesSdk usesSdk) {
Set<Sdk> sdks = new TreeSet<>(configuredSdks(config, usesSdk));
if (enabledSdks != null) {
sdks = Sets.intersection(sdks, enabledSdks);
diff --git a/robolectric/src/main/java/org/robolectric/plugins/HierarchicalConfigurationStrategy.java b/robolectric/src/main/java/org/robolectric/plugins/HierarchicalConfigurationStrategy.java
deleted file mode 100644
index 0b8fd03..0000000
--- a/robolectric/src/main/java/org/robolectric/plugins/HierarchicalConfigurationStrategy.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package org.robolectric.plugins;
-
-import com.google.auto.service.AutoService;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-import javax.annotation.Priority;
-import org.robolectric.pluginapi.ConfigurationStrategy;
-import org.robolectric.pluginapi.Configurer;
-
-/**
- * Robolectric's default {@link ConfigurationStrategy}.
- *
- * See [Configuring Robolectric](http://robolectric.org/configuring/).
- */
-@SuppressWarnings({"AndroidJdkLibsChecker", "NewApi"})
-@AutoService(ConfigurationStrategy.class)
-@Priority(Integer.MIN_VALUE)
-public class HierarchicalConfigurationStrategy implements ConfigurationStrategy {
-
- /** The cache is sized to avoid repeated resolutions for any node. */
- private int highWaterMark = 0;
- private final Map<String, Object[]> cache =
- new LinkedHashMap<String, Object[]>() {
- @Override
- protected boolean removeEldestEntry(Map.Entry<String, Object[]> eldest) {
- return size() > highWaterMark + 1;
- }
- };
-
- private final Configurer<?>[] configurers;
- private final Object[] defaultConfigs;
-
- public HierarchicalConfigurationStrategy(Configurer<?>... configurers) {
- this.configurers = configurers;
-
- defaultConfigs = new Object[configurers.length];
- for (int i = 0; i < configurers.length; i++) {
- Configurer<?> configurer = configurers[i];
- defaultConfigs[i] = configurer.defaultConfig();
- }
- }
-
- @Override
- public ConfigurationImpl getConfig(Class<?> testClass, Method method) {
- final Counter counter = new Counter();
- Object[] configs = cache(testClass.getName() + "/" + method.getName(), counter, s -> {
- counter.incr();
- Object[] methodConfigs = getConfigs(counter,
- configurer -> configurer.getConfigFor(method));
- return merge(getFirstClassConfig(testClass, counter), methodConfigs);
- });
-
- ConfigurationImpl testConfig = new ConfigurationImpl();
- for (int i = 0; i < configurers.length; i++) {
- put(testConfig, configurers[i].getConfigClass(), configs[i]);
- }
-
- return testConfig;
- }
-
- private Object[] getFirstClassConfig(Class<?> testClass, Counter counter) {
- // todo: should parent class configs have lower precedence than package configs?
- return cache("first:" + testClass, counter, s -> {
- Object[] configsForClass = getClassConfig(testClass, counter);
- Package pkg = testClass.getPackage();
- Object[] configsForPackage = getPackageConfig(pkg == null ? "" : pkg.getName(), counter);
- return merge(configsForPackage, configsForClass);
- }
- );
- }
-
- private Object[] getPackageConfig(String packageName, Counter counter) {
- return cache(packageName, counter, s -> {
- Object[] packageConfigs = getConfigs(counter,
- configurer -> configurer.getConfigFor(packageName));
- String parentPackage = parentPackage(packageName);
- if (parentPackage == null) {
- return merge(defaultConfigs, packageConfigs);
- } else {
- Object[] packageConfig = getPackageConfig(parentPackage, counter);
- return merge(packageConfig, packageConfigs);
- }
- });
- }
-
- private String parentPackage(String name) {
- if (name.isEmpty()) {
- return null;
- }
- int lastDot = name.lastIndexOf('.');
- return lastDot > -1 ? name.substring(0, lastDot) : "";
- }
-
- private Object[] getClassConfig(Class<?> testClass, Counter counter) {
- return cache(testClass.getName(), counter, s -> {
- Object[] classConfigs = getConfigs(counter, configurer -> configurer.getConfigFor(testClass));
-
- Class<?> superclass = testClass.getSuperclass();
- if (superclass != Object.class) {
- Object[] superclassConfigs = getClassConfig(superclass, counter);
- return merge(superclassConfigs, classConfigs);
- }
- return classConfigs;
- });
- }
-
- private Object[] cache(String name, Counter counter, Function<String, Object[]> fn) {
- // make sure the cache is optimally sized this test suite
- if (counter.depth > highWaterMark) {
- highWaterMark = counter.depth;
- }
-
- Object[] configs = cache.get(name);
- if (configs == null) {
- configs = fn.apply(name);
- cache.put(name, configs);
- }
- return configs;
- }
-
- interface GetConfig {
- Object getConfig(Configurer<?> configurer);
- }
-
- private Object[] getConfigs(Counter counter, GetConfig getConfig) {
- counter.incr();
-
- Object[] objects = new Object[configurers.length];
- for (int i = 0; i < configurers.length; i++) {
- objects[i] = getConfig.getConfig(configurers[i]);
- }
- return objects;
- }
-
- private void put(ConfigurationImpl testConfig, Class<?> configClass, Object config) {
- testConfig.put((Class) configClass, config);
- }
-
- private Object[] merge(Object[] parentConfigs, Object[] childConfigs) {
- Object[] objects = new Object[configurers.length];
- for (int i = 0; i < configurers.length; i++) {
- Configurer configurer = configurers[i];
- Object childConfig = childConfigs[i];
- Object parentConfig = parentConfigs[i];
- objects[i] = childConfig == null
- ? parentConfig
- : parentConfig == null
- ? childConfig
- : configurer.merge(parentConfig, childConfig);
- }
- return objects;
- }
-
- public static class ConfigurationImpl implements Configuration {
-
- private final Map<Class<?>, Object> configs = new HashMap<>();
-
- public <T> void put(Class<T> klass, T instance) {
- configs.put(klass, instance);
- }
-
- @Override
- public <T> T get(Class<T> klass) {
- return klass.cast(configs.get(klass));
- }
-
- @Override
- public Set<Class<?>> keySet() {
- return configs.keySet();
- }
-
- }
-
- private static class Counter {
- private int depth = 0;
-
- void incr() {
- depth++;
- }
- }
-}
diff --git a/robolectric/src/main/java/org/robolectric/plugins/PackagePropertiesLoader.java b/robolectric/src/main/java/org/robolectric/plugins/PackagePropertiesLoader.java
deleted file mode 100644
index 7957737..0000000
--- a/robolectric/src/main/java/org/robolectric/plugins/PackagePropertiesLoader.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.robolectric.plugins;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Properties;
-import javax.annotation.Nonnull;
-import org.robolectric.RobolectricTestRunner;
-
-/**
- * Provides cached access to `robolectric-properties` files, for all your configuration needs!
- *
- * Used by {@link ConfigConfigurer} to support package configuration (see [Configuring
- * Robolectric](http://robolectric.org/configuring/) but it may be useful for other
- * {@link org.robolectric.pluginapi.Configurer}s as well.
- */
-@SuppressWarnings({"AndroidJdkLibsChecker", "NewApi"})
-public class PackagePropertiesLoader {
-
- /**
- * We should get very high cache hit rates even with a tiny cache if we're called sequentially
- * by multiple {@link org.robolectric.pluginapi.Configurer}s for the same package.
- */
- private final Map<String, Properties> cache = new LinkedHashMap<String, Properties>() {
- @Override
- protected boolean removeEldestEntry(Map.Entry<String, Properties> eldest) {
- return size() > 3;
- }
- };
-
- /**
- * Return a {@link Properties} file for the given package name, or {@code null} if none is
- * available.
- *
- * @since 3.2
- */
- public Properties getConfigProperties(@Nonnull String packageName) {
- return cache.computeIfAbsent(packageName, s -> {
- StringBuilder buf = new StringBuilder();
- if (!packageName.isEmpty()) {
- buf.append(packageName.replace('.', '/'));
- buf.append('/');
- }
- buf.append(RobolectricTestRunner.CONFIG_PROPERTIES);
- final String resourceName = buf.toString();
-
- try (InputStream resourceAsStream = getResourceAsStream(resourceName)) {
- if (resourceAsStream == null) {
- return null;
- }
- Properties properties = new Properties();
- properties.load(resourceAsStream);
- return properties;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- });
- }
-
- // visible for testing
- InputStream getResourceAsStream(String resourceName) {
- return getClass().getClassLoader().getResourceAsStream(resourceName);
- }
-}
diff --git a/robolectric/src/test/java/org/robolectric/BootstrapDeferringRobolectricTestRunner.java b/robolectric/src/test/java/org/robolectric/BootstrapDeferringRobolectricTestRunner.java
index 66bb411..29a7243 100644
--- a/robolectric/src/test/java/org/robolectric/BootstrapDeferringRobolectricTestRunner.java
+++ b/robolectric/src/test/java/org/robolectric/BootstrapDeferringRobolectricTestRunner.java
@@ -9,12 +9,12 @@
import javax.annotation.Nonnull;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
+import org.robolectric.annotation.Config;
import org.robolectric.internal.ParallelUniverseInterface;
import org.robolectric.internal.SdkEnvironment;
import org.robolectric.internal.bytecode.InstrumentationConfiguration;
import org.robolectric.internal.bytecode.InstrumentationConfiguration.Builder;
import org.robolectric.manifest.AndroidManifest;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
import org.robolectric.pluginapi.Sdk;
/**
@@ -80,7 +80,7 @@
public boolean legacyResources;
public ApkLoader apkLoader;
public Method method;
- public Configuration config;
+ public Config config;
public AndroidManifest appManifest;
public SdkEnvironment sdkEnvironment;
@@ -100,7 +100,7 @@
}
@Override
- public void setUpApplicationState(ApkLoader apkLoader, Method method, Configuration config,
+ public void setUpApplicationState(ApkLoader apkLoader, Method method, Config config,
AndroidManifest appManifest, SdkEnvironment sdkEnvironment) {
this.apkLoader = apkLoader;
this.method = method;
diff --git a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java
index 9add700..3b212a0 100644
--- a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java
+++ b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerTest.java
@@ -38,16 +38,13 @@
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.JUnit4;
import org.junit.runners.MethodSorters;
-import org.junit.runners.model.FrameworkMethod;
import org.robolectric.RobolectricTestRunner.ResourcesMode;
import org.robolectric.RobolectricTestRunner.RobolectricFrameworkMethod;
import org.robolectric.android.internal.ParallelUniverse;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Config.Implementation;
import org.robolectric.internal.ParallelUniverseInterface;
import org.robolectric.internal.SdkEnvironment;
import org.robolectric.manifest.AndroidManifest;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
import org.robolectric.pluginapi.SdkProvider;
import org.robolectric.plugins.DefaultSdkPicker;
import org.robolectric.plugins.DefaultSdkProvider;
@@ -128,19 +125,6 @@
}
@Test
- public void supportsOldGetConfigUntil4dot3() throws Exception {
- Implementation overriddenConfig = Config.Builder.defaults().build();
- List<FrameworkMethod> children = new SingleSdkRobolectricTestRunner(TestWithTwoMethods.class) {
- @Override
- public Config getConfig(Method method) {
- return overriddenConfig;
- }
- }.getChildren();
- Config config = ((RobolectricFrameworkMethod) children.get(0)).config.get(Config.class);
- assertThat(config).isSameAs(overriddenConfig);
- }
-
- @Test
public void failureInResetterDoesntBreakAllTests() throws Exception {
RobolectricTestRunner runner =
new SingleSdkRobolectricTestRunner(TestWithTwoMethods.class) {
@@ -200,7 +184,7 @@
method,
mock(AndroidManifest.class),
sdkCollection.getSdk(16),
- mock(Configuration.class),
+ mock(Config.class),
ResourcesMode.legacy,
ResourcesMode.legacy,
false);
@@ -209,7 +193,7 @@
method,
mock(AndroidManifest.class),
sdkCollection.getSdk(17),
- mock(Configuration.class),
+ mock(Config.class),
ResourcesMode.legacy,
ResourcesMode.legacy,
false);
@@ -218,7 +202,7 @@
method,
mock(AndroidManifest.class),
sdkCollection.getSdk(16),
- mock(Configuration.class),
+ mock(Config.class),
ResourcesMode.legacy,
ResourcesMode.legacy,
false);
@@ -227,7 +211,7 @@
method,
mock(AndroidManifest.class),
sdkCollection.getSdk(16),
- mock(Configuration.class),
+ mock(Config.class),
ResourcesMode.binary,
ResourcesMode.legacy,
false);
@@ -277,7 +261,7 @@
@Override
public void setUpApplicationState(ApkLoader apkLoader, Method method,
- Configuration configuration, AndroidManifest appManifest, SdkEnvironment environment) {
+ Config config, AndroidManifest appManifest, SdkEnvironment environment) {
throw new RuntimeException("fake error in setUpApplicationState");
}
}
@@ -300,7 +284,6 @@
@Ignore
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
- @Config(qualifiers = "w123dp-h456dp-land-hdpi")
public static class TestWithTwoMethods {
@Test
public void first() throws Exception {
diff --git a/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java b/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java
index 0f3a6d1..bf9a010 100644
--- a/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java
+++ b/robolectric/src/test/java/org/robolectric/SingleSdkRobolectricTestRunner.java
@@ -5,31 +5,22 @@
import java.util.List;
import javax.annotation.Nonnull;
import org.junit.runners.model.InitializationError;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
+import org.robolectric.annotation.Config;
import org.robolectric.pluginapi.Sdk;
import org.robolectric.pluginapi.SdkPicker;
import org.robolectric.pluginapi.UsesSdk;
import org.robolectric.util.TestUtil;
import org.robolectric.util.inject.Injector;
-public class SingleSdkRobolectricTestRunner extends RobolectricTestRunner {
+class SingleSdkRobolectricTestRunner extends RobolectricTestRunner {
- private static final Injector INJECTOR = defaultInjector().build();
+ private static final Injector INJECTOR =
+ defaultInjector().bind(SdkPicker.class, SingleSdkPicker.class).build();
- public static Injector.Builder defaultInjector() {
- return RobolectricTestRunner.defaultInjector()
- .bind(SdkPicker.class, SingleSdkPicker.class);
- }
-
- public SingleSdkRobolectricTestRunner(Class<?> testClass) throws InitializationError {
+ SingleSdkRobolectricTestRunner(Class<?> testClass) throws InitializationError {
super(testClass, INJECTOR);
}
- public SingleSdkRobolectricTestRunner(Class<?> testClass, Injector injector)
- throws InitializationError {
- super(testClass, injector);
- }
-
@Override
ResourcesMode getResourcesMode() {
return ResourcesMode.binary;
@@ -49,7 +40,7 @@
@Nonnull
@Override
- public List<Sdk> selectSdks(Configuration configuration, UsesSdk usesSdk) {
+ public List<Sdk> selectSdks(Config config, UsesSdk usesSdk) {
return Collections.singletonList(sdk);
}
}
diff --git a/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java b/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java
index d9594fd..b3396cc 100644
--- a/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java
+++ b/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java
@@ -33,7 +33,6 @@
import org.robolectric.annotation.Config;
import org.robolectric.manifest.AndroidManifest;
import org.robolectric.manifest.RoboNotFoundException;
-import org.robolectric.plugins.HierarchicalConfigurationStrategy.ConfigurationImpl;
import org.robolectric.res.ResourceTable;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowApplication;
@@ -116,9 +115,7 @@
@Test
public void setUpApplicationState_setsVersionQualifierFromSdk() {
String givenQualifiers = "";
- ConfigurationImpl config = new ConfigurationImpl();
- config.put(Config.class, new Config.Builder().setQualifiers(givenQualifiers).build());
- bootstrapWrapper.config = config;
+ bootstrapWrapper.config = new Config.Builder().setQualifiers(givenQualifiers).build();
bootstrapWrapper.callSetUpApplicationState();
assertThat(RuntimeEnvironment.getQualifiers()).contains("v" + Build.VERSION.RESOURCES_SDK_INT);
}
@@ -126,10 +123,7 @@
@Test
public void setUpApplicationState_setsVersionQualifierFromSdkWithOtherQualifiers() {
String givenQualifiers = "large-land";
- ConfigurationImpl config = new ConfigurationImpl();
- config.put(Config.class, new Config.Builder().setQualifiers(givenQualifiers).build());
- bootstrapWrapper.config = config;
-
+ bootstrapWrapper.config = new Config.Builder().setQualifiers(givenQualifiers).build();
bootstrapWrapper.callSetUpApplicationState();
String optsForO = RuntimeEnvironment.getApiLevel() >= O
diff --git a/robolectric/src/test/java/org/robolectric/plugins/CustomConfigurerTest.java b/robolectric/src/test/java/org/robolectric/plugins/CustomConfigurerTest.java
deleted file mode 100644
index d64fa15..0000000
--- a/robolectric/src/test/java/org/robolectric/plugins/CustomConfigurerTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.robolectric.plugins;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.util.stream.Collectors.toList;
-import static org.junit.Assert.fail;
-
-import java.lang.annotation.Annotation;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.reflect.Method;
-import java.util.List;
-import javax.annotation.Nonnull;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.JUnit4;
-import org.junit.runners.model.InitializationError;
-import org.robolectric.SingleSdkRobolectricTestRunner;
-import org.robolectric.android.FailureListener;
-import org.robolectric.config.ConfigurationRegistry;
-import org.robolectric.pluginapi.ConfigurationStrategy;
-import org.robolectric.pluginapi.Configurer;
-
-@RunWith(JUnit4.class)
-public class CustomConfigurerTest {
-
- @Test
- public void customConfigCanBeAccessedFromWithinSandbox() throws Exception {
- List<String> failures = runAndGetFailures(TestWithConfig.class);
- assertThat(failures).containsExactly("someConfig value is the value");
- }
-
- /////////////////////
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target(value = {ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD})
- public @interface SomeConfig {
- String value();
- }
-
- @Ignore
- public static class TestWithConfig {
-
- @Test
- @SomeConfig(value = "the value")
- public void shouldHaveValue() throws Exception {
- SomeConfig someConfig = ConfigurationRegistry.get(SomeConfig.class);
- fail("someConfig value is " + someConfig.value());
- }
- }
-
- static class SomeConfigConfigurer implements Configurer<SomeConfig> {
-
- @Override
- public Class<SomeConfig> getConfigClass() {
- return SomeConfig.class;
- }
-
- @Nonnull
- @Override
- public SomeConfig defaultConfig() {
- return new MySomeConfig();
- }
-
- @Override
- public SomeConfig getConfigFor(@Nonnull String packageName) {
- return null;
- }
-
- @Override
- public SomeConfig getConfigFor(@Nonnull Class<?> testClass) {
- return testClass.getAnnotation(SomeConfig.class);
- }
-
- @Override
- public SomeConfig getConfigFor(@Nonnull Method method) {
- return method.getAnnotation(SomeConfig.class);
- }
-
- @Nonnull
- @Override
- public SomeConfig merge(@Nonnull SomeConfig parentConfig, @Nonnull SomeConfig childConfig) {
- return childConfig;
- }
-
- @SuppressWarnings("BadAnnotationImplementation")
- private static class MySomeConfig implements SomeConfig {
-
- @Override
- public Class<? extends Annotation> annotationType() {
- return Annotation.class;
- }
-
- @Override
- public String value() {
- return "default value";
- }
- }
- }
-
- private List<String> runAndGetFailures(Class<TestWithConfig> testClass)
- throws InitializationError {
- RunNotifier notifier = new RunNotifier();
- FailureListener failureListener = new FailureListener();
- notifier.addListener(failureListener);
-
- HierarchicalConfigurationStrategy configurationStrategy =
- new HierarchicalConfigurationStrategy(
- new ConfigConfigurer(new PackagePropertiesLoader()),
- new SomeConfigConfigurer());
-
- SingleSdkRobolectricTestRunner testRunner = new SingleSdkRobolectricTestRunner(
- testClass,
- SingleSdkRobolectricTestRunner.defaultInjector()
- .bind(ConfigurationStrategy.class, configurationStrategy)
- .build());
-
- testRunner.run(notifier);
- return failureListener.failures.stream().map(Failure::getMessage).collect(toList());
- }
-
-}
diff --git a/robolectric/src/test/java/org/robolectric/plugins/HierarchicalConfigurationStrategyTest.java b/robolectric/src/test/java/org/robolectric/plugins/DefaultConfigMergerTest.java
similarity index 65%
rename from robolectric/src/test/java/org/robolectric/plugins/HierarchicalConfigurationStrategyTest.java
rename to robolectric/src/test/java/org/robolectric/plugins/DefaultConfigMergerTest.java
index 86ff598..37d1b2c 100644
--- a/robolectric/src/test/java/org/robolectric/plugins/HierarchicalConfigurationStrategyTest.java
+++ b/robolectric/src/test/java/org/robolectric/plugins/DefaultConfigMergerTest.java
@@ -9,29 +9,25 @@
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import javax.annotation.Nonnull;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.junit.runners.model.InitializationError;
import org.robolectric.TestFakeApp;
import org.robolectric.annotation.Config;
-import org.robolectric.pluginapi.ConfigurationStrategy;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
-import org.robolectric.pluginapi.Configurer;
import org.robolectric.shadows.ShadowView;
import org.robolectric.shadows.ShadowViewGroup;
import org.robolectric.shadows.testing.TestApplication;
@RunWith(JUnit4.class)
-public class HierarchicalConfigurationStrategyTest {
+public class DefaultConfigMergerTest {
@Test public void defaultValuesAreMerged() throws Exception {
- assertThat(configFor(Test2.class, "withoutAnnotation").manifest())
+ assertThat(configFor(Test2.class, "withoutAnnotation",
+ new Config.Builder().build()).manifest())
.isEqualTo("AndroidManifest.xml");
}
@@ -42,8 +38,7 @@
}
@Test
- public void whenClassHasConfigAnnotation_getConfig_shouldMergeClassAndMethodConfig()
- throws Exception {
+ public void whenClassHasConfigAnnotation_getConfig_shouldMergeClassAndMethodConfig() throws Exception {
assertConfig(
configFor(Test1.class, "withoutAnnotation"),
new int[] {1},
@@ -53,7 +48,7 @@
"from-test",
"test/res",
"test/assets",
- new Class<?>[] {Test1.class},
+ new Class[] {Test1.class},
new String[] {"com.example.test1"},
new String[] {"libs/test"});
@@ -66,7 +61,7 @@
"from-test",
"test/res",
"test/assets",
- new Class<?>[] {Test1.class},
+ new Class[] {Test1.class},
new String[] {"com.example.test1"},
new String[] {"libs/test"});
@@ -79,14 +74,13 @@
"from-method",
"method/res",
"method/assets",
- new Class<?>[] {Test1.class, Test2.class},
+ new Class[] {Test1.class, Test2.class},
new String[] {"com.example.test1", "com.example.method1"},
new String[] {"libs/method", "libs/test"});
}
@Test
- public void whenClassDoesntHaveConfigAnnotation_getConfig_shouldUseMethodConfig()
- throws Exception {
+ public void whenClassDoesntHaveConfigAnnotation_getConfig_shouldUseMethodConfig() throws Exception {
assertConfig(
configFor(Test2.class, "withoutAnnotation"),
new int[0],
@@ -96,7 +90,7 @@
"",
"res",
"assets",
- new Class<?>[] {},
+ new Class[] {},
new String[] {},
new String[] {});
@@ -109,7 +103,7 @@
"",
"res",
"assets",
- new Class<?>[] {},
+ new Class[] {},
new String[] {},
new String[] {});
@@ -122,16 +116,15 @@
"from-method",
"method/res",
"method/assets",
- new Class<?>[] {Test1.class},
+ new Class[] {Test1.class},
new String[] {"com.example.method2"},
new String[] {"libs/method"});
}
@Test
- public void whenClassDoesntHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig()
- throws Exception {
+ public void whenClassDoesntHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig() throws Exception {
assertConfig(
- configFor(Test1B.class, "withoutAnnotation"),
+ configFor(Test5.class, "withoutAnnotation"),
new int[] {1},
"foo",
TestFakeApp.class,
@@ -139,12 +132,12 @@
"from-test",
"test/res",
"test/assets",
- new Class<?>[] {Test1.class, Test1.class},
+ new Class[] {Test1.class, Test1.class},
new String[] {"com.example.test1"},
new String[] {"libs/test"});
assertConfig(
- configFor(Test1B.class, "withDefaultsAnnotation"),
+ configFor(Test5.class, "withDefaultsAnnotation"),
new int[] {1},
"foo",
TestFakeApp.class,
@@ -152,12 +145,12 @@
"from-test",
"test/res",
"test/assets",
- new Class<?>[] {Test1.class, Test1.class},
+ new Class[] {Test1.class, Test1.class},
new String[] {"com.example.test1"},
new String[] {"libs/test"});
assertConfig(
- configFor(Test1B.class, "withOverrideAnnotation"),
+ configFor(Test5.class, "withOverrideAnnotation"),
new int[] {14},
"foo",
TestFakeApp.class,
@@ -165,16 +158,15 @@
"from-method5",
"test/res",
"method5/assets",
- new Class<?>[] {Test1.class, Test1.class, Test1B.class},
+ new Class[] {Test1.class, Test1.class, Test5.class},
new String[] {"com.example.test1", "com.example.method5"},
new String[] {"libs/test"});
}
@Test
- public void whenClassAndParentClassHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig()
- throws Exception {
+ public void whenClassAndParentClassHaveConfigAnnotation_getConfig_shouldMergeParentClassAndMethodConfig() throws Exception {
assertConfig(
- configFor(Test1C.class, "withoutAnnotation"),
+ configFor(Test6.class, "withoutAnnotation"),
new int[] {1},
"foo",
TestFakeApp.class,
@@ -182,12 +174,12 @@
"from-class6",
"class6/res",
"test/assets",
- new Class<?>[] {Test1.class, Test1.class, Test1C.class},
+ new Class[] {Test1.class, Test1.class, Test6.class},
new String[] {"com.example.test1", "com.example.test6"},
new String[] {"libs/test"});
assertConfig(
- configFor(Test1C.class, "withDefaultsAnnotation"),
+ configFor(Test6.class, "withDefaultsAnnotation"),
new int[] {1},
"foo",
TestFakeApp.class,
@@ -195,12 +187,12 @@
"from-class6",
"class6/res",
"test/assets",
- new Class<?>[] {Test1.class, Test1.class, Test1C.class},
+ new Class[] {Test1.class, Test1.class, Test6.class},
new String[] {"com.example.test1", "com.example.test6"},
new String[] {"libs/test"});
assertConfig(
- configFor(Test1C.class, "withOverrideAnnotation"),
+ configFor(Test6.class, "withOverrideAnnotation"),
new int[] {14},
"foo",
TestFakeApp.class,
@@ -208,16 +200,15 @@
"from-method5",
"class6/res",
"method5/assets",
- new Class<?>[] {Test1.class, Test1.class, Test1C.class, Test1B.class},
+ new Class[] {Test1.class, Test1.class, Test6.class, Test5.class},
new String[] {"com.example.test1", "com.example.method5", "com.example.test6"},
new String[] {"libs/test"});
}
@Test
- public void whenClassAndSubclassHaveConfigAnnotation_getConfig_shouldMergeClassSubclassAndMethodConfig()
- throws Exception {
+ public void whenClassAndSubclassHaveConfigAnnotation_getConfig_shouldMergeClassSubclassAndMethodConfig() throws Exception {
assertConfig(
- configFor(Test1A.class, "withoutAnnotation"),
+ configFor(Test3.class, "withoutAnnotation"),
new int[] {1},
"foo",
TestFakeApp.class,
@@ -225,12 +216,12 @@
"from-subclass",
"test/res",
"test/assets",
- new Class<?>[] {Test1.class},
+ new Class[] {Test1.class},
new String[] {"com.example.test1"},
new String[] {"libs/test"});
assertConfig(
- configFor(Test1A.class, "withDefaultsAnnotation"),
+ configFor(Test3.class, "withDefaultsAnnotation"),
new int[] {1},
"foo",
TestFakeApp.class,
@@ -238,12 +229,12 @@
"from-subclass",
"test/res",
"test/assets",
- new Class<?>[] {Test1.class},
+ new Class[] {Test1.class},
new String[] {"com.example.test1"},
new String[] {"libs/test"});
assertConfig(
- configFor(Test1A.class, "withOverrideAnnotation"),
+ configFor(Test3.class, "withOverrideAnnotation"),
new int[] {9},
"furf",
TestApplication.class,
@@ -251,16 +242,15 @@
"from-method",
"method/res",
"method/assets",
- new Class<?>[] {Test1.class, Test2.class},
+ new Class[] {Test1.class, Test2.class},
new String[] {"com.example.test1", "com.example.method1"},
new String[] {"libs/method", "libs/test"});
}
@Test
- public void whenClassDoesntHaveConfigAnnotationButSubclassDoes_getConfig_shouldMergeSubclassAndMethodConfig()
- throws Exception {
+ public void whenClassDoesntHaveConfigAnnotationButSubclassDoes_getConfig_shouldMergeSubclassAndMethodConfig() throws Exception {
assertConfig(
- configFor(Test2A.class, "withoutAnnotation"),
+ configFor(Test4.class, "withoutAnnotation"),
new int[0],
"AndroidManifest.xml",
DEFAULT_APPLICATION,
@@ -268,12 +258,12 @@
"from-subclass",
"res",
"assets",
- new Class<?>[] {},
+ new Class[] {},
new String[] {},
new String[] {});
assertConfig(
- configFor(Test2A.class, "withDefaultsAnnotation"),
+ configFor(Test4.class, "withDefaultsAnnotation"),
new int[0],
"AndroidManifest.xml",
DEFAULT_APPLICATION,
@@ -281,12 +271,12 @@
"from-subclass",
"res",
"assets",
- new Class<?>[] {},
+ new Class[] {},
new String[] {},
new String[] {});
assertConfig(
- configFor(Test2A.class, "withOverrideAnnotation"),
+ configFor(Test4.class, "withOverrideAnnotation"),
new int[] {9},
"furf",
TestFakeApp.class,
@@ -294,7 +284,7 @@
"from-method",
"method/res",
"method/assets",
- new Class<?>[] {Test1.class},
+ new Class[] {Test1.class},
new String[] {"com.example.method2"},
new String[] {"libs/method"});
}
@@ -322,7 +312,7 @@
"from-properties-file",
"from/properties/file/res",
"from/properties/file/assets",
- new Class<?>[] {ShadowView.class, ShadowViewGroup.class},
+ new Class[] {ShadowView.class, ShadowViewGroup.class},
new String[] {"com.example.test1", "com.example.test2"},
new String[] {"libs/test", "libs/test2"});
}
@@ -341,7 +331,7 @@
"",
"res",
"assets",
- new Class<?>[] {},
+ new Class[] {},
new String[] {},
new String[] {});
}
@@ -366,7 +356,7 @@
"from-org-robolectric",
"res",
"assets",
- new Class<?>[] {},
+ new Class[] {},
new String[] {},
new String[] {"FromOrgRobolectric", "FromOrg", "FromTopLevel"});
}
@@ -382,126 +372,40 @@
"",
"res",
"assets",
- new Class<?>[] {},
+ new Class[] {},
new String[] {},
new String[] {});
}
- @Test public void testPrecedence() throws Exception {
- SpyConfigurer spyConfigurer = new SpyConfigurer();
-
- ConfigurationStrategy configStrategy =
- new HierarchicalConfigurationStrategy(spyConfigurer);
-
- assertThat(computeConfig(configStrategy, Test1.class, "withoutAnnotation"))
- .isEqualTo(
- "default:(top):org:org.robolectric:org.robolectric.plugins"
- + ":" + Test1.class.getName()
- + ":withoutAnnotation");
-
- assertThat(computeConfig(configStrategy, Test1A.class, "withOverrideAnnotation"))
- .isEqualTo(
- "default:(top):org:org.robolectric:org.robolectric.plugins"
- + ":" + Test1.class.getName()
- + ":" + Test1A.class.getName()
- + ":withOverrideAnnotation");
- }
-
- @Test public void testTestClassMatters() throws Exception {
- SpyConfigurer spyConfigurer = new SpyConfigurer();
-
- ConfigurationStrategy configStrategy =
- new HierarchicalConfigurationStrategy(spyConfigurer);
-
- assertThat(computeConfig(configStrategy, Test1.class, "withoutAnnotation"))
- .isEqualTo(
- "default:(top):org:org.robolectric:org.robolectric.plugins"
- + ":" + Test1.class.getName()
- + ":withoutAnnotation");
-
- assertThat(computeConfig(configStrategy, Test1A.class, "withoutAnnotation"))
- .isEqualTo(
- "default:(top):org:org.robolectric:org.robolectric.plugins"
- + ":" + Test1.class.getName()
- + ":" + Test1A.class.getName()
- + ":withoutAnnotation");
- }
-
- @Test public void testBigOAndCaching() throws Exception {
- SpyConfigurer spyConfigurer = new SpyConfigurer();
- ConfigurationStrategy configStrategy =
- new HierarchicalConfigurationStrategy(spyConfigurer);
- computeConfig(configStrategy, Test1A.class, "withoutAnnotation");
-
- assertThat(spyConfigurer.log).containsExactly(
- "default",
- "withoutAnnotation",
- Test1A.class.getName(),
- Test1.class.getName(),
- "org.robolectric.plugins",
- "org.robolectric",
- "org",
- "(top)"
- ).inOrder();
-
- spyConfigurer.log.clear();
- computeConfig(configStrategy, Test1.class, "withoutAnnotation");
- assertThat(spyConfigurer.log).containsExactly(
- "withoutAnnotation"
- ).inOrder();
-
- spyConfigurer.log.clear();
- computeConfig(configStrategy, Test2A.class, "withOverrideAnnotation");
- assertThat(spyConfigurer.log).containsExactly(
- "withOverrideAnnotation",
- Test2A.class.getName(),
- Test2.class.getName()
- ).inOrder();
+ @Test public void testPackageHierarchyOf() throws Exception {
+ assertThat(new DefaultConfigMerger().packageHierarchyOf(DefaultConfigMergerTest.class))
+ .containsExactly("org.robolectric.plugins", "org.robolectric", "org", "");
}
/////////////////////////////
-
- private String computeConfig(ConfigurationStrategy configStrategy,
- Class<?> testClass, String methodName)
- throws NoSuchMethodException {
- return configStrategy
- .getConfig(testClass,
- testClass.getMethod(methodName))
- .get(String.class);
+ private Config configFor(Class<?> testClass, String methodName, final Map<String, String> configProperties) throws InitializationError {
+ return configFor(testClass, methodName, configProperties, Config.Builder.defaults().build());
}
- private Config configFor(Class<?> testClass, String methodName,
- final Map<String, String> configProperties) {
- return configFor(testClass, methodName, configProperties, null);
- }
-
- private Config configFor(Class<?> testClass, String methodName) {
+ private Config configFor(Class<?> testClass, String methodName) throws InitializationError {
Config.Implementation globalConfig = Config.Builder.defaults().build();
return configFor(testClass, methodName, globalConfig);
}
- private Config configFor(Class<?> testClass, String methodName,
- Config.Implementation globalConfig) {
+ private Config configFor(Class<?> testClass, String methodName, Config.Implementation globalConfig) throws InitializationError {
return configFor(testClass, methodName, new HashMap<>(), globalConfig);
}
- private Config configFor(Class<?> testClass, String methodName,
- final Map<String, String> configProperties, Config.Implementation globalConfig) {
+ private Config configFor(Class<?> testClass, String methodName, final Map<String, String> configProperties, Config.Implementation globalConfig) throws InitializationError {
Method info = getMethod(testClass, methodName);
- PackagePropertiesLoader packagePropertiesLoader = new PackagePropertiesLoader() {
+ return new DefaultConfigMerger() {
@Override
InputStream getResourceAsStream(String resourceName) {
String properties = configProperties.get(resourceName);
return properties == null ? null : new ByteArrayInputStream(properties.getBytes(UTF_8));
}
- };
- ConfigurationStrategy defaultConfigStrategy =
- new HierarchicalConfigurationStrategy(
- new ConfigConfigurer(packagePropertiesLoader, () ->
- globalConfig == null ? Config.Builder.defaults().build() : globalConfig));
- Configuration config = defaultConfigStrategy.getConfig(testClass, info);
- return config.get(Config.class);
+ }.getConfig(testClass, info, globalConfig);
}
private static Method getMethod(Class<?> testClass, String methodName) {
@@ -601,16 +505,16 @@
@Ignore
@Config(qualifiers = "from-subclass")
- public static class Test1A extends Test1 {
+ public static class Test3 extends Test1 {
}
@Ignore
@Config(qualifiers = "from-subclass")
- public static class Test2A extends Test2 {
+ public static class Test4 extends Test2 {
}
@Ignore
- public static class Test1B extends Test1 {
+ public static class Test5 extends Test1 {
@Override
@Test
public void withoutAnnotation() throws Exception {
@@ -626,7 +530,7 @@
@Test
@Config(
sdk = 14,
- shadows = Test1B.class,
+ shadows = Test5.class,
instrumentedPackages = "com.example.method5",
packageName = "com.example.test",
qualifiers = "from-method5",
@@ -637,50 +541,8 @@
@Ignore
@Config(
qualifiers = "from-class6",
- shadows = Test1C.class,
+ shadows = Test6.class,
instrumentedPackages = "com.example.test6",
resourceDir = "class6/res")
- public static class Test1C extends Test1B {}
-
- private static class SpyConfigurer implements Configurer<String> {
-
- final List<String> log = new ArrayList<>();
-
- @Override
- public Class<String> getConfigClass() {
- return String.class;
- }
-
- @Nonnull
- @Override
- public String defaultConfig() {
- return log("default");
- }
-
- @Override
- public String getConfigFor(@Nonnull String packageName) {
- return log(packageName.isEmpty() ? "(top)" : packageName);
- }
-
- @Override
- public String getConfigFor(@Nonnull Class<?> testClass) {
- return log(testClass.getName());
- }
-
- @Override
- public String getConfigFor(@Nonnull Method method) {
- return log(method.getName());
- }
-
- @Nonnull
- @Override
- public String merge(@Nonnull String parentConfig, @Nonnull String childConfig) {
- return parentConfig + ":" + childConfig;
- }
-
- private String log(String s) {
- log.add(s);
- return s;
- }
- }
+ public static class Test6 extends Test5 {}
}
diff --git a/robolectric/src/test/java/org/robolectric/plugins/DefaultSdkPickerTest.java b/robolectric/src/test/java/org/robolectric/plugins/DefaultSdkPickerTest.java
index 556c81a..c002107 100644
--- a/robolectric/src/test/java/org/robolectric/plugins/DefaultSdkPickerTest.java
+++ b/robolectric/src/test/java/org/robolectric/plugins/DefaultSdkPickerTest.java
@@ -15,11 +15,9 @@
import org.junit.runners.JUnit4;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.internal.ConfigUtils;
-import org.robolectric.pluginapi.ConfigurationStrategy.Configuration;
import org.robolectric.pluginapi.Sdk;
import org.robolectric.pluginapi.SdkPicker;
import org.robolectric.pluginapi.UsesSdk;
-import org.robolectric.plugins.HierarchicalConfigurationStrategy.ConfigurationImpl;
@RunWith(JUnit4.class)
public class DefaultSdkPickerTest {
@@ -38,7 +36,7 @@
@Test
public void withDefaultSdk_shouldUseTargetSdkFromAndroidManifest() throws Exception {
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder()), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().build(), usesSdk))
.containsExactly(sdkCollection.getSdk(22));
}
@@ -47,7 +45,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
when(usesSdk.getMinSdkVersion()).thenReturn(19);
when(usesSdk.getMaxSdkVersion()).thenReturn(23);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(Config.ALL_SDKS)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(Config.ALL_SDKS).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(19), sdkCollection.getSdk(21),
sdkCollection.getSdk(22), sdkCollection.getSdk(23));
}
@@ -57,7 +55,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
when(usesSdk.getMinSdkVersion()).thenReturn(1);
when(usesSdk.getMaxSdkVersion()).thenReturn(22);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(Config.ALL_SDKS)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(Config.ALL_SDKS).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(16), sdkCollection.getSdk(17),
sdkCollection.getSdk(18), sdkCollection.getSdk(19),
sdkCollection.getSdk(21), sdkCollection.getSdk(22));
@@ -68,7 +66,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
when(usesSdk.getMinSdkVersion()).thenReturn(19);
when(usesSdk.getMaxSdkVersion()).thenReturn(null);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(Config.ALL_SDKS)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(Config.ALL_SDKS).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(19), sdkCollection.getSdk(21),
sdkCollection.getSdk(22), sdkCollection.getSdk(23));
}
@@ -78,7 +76,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(23);
when(usesSdk.getMinSdkVersion()).thenReturn(1);
when(usesSdk.getMaxSdkVersion()).thenReturn(null);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setMinSdk(24)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setMinSdk(24).build(), usesSdk))
.isEmpty();
}
@@ -90,7 +88,7 @@
try {
sdkPicker.selectSdks(
- buildConfig(new Config.Builder().setMinSdk(22).setMaxSdk(21)), usesSdk);
+ new Config.Builder().setMinSdk(22).setMaxSdk(21).build(), usesSdk);
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains("minSdk may not be larger than maxSdk (minSdk=22, maxSdk=21)");
@@ -103,7 +101,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
try {
- sdkPicker.selectSdks(buildConfig(new Config.Builder()), usesSdk);
+ sdkPicker.selectSdks(new Config.Builder().build(), usesSdk);
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains("Package targetSdkVersion=22 < minSdkVersion=23");
@@ -115,7 +113,7 @@
when(usesSdk.getMaxSdkVersion()).thenReturn(21);
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
try {
- sdkPicker.selectSdks(buildConfig(new Config.Builder()), usesSdk);
+ sdkPicker.selectSdks(new Config.Builder().build(), usesSdk);
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains("Package targetSdkVersion=22 > maxSdkVersion=21");
@@ -127,7 +125,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(1);
when(usesSdk.getMinSdkVersion()).thenReturn(1);
when(usesSdk.getMaxSdkVersion()).thenReturn(null);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder()), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().build(), usesSdk))
.containsExactly(sdkCollection.getSdk(16));
}
@@ -136,7 +134,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
when(usesSdk.getMinSdkVersion()).thenReturn(19);
when(usesSdk.getMaxSdkVersion()).thenReturn(23);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setMinSdk(21)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setMinSdk(21).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(21), sdkCollection.getSdk(22),
sdkCollection.getSdk(23));
}
@@ -146,7 +144,7 @@
when(usesSdk.getTargetSdkVersion()).thenReturn(22);
when(usesSdk.getMinSdkVersion()).thenReturn(19);
when(usesSdk.getMaxSdkVersion()).thenReturn(23);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setMaxSdk(21)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setMaxSdk(21).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(19), sdkCollection.getSdk(21));
}
@@ -156,18 +154,18 @@
when(usesSdk.getMinSdkVersion()).thenReturn(19);
when(usesSdk.getMaxSdkVersion()).thenReturn(22);
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(21)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(21).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(21));
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(Config.OLDEST_SDK)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(Config.OLDEST_SDK).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(19));
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(Config.TARGET_SDK)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(Config.TARGET_SDK).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(21));
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(Config.NEWEST_SDK)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(Config.NEWEST_SDK).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(22));
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(16)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(16).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(16));
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(23)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(23).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(23));
}
@@ -176,7 +174,7 @@
when(usesSdk.getMinSdkVersion()).thenReturn(16);
when(usesSdk.getMaxSdkVersion()).thenReturn(23);
sdkPicker = new DefaultSdkPicker(sdkCollection, "17,18");
- assertThat(sdkPicker.selectSdks(buildConfig(new Config.Builder().setSdk(Config.ALL_SDKS)), usesSdk))
+ assertThat(sdkPicker.selectSdks(new Config.Builder().setSdk(Config.ALL_SDKS).build(), usesSdk))
.containsExactly(sdkCollection.getSdk(17), sdkCollection.getSdk(18));
}
@@ -190,12 +188,6 @@
.containsExactly(VERSION_CODES.KITKAT, VERSION_CODES.LOLLIPOP);
}
- private Configuration buildConfig(Config.Builder builder) {
- ConfigurationImpl testConfig = new ConfigurationImpl();
- testConfig.put(Config.class, builder.build());
- return testConfig;
- }
-
private List<Sdk> map(int... sdkInts) {
SdkCollection allSdks = new SdkCollection(new DefaultSdkProvider(null));
return Arrays.stream(sdkInts).mapToObj(allSdks::getSdk).collect(Collectors.toList());
diff --git a/utils/src/main/java/org/robolectric/util/inject/Injector.java b/utils/src/main/java/org/robolectric/util/inject/Injector.java
index aa96952..554971f 100644
--- a/utils/src/main/java/org/robolectric/util/inject/Injector.java
+++ b/utils/src/main/java/org/robolectric/util/inject/Injector.java
@@ -5,7 +5,6 @@
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
-import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -239,8 +238,7 @@
}
return ctor.newInstance(params);
- } catch (InstantiationException | IllegalAccessException
- | InvocationTargetException | IllegalArgumentException e) {
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new InjectionException(implementingClass, e);
}
}
@@ -385,8 +383,7 @@
}
public boolean isArray() {
- return (theInterface instanceof Class && ((Class) theInterface).isArray())
- || theInterface instanceof GenericArrayType;
+ return theInterface instanceof Class && ((Class) theInterface).isArray();
}
public boolean isCollection() {
@@ -399,14 +396,7 @@
Class<?> getComponentType() {
if (isArray()) {
- if (theInterface instanceof Class) {
- return ((Class) theInterface).getComponentType();
- } else if (theInterface instanceof GenericArrayType) {
- Type genericComponentType = ((GenericArrayType) theInterface).getGenericComponentType();
- return (Class<?>) ((ParameterizedType) genericComponentType).getRawType();
- } else {
- throw new InjectionException(this, new IllegalArgumentException());
- }
+ return ((Class) theInterface).getComponentType();
} else if (isCollection() && theInterface instanceof ParameterizedType) {
return (Class) ((ParameterizedType) theInterface).getActualTypeArguments()[0];
} else {