• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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