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