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