• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
testGuessCacheDir_SimpleExample()34     public void testGuessCacheDir_SimpleExample() {
35         guessCacheDirFor("/data/app/a.b.c-xxx/base.apk")
36                 .shouldGive("/data/data/a.b.c/cache");
37         guessCacheDirFor("/data/app/a.b.c.tests-xxx/base.apk")
38                 .shouldGive("/data/data/a.b.c.tests/cache");
39     }
40 
41     @Test
testGuessCacheDir_MultipleResultsSeparatedByColon()42     public void testGuessCacheDir_MultipleResultsSeparatedByColon() {
43         guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:/data/app/d.e.f-xxx/base.apk")
44                 .shouldGive("/data/data/a.b.c/cache", "/data/data/d.e.f/cache");
45     }
46 
47     @Test
testGuessCacheDir_NotWriteableSkipped()48     public void testGuessCacheDir_NotWriteableSkipped() {
49         guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:/data/app/d.e.f-xxx/base.apk")
50                 .withNonWriteable("/data/data/a.b.c/cache")
51                 .shouldGive("/data/data/d.e.f/cache");
52     }
53 
54     @Test
testGuessCacheDir_ForSecondaryUser()55     public void testGuessCacheDir_ForSecondaryUser() {
56         guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:/data/app/d.e.f-xxx/base.apk")
57                 .withNonWriteable("/data/data/a.b.c", "/data/data/d.e.f")
58                 .withProcessUid(1110009)
59                 .shouldGive("/data/user/11/a.b.c/cache", "/data/user/11/d.e.f/cache");
60     }
61 
62     @Test
testGuessCacheDir_StripHyphenatedSuffixes()63     public void testGuessCacheDir_StripHyphenatedSuffixes() {
64         guessCacheDirFor("/data/app/a.b.c-2/base.apk")
65                 .shouldGive("/data/data/a.b.c/cache");
66     }
67 
68     @Test
testGuessCacheDir_LeadingAndTrailingColonsIgnored()69     public void testGuessCacheDir_LeadingAndTrailingColonsIgnored() {
70         guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:asdf:")
71                 .shouldGive("/data/data/a.b.c/cache");
72         guessCacheDirFor(":asdf:/data/app/a.b.c-xxx/base.apk")
73                 .shouldGive("/data/data/a.b.c/cache");
74     }
75 
76     @Test
testGuessCacheDir_InvalidInputsGiveEmptyArray()77     public void testGuessCacheDir_InvalidInputsGiveEmptyArray() {
78         guessCacheDirFor("").shouldGive();
79     }
80 
81     @Test
testGuessCacheDir_JarsIgnored()82     public void testGuessCacheDir_JarsIgnored() {
83         guessCacheDirFor("/data/app/a.b.c.jar").shouldGive();
84         guessCacheDirFor("/system/framework/android.test.runner.jar").shouldGive();
85     }
86 
87     @Test
testGuessCacheDir_RealWorldExample()88     public void testGuessCacheDir_RealWorldExample() {
89         String realPath = "/system/framework/android.test.runner.jar:" +
90                 "/data/app/com.google.android.voicesearch.tests-2/base.apk:" +
91                 "/data/app/com.google.android.voicesearch-1/base.apk";
92         guessCacheDirFor(realPath)
93                 .withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
94                 .shouldGive("/data/data/com.google.android.voicesearch/cache");
95     }
96 
97     @Test
testGuessCacheDir_RealWorldExampleWithOneLevelSubDirectories()98     public void testGuessCacheDir_RealWorldExampleWithOneLevelSubDirectories() {
99         String realPath = "/system/framework/android.test.runner.jar:" +
100                 "/data/app/com.google.android.voicesearch.tests-abcde/base.apk:" +
101                 "/data/app/com.google.android.voicesearch-fghij/base.apk";
102         guessCacheDirFor(realPath)
103                 .withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
104                 .shouldGive("/data/data/com.google.android.voicesearch/cache");
105     }
106 
107     @Test
testGuessCacheDir_RealWorldExampleWithTwoLevelSubDirectories()108     public void testGuessCacheDir_RealWorldExampleWithTwoLevelSubDirectories() {
109         String realPath = "/system/framework/android.test.runner.jar:" +
110                 "/data/app/abcde/com.google.android.voicesearch.tests-fghij/base.apk:" +
111                 "/data/app/klmno/com.google.android.voicesearch-pqrst/base.apk";
112         guessCacheDirFor(realPath)
113                 .withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
114                 .shouldGive("/data/data/com.google.android.voicesearch/cache");
115     }
116 
117     @Test
testGuessCacheDir_RealWorldExampleWithHyphensInPath()118     public void testGuessCacheDir_RealWorldExampleWithHyphensInPath() {
119         String realPath = "/system/framework/android.test.runner.jar:" +
120                 "/data/app/a-b-c/com.google.android.voicesearch.tests-e-f-g/base.apk:" +
121                 "/data/app/com.google.android.voicesearch-k-l-n/base.apk";
122         guessCacheDirFor(realPath)
123                 .withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
124                 .shouldGive("/data/data/com.google.android.voicesearch/cache");
125     }
126 
127     @Test
testSplitPathList()128     public void testSplitPathList() {
129         final String[] expected = { "foo", "bar" };
130         assertTrue(Arrays.equals(expected, AppDataDirGuesser.splitPathList("foo:bar")));
131         assertTrue(Arrays.equals(expected,
132                 AppDataDirGuesser.splitPathList("dexPath=foo:bar")));
133         assertTrue(Arrays.equals(expected,
134                 AppDataDirGuesser.splitPathList("dexPath=foo:bar,bazPath=bar:bar2")));
135     }
136 
137     @Test
testPre43PathProcessing()138     public void testPre43PathProcessing() {
139         String input = "dalvik.system.PathClassLoader[dexPath=/data/app/abc-1.apk," +
140                        "libraryPath=/data/app-lib/abc-1]";
141         String processed = AppDataDirGuesser.processClassLoaderString(input);
142         assertTrue("dexPath=/data/app/abc-1.apk,libraryPath=/data/app-lib/abc-1".equals(processed));
143     }
144 
145     @Test
test43PathProcessing()146     public void test43PathProcessing() {
147         String input = "dalvik.system.PathClassLoader[DexPathList[[zip file " +
148                        "\"/data/app/abc-1/base.apk\", zip file \"/data/app/def-1/base.apk\"], " +
149                        "nativeLibraryDirectories=[/data/app-lib/abc-1]]]";
150         String processed = AppDataDirGuesser.processClassLoaderString(input);
151         assertTrue("/data/app/abc-1/base.apk:/data/app/def-1/base.apk".equals(processed));
152     }
153 
154     @Test
testApiLevel17PlusPathProcessing()155     public void testApiLevel17PlusPathProcessing() {
156         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
157             // Our processing should work for anything >= Android 4.2.
158             String input = getClass().getClassLoader().toString();
159             String processed = AppDataDirGuesser.processClassLoaderString(input);
160             // TODO: this comment is no longer true now that we run tests on Android instead of vogar
161             // A tighter check would be interesting. But vogar doesn't run the tests in a directory
162             // recognized by the guesser (usually under /data/local/tmp), so we cannot use the
163             // processed result as input to guessPath.
164             assertTrue(!input.equals(processed));
165         }
166     }
167 
168     @Test
testGetProcessUid()169     public void testGetProcessUid() {
170         AppDataDirGuesser guesser = new AppDataDirGuesser();
171         assertTrue(guesser.getProcessUid() == Process.myUid());
172     }
173 
174     private interface TestCondition {
withNonWriteable(String... files)175         TestCondition withNonWriteable(String... files);
withProcessUid(Integer uid)176         TestCondition withProcessUid(Integer uid);
shouldGive(String... files)177         void shouldGive(String... files);
178     }
179 
guessCacheDirFor(final String path)180     private TestCondition guessCacheDirFor(final String path) {
181         final Set<String> notWriteable = new HashSet<>();
182         return new TestCondition() {
183             private Integer processUid;
184             @Override
185             public void shouldGive(String... files) {
186                 AppDataDirGuesser guesser = new AppDataDirGuesser() {
187                     @Override
188                     public boolean isWriteableDirectory(File file) {
189                         return !notWriteable.contains(file.getAbsolutePath());
190                     }
191                     @Override
192                     boolean fileOrDirExists(File file) {
193                         return true;
194                     }
195                     @Override
196                     Integer getProcessUid() {
197                         return processUid;
198                     }
199                 };
200                 File[] results = guesser.guessPath(path);
201                 assertNotNull("Null results for " + path, results);
202                 assertEquals("Bad lengths for " + path, files.length, results.length);
203                 for (int i = 0; i < files.length; ++i) {
204                     assertEquals("Element " + i, new File(files[i]), results[i]);
205                 }
206             }
207 
208             @Override
209             public TestCondition withNonWriteable(String... files) {
210                 notWriteable.addAll(Arrays.asList(files));
211                 return this;
212             }
213 
214             @Override
215             public TestCondition withProcessUid(Integer uid) {
216                 processUid = uid;
217                 return this;
218             }
219         };
220     }
221 }
222