package org.fdroid.fdroid.compat; import android.app.Instrumentation; import android.content.Context; import android.os.Build; import android.os.Environment; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.fdroid.fdroid.AssetUtils; import org.fdroid.fdroid.data.SanitizedFile; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; import java.util.UUID; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; /** * This test needs to run on the emulator, even though it technically could * run as a plain JUnit test, because it is testing the specifics of * Android's symlink handling. */ @RunWith(AndroidJUnit4.class) public class FileCompatTest { private SanitizedFile sourceFile; private SanitizedFile destFile; @Before public void setUp() { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); File dir = getWriteableDir(instrumentation); sourceFile = SanitizedFile.knownSanitized( AssetUtils.copyAssetToDir(instrumentation.getContext(), "simpleIndex.jar", dir)); destFile = new SanitizedFile(dir, "dest-" + UUID.randomUUID() + ".testproduct"); assertFalse(destFile.exists()); assertTrue(sourceFile.getAbsolutePath() + " should exist.", sourceFile.exists()); } @After public void tearDown() { if (!sourceFile.delete()) { System.out.println("Can't delete " + sourceFile.getAbsolutePath() + "."); } if (!destFile.delete()) { System.out.println("Can't delete " + destFile.getAbsolutePath() + "."); } } @Test public void testSymlinkRuntime() { FileCompat.symlinkRuntime(sourceFile, destFile); assertTrue(destFile.getAbsolutePath() + " should exist after symlinking", destFile.exists()); } @Test public void testSymlinkLibcore() { assumeTrue(Build.VERSION.SDK_INT >= 19); FileCompat.symlinkLibcore(sourceFile, destFile); assertTrue(destFile.getAbsolutePath() + " should exist after symlinking", destFile.exists()); } @Test public void testSymlinkOs() { assumeTrue(Build.VERSION.SDK_INT >= 21); FileCompat.symlinkOs(sourceFile, destFile); assertTrue(destFile.getAbsolutePath() + " should exist after symlinking", destFile.exists()); } /** * Prefer internal over external storage, because external tends to be FAT filesystems, * which don't support symlinks (which we test using this method). */ public static File getWriteableDir(Instrumentation instrumentation) { Context context = instrumentation.getContext(); Context targetContext = instrumentation.getTargetContext(); File[] dirsToTry = new File[]{ context.getCacheDir(), context.getFilesDir(), targetContext.getCacheDir(), targetContext.getFilesDir(), context.getExternalCacheDir(), context.getExternalFilesDir(null), targetContext.getExternalCacheDir(), targetContext.getExternalFilesDir(null), Environment.getExternalStorageDirectory(), }; return getWriteableDir(dirsToTry); } private static File getWriteableDir(File[] dirsToTry) { for (File dir : dirsToTry) { if (dir != null && dir.canWrite()) { return dir; } } return null; } }