1a307039346a769b1fc62782ef847e71c9691838aBrett Chabot/* 2a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * Copyright (C) 2012 The Android Open Source Project 3a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * 4a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License"); 5a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * you may not use this file except in compliance with the License. 6a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * You may obtain a copy of the License at 7a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * 8a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * http://www.apache.org/licenses/LICENSE-2.0 9a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * 10a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * Unless required by applicable law or agreed to in writing, software 11a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * distributed under the License is distributed on an "AS IS" BASIS, 12a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * See the License for the specific language governing permissions and 14a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * limitations under the License. 15a307039346a769b1fc62782ef847e71c9691838aBrett Chabot */ 16a307039346a769b1fc62782ef847e71c9691838aBrett Chabotpackage com.android.test.runner.listener; 17a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 18a307039346a769b1fc62782ef847e71c9691838aBrett Chabotimport android.app.Instrumentation; 19a307039346a769b1fc62782ef847e71c9691838aBrett Chabotimport android.os.Bundle; 20a307039346a769b1fc62782ef847e71c9691838aBrett Chabotimport android.util.Log; 21a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 22a307039346a769b1fc62782ef847e71c9691838aBrett Chabotimport java.io.File; 23a307039346a769b1fc62782ef847e71c9691838aBrett Chabotimport java.io.PrintStream; 24a307039346a769b1fc62782ef847e71c9691838aBrett Chabotimport java.lang.reflect.InvocationTargetException; 25a307039346a769b1fc62782ef847e71c9691838aBrett Chabotimport java.lang.reflect.Method; 26a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 27a307039346a769b1fc62782ef847e71c9691838aBrett Chabot/** 28a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * A test {@link RunListener} that generates EMMA code coverage. 29a307039346a769b1fc62782ef847e71c9691838aBrett Chabot */ 30a307039346a769b1fc62782ef847e71c9691838aBrett Chabotpublic class CoverageListener extends InstrumentationRunListener { 31a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 32a307039346a769b1fc62782ef847e71c9691838aBrett Chabot private String mCoverageFilePath; 33a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 34a307039346a769b1fc62782ef847e71c9691838aBrett Chabot /** 35a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 36a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * identifies the path to the generated code coverage file. 37a307039346a769b1fc62782ef847e71c9691838aBrett Chabot */ 38a307039346a769b1fc62782ef847e71c9691838aBrett Chabot private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath"; 39a307039346a769b1fc62782ef847e71c9691838aBrett Chabot // Default file name for code coverage 40a307039346a769b1fc62782ef847e71c9691838aBrett Chabot private static final String DEFAULT_COVERAGE_FILE_NAME = "coverage.ec"; 41a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 42a307039346a769b1fc62782ef847e71c9691838aBrett Chabot private static final String LOG_TAG = null; 43a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 44a307039346a769b1fc62782ef847e71c9691838aBrett Chabot /** 45a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * Creates a {@link CoverageListener). 46a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * 47a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * @param instr the {@link Instrumentation} that the test is running under 48a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * @param customCoverageFilePath an optional user specified path for the coverage file 49a307039346a769b1fc62782ef847e71c9691838aBrett Chabot * If null, file will be generated in test app's file directory. 50a307039346a769b1fc62782ef847e71c9691838aBrett Chabot */ 51a307039346a769b1fc62782ef847e71c9691838aBrett Chabot public CoverageListener(Instrumentation instr, String customCoverageFilePath) { 52a307039346a769b1fc62782ef847e71c9691838aBrett Chabot super(instr); 53a307039346a769b1fc62782ef847e71c9691838aBrett Chabot mCoverageFilePath = customCoverageFilePath; 54a307039346a769b1fc62782ef847e71c9691838aBrett Chabot if (mCoverageFilePath == null) { 55a307039346a769b1fc62782ef847e71c9691838aBrett Chabot mCoverageFilePath = instr.getTargetContext().getFilesDir().getAbsolutePath() + 56a307039346a769b1fc62782ef847e71c9691838aBrett Chabot File.separator + DEFAULT_COVERAGE_FILE_NAME; 57a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } 58a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } 59a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 60a307039346a769b1fc62782ef847e71c9691838aBrett Chabot @Override 61a307039346a769b1fc62782ef847e71c9691838aBrett Chabot public void instrumentationRunFinished(PrintStream writer, Bundle results) { 62a307039346a769b1fc62782ef847e71c9691838aBrett Chabot generateCoverageReport(writer, results); 63a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } 64a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 65a307039346a769b1fc62782ef847e71c9691838aBrett Chabot private void generateCoverageReport(PrintStream writer, Bundle results) { 66a307039346a769b1fc62782ef847e71c9691838aBrett Chabot // use reflection to call emma dump coverage method, to avoid 67a307039346a769b1fc62782ef847e71c9691838aBrett Chabot // always statically compiling against emma jar 68a307039346a769b1fc62782ef847e71c9691838aBrett Chabot java.io.File coverageFile = new java.io.File(mCoverageFilePath); 69a307039346a769b1fc62782ef847e71c9691838aBrett Chabot try { 70a307039346a769b1fc62782ef847e71c9691838aBrett Chabot Class<?> emmaRTClass = Class.forName("com.vladium.emma.rt.RT"); 71a307039346a769b1fc62782ef847e71c9691838aBrett Chabot Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData", 72a307039346a769b1fc62782ef847e71c9691838aBrett Chabot coverageFile.getClass(), boolean.class, boolean.class); 73a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 74a307039346a769b1fc62782ef847e71c9691838aBrett Chabot dumpCoverageMethod.invoke(null, coverageFile, false, false); 75a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 76a307039346a769b1fc62782ef847e71c9691838aBrett Chabot // output path to generated coverage file so it can be parsed by a test harness if 77a307039346a769b1fc62782ef847e71c9691838aBrett Chabot // needed 78a307039346a769b1fc62782ef847e71c9691838aBrett Chabot results.putString(REPORT_KEY_COVERAGE_PATH, mCoverageFilePath); 79a307039346a769b1fc62782ef847e71c9691838aBrett Chabot // also output a more user friendly msg 80a307039346a769b1fc62782ef847e71c9691838aBrett Chabot writer.format("\nGenerated code coverage data to %s",mCoverageFilePath); 81a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } catch (ClassNotFoundException e) { 82a307039346a769b1fc62782ef847e71c9691838aBrett Chabot reportEmmaError(writer, "Is emma jar on classpath?", e); 83a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } catch (SecurityException e) { 84a307039346a769b1fc62782ef847e71c9691838aBrett Chabot reportEmmaError(writer, e); 85a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } catch (NoSuchMethodException e) { 86a307039346a769b1fc62782ef847e71c9691838aBrett Chabot reportEmmaError(writer, e); 87a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } catch (IllegalArgumentException e) { 88a307039346a769b1fc62782ef847e71c9691838aBrett Chabot reportEmmaError(writer, e); 89a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } catch (IllegalAccessException e) { 90a307039346a769b1fc62782ef847e71c9691838aBrett Chabot reportEmmaError(writer, e); 91a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } catch (InvocationTargetException e) { 92a307039346a769b1fc62782ef847e71c9691838aBrett Chabot reportEmmaError(writer, e); 93a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } 94a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } 95a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 96a307039346a769b1fc62782ef847e71c9691838aBrett Chabot private void reportEmmaError(PrintStream writer, Exception e) { 97a307039346a769b1fc62782ef847e71c9691838aBrett Chabot reportEmmaError(writer, "", e); 98a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } 99a307039346a769b1fc62782ef847e71c9691838aBrett Chabot 100a307039346a769b1fc62782ef847e71c9691838aBrett Chabot private void reportEmmaError(PrintStream writer, String hint, Exception e) { 101a307039346a769b1fc62782ef847e71c9691838aBrett Chabot String msg = "Failed to generate emma coverage. " + hint; 102a307039346a769b1fc62782ef847e71c9691838aBrett Chabot Log.e(LOG_TAG, msg, e); 103a307039346a769b1fc62782ef847e71c9691838aBrett Chabot writer.format("\nError: %s", msg); 104a307039346a769b1fc62782ef847e71c9691838aBrett Chabot } 105a307039346a769b1fc62782ef847e71c9691838aBrett Chabot} 106