Home | History | Annotate | Download | only in skqp
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 package org.skia.skqp;
      9 
     10 import android.content.Context;
     11 import android.content.res.AssetManager;
     12 import android.content.res.Resources;
     13 import android.support.test.InstrumentationRegistry;
     14 import android.util.Log;
     15 import java.io.File;
     16 import java.io.IOException;
     17 import org.junit.runner.Description;
     18 import org.junit.runner.RunWith;
     19 import org.junit.runner.Runner;
     20 import org.junit.runner.manipulation.Filter;
     21 import org.junit.runner.manipulation.Filterable;
     22 import org.junit.runner.manipulation.NoTestsRemainException;
     23 import org.junit.runner.notification.Failure;
     24 import org.junit.runner.notification.RunNotifier;
     25 
     26 @RunWith(SkQPRunner.class)
     27 public class SkQPRunner extends Runner implements Filterable {
     28     private int mShouldRunTestCount;
     29     private Description[] mTests;
     30     private boolean[] mShouldSkipTest;
     31     private SkQP impl;
     32     private static final String TAG = SkQP.LOG_PREFIX;
     33 
     34     private static void Fail(Description desc, RunNotifier notifier, String failure) {
     35         notifier.fireTestFailure(new Failure(desc, new Throwable(failure)));
     36     }
     37 
     38     private static File GetOutputDir() {
     39         Context c = InstrumentationRegistry.getTargetContext();
     40         // File f = c.getFilesDir();
     41         File f = c.getExternalFilesDir(null);
     42         return new File(f, "output");
     43     }
     44 
     45     ////////////////////////////////////////////////////////////////////////////
     46 
     47     public SkQPRunner(Class testClass) {
     48         impl = new SkQP();
     49         File filesDir = SkQPRunner.GetOutputDir();
     50         try {
     51             SkQP.ensureEmtpyDirectory(filesDir);
     52         } catch (IOException e) {
     53             Log.w(TAG, "ensureEmtpyDirectory: " + e.getMessage());
     54         }
     55         Log.i(TAG, String.format("output written to \"%s\"", filesDir.getAbsolutePath()));
     56 
     57         Resources resources = InstrumentationRegistry.getTargetContext().getResources();
     58         AssetManager mAssetManager = resources.getAssets();
     59         impl.nInit(mAssetManager, filesDir.getAbsolutePath(), false);
     60 
     61         mTests = new Description[this.testCount()];
     62         mShouldSkipTest = new boolean[mTests.length]; // = {false, false, ....};
     63         int index = 0;
     64         for (int backend = 0; backend < impl.mBackends.length; backend++) {
     65             for (int gm = 0; gm < impl.mGMs.length; gm++) {
     66                 mTests[index++] = Description.createTestDescription(SkQPRunner.class,
     67                     impl.mBackends[backend] + "/" + impl.mGMs[gm]);
     68             }
     69         }
     70         for (int unitTest = 0; unitTest < impl.mUnitTests.length; unitTest++) {
     71             mTests[index++] = Description.createTestDescription(SkQPRunner.class,
     72                     "unitTest/" + impl.mUnitTests[unitTest]);
     73         }
     74         assert(index == mTests.length);
     75         mShouldRunTestCount = mTests.length;
     76     }
     77 
     78     @Override
     79     public void filter(Filter filter) throws NoTestsRemainException {
     80         int count = 0;
     81         for (int i = 0; i < mTests.length; ++i) {
     82             mShouldSkipTest[i] = !filter.shouldRun(mTests[i]);
     83             if (!mShouldSkipTest[i]) {
     84                 ++count;
     85             }
     86         }
     87         mShouldRunTestCount = count;
     88         if (0 == count) {
     89             throw new NoTestsRemainException();
     90         }
     91     }
     92 
     93     @Override
     94     public Description getDescription() {
     95         Description d = Description.createSuiteDescription(SkQP.class);
     96         for (int i = 0; i < mTests.length; ++i) {
     97             d.addChild(mTests[i]);
     98         }
     99         return d;
    100     }
    101 
    102     @Override
    103     public int testCount() {
    104         return impl.mUnitTests.length + impl.mGMs.length * impl.mBackends.length;
    105     }
    106 
    107     @Override
    108     public void run(RunNotifier notifier) {
    109         int testNumber = 1;  // out of number of actually run tests.
    110         int testIndex = 0;  // out of potential tests.
    111         for (int backend = 0; backend < impl.mBackends.length; backend++) {
    112             for (int gm = 0; gm < impl.mGMs.length; gm++, testIndex++) {
    113                 Description desc = mTests[testIndex];
    114                 String name = desc.getMethodName();
    115                 if (mShouldSkipTest[testIndex]) {
    116                     continue;
    117                 }
    118                 Log.v(TAG, String.format("Rendering Test '%s' started (%d/%d).",
    119                                          name, testNumber++, mShouldRunTestCount));
    120                 notifier.fireTestStarted(desc);
    121                 float value = java.lang.Float.MAX_VALUE;
    122                 String error = null;
    123                 try {
    124                     value = impl.nExecuteGM(gm, backend);
    125                 } catch (SkQPException exept) {
    126                     error = exept.getMessage();
    127                 }
    128                 if (error != null) {
    129                     SkQPRunner.Fail(desc, notifier, String.format("Exception: %s", error));
    130                     Log.w(TAG, String.format("[ERROR] '%s': %s", name, error));
    131                 } else if (value != 0) {
    132                     SkQPRunner.Fail(desc, notifier, String.format(
    133                                 "Image mismatch: max channel diff = %f", value));
    134                     Log.w(TAG, String.format("[FAIL] '%s': %f > 0", name, value));
    135                 } else {
    136                     Log.i(TAG, String.format("Rendering Test '%s' passed", name));
    137                 }
    138                 notifier.fireTestFinished(desc);
    139             }
    140         }
    141         for (int unitTest = 0; unitTest < impl.mUnitTests.length; unitTest++, testIndex++) {
    142             Description desc = mTests[testIndex];
    143             String name = desc.getMethodName();
    144             if (mShouldSkipTest[testIndex]) {
    145                 continue;
    146             }
    147 
    148             Log.v(TAG, String.format("Test '%s' started (%d/%d).",
    149                                      name, testNumber++, mShouldRunTestCount));
    150             notifier.fireTestStarted(desc);
    151             String[] errors = impl.nExecuteUnitTest(unitTest);
    152             if (errors != null && errors.length > 0) {
    153                 Log.w(TAG, String.format("[FAIL] Test '%s' had %d failures.", name, errors.length));
    154                 for (String error : errors) {
    155                     SkQPRunner.Fail(desc, notifier, error);
    156                     Log.w(TAG, String.format("[FAIL] '%s': %s", name, error));
    157                 }
    158             } else {
    159                 Log.i(TAG, String.format("Test '%s' passed.", name));
    160             }
    161             notifier.fireTestFinished(desc);
    162         }
    163         impl.nMakeReport();
    164         Log.i(TAG, String.format("output written to \"%s\"", GetOutputDir().getAbsolutePath()));
    165     }
    166 }
    167