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 package com.android.test.runner.junit4; 17 18 import android.app.Instrumentation; 19 import android.content.Context; 20 import android.os.Bundle; 21 import android.util.Log; 22 23 import com.android.test.InjectBundle; 24 import com.android.test.InjectContext; 25 import com.android.test.InjectInstrumentation; 26 27 import org.junit.runners.BlockJUnit4ClassRunner; 28 import org.junit.runners.model.FrameworkField; 29 import org.junit.runners.model.InitializationError; 30 31 import java.lang.reflect.Field; 32 import java.util.List; 33 34 /** 35 * A specialized {@link BlockJUnit4ClassRunner} that can handle {@link InjectContext} and 36 * {@link InjectInstrumentation}. 37 */ 38 class AndroidJUnit4ClassRunner extends BlockJUnit4ClassRunner { 39 40 private static final String LOG_TAG = "AndroidJUnit4ClassRunner"; 41 private final Instrumentation mInstr; 42 private final Bundle mBundle; 43 44 @SuppressWarnings("serial") 45 private static class InvalidInjectException extends Exception { 46 InvalidInjectException(String message) { 47 super(message); 48 } 49 } 50 51 public AndroidJUnit4ClassRunner(Class<?> klass, Instrumentation instr, Bundle bundle) 52 throws InitializationError { 53 super(klass); 54 mInstr = instr; 55 mBundle = bundle; 56 } 57 58 @Override 59 protected Object createTest() throws Exception { 60 Object test = super.createTest(); 61 inject(test); 62 return test; 63 } 64 65 @Override 66 protected void collectInitializationErrors(List<Throwable> errors) { 67 super.collectInitializationErrors(errors); 68 69 validateInjectFields(errors); 70 } 71 72 private void validateInjectFields(List<Throwable> errors) { 73 List<FrameworkField> instrFields = getTestClass().getAnnotatedFields( 74 InjectInstrumentation.class); 75 for (FrameworkField instrField : instrFields) { 76 validateInjectField(errors, instrField, Instrumentation.class); 77 } 78 List<FrameworkField> contextFields = getTestClass().getAnnotatedFields( 79 InjectContext.class); 80 for (FrameworkField contextField : contextFields) { 81 validateInjectField(errors, contextField, Context.class); 82 } 83 List<FrameworkField> bundleFields = getTestClass().getAnnotatedFields( 84 InjectBundle.class); 85 for (FrameworkField bundleField : bundleFields) { 86 validateInjectField(errors, bundleField, Bundle.class); 87 } 88 } 89 90 private void validateInjectField(List<Throwable> errors, FrameworkField instrField, 91 Class<?> expectedType) { 92 if (!instrField.isPublic()) { 93 errors.add(new InvalidInjectException(String.format( 94 "field %s in class %s has an InjectInstrumentation annotation," + 95 " but is not public", instrField.getName(), getTestClass().getName()))); 96 } 97 if (!expectedType.isAssignableFrom(instrField.getType())) { 98 errors.add(new InvalidInjectException(String.format( 99 "field %s in class %s has an InjectInstrumentation annotation," + 100 " but its not of %s type", instrField.getName(), 101 getTestClass().getName(), expectedType.getName()))); 102 } 103 } 104 105 private void inject(Object test) { 106 List<FrameworkField> instrFields = getTestClass().getAnnotatedFields( 107 InjectInstrumentation.class); 108 for (FrameworkField instrField : instrFields) { 109 setFieldValue(test, instrField.getField(), mInstr); 110 } 111 List<FrameworkField> contextFields = getTestClass().getAnnotatedFields( 112 InjectContext.class); 113 for (FrameworkField contextField : contextFields) { 114 setFieldValue(test, contextField.getField(), mInstr.getTargetContext()); 115 } 116 List<FrameworkField> bundleFields = getTestClass().getAnnotatedFields( 117 InjectBundle.class); 118 for (FrameworkField bundleField : bundleFields) { 119 setFieldValue(test, bundleField.getField(), mBundle); 120 } 121 } 122 123 private void setFieldValue(Object test, Field field, Object value) { 124 try { 125 field.set(test, value); 126 } catch (IllegalArgumentException e) { 127 Log.e(LOG_TAG, String.format( 128 "Failed to inject value for field %s in class %s", field.getName(), 129 test.getClass().getName()), e); 130 } catch (IllegalAccessException e) { 131 Log.e(LOG_TAG, String.format( 132 "Failed to inject value for field %s in class %s", field.getName(), 133 test.getClass().getName()), e); 134 } 135 } 136 } 137