1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx; 18 19 import android.os.Build; 20 import android.os.Process; 21 import org.junit.Test; 22 23 import java.io.File; 24 import java.util.Arrays; 25 import java.util.HashSet; 26 import java.util.Set; 27 28 import static org.junit.Assert.assertEquals; 29 import static org.junit.Assert.assertNotNull; 30 import static org.junit.Assert.assertTrue; 31 32 public final class AppDataDirGuesserTest { 33 @Test 34 public void testGuessCacheDir_SimpleExample() { 35 guessCacheDirFor("/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache"); 36 guessCacheDirFor("/data/app/a.b.c.tests.apk").shouldGive("/data/data/a.b.c.tests/cache"); 37 } 38 39 @Test 40 public void testGuessCacheDir_MultipleResultsSeparatedByColon() { 41 guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk") 42 .shouldGive("/data/data/a.b.c/cache", "/data/data/d.e.f/cache"); 43 } 44 45 @Test 46 public void testGuessCacheDir_NotWriteableSkipped() { 47 guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk") 48 .withNonWriteable("/data/data/a.b.c/cache") 49 .shouldGive("/data/data/d.e.f/cache"); 50 } 51 52 @Test 53 public void testGuessCacheDir_ForSecondaryUser() { 54 guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk") 55 .withNonWriteable("/data/data/a.b.c", "/data/data/d.e.f") 56 .withProcessUid(1110009) 57 .shouldGive("/data/user/11/a.b.c/cache", "/data/user/11/d.e.f/cache"); 58 } 59 60 @Test 61 public void testGuessCacheDir_StripHyphenatedSuffixes() { 62 guessCacheDirFor("/data/app/a.b.c-2.apk").shouldGive("/data/data/a.b.c/cache"); 63 } 64 65 @Test 66 public void testGuessCacheDir_LeadingAndTrailingColonsIgnored() { 67 guessCacheDirFor("/data/app/a.b.c.apk:asdf:").shouldGive("/data/data/a.b.c/cache"); 68 guessCacheDirFor(":asdf:/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache"); 69 } 70 71 @Test 72 public void testGuessCacheDir_InvalidInputsGiveEmptyArray() { 73 guessCacheDirFor("").shouldGive(); 74 } 75 76 @Test 77 public void testGuessCacheDir_JarsIgnored() { 78 guessCacheDirFor("/data/app/a.b.c.jar").shouldGive(); 79 guessCacheDirFor("/system/framework/android.test.runner.jar").shouldGive(); 80 } 81 82 @Test 83 public void testGuessCacheDir_RealWorldExample() { 84 String realPath = "/system/framework/android.test.runner.jar:" + 85 "/data/app/com.google.android.voicesearch.tests-2.apk:" + 86 "/data/app/com.google.android.voicesearch-1.apk"; 87 guessCacheDirFor(realPath) 88 .withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache") 89 .shouldGive("/data/data/com.google.android.voicesearch/cache"); 90 } 91 92 @Test 93 public void testSplitPathList() { 94 final String[] expected = { "foo", "bar" }; 95 assertTrue(Arrays.equals(expected, AppDataDirGuesser.splitPathList("foo:bar"))); 96 assertTrue(Arrays.equals(expected, 97 AppDataDirGuesser.splitPathList("dexPath=foo:bar"))); 98 assertTrue(Arrays.equals(expected, 99 AppDataDirGuesser.splitPathList("dexPath=foo:bar,bazPath=bar:bar2"))); 100 } 101 102 @Test 103 public void testPre43PathProcessing() { 104 String input = "dalvik.system.PathClassLoader[dexPath=/data/app/abc-1.apk," + 105 "libraryPath=/data/app-lib/abc-1]"; 106 String processed = AppDataDirGuesser.processClassLoaderString(input); 107 assertTrue("dexPath=/data/app/abc-1.apk,libraryPath=/data/app-lib/abc-1".equals(processed)); 108 } 109 110 @Test 111 public void test43PathProcessing() { 112 String input = "dalvik.system.PathClassLoader[DexPathList[[zip file " + 113 "\"/data/app/abc-1/base.apk\", zip file \"/data/app/def-1/base.apk\"], " + 114 "nativeLibraryDirectories=[/data/app-lib/abc-1]]]"; 115 String processed = AppDataDirGuesser.processClassLoaderString(input); 116 assertTrue("/data/app/abc-1/base.apk:/data/app/def-1/base.apk".equals(processed)); 117 } 118 119 @Test 120 public void testApiLevel17PlusPathProcessing() { 121 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 122 // Our processing should work for anything >= Android 4.2. 123 String input = getClass().getClassLoader().toString(); 124 String processed = AppDataDirGuesser.processClassLoaderString(input); 125 // TODO: this comment is no longer true now that we run tests on Android instead of vogar 126 // A tighter check would be interesting. But vogar doesn't run the tests in a directory 127 // recognized by the guesser (usually under /data/local/tmp), so we cannot use the 128 // processed result as input to guessPath. 129 assertTrue(!input.equals(processed)); 130 } 131 } 132 133 @Test 134 public void testGetProcessUid() { 135 AppDataDirGuesser guesser = new AppDataDirGuesser(); 136 assertTrue(guesser.getProcessUid() == Process.myUid()); 137 } 138 139 private interface TestCondition { 140 TestCondition withNonWriteable(String... files); 141 TestCondition withProcessUid(Integer uid); 142 void shouldGive(String... files); 143 } 144 145 private TestCondition guessCacheDirFor(final String path) { 146 final Set<String> notWriteable = new HashSet<>(); 147 return new TestCondition() { 148 private Integer processUid; 149 @Override 150 public void shouldGive(String... files) { 151 AppDataDirGuesser guesser = new AppDataDirGuesser() { 152 @Override 153 public boolean isWriteableDirectory(File file) { 154 return !notWriteable.contains(file.getAbsolutePath()); 155 } 156 @Override 157 boolean fileOrDirExists(File file) { 158 return true; 159 } 160 @Override 161 Integer getProcessUid() { 162 return processUid; 163 } 164 }; 165 File[] results = guesser.guessPath(path); 166 assertNotNull("Null results for " + path, results); 167 assertEquals("Bad lengths for " + path, files.length, results.length); 168 for (int i = 0; i < files.length; ++i) { 169 assertEquals("Element " + i, new File(files[i]), results[i]); 170 } 171 } 172 173 @Override 174 public TestCondition withNonWriteable(String... files) { 175 notWriteable.addAll(Arrays.asList(files)); 176 return this; 177 } 178 179 @Override 180 public TestCondition withProcessUid(Integer uid) { 181 processUid = uid; 182 return this; 183 } 184 }; 185 } 186 } 187