blob: 3b14876744b4a4950ab341a37d06ff78c0fcb0e0 [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. AND ITS CONTRIBUTORS ``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 ITS 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.
import Foundation
import struct Swift.String
#if WTF_PLATFORM_MAC
private import AppKit
#endif
@main
struct TestWebKitAPI {
private static func forceSiteIsolationForTesting() {
let theClass = NSClassFromString("WKPreferences") as? NSObject.Type
let sel = Selector(("_forceSiteIsolationAlwaysOnForTesting"))
if let theClass, theClass.responds(to: sel) {
unsafe theClass.perform(sel)
}
}
private func handleArguments(_ argumentDefaults: inout [String: Any]) {
// FIXME: We should switch these defaults to use overlay scrollbars, since they are the
// default on the platform, but a variety of tests will need changes.
argumentDefaults["NSOverlayScrollersEnabled"] = false
argumentDefaults["AppleShowScrollBars"] = "Always"
// FIXME: Remove once the root cause is fixed in rdar://159372811
argumentDefaults["NSEventConcurrentProcessingEnabled"] = false
for argument in CommandLine.arguments[1...] {
// These defaults are not propagated manually but are only consulted in the UI process.
switch argument {
case "--remote-layer-tree":
argumentDefaults["WebKit2UseRemoteLayerTreeDrawingArea"] = true
case "--no-remote-layer-tree":
argumentDefaults["WebKit2UseRemoteLayerTreeDrawingArea"] = false
case "--use-gpu-process":
argumentDefaults["WebKit2GPUProcessForDOMRendering"] = true
case "--no-use-gpu-process":
argumentDefaults["WebKit2GPUProcessForDOMRendering"] = false
case "--site-isolation-enabled-by-default":
Self.forceSiteIsolationForTesting()
default:
break
}
}
}
@MainActor
private func configure() -> TestRunner.Configuration {
#if WTF_PLATFORM_MACCATALYST
UINSApplicationInstantiate()
#endif
UserDefaults.standard.removePersistentDomain(forName: "TestWebKitAPI")
var argumentDomain = UserDefaults.standard.volatileDomain(forName: UserDefaults.argumentDomain)
#if WTF_PLATFORM_MAC
// CAUTION: Defaults set here are not automatically propagated to the
// Web Content process. Those listed below are propagated manually.
handleArguments(&argumentDomain)
#endif
UserDefaults.standard.setVolatileDomain(argumentDomain, forName: UserDefaults.argumentDomain)
#if !WTF_PLATFORM_MAC
let uiKitDefaults = UserDefaults(suiteName: "com.apple.UIKit")
uiKitDefaults?
.register(
defaults: [
"ForceLegacyHostingRemoteViewControllerForService": "com.apple.ScreenTime.ScreenTimeWebExtension"
]
)
#endif // !WTF_PLATFORM_MAC
TestWebKitAPIEnableAllSDKAlignedBehaviors()
#if WTF_PLATFORM_MAC
_ = NSApplication.shared
#endif
return TestRunner.Configuration(parsing: CommandLine.arguments)
}
@MainActor
private func runGoogleTests(with configuration: TestRunner.Configuration) async throws -> (passed: Bool, didRun: Bool) {
let (passed, didRun) = try await GoogleTestsController.shared.run(with: configuration)
if didRun && !configuration.listTests {
exit(passed ? EXIT_SUCCESS : EXIT_FAILURE)
}
return (passed, didRun)
}
@MainActor
private func runSwiftTests(with configuration: TestRunner.Configuration, googleTestsPassed: Bool) async throws {
let (passed, didRun) = try await SwiftTestsController.shared.run(with: configuration)
if didRun && !configuration.listTests {
exit(passed ? EXIT_SUCCESS : EXIT_FAILURE)
}
exit(googleTestsPassed && passed ? EXIT_SUCCESS : EXIT_FAILURE)
}
static func main() async throws {
let instance = TestWebKitAPI()
let configuration = instance.configure()
if configuration.help {
print(configuration.usage)
exit(EXIT_SUCCESS)
}
let (googleTestsPassed, didRunGoogleTests) = try await instance.runGoogleTests(with: configuration)
#if WTF_PLATFORM_MAC
// Some tests synthesize HID events that the system delivers only to the frontmost app, and
// delivery requires a running AppKit event loop. Only start it when we will actually run
// Swift tests: i.e. when running (not listing) tests and no GoogleTest tests have run.
if !configuration.listTests && !didRunGoogleTests {
let application = NSApplication.shared
application.setActivationPolicy(.regular)
Task { @MainActor in
do {
try await instance.runSwiftTests(with: configuration, googleTestsPassed: googleTestsPassed)
} catch {
exit(EXIT_FAILURE)
}
}
application.activate(ignoringOtherApps: true)
application.run()
return
}
#endif
// Non-macOS, or macOS when listing tests / after GoogleTest tests ran: no event loop needed.
try await instance.runSwiftTests(with: configuration, googleTestsPassed: googleTestsPassed)
}
}