blob: 8b93cab90fbede45eb784030bb66c1fd6bff5faa [file] [edit]
/*
* Copyright (C) 2026 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Mirrors Runner/TestWebKitAPI.swift (the Xcode @main). Drop and switch to the
// Swift runner once the CMake port supports Swift + Swift Testing.
#import "config.h"
#import "Runner/TestsController.h"
#import <Cocoa/Cocoa.h>
#import <objc/runtime.h>
#import <string>
#import <vector>
#import <wtf/cocoa/RuntimeApplicationChecksCocoa.h>
namespace {
void resetPersistentDomain()
{
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:@"TestWebKitAPI"];
}
NSMutableDictionary *mutableArgumentDomain()
{
NSDictionary *current = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSArgumentDomain];
if (current)
return [current mutableCopy];
return [NSMutableDictionary dictionary];
}
void writeArgumentDomain(NSDictionary *domain)
{
[[NSUserDefaults standardUserDefaults] setVolatileDomain:domain forName:NSArgumentDomain];
}
void applyAlwaysSetDefaults()
{
NSMutableDictionary *args = mutableArgumentDomain();
// FIXME: Switch to overlay scrollbars (the platform default) once tests are updated.
args[@"NSOverlayScrollersEnabled"] = @NO;
args[@"AppleShowScrollBars"] = @"Always";
// FIXME: Remove once rdar://159372811 is fixed.
args[@"NSEventConcurrentProcessingEnabled"] = @NO;
writeArgumentDomain(args);
}
void setBoolArgumentDomain(NSString *key, BOOL value)
{
NSMutableDictionary *args = mutableArgumentDomain();
args[key] = @(value);
writeArgumentDomain(args);
}
void forceSiteIsolation()
{
Class cls = NSClassFromString(@"WKPreferences");
SEL sel = NSSelectorFromString(@"_forceSiteIsolationAlwaysOnForTesting");
if (!cls || ![cls respondsToSelector:sel])
return;
// performSelector returns void; the leak warning is spurious.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel];
#pragma clang diagnostic pop
}
std::vector<std::string> translateArgv(int argc, char** argv)
{
std::vector<std::string> out;
out.reserve(argc + 8);
if (argc > 0)
out.emplace_back(argv[0]);
std::vector<std::string> posFilters;
std::vector<std::string> negFilters;
bool listTests = false;
bool force = false;
bool pretty = false;
bool hasRepetitions = false;
std::string repetitions;
auto needsValue = [&](int& i, const char* /*flag*/) -> const char* {
if (i + 1 >= argc)
return nullptr;
return argv[++i];
};
for (int i = 1; i < argc; ++i) {
std::string token { argv[i] };
if (token == "--filter") {
if (const char* value = needsValue(i, "--filter"))
posFilters.emplace_back(value);
continue;
}
if (token == "--skip") {
if (const char* value = needsValue(i, "--skip"))
negFilters.emplace_back(value);
continue;
}
if (token == "--repetitions") {
if (const char* value = needsValue(i, "--repetitions")) {
repetitions = value;
hasRepetitions = true;
}
continue;
}
if (token == "--list-tests") {
listTests = true;
continue;
}
if (token == "--force") {
force = true;
continue;
}
if (token == "--pretty") {
pretty = true;
continue;
}
if (token == "--site-isolation") {
forceSiteIsolation();
continue;
}
if (token == "--remote-layer-tree") {
setBoolArgumentDomain(@"WebKit2UseRemoteLayerTreeDrawingArea", YES);
continue;
}
if (token == "--no-remote-layer-tree") {
setBoolArgumentDomain(@"WebKit2UseRemoteLayerTreeDrawingArea", NO);
continue;
}
if (token == "--use-gpu-process") {
setBoolArgumentDomain(@"WebKit2GPUProcessForDOMRendering", YES);
continue;
}
if (token == "--no-use-gpu-process") {
setBoolArgumentDomain(@"WebKit2GPUProcessForDOMRendering", NO);
continue;
}
if (token == "--parallel")
continue;
out.push_back(WTF::move(token));
}
if (listTests)
out.emplace_back("--gtest_list_tests");
if (pretty)
out.emplace_back("--gtest_brief=0");
if (force)
out.emplace_back("--gtest_also_run_disabled_tests");
// gtest treats a leading '-' in --gtest_filter as "exclude only".
if (!posFilters.empty() || !negFilters.empty()) {
std::string filter = "--gtest_filter=";
for (size_t i = 0; i < posFilters.size(); ++i) {
if (i)
filter += ':';
filter += posFilters[i];
}
if (!negFilters.empty()) {
filter += '-';
for (size_t i = 0; i < negFilters.size(); ++i) {
if (i)
filter += ':';
filter += negFilters[i];
}
}
out.push_back(WTF::move(filter));
}
if (hasRepetitions)
out.emplace_back("--gtest_repeat=" + repetitions);
return out;
}
} // namespace
int main(int argc, char** argv)
{
@autoreleasepool {
WTF::enableAllSDKAlignedBehaviors();
resetPersistentDomain();
applyAlwaysSetDefaults();
auto translated = translateArgv(argc, argv);
std::vector<char*> ptrs;
ptrs.reserve(translated.size() + 1);
for (auto& s : translated)
ptrs.push_back(s.data());
ptrs.push_back(nullptr);
int newArgc = static_cast<int>(translated.size());
// Instantiate NSApp; some tests rely on it being non-nil.
(void)[NSApplication sharedApplication];
return TestWebKitAPI::TestsController::singleton().run(newArgc, ptrs.data()) ? EXIT_SUCCESS : EXIT_FAILURE;
}
}