Home | History | Annotate | Download | only in listener
      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.listener;
     17 
     18 import android.app.Instrumentation;
     19 import android.os.Bundle;
     20 import android.util.Log;
     21 
     22 import java.io.File;
     23 import java.io.PrintStream;
     24 import java.lang.reflect.InvocationTargetException;
     25 import java.lang.reflect.Method;
     26 
     27 /**
     28  * A test {@link RunListener} that generates EMMA code coverage.
     29  */
     30 public class CoverageListener extends InstrumentationRunListener {
     31 
     32     private String mCoverageFilePath;
     33 
     34     /**
     35      * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
     36      * identifies the path to the generated code coverage file.
     37      */
     38     private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath";
     39     // Default file name for code coverage
     40     private static final String DEFAULT_COVERAGE_FILE_NAME = "coverage.ec";
     41 
     42     private static final String LOG_TAG = null;
     43 
     44     /**
     45      * Creates a {@link CoverageListener).
     46      *
     47      * @param instr the {@link Instrumentation} that the test is running under
     48      * @param customCoverageFilePath an optional user specified path for the coverage file
     49      *         If null, file will be generated in test app's file directory.
     50      */
     51     public CoverageListener(Instrumentation instr, String customCoverageFilePath) {
     52         super(instr);
     53         mCoverageFilePath = customCoverageFilePath;
     54         if (mCoverageFilePath == null) {
     55             mCoverageFilePath = instr.getTargetContext().getFilesDir().getAbsolutePath() +
     56                     File.separator + DEFAULT_COVERAGE_FILE_NAME;
     57         }
     58     }
     59 
     60     @Override
     61     public void instrumentationRunFinished(PrintStream writer, Bundle results) {
     62         generateCoverageReport(writer, results);
     63     }
     64 
     65     private void generateCoverageReport(PrintStream writer, Bundle results) {
     66         // use reflection to call emma dump coverage method, to avoid
     67         // always statically compiling against emma jar
     68         java.io.File coverageFile = new java.io.File(mCoverageFilePath);
     69         try {
     70             Class<?> emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
     71             Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData",
     72                     coverageFile.getClass(), boolean.class, boolean.class);
     73 
     74             dumpCoverageMethod.invoke(null, coverageFile, false, false);
     75 
     76             // output path to generated coverage file so it can be parsed by a test harness if
     77             // needed
     78             results.putString(REPORT_KEY_COVERAGE_PATH, mCoverageFilePath);
     79             // also output a more user friendly msg
     80             writer.format("\nGenerated code coverage data to %s",mCoverageFilePath);
     81         } catch (ClassNotFoundException e) {
     82             reportEmmaError(writer, "Is emma jar on classpath?", e);
     83         } catch (SecurityException e) {
     84             reportEmmaError(writer, e);
     85         } catch (NoSuchMethodException e) {
     86             reportEmmaError(writer, e);
     87         } catch (IllegalArgumentException e) {
     88             reportEmmaError(writer, e);
     89         } catch (IllegalAccessException e) {
     90             reportEmmaError(writer, e);
     91         } catch (InvocationTargetException e) {
     92             reportEmmaError(writer, e);
     93         }
     94     }
     95 
     96     private void reportEmmaError(PrintStream writer, Exception e) {
     97         reportEmmaError(writer, "", e);
     98     }
     99 
    100     private void reportEmmaError(PrintStream writer, String hint, Exception e) {
    101         String msg = "Failed to generate emma coverage. " + hint;
    102         Log.e(LOG_TAG, msg, e);
    103         writer.format("\nError: %s", msg);
    104     }
    105 }
    106