package org.robolectric.util; import android.app.Application; import javax.annotation.Nonnull; import org.robolectric.R; import org.robolectric.annotation.Config; import org.robolectric.internal.SdkConfig; import org.robolectric.internal.dependency.MavenDependencyResolver; import org.robolectric.manifest.AndroidManifest; import org.robolectric.res.Fs; import org.robolectric.res.FsFile; import org.robolectric.res.ResourcePath; import java.io.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertTrue; public abstract class TestUtil { private static ResourcePath SYSTEM_RESOURCE_PATH; public static final ResourcePath TEST_RESOURCE_PATH = new ResourcePath(R.class, resourceFile("res"), resourceFile("assets")); public static final String TEST_PACKAGE = R.class.getPackage().getName(); public static File testDirLocation; public static void assertEquals(Collection<?> expected, Collection<?> actual) { org.junit.Assert.assertEquals(stringify(expected), stringify(actual)); } public static String stringify(Collection<?> collection) { StringBuilder buf = new StringBuilder(); for (Object o : collection) { if (buf.length() > 0) buf.append("\n"); buf.append(o); } return buf.toString(); } public static <T> void assertInstanceOf(Class<? extends T> expectedClass, T object) { Class actualClass = object.getClass(); assertTrue(expectedClass + " should be assignable from " + actualClass, expectedClass.isAssignableFrom(actualClass)); } public static FsFile resourcesBaseDir() { return Fs.newFile(resourcesBaseDirFile()); } private static File resourcesBaseDirFile() { if (testDirLocation == null) { File testDir = Util.file("src", "test", "resources"); if (hasTestManifest(testDir)) return testDirLocation = testDir; File roboTestDir = Util.file("robolectric", "src", "test", "resources"); if (hasTestManifest(roboTestDir)) return testDirLocation = roboTestDir; File submoduleDir = Util.file("submodules", "robolectric", "src", "test", "resources"); if (hasTestManifest(submoduleDir)) return testDirLocation = submoduleDir; //required for robolectric-sqlite to find resources to test against File roboSiblingTestDir = Util.file(new File(new File(".").getAbsolutePath()).getParentFile().getParentFile(), "robolectric", "src", "test", "resources"); if (hasTestManifest(roboSiblingTestDir)) return testDirLocation = roboSiblingTestDir; throw new RuntimeException("can't find your TestAndroidManifest.xml in " + testDir.getAbsolutePath() + " or " + roboTestDir.getAbsolutePath() + "\n or " + roboSiblingTestDir.getAbsolutePath()); } else { return testDirLocation; } } private static boolean hasTestManifest(File testDir) { return new File(testDir, "TestAndroidManifest.xml").isFile(); } public static FsFile resourceFile(String... pathParts) { return resourcesBaseDir().join(pathParts); } public static ResourcePath testResources() { return TEST_RESOURCE_PATH; } public static ResourcePath lib1Resources() { return new ResourcePath(org.robolectric.lib1.R.class, resourceFile("lib1/res"), resourceFile("lib1/assets")); } public static ResourcePath lib2Resources() { return new ResourcePath(org.robolectric.lib2.R.class, resourceFile("lib2/res"), resourceFile("lib2/assets")); } public static ResourcePath lib3Resources() { return new ResourcePath(org.robolectric.lib3.R.class, resourceFile("lib3/res"), resourceFile("lib3/assets")); } public static ResourcePath systemResources() { if (SYSTEM_RESOURCE_PATH == null) { SdkConfig sdkConfig = new SdkConfig(SdkConfig.MAX_SDK_VERSION); Fs fs = Fs.fromJar(new MavenDependencyResolver().getLocalArtifactUrl(sdkConfig.getAndroidSdkDependency())); SYSTEM_RESOURCE_PATH = new ResourcePath(android.R.class, fs.join("res"), fs.join("assets")); } return SYSTEM_RESOURCE_PATH; } @Nonnull public static ResourcePath sdkResources(int apiLevel) { Fs sdkResFs = Fs.fromJar(new MavenDependencyResolver().getLocalArtifactUrl(new SdkConfig(apiLevel).getAndroidSdkDependency())); return new ResourcePath(null, sdkResFs.join("res"), null, null); } public static ResourcePath gradleAppResources() { return new ResourcePath(org.robolectric.gradleapp.R.class, resourceFile("gradle/res/layoutFlavor/menuBuildType"), resourceFile("gradle/assets/layoutFlavor/menuBuildType")); } public static AndroidManifest newConfig(String androidManifestFile) { return new AndroidManifest(resourceFile(androidManifestFile), null, null); } public static String readString(InputStream is) throws IOException { Writer writer = new StringWriter(); char[] buffer = new char[1024]; try { Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); int n; while ((n = reader.read(buffer)) != -1) { writer.write(buffer, 0, n); } } finally { is.close(); } return writer.toString(); } public static String joinPath(String... parts) { File file = new File(parts[0]); for (int i = 1; i < parts.length; i++) { String part = parts[i]; file = new File(file, part); } return file.getPath(); } public static File newFile(File file, String contents) throws IOException { FileWriter fileWriter = new FileWriter(file); try { fileWriter.write(contents); } finally { fileWriter.close(); } return file; } public static String stringify(Config config) { int[] sdk = config.sdk(); String manifest = config.manifest(); Class<? extends Application> application = config.application(); String packageName = config.packageName(); String qualifiers = config.qualifiers(); String resourceDir = config.resourceDir(); String assetsDir = config.assetDir(); Class<?>[] shadows = config.shadows(); String[] instrumentedPackages = config.instrumentedPackages(); String[] libraries = config.libraries(); Class<?> constants = config.constants(); return stringify(sdk, manifest, application, packageName, qualifiers, resourceDir, assetsDir, shadows, instrumentedPackages, libraries, constants); } public static String stringify(int[] sdk, String manifest, Class<? extends Application> application, String packageName, String qualifiers, String resourceDir, String assetsDir, Class<?>[] shadows, String[] instrumentedPackages, String[] libraries, Class<?> constants) { String[] stringClasses = new String[shadows.length]; for (int i = 0; i < stringClasses.length; i++) { stringClasses[i] = shadows[i].toString(); } Arrays.sort(stringClasses); String[] sortedLibraries = libraries.clone(); Arrays.sort(sortedLibraries); String[] sortedInstrumentedPackages = instrumentedPackages.clone(); Arrays.sort(sortedInstrumentedPackages); return "sdk=" + Arrays.toString(sdk) + "\n" + "manifest=" + manifest + "\n" + "application=" + application + "\n" + "packageName=" + packageName + "\n" + "qualifiers=" + qualifiers + "\n" + "resourceDir=" + resourceDir + "\n" + "assetDir=" + assetsDir + "\n" + "shadows=" + Arrays.toString(stringClasses) + "\n" + "instrumentedPackages" + Arrays.toString(sortedInstrumentedPackages) + "\n" + "libraries=" + Arrays.toString(sortedLibraries) + "\n" + "constants=" + constants; } public static void assertStringsInclude(List<String> list, String... expectedStrings) { List<String> original = new ArrayList<>(list); for (String expectedEvent : expectedStrings) { int index = list.indexOf(expectedEvent); if (index == -1) { assertThat(original).containsExactly(expectedStrings); } list.subList(0, index + 1).clear(); } } }