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 org.junit.Test; 21 22 import java.io.File; 23 import java.util.Arrays; 24 import java.util.HashSet; 25 import java.util.Set; 26 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertNotNull; 29 import static org.junit.Assert.assertTrue; 30 31 public final class AppDataDirGuesserTest { 32 @Test 33 public void testGuessCacheDir_SimpleExample() { 34 guessCacheDirFor("/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache"); 35 guessCacheDirFor("/data/app/a.b.c.tests.apk").shouldGive("/data/data/a.b.c.tests/cache"); 36 } 37 38 @Test 39 public void testGuessCacheDir_MultipleResultsSeparatedByColon() { 40 guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk") 41 .shouldGive("/data/data/a.b.c/cache", "/data/data/d.e.f/cache"); 42 } 43 44 @Test 45 public void testGuessCacheDir_NotWriteableSkipped() { 46 guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk") 47 .withNonWriteable("/data/data/a.b.c/cache") 48 .shouldGive("/data/data/d.e.f/cache"); 49 } 50 51 @Test 52 public void testGuessCacheDir_StripHyphenatedSuffixes() { 53 guessCacheDirFor("/data/app/a.b.c-2.apk").shouldGive("/data/data/a.b.c/cache"); 54 } 55 56 @Test 57 public void testGuessCacheDir_LeadingAndTrailingColonsIgnored() { 58 guessCacheDirFor("/data/app/a.b.c.apk:asdf:").shouldGive("/data/data/a.b.c/cache"); 59 guessCacheDirFor(":asdf:/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache"); 60 } 61 62 @Test 63 public void testGuessCacheDir_InvalidInputsGiveEmptyArray() { 64 guessCacheDirFor("").shouldGive(); 65 } 66 67 @Test 68 public void testGuessCacheDir_JarsIgnored() { 69 guessCacheDirFor("/data/app/a.b.c.jar").shouldGive(); 70 guessCacheDirFor("/system/framework/android.test.runner.jar").shouldGive(); 71 } 72 73 @Test 74 public void testGuessCacheDir_RealWorldExample() { 75 String realPath = "/system/framework/android.test.runner.jar:" + 76 "/data/app/com.google.android.voicesearch.tests-2.apk:" + 77 "/data/app/com.google.android.voicesearch-1.apk"; 78 guessCacheDirFor(realPath) 79 .withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache") 80 .shouldGive("/data/data/com.google.android.voicesearch/cache"); 81 } 82 83 @Test 84 public void testSplitPathList() { 85 final String[] expected = { "foo", "bar" }; 86 assertTrue(Arrays.equals(expected, AppDataDirGuesser.splitPathList("foo:bar"))); 87 assertTrue(Arrays.equals(expected, 88 AppDataDirGuesser.splitPathList("dexPath=foo:bar"))); 89 assertTrue(Arrays.equals(expected, 90 AppDataDirGuesser.splitPathList("dexPath=foo:bar,bazPath=bar:bar2"))); 91 } 92 93 @Test 94 public void testPre43PathProcessing() { 95 String input = "dalvik.system.PathClassLoader[dexPath=/data/app/abc-1.apk," + 96 "libraryPath=/data/app-lib/abc-1]"; 97 String processed = AppDataDirGuesser.processClassLoaderString(input); 98 assertTrue("dexPath=/data/app/abc-1.apk,libraryPath=/data/app-lib/abc-1".equals(processed)); 99 } 100 101 @Test 102 public void test43PathProcessing() { 103 String input = "dalvik.system.PathClassLoader[DexPathList[[zip file " + 104 "\"/data/app/abc-1/base.apk\", zip file \"/data/app/def-1/base.apk\"], " + 105 "nativeLibraryDirectories=[/data/app-lib/abc-1]]]"; 106 String processed = AppDataDirGuesser.processClassLoaderString(input); 107 assertTrue("/data/app/abc-1/base.apk:/data/app/def-1/base.apk".equals(processed)); 108 } 109 110 @Test 111 public void testApiLevel17PlusPathProcessing() { 112 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 113 // Our processing should work for anything >= Android 4.2. 114 String input = getClass().getClassLoader().toString(); 115 String processed = AppDataDirGuesser.processClassLoaderString(input); 116 // TODO: this comment is no longer true now that we run tests on Android instead of vogar 117 // A tighter check would be interesting. But vogar doesn't run the tests in a directory 118 // recognized by the guesser (usually under /data/local/tmp), so we cannot use the 119 // processed result as input to guessPath. 120 assertTrue(!input.equals(processed)); 121 } 122 } 123 124 private interface TestCondition { 125 TestCondition withNonWriteable(String... files); 126 void shouldGive(String... files); 127 } 128 129 private TestCondition guessCacheDirFor(final String path) { 130 final Set<String> notWriteable = new HashSet<>(); 131 return new TestCondition() { 132 public void shouldGive(String... files) { 133 AppDataDirGuesser guesser = new AppDataDirGuesser() { 134 @Override 135 public boolean isWriteableDirectory(File file) { 136 return !notWriteable.contains(file.getAbsolutePath()); 137 } 138 @Override 139 boolean fileOrDirExists(File file) { 140 return true; 141 } 142 }; 143 File[] results = guesser.guessPath(path); 144 assertNotNull("Null results for " + path, results); 145 assertEquals("Bad lengths for " + path, files.length, results.length); 146 for (int i = 0; i < files.length; ++i) { 147 assertEquals("Element " + i, new File(files[i]), results[i]); 148 } 149 } 150 151 public TestCondition withNonWriteable(String... files) { 152 notWriteable.addAll(Arrays.asList(files)); 153 return this; 154 } 155 }; 156 } 157 } 158