blob: a4a340736d23fb52f8d5872d7471ed8187ae1a0e [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx;
import android.os.Build;
import android.os.Process;
import org.junit.Test;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public final class AppDataDirGuesserTest {
@Test
public void testGuessCacheDir_SimpleExample() {
guessCacheDirFor("/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor("/data/app/a.b.c.tests.apk").shouldGive("/data/data/a.b.c.tests/cache");
}
@Test
public void testGuessCacheDir_MultipleResultsSeparatedByColon() {
guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk")
.shouldGive("/data/data/a.b.c/cache", "/data/data/d.e.f/cache");
}
@Test
public void testGuessCacheDir_NotWriteableSkipped() {
guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk")
.withNonWriteable("/data/data/a.b.c/cache")
.shouldGive("/data/data/d.e.f/cache");
}
@Test
public void testGuessCacheDir_ForSecondaryUser() {
guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk")
.withNonWriteable("/data/data/a.b.c", "/data/data/d.e.f")
.withProcessUid(1110009)
.shouldGive("/data/user/11/a.b.c/cache", "/data/user/11/d.e.f/cache");
}
@Test
public void testGuessCacheDir_StripHyphenatedSuffixes() {
guessCacheDirFor("/data/app/a.b.c-2.apk").shouldGive("/data/data/a.b.c/cache");
}
@Test
public void testGuessCacheDir_LeadingAndTrailingColonsIgnored() {
guessCacheDirFor("/data/app/a.b.c.apk:asdf:").shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor(":asdf:/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache");
}
@Test
public void testGuessCacheDir_InvalidInputsGiveEmptyArray() {
guessCacheDirFor("").shouldGive();
}
@Test
public void testGuessCacheDir_JarsIgnored() {
guessCacheDirFor("/data/app/a.b.c.jar").shouldGive();
guessCacheDirFor("/system/framework/android.test.runner.jar").shouldGive();
}
@Test
public void testGuessCacheDir_RealWorldExample() {
String realPath = "/system/framework/android.test.runner.jar:" +
"/data/app/com.google.android.voicesearch.tests-2.apk:" +
"/data/app/com.google.android.voicesearch-1.apk";
guessCacheDirFor(realPath)
.withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
.shouldGive("/data/data/com.google.android.voicesearch/cache");
}
@Test
public void testSplitPathList() {
final String[] expected = { "foo", "bar" };
assertTrue(Arrays.equals(expected, AppDataDirGuesser.splitPathList("foo:bar")));
assertTrue(Arrays.equals(expected,
AppDataDirGuesser.splitPathList("dexPath=foo:bar")));
assertTrue(Arrays.equals(expected,
AppDataDirGuesser.splitPathList("dexPath=foo:bar,bazPath=bar:bar2")));
}
@Test
public void testPre43PathProcessing() {
String input = "dalvik.system.PathClassLoader[dexPath=/data/app/abc-1.apk," +
"libraryPath=/data/app-lib/abc-1]";
String processed = AppDataDirGuesser.processClassLoaderString(input);
assertTrue("dexPath=/data/app/abc-1.apk,libraryPath=/data/app-lib/abc-1".equals(processed));
}
@Test
public void test43PathProcessing() {
String input = "dalvik.system.PathClassLoader[DexPathList[[zip file " +
"\"/data/app/abc-1/base.apk\", zip file \"/data/app/def-1/base.apk\"], " +
"nativeLibraryDirectories=[/data/app-lib/abc-1]]]";
String processed = AppDataDirGuesser.processClassLoaderString(input);
assertTrue("/data/app/abc-1/base.apk:/data/app/def-1/base.apk".equals(processed));
}
@Test
public void testApiLevel17PlusPathProcessing() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
// Our processing should work for anything >= Android 4.2.
String input = getClass().getClassLoader().toString();
String processed = AppDataDirGuesser.processClassLoaderString(input);
// TODO: this comment is no longer true now that we run tests on Android instead of vogar
// A tighter check would be interesting. But vogar doesn't run the tests in a directory
// recognized by the guesser (usually under /data/local/tmp), so we cannot use the
// processed result as input to guessPath.
assertTrue(!input.equals(processed));
}
}
@Test
public void testGetProcessUid() {
AppDataDirGuesser guesser = new AppDataDirGuesser();
assertTrue(guesser.getProcessUid() == Process.myUid());
}
private interface TestCondition {
TestCondition withNonWriteable(String... files);
TestCondition withProcessUid(Integer uid);
void shouldGive(String... files);
}
private TestCondition guessCacheDirFor(final String path) {
final Set<String> notWriteable = new HashSet<>();
return new TestCondition() {
private Integer processUid;
public void shouldGive(String... files) {
AppDataDirGuesser guesser = new AppDataDirGuesser() {
@Override
public boolean isWriteableDirectory(File file) {
return !notWriteable.contains(file.getAbsolutePath());
}
@Override
boolean fileOrDirExists(File file) {
return true;
}
@Override
Integer getProcessUid() {
return processUid;
}
};
File[] results = guesser.guessPath(path);
assertNotNull("Null results for " + path, results);
assertEquals("Bad lengths for " + path, files.length, results.length);
for (int i = 0; i < files.length; ++i) {
assertEquals("Element " + i, new File(files[i]), results[i]);
}
}
public TestCondition withNonWriteable(String... files) {
notWriteable.addAll(Arrays.asList(files));
return this;
}
@Override
public TestCondition withProcessUid(Integer uid) {
processUid = uid;
return this;
}
};
}
}