1 /* 2 * Copyright (C) 2007 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 android.test; 18 19 import android.content.Context; 20 import android.content.ContextWrapper; 21 import android.content.ContentProvider; 22 import android.database.DatabaseErrorHandler; 23 import android.database.sqlite.SQLiteDatabase; 24 import android.test.mock.MockContentProvider; 25 import android.util.Log; 26 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.io.FileNotFoundException; 30 import java.io.FileOutputStream; 31 import java.io.IOException; 32 import java.nio.file.Files; 33 import java.nio.file.Paths; 34 import java.nio.file.attribute.PosixFilePermission; 35 import java.nio.file.attribute.PosixFilePermissions; 36 import java.util.EnumSet; 37 import java.util.HashSet; 38 import java.util.Set; 39 40 /** 41 * This is a class which delegates to the given context, but performs database 42 * and file operations with a renamed database/file name (prefixes default 43 * names with a given prefix). 44 * 45 * @deprecated New tests should be written using the 46 * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. 47 */ 48 @Deprecated 49 public class RenamingDelegatingContext extends ContextWrapper { 50 51 private Context mFileContext; 52 private String mFilePrefix = null; 53 private File mCacheDir; 54 private final Object mSync = new Object(); 55 56 private Set<String> mDatabaseNames = new HashSet<>(); 57 private Set<String> mFileNames = new HashSet<>(); 58 providerWithRenamedContext( Class<T> contentProvider, Context c, String filePrefix)59 public static <T extends ContentProvider> T providerWithRenamedContext( 60 Class<T> contentProvider, Context c, String filePrefix) 61 throws IllegalAccessException, InstantiationException { 62 return providerWithRenamedContext(contentProvider, c, filePrefix, false); 63 } 64 providerWithRenamedContext( Class<T> contentProvider, Context c, String filePrefix, boolean allowAccessToExistingFilesAndDbs)65 public static <T extends ContentProvider> T providerWithRenamedContext( 66 Class<T> contentProvider, Context c, String filePrefix, 67 boolean allowAccessToExistingFilesAndDbs) 68 throws IllegalAccessException, InstantiationException { 69 Class<T> mProviderClass = contentProvider; 70 T mProvider = mProviderClass.newInstance(); 71 RenamingDelegatingContext mContext = new RenamingDelegatingContext(c, filePrefix); 72 if (allowAccessToExistingFilesAndDbs) { 73 mContext.makeExistingFilesAndDbsAccessible(); 74 } 75 MockContentProvider.attachInfoForTesting(mProvider, mContext, null); 76 return mProvider; 77 } 78 79 /** 80 * Makes accessible all files and databases whose names match the filePrefix that was passed to 81 * the constructor. Normally only files and databases that were created through this context are 82 * accessible. 83 */ makeExistingFilesAndDbsAccessible()84 public void makeExistingFilesAndDbsAccessible() { 85 String[] databaseList = mFileContext.databaseList(); 86 for (String diskName : databaseList) { 87 if (shouldDiskNameBeVisible(diskName)) { 88 mDatabaseNames.add(publicNameFromDiskName(diskName)); 89 } 90 } 91 String[] fileList = mFileContext.fileList(); 92 for (String diskName : fileList) { 93 if (shouldDiskNameBeVisible(diskName)) { 94 mFileNames.add(publicNameFromDiskName(diskName)); 95 } 96 } 97 } 98 99 /** 100 * Returns if the given diskName starts with the given prefix or not. 101 * @param diskName name of the database/file. 102 */ shouldDiskNameBeVisible(String diskName)103 boolean shouldDiskNameBeVisible(String diskName) { 104 return diskName.startsWith(mFilePrefix); 105 } 106 107 /** 108 * Returns the public name (everything following the prefix) of the given diskName. 109 * @param diskName name of the database/file. 110 */ publicNameFromDiskName(String diskName)111 String publicNameFromDiskName(String diskName) { 112 if (!shouldDiskNameBeVisible(diskName)) { 113 throw new IllegalArgumentException("disk file should not be visible: " + diskName); 114 } 115 return diskName.substring(mFilePrefix.length(), diskName.length()); 116 } 117 118 /** 119 * @param context : the context that will be delegated. 120 * @param filePrefix : a prefix with which database and file names will be 121 * prefixed. 122 */ RenamingDelegatingContext(Context context, String filePrefix)123 public RenamingDelegatingContext(Context context, String filePrefix) { 124 super(context); 125 mFileContext = context; 126 mFilePrefix = filePrefix; 127 } 128 129 /** 130 * @param context : the context that will be delegated. 131 * @param fileContext : the context that file and db methods will be delegated to 132 * @param filePrefix : a prefix with which database and file names will be 133 * prefixed. 134 */ RenamingDelegatingContext(Context context, Context fileContext, String filePrefix)135 public RenamingDelegatingContext(Context context, Context fileContext, String filePrefix) { 136 super(context); 137 mFileContext = fileContext; 138 mFilePrefix = filePrefix; 139 } 140 getDatabasePrefix()141 public String getDatabasePrefix() { 142 return mFilePrefix; 143 } 144 renamedFileName(String name)145 private String renamedFileName(String name) { 146 return mFilePrefix + name; 147 } 148 149 @Override openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory)150 public SQLiteDatabase openOrCreateDatabase(String name, 151 int mode, SQLiteDatabase.CursorFactory factory) { 152 final String internalName = renamedFileName(name); 153 if (!mDatabaseNames.contains(name)) { 154 mDatabaseNames.add(name); 155 mFileContext.deleteDatabase(internalName); 156 } 157 return mFileContext.openOrCreateDatabase(internalName, mode, factory); 158 } 159 160 @Override openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler)161 public SQLiteDatabase openOrCreateDatabase(String name, 162 int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) { 163 final String internalName = renamedFileName(name); 164 if (!mDatabaseNames.contains(name)) { 165 mDatabaseNames.add(name); 166 mFileContext.deleteDatabase(internalName); 167 } 168 return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler); 169 } 170 171 @Override deleteDatabase(String name)172 public boolean deleteDatabase(String name) { 173 if (mDatabaseNames.contains(name)) { 174 mDatabaseNames.remove(name); 175 return mFileContext.deleteDatabase(renamedFileName(name)); 176 } else { 177 return false; 178 } 179 } 180 181 @Override getDatabasePath(String name)182 public File getDatabasePath(String name) { 183 return mFileContext.getDatabasePath(renamedFileName(name)); 184 } 185 186 @Override databaseList()187 public String[] databaseList() { 188 return mDatabaseNames.toArray(new String[]{}); 189 } 190 191 @Override openFileInput(String name)192 public FileInputStream openFileInput(String name) 193 throws FileNotFoundException { 194 final String internalName = renamedFileName(name); 195 if (mFileNames.contains(name)) { 196 return mFileContext.openFileInput(internalName); 197 } else { 198 throw new FileNotFoundException(internalName); 199 } 200 } 201 202 @Override openFileOutput(String name, int mode)203 public FileOutputStream openFileOutput(String name, int mode) 204 throws FileNotFoundException { 205 mFileNames.add(name); 206 return mFileContext.openFileOutput(renamedFileName(name), mode); 207 } 208 209 @Override getFileStreamPath(String name)210 public File getFileStreamPath(String name) { 211 return mFileContext.getFileStreamPath(renamedFileName(name)); 212 } 213 214 @Override deleteFile(String name)215 public boolean deleteFile(String name) { 216 if (mFileNames.contains(name)) { 217 mFileNames.remove(name); 218 return mFileContext.deleteFile(renamedFileName(name)); 219 } else { 220 return false; 221 } 222 } 223 224 @Override fileList()225 public String[] fileList() { 226 return mFileNames.toArray(new String[]{}); 227 } 228 229 /** 230 * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real 231 * one) and return it instead. This code is basically getCacheDir(), except it uses the real 232 * cache dir as the parent directory and creates a test cache dir inside that. 233 */ 234 @Override getCacheDir()235 public File getCacheDir() { 236 synchronized (mSync) { 237 if (mCacheDir == null) { 238 mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache")); 239 } 240 if (!mCacheDir.exists()) { 241 if(!mCacheDir.mkdirs()) { 242 Log.w("RenamingDelegatingContext", "Unable to create cache directory"); 243 return null; 244 } 245 try { 246 // Give the directory all possible permissions. 247 Files.setPosixFilePermissions(mCacheDir.toPath(), 248 EnumSet.allOf(PosixFilePermission.class)); 249 } catch (IOException e) { 250 Log.e("RenamingDelegatingContext", 251 "Could not set permissions of test cacheDir", e); 252 } 253 } 254 } 255 return mCacheDir; 256 } 257 } 258