Flutter Engine
The Flutter Engine
SkQPRunner.java
Go to the documentation of this file.
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
8package org.skia.skqp;
9
10import android.content.Context;
11import android.content.res.AssetManager;
12import android.content.res.Resources;
13import android.graphics.RuntimeShader;
14import android.util.Log;
15import androidx.test.InstrumentationRegistry;
16import java.io.File;
17import java.io.IOException;
18import java.text.SimpleDateFormat;
19import java.util.Date;
20import java.util.regex.Pattern;
21import org.junit.runner.Description;
22import org.junit.runner.RunWith;
23import org.junit.runner.Runner;
24import org.junit.runner.manipulation.Filter;
25import org.junit.runner.manipulation.Filterable;
26import org.junit.runner.manipulation.NoTestsRemainException;
27import org.junit.runner.notification.Failure;
28import org.junit.runner.notification.RunNotifier;
29
30@RunWith(SkQPRunner.class)
31public class SkQPRunner extends Runner implements Filterable {
32 private Description[] mUnitTestDesc;
33 private Description[] mSkSLErrorTestDesc;
34 private Description mSuiteDesc;
35 private String mOutputDirectory;
36 private SkQP mImpl;
37 private static final String TAG = SkQP.LOG_PREFIX;
38
39 private interface TestExecutor {
40 public int numTests();
41 public String name(int index);
42 public Description desc(int index);
43 public boolean run(RunNotifier notifier, int index);
44 }
45
46 private static void Fail(Description desc, RunNotifier notifier, String failure) {
47 notifier.fireTestFailure(new Failure(desc, new SkQPFailure(failure)));
48 }
49
50 ////////////////////////////////////////////////////////////////////////////
51
52 public SkQPRunner(Class testClass) {
53 mImpl = new SkQP();
54 Context context = InstrumentationRegistry.getTargetContext();
55 String now = (new SimpleDateFormat("yyyy-MM-dd'T'HHmmss")).format(new Date());
56 File reportPath = new File(context.getExternalFilesDir(null), "skqp_report_" + now);
57 reportPath.mkdirs();
58 mOutputDirectory = reportPath.getAbsolutePath();
59 Log.i(TAG, String.format("output written to \"%s\"", mOutputDirectory));
60
61 AssetManager assetManager = context.getResources().getAssets();
62 mImpl.nInit(assetManager, mOutputDirectory);
63
64 mUnitTestDesc = new Description[mImpl.mUnitTests.length];
65 for (int index = 0; index < mUnitTestDesc.length; ++index) {
66 mUnitTestDesc[index] = Description.createTestDescription(
67 SkQPRunner.class, "UnitTest_" + mImpl.mUnitTests[index]);
68 }
69
70 mSkSLErrorTestDesc = new Description[mImpl.mSkSLErrorTestName.length];
71 for (int index = 0; index < mSkSLErrorTestDesc.length; ++index) {
72 mSkSLErrorTestDesc[index] = Description.createTestDescription(
73 SkQPRunner.class, "SkSLErrorTest_" + mImpl.mSkSLErrorTestName[index]);
74 }
75
76 this.applyFilter(null);
77 }
78
79 private void applyFilter(Filter filter) {
80 mSuiteDesc = Description.createSuiteDescription(SkQP.class);
81 addFilteredTestsToSuite(mUnitTestDesc, filter);
82 addFilteredTestsToSuite(mSkSLErrorTestDesc, filter);
83 }
84
85 private void addFilteredTestsToSuite(Description[] tests, Filter filter) {
86 for (int i = 0; i < tests.length; ++i) {
87 if (filter == null || filter.shouldRun(tests[i])) {
88 mSuiteDesc.addChild(tests[i]);
89 } else {
90 tests[i] = Description.EMPTY;
91 }
92 }
93 }
94
95 @Override
96 public void filter(Filter filter) throws NoTestsRemainException {
97 this.applyFilter(filter);
98 if (mSuiteDesc.isEmpty()) {
99 throw new NoTestsRemainException();
100 }
101 }
102
103 @Override
104 public Description getDescription() {
105 return mSuiteDesc;
106 }
107
108 @Override
109 public void run(RunNotifier notifier) {
110 int testNumber = 0;
111 testNumber = runTests(notifier, new SkSLErrorTestExecutor(), testNumber);
112 testNumber = runTests(notifier, new UnitTestExecutor(), testNumber);
113
114 mImpl.nMakeReport();
115 Log.i(TAG, String.format("output written to \"%s\"", mOutputDirectory));
116 }
117
118 private int runTests(RunNotifier notifier, TestExecutor executor, int testNumber) {
119 for (int index = 0; index < executor.numTests(); index++) {
120 Description desc = executor.desc(index);
121 if (desc.isEmpty()) {
122 // This test was filtered out and can be skipped.
123 continue;
124 }
125
126 ++testNumber;
127 notifier.fireTestStarted(desc);
128
129 String result = executor.run(notifier, index) ? "pass" : "FAIL";
130
131 notifier.fireTestFinished(desc);
132 Log.i(TAG, String.format("Test '%s' complete (%d/%d). [%s]", executor.name(index),
133 testNumber, mSuiteDesc.testCount(), result));
134 }
135 return testNumber;
136 }
137
138 class UnitTestExecutor implements TestExecutor {
139 public int numTests() {
140 return mUnitTestDesc.length;
141 }
142 public String name(int index) {
143 return desc(index).getMethodName();
144 }
145 public Description desc(int index) {
146 return mUnitTestDesc[index];
147 }
148 public boolean run(RunNotifier notifier, int index) {
149 String[] errors = mImpl.nExecuteUnitTest(index);
150 if (errors != null && errors.length > 0) {
151 Log.w(TAG, String.format("[FAIL] Test '%s' had %d failures.",
152 name(index), errors.length));
153 for (String error : errors) {
154 SkQPRunner.Fail(desc(index), notifier, error);
155 Log.w(TAG, String.format("[FAIL] '%s': %s", name(index), error));
156 }
157 return false;
158 }
159
160 return true;
161 }
162 }
163
164 class SkSLErrorTestExecutor implements TestExecutor {
165 public int numTests() {
166 return mSkSLErrorTestDesc.length;
167 }
168 public String name(int index) {
169 return mImpl.mSkSLErrorTestName[index];
170 }
171 public Description desc(int index) {
172 return mSkSLErrorTestDesc[index];
173 }
174 public boolean run(RunNotifier notifier, int index) {
175 String shaderText = mImpl.mSkSLErrorTestShader[index];
176 try {
177 new RuntimeShader(shaderText);
178 // Because this is an error test, we expected an exception to be thrown.
179 // If we reach this point, no exception occurred; report this as an error.
180 SkQPRunner.Fail(desc(index), notifier, "Shader did not generate any errors.");
181 Log.w(TAG, String.format("[FAIL] '%s': Shader did not generate any errors",
182 name(index)));
183 return false;
184 }
185 catch (Exception ex) { } // Assume any exception is an expected SkSL error.
186 return true;
187 }
188 }
189}
static BlurTest tests[]
Definition: BlurTest.cpp:84
SkFilterMode
boolean run(RunNotifier notifier, int index)
boolean run(RunNotifier notifier, int index)
Description getDescription()
SkQPRunner(Class testClass)
Definition: SkQPRunner.java:52
void run(RunNotifier notifier)
void filter(Filter filter)
Definition: SkQPRunner.java:96
native void nMakeReport()
static final String LOG_PREFIX
Definition: SkQP.java:30
String[] mUnitTests
Definition: SkQP.java:21
native String[] nExecuteUnitTest(int test)
native void nInit(AssetManager assetManager, String dataDir)
String[] mSkSLErrorTestShader
Definition: SkQP.java:26
String[] mSkSLErrorTestName
Definition: SkQP.java:25
void Fail(const char *name, Dart_Handle result)
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
uint32_t uint32_t * format
void Log(const char *format,...) SK_PRINTF_LIKE(1
Definition: TestRunner.cpp:137
static TTSTestCase Failure(const TTSTestCase &original)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
def run(cmd)
Definition: run.py:14
#define TAG()
GrSamplerState::Filter Filter
Definition: texelsubset.cpp:39