1 /*
2  * Copyright (C) 2017 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 com.android.gtestrunner;
18 
19 import java.util.Iterator;
20 import java.util.List;
21 import org.junit.runner.Description;
22 import org.junit.runner.Runner;
23 import org.junit.runner.manipulation.Filter;
24 import org.junit.runner.manipulation.Filterable;
25 import org.junit.runner.manipulation.NoTestsRemainException;
26 import org.junit.runner.notification.RunNotifier;
27 
28 /**
29  * Custom Runner that implements a bridge between JUnit and GTest.
30  *
31  * Use this Runner in a @RunWith annotation together with a @TargetLibrary
32  * annotation on an empty class to create a CTS test that consists of native
33  * tests written against the Google Test Framework. See the CTS module in
34  * cts/tests/tests/nativehardware for an example.
35  */
36 public class GtestRunner extends Runner implements Filterable {
37     private static boolean sOnceFlag = false;
38 
39     private Class mTargetClass;
40     private Description mDescription;
41 
GtestRunner(Class testClass)42     public GtestRunner(Class testClass) {
43         synchronized (GtestRunner.class) {
44             if (sOnceFlag) {
45                 throw new IllegalStateException("Error multiple GtestRunners defined");
46             }
47             sOnceFlag = true;
48         }
49 
50         mTargetClass = testClass;
51         TargetLibrary library = (TargetLibrary) testClass.getAnnotation(TargetLibrary.class);
52         if (library == null) {
53             throw new IllegalStateException("Missing required @TargetLibrary annotation");
54         }
55         System.loadLibrary(library.value());
56         mDescription = Description.createSuiteDescription(testClass);
57         // The nInitialize native method will populate the description based on
58         // GTest test data.
59         nInitialize(testClass.getName(), mDescription);
60     }
61 
62     @Override
getDescription()63     public Description getDescription() {
64         return mDescription;
65     }
66 
67     @Override
filter(Filter filter)68     public void filter(Filter filter) throws NoTestsRemainException {
69         List<Description> children = mDescription.getChildren();
70         mDescription = Description.createSuiteDescription(mTargetClass);
71         for (Iterator<Description> iter = children.iterator(); iter.hasNext(); ) {
72             Description testDescription = iter.next();
73             if (filter.shouldRun(testDescription)) {
74                 mDescription.addChild(testDescription);
75             }
76         }
77         if (mDescription.getChildren().isEmpty()) {
78             throw new NoTestsRemainException();
79         }
80     }
81 
82     @Override
run(RunNotifier notifier)83     public void run(RunNotifier notifier) {
84         for (Description description : mDescription.getChildren()) {
85             nAddTest(description.getMethodName());
86         }
87         nRun(mTargetClass.getName(), notifier);
88     }
89 
nInitialize(String className, Description description)90     private static native void nInitialize(String className, Description description);
nAddTest(String testName)91     private static native void nAddTest(String testName);
nRun(String className, RunNotifier notifier)92     private static native boolean nRun(String className, RunNotifier notifier);
93 }
94