xref: /aosp_15_r20/external/skia/tools/testrunners/unit/BazelUnitTestRunner.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2022 Google LLC
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  * This runs *all* the tests registered via the Test registry in series. If one or more fail, those
8  * error messages will be printed out and a non-zero exit code will be returned. Otherwise, the
9  * exit code will be 0.
10  */
11 
12 #include "include/core/SkString.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/base/SkDebug.h"
15 #include "tests/Test.h"
16 #include "tests/TestHarness.h"
17 #include "tools/flags/CommandLineFlags.h"
18 #include "tools/testrunners/common/TestRunner.h"
19 
20 #if defined(SK_GANESH)
21 #include "include/gpu/ganesh/GrContextOptions.h"
22 #include "include/gpu/ganesh/GrDirectContext.h"
23 #include "include/gpu/ganesh/GrTypes.h"
24 #include "include/private/gpu/ganesh/GrTypesPriv.h"
25 #include "tools/gpu/ContextType.h"
26 #include "tools/gpu/TestContext.h"
27 #endif
28 
29 #include <ctime>
30 #include <cwchar>
31 #include <functional>
32 #include <iomanip>
33 #include <sstream>
34 #include <string>
35 
36 struct tm;
37 
38 static DEFINE_string(skip, "", "Space-separated list of test cases (regexps) to skip.");
39 static DEFINE_string(
40         match,
41         "",
42         "Space-separated list of test cases (regexps) to run. Will run all tests if omitted.");
43 
44 // Set in //bazel/devicesrc but consumed by other C++ test runners.
45 static DEFINE_string(key, "", "Ignored by this test runner.");
46 static DEFINE_string(cpuName, "", "Ignored by this test runner.");
47 static DEFINE_string(gpuName, "", "Ignored by this test runner.");
48 
49 // Set in //bazel/devicesrc but only consumed by adb_test_runner.go. We cannot use the
50 // DEFINE_string macro because the flag name includes dashes.
51 [[maybe_unused]] static bool unused =
52         SkFlagInfo::CreateStringFlag("device-specific-bazel-config",
53                                      nullptr,
54                                      new CommandLineFlags::StringArray(),
55                                      nullptr,
56                                      "Ignored by this test runner.",
57                                      nullptr);
58 
59 class BazelReporter : public skiatest::Reporter {
60 public:
reportFailed(const skiatest::Failure & failure)61     void reportFailed(const skiatest::Failure& failure) override {
62         TestRunner::Log("FAIL: %s", failure.toString().c_str());
63         fFailed = true;
64     }
allowExtendedTest() const65     bool allowExtendedTest() const override { return false; }
verbose() const66     bool verbose() const override { return false; }
ok()67     bool ok() { return !fFailed; }
68 
69 private:
70     bool fFailed = false;
71 };
72 
73 #if defined(SK_GANESH)
74 namespace skiatest {
IsGLContextType(skgpu::ContextType type)75 bool IsGLContextType(skgpu::ContextType type) {
76     return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kOpenGL;
77 }
IsVulkanContextType(skgpu::ContextType type)78 bool IsVulkanContextType(skgpu::ContextType type) {
79     return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kVulkan;
80 }
IsMetalContextType(skgpu::ContextType type)81 bool IsMetalContextType(skgpu::ContextType type) {
82     return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kMetal;
83 }
IsDirect3DContextType(skgpu::ContextType type)84 bool IsDirect3DContextType(skgpu::ContextType type) {
85     return skgpu::ganesh::ContextTypeBackend(type) == GrBackendApi::kDirect3D;
86 }
IsMockContextType(skgpu::ContextType type)87 bool IsMockContextType(skgpu::ContextType type) { return type == skgpu::ContextType::kMock; }
88 
89 skgpu::ContextType compiledInContextTypes[] = {
90 #if defined(SK_GL)
91 // Use "native" instead of explicitly trying both OpenGL and OpenGL ES. Do not use GLES on
92 // desktop since tests do not account for not fixing http://skbug.com/2809
93 #if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
94         skgpu::ContextType::kGL,
95 #else
96         skgpu::ContextType::kGLES,
97 #endif
98 #endif  // defined(SK_GL)
99 #if defined(SK_VULKAN)
100         skgpu::ContextType::kVulkan,
101 #endif
102 #if defined(SK_DAWN)
103         skgpu::ContextType::kDawn,
104 #endif
105         // TODO(kjlubick) Other Ganesh backends
106         skgpu::ContextType::kMock,
107 };
108 
109 // The macros defined in Test.h eventually call into this function. For each GPU backend that is
110 // compiled in, we run the testFn with a freshly created
RunWithGaneshTestContexts(GrContextTestFn * testFn,ContextTypeFilterFn * filter,Reporter * reporter,const GrContextOptions & options)111 void RunWithGaneshTestContexts(GrContextTestFn* testFn,
112                                ContextTypeFilterFn* filter,
113                                Reporter* reporter,
114                                const GrContextOptions& options) {
115     sk_gpu_test::GrContextFactory factory(options);
116 
117     for (skgpu::ContextType ctxType : compiledInContextTypes) {
118         if (filter && !(*filter)(ctxType)) {
119             continue;
120         }
121 
122         sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(ctxType);
123         if (ctxInfo.directContext()) {
124             (*testFn)(reporter, ctxInfo);
125             // In case the test changed the current context make sure we move it back before
126             // calling flush.
127             ctxInfo.testContext()->makeCurrent();
128             // Sync so any release/finished procs get called.
129             ctxInfo.directContext()->flushAndSubmit(GrSyncCpu::kYes);
130         } else {
131             TestRunner::Log("Unable to make direct context for Ganesh test.");
132             SkASSERT(false);
133             return;
134         }
135     }
136 }
137 
138 }  // namespace skiatest
139 #endif  // #if defined(SK_GANESH)
140 
CurrentTestHarness()141 TestHarness CurrentTestHarness() { return TestHarness::kBazelUnitTestRunner; }
142 
maybeRunTest(const char * name,std::function<void ()> testFn)143 void maybeRunTest(const char* name, std::function<void()> testFn) {
144     if (!TestRunner::ShouldRunTestCase(name, FLAGS_match, FLAGS_skip)) {
145         TestRunner::Log("Skipping %s", name);
146         return;
147     }
148 
149     TestRunner::Log("Running %s", name);
150     testFn();
151     TestRunner::Log("\tDone");
152 }
153 
main(int argc,char ** argv)154 int main(int argc, char** argv) {
155     TestRunner::InitAndLogCmdlineArgs(argc, argv);
156 
157     CommandLineFlags::Parse(argc, argv);
158 
159     BazelReporter reporter;
160     for (skiatest::Test test : skiatest::TestRegistry::Range()) {
161         if (test.fTestType == skiatest::TestType::kCPU) {
162             maybeRunTest(test.fName, [&]() { test.cpu(&reporter); });
163         }
164     }
165 
166 #if defined(SK_GANESH)
167     GrContextOptions grCtxOptions;
168     // TODO(kjlubick) DM has grContextOptions set via flags. Should this runner have that too?
169     grCtxOptions.fExecutor = nullptr;
170     grCtxOptions.fAllowPathMaskCaching = true;
171     grCtxOptions.fFailFlushTimeCallbacks = false;
172     grCtxOptions.fAllPathsVolatile = false;
173     grCtxOptions.fGpuPathRenderers = GpuPathRenderers::kDefault;
174     grCtxOptions.fDisableDriverCorrectnessWorkarounds = false;
175     grCtxOptions.fResourceCacheLimitOverride = -1;
176     grCtxOptions.fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo;
177     for (skiatest::Test test : skiatest::TestRegistry::Range()) {
178         if (test.fTestType == skiatest::TestType::kGanesh) {
179             maybeRunTest(test.fName, [&]() { test.ganesh(&reporter, grCtxOptions); });
180         }
181     }
182 #endif
183 
184     // TODO(kjlubick) Graphite support
185 
186     if (reporter.ok()) {
187         TestRunner::Log("PASS");
188         return 0;
189     }
190     TestRunner::Log("FAIL");
191     return 1;
192 }
193