/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.test.runner.junit4; import android.app.Instrumentation; import android.content.Context; import android.util.Log; import com.android.test.InjectContext; import com.android.test.InjectInstrumentation; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkField; import org.junit.runners.model.InitializationError; import java.lang.reflect.Field; import java.util.List; /** * A specialized {@link BlockJUnit4ClassRunner} that can handle {@link InjectContext} and * {@link InjectInstrumentation}. */ class AndroidJUnit4ClassRunner extends BlockJUnit4ClassRunner { private static final String LOG_TAG = "AndroidJUnit4ClassRunner"; private final Instrumentation mInstr; @SuppressWarnings("serial") private static class InvalidInjectException extends Exception { InvalidInjectException(String message) { super(message); } } public AndroidJUnit4ClassRunner(Class klass, Instrumentation instr) throws InitializationError { super(klass); mInstr = instr; } @Override protected Object createTest() throws Exception { Object test = super.createTest(); inject(test); return test; } @Override protected void collectInitializationErrors(List errors) { super.collectInitializationErrors(errors); validateInjectFields(errors); } private void validateInjectFields(List errors) { List instrFields = getTestClass().getAnnotatedFields( InjectInstrumentation.class); for (FrameworkField instrField : instrFields) { validateInjectField(errors, instrField, Instrumentation.class); } List contextFields = getTestClass().getAnnotatedFields( InjectContext.class); for (FrameworkField contextField : contextFields) { validateInjectField(errors, contextField, Context.class); } } private void validateInjectField(List errors, FrameworkField instrField, Class expectedType) { if (!instrField.isPublic()) { errors.add(new InvalidInjectException(String.format( "field %s in class %s has an InjectInstrumentation annotation," + " but is not public", instrField.getName(), getTestClass().getName()))); } if (!expectedType.isAssignableFrom(instrField.getType())) { errors.add(new InvalidInjectException(String.format( "field %s in class %s has an InjectInstrumentation annotation," + " but its not of %s type", instrField.getName(), getTestClass().getName(), expectedType.getName()))); } } private void inject(Object test) { List instrFields = getTestClass().getAnnotatedFields( InjectInstrumentation.class); for (FrameworkField instrField : instrFields) { setFieldValue(test, instrField.getField(), mInstr); } List contextFields = getTestClass().getAnnotatedFields( InjectContext.class); for (FrameworkField contextField : contextFields) { setFieldValue(test, contextField.getField(), mInstr.getTargetContext()); } } private void setFieldValue(Object test, Field field, Object value) { try { field.set(test, value); } catch (IllegalArgumentException e) { Log.e(LOG_TAG, String.format( "Failed to inject value for field %s in class %s", field.getName(), test.getClass().getName()), e); } catch (IllegalAccessException e) { Log.e(LOG_TAG, String.format( "Failed to inject value for field %s in class %s", field.getName(), test.getClass().getName()), e); } } }