Unreviewed, rolling out r241620.
[WebKit-https.git] / Tools / WebKitTestRunner / cocoa / TestControllerCocoa.mm
index e798cae..fe3bd6e 100644 (file)
 
 #import "CrashReporterInfo.h"
 #import "PlatformWebView.h"
+#import "StringFunctions.h"
 #import "TestInvocation.h"
 #import "TestRunnerWKWebView.h"
+#import "TestWebsiteDataStoreDelegate.h"
 #import <Foundation/Foundation.h>
+#import <Security/SecItem.h>
 #import <WebKit/WKContextConfigurationRef.h>
+#import <WebKit/WKCookieManager.h>
 #import <WebKit/WKPreferencesRefPrivate.h>
 #import <WebKit/WKProcessPoolPrivate.h>
 #import <WebKit/WKStringCF.h>
 #import <WebKit/WKWebViewConfiguration.h>
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
-#import <WebKit/_WKProcessPoolConfiguration.h>
+#import <WebKit/WKWebsiteDataRecordPrivate.h>
+#import <WebKit/WKWebsiteDataStorePrivate.h>
+#import <WebKit/WKWebsiteDataStoreRef.h>
+#import <WebKit/_WKApplicationManifest.h>
 #import <WebKit/_WKUserContentExtensionStore.h>
 #import <WebKit/_WKUserContentExtensionStorePrivate.h>
 #import <wtf/MainThread.h>
@@ -49,17 +56,42 @@ namespace WTR {
 
 static WKWebViewConfiguration *globalWebViewConfiguration;
 
+#if WK_API_ENABLED
+static TestWebsiteDataStoreDelegate *globalWebsiteDataStoreDelegateClient;
+#endif
+
 void initializeWebViewConfiguration(const char* libraryPath, WKStringRef injectedBundlePath, WKContextRef context, WKContextConfigurationRef contextConfiguration)
 {
 #if WK_API_ENABLED
     [globalWebViewConfiguration release];
     globalWebViewConfiguration = [[WKWebViewConfiguration alloc] init];
 
-    globalWebViewConfiguration.processPool = WTF::adoptNS([[WKProcessPool alloc] _initWithConfiguration:(_WKProcessPoolConfiguration *)contextConfiguration]).get();
-    globalWebViewConfiguration.websiteDataStore = (WKWebsiteDataStore *)WKContextGetWebsiteDataStore(context);
+    globalWebViewConfiguration.processPool = (__bridge WKProcessPool *)context;
+    globalWebViewConfiguration.websiteDataStore = (__bridge WKWebsiteDataStore *)WKContextGetWebsiteDataStore(context);
     globalWebViewConfiguration._allowUniversalAccessFromFileURLs = YES;
+    globalWebViewConfiguration._applePayEnabled = YES;
+
+    WKCookieManagerSetStorageAccessAPIEnabled(WKContextGetCookieManager(context), true);
+
+    WKWebsiteDataStore* poolWebsiteDataStore = (__bridge WKWebsiteDataStore *)WKContextGetWebsiteDataStore((__bridge WKContextRef)globalWebViewConfiguration.processPool);
+    if (libraryPath) {
+        String cacheStorageDirectory = String(libraryPath) + '/' + "CacheStorage";
+        [poolWebsiteDataStore _setCacheStorageDirectory: cacheStorageDirectory];
+
+        String serviceWorkerRegistrationDirectory = String(libraryPath) + '/' + "ServiceWorkers";
+        [poolWebsiteDataStore _setServiceWorkerRegistrationDirectory: serviceWorkerRegistrationDirectory];
+    }
 
-#if TARGET_OS_IPHONE
+    [globalWebViewConfiguration.websiteDataStore _setResourceLoadStatisticsEnabled:YES];
+    [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetShouldSubmitTelemetry:NO];
+
+#if WK_API_ENABLED
+    [globalWebsiteDataStoreDelegateClient release];
+    globalWebsiteDataStoreDelegateClient = [[TestWebsiteDataStoreDelegate alloc] init];
+    [globalWebViewConfiguration.websiteDataStore set_delegate:globalWebsiteDataStoreDelegateClient];
+#endif
+
+#if PLATFORM(IOS_FAMILY)
     globalWebViewConfiguration.allowsInlineMediaPlayback = YES;
     globalWebViewConfiguration._inlineMediaPlaybackRequiresPlaysInlineAttribute = NO;
     globalWebViewConfiguration._invisibleAutoplayNotPermitted = NO;
@@ -68,29 +100,94 @@ void initializeWebViewConfiguration(const char* libraryPath, WKStringRef injecte
 #endif
     globalWebViewConfiguration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
 #endif
+
+#if USE(SYSTEM_PREVIEW)
+    globalWebViewConfiguration._systemPreviewEnabled = YES;
+#endif
+}
+
+void TestController::cocoaPlatformInitialize()
+{
+    const char* dumpRenderTreeTemp = libraryPathForTesting();
+    if (!dumpRenderTreeTemp)
+        return;
+
+    String resourceLoadStatisticsFolder = String(dumpRenderTreeTemp) + '/' + "ResourceLoadStatistics";
+    [[NSFileManager defaultManager] createDirectoryAtPath:resourceLoadStatisticsFolder withIntermediateDirectories:YES attributes:nil error: nil];
+    String fullBrowsingSessionResourceLog = resourceLoadStatisticsFolder + '/' + "full_browsing_session_resourceLog.plist";
+    NSDictionary *resourceLogPlist = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithInt:1], @"version", nil];
+    if (![resourceLogPlist writeToFile:fullBrowsingSessionResourceLog atomically:YES])
+        WTFCrash();
+    [resourceLogPlist release];
+}
+
+WKContextRef TestController::platformContext()
+{
+#if WK_API_ENABLED
+    return (__bridge WKContextRef)globalWebViewConfiguration.processPool;
+#else
+    return nullptr;
+#endif
 }
 
 WKPreferencesRef TestController::platformPreferences()
 {
 #if WK_API_ENABLED
-    return (WKPreferencesRef)globalWebViewConfiguration.preferences;
+    return (__bridge WKPreferencesRef)globalWebViewConfiguration.preferences;
 #else
     return nullptr;
 #endif
 }
 
+void TestController::platformAddTestOptions(TestOptions& options) const
+{
+    if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EnableProcessSwapOnNavigation"])
+        options.enableProcessSwapOnNavigation = true;
+    if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EnableProcessSwapOnWindowOpen"])
+        options.enableProcessSwapOnWindowOpen = true;
+}
+
 void TestController::platformCreateWebView(WKPageConfigurationRef, const TestOptions& options)
 {
 #if WK_API_ENABLED
     RetainPtr<WKWebViewConfiguration> copiedConfiguration = adoptNS([globalWebViewConfiguration copy]);
-#if TARGET_OS_IPHONE
+
+#if PLATFORM(IOS_FAMILY)
     if (options.useDataDetection)
         [copiedConfiguration setDataDetectorTypes:WKDataDetectorTypeAll];
     if (options.ignoresViewportScaleLimits)
         [copiedConfiguration setIgnoresViewportScaleLimits:YES];
+    if (options.useCharacterSelectionGranularity)
+        [copiedConfiguration setSelectionGranularity:WKSelectionGranularityCharacter];
+    if (options.useCharacterSelectionGranularity)
+        [copiedConfiguration setSelectionGranularity:WKSelectionGranularityCharacter];
 #endif
 
+    if (options.enableAttachmentElement)
+        [copiedConfiguration _setAttachmentElementEnabled:YES];
+
+    if (options.enableColorFilter)
+        [copiedConfiguration _setColorFilterEnabled:YES];
+
+    if (options.enableEditableImages)
+        [copiedConfiguration _setEditableImagesEnabled:YES];
+
+    if (options.enableUndoManagerAPI)
+        [copiedConfiguration _setUndoManagerAPIEnabled:YES];
+
+    if (options.applicationManifest.length()) {
+        auto manifestPath = [NSString stringWithUTF8String:options.applicationManifest.c_str()];
+        NSString *text = [NSString stringWithContentsOfFile:manifestPath usedEncoding:nullptr error:nullptr];
+        [copiedConfiguration _setApplicationManifest:[_WKApplicationManifest applicationManifestFromJSON:text manifestURL:nil documentURL:nil]];
+    }
+
     m_mainWebView = std::make_unique<PlatformWebView>(copiedConfiguration.get(), options);
+
+    if (options.punchOutWhiteBackgroundsInDarkMode)
+        m_mainWebView->setDrawsBackground(false);
+
+    if (options.editable)
+        m_mainWebView->setEditable(true);
 #else
     m_mainWebView = std::make_unique<PlatformWebView>(globalWebViewConfiguration, options);
 #endif
@@ -111,32 +208,71 @@ WKContextRef TestController::platformAdjustContext(WKContextRef context, WKConte
 {
 #if WK_API_ENABLED
     initializeWebViewConfiguration(libraryPathForTesting(), injectedBundlePath(), context, contextConfiguration);
-    return (WKContextRef)globalWebViewConfiguration.processPool;
+    return (__bridge WKContextRef)globalWebViewConfiguration.processPool;
 #else
     return nullptr;
 #endif
 }
 
-void TestController::platformRunUntil(bool& done, double timeout)
+void TestController::platformRunUntil(bool& done, WTF::Seconds timeout)
 {
-    NSDate *endDate = (timeout > 0) ? [NSDate dateWithTimeIntervalSinceNow:timeout] : [NSDate distantFuture];
+    NSDate *endDate = (timeout > 0_s) ? [NSDate dateWithTimeIntervalSinceNow:timeout.seconds()] : [NSDate distantFuture];
 
     while (!done && [endDate compare:[NSDate date]] == NSOrderedDescending)
         [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];
 }
 
-void TestController::cocoaResetStateToConsistentValues()
+static NSCalendar *swizzledCalendar()
+{
+    return [NSCalendar calendarWithIdentifier:TestController::singleton().getOverriddenCalendarIdentifier().get()];
+}
+    
+RetainPtr<NSString> TestController::getOverriddenCalendarIdentifier() const
+{
+    return m_overriddenCalendarIdentifier;
+}
+
+void TestController::setDefaultCalendarType(NSString *identifier)
+{
+    m_overriddenCalendarIdentifier = identifier;
+    if (!m_calendarSwizzler)
+        m_calendarSwizzler = std::make_unique<ClassMethodSwizzler>([NSCalendar class], @selector(currentCalendar), reinterpret_cast<IMP>(swizzledCalendar));
+}
+
+void TestController::resetContentExtensions()
 {
 #if WK_API_ENABLED
     __block bool doneRemoving = false;
     [[_WKUserContentExtensionStore defaultStore] removeContentExtensionForIdentifier:@"TestContentExtensions" completionHandler:^(NSError *error) {
         doneRemoving = true;
     }];
-    platformRunUntil(doneRemoving, 0);
+    platformRunUntil(doneRemoving, noTimeout);
     [[_WKUserContentExtensionStore defaultStore] _removeAllContentExtensions];
 
-    if (PlatformWebView* webView = mainWebView())
-        [webView->platformView().configuration.userContentController _removeAllUserContentFilters];
+    if (auto* webView = mainWebView()) {
+        TestRunnerWKWebView *platformView = webView->platformView();
+        [platformView.configuration.userContentController _removeAllUserContentFilters];
+    }
+#endif
+}
+
+void TestController::cocoaResetStateToConsistentValues(const TestOptions& options)
+{
+#if WK_API_ENABLED
+    m_calendarSwizzler = nullptr;
+    m_overriddenCalendarIdentifier = nil;
+    
+    if (auto* webView = mainWebView()) {
+        TestRunnerWKWebView *platformView = webView->platformView();
+        platformView._viewScale = 1;
+        platformView._minimumEffectiveDeviceWidth = 0;
+
+        // Toggle on before the test, and toggle off after the test.
+        if (options.shouldShowSpellCheckingDots)
+            [platformView toggleContinuousSpellChecking:nil];
+    }
+
+    [globalWebsiteDataStoreDelegateClient setAllowRaisingQuota: false];
 #endif
 }
 
@@ -153,7 +289,7 @@ unsigned TestController::imageCountInGeneralPasteboard() const
 {
 #if PLATFORM(MAC)
     NSData *data = [[NSPasteboard generalPasteboard] dataForType:WebArchivePboardType];
-#elif PLATFORM(IOS)
+#elif PLATFORM(IOS_FAMILY)
     NSData *data = [[UIPasteboard generalPasteboard] valueForPasteboardType:WebArchivePboardType];
 #endif
     if (!data)
@@ -176,4 +312,123 @@ unsigned TestController::imageCountInGeneralPasteboard() const
     return imagesArray.count;
 }
 
+void TestController::removeAllSessionCredentials()
+{
+#if WK_API_ENABLED
+    auto types = adoptNS([[NSSet alloc] initWithObjects:_WKWebsiteDataTypeCredentials, nil]);
+    [globalWebViewConfiguration.websiteDataStore removeDataOfTypes:types.get() modifiedSince:[NSDate distantPast] completionHandler:^() {
+        m_currentInvocation->didRemoveAllSessionCredentials();
+    }];
+#endif
+}
+
+void TestController::getAllStorageAccessEntries()
+{
+#if WK_API_ENABLED
+    auto* parentView = mainWebView();
+    if (!parentView)
+        return;
+
+    [globalWebViewConfiguration.websiteDataStore _getAllStorageAccessEntriesFor:parentView->platformView() completionHandler:^(NSArray<NSString *> *nsDomains) {
+        Vector<String> domains;
+        domains.reserveInitialCapacity(nsDomains.count);
+        for (NSString *domain : nsDomains)
+            domains.uncheckedAppend(domain);
+        m_currentInvocation->didReceiveAllStorageAccessEntries(domains);
+    }];
+#endif
+}
+
+void TestController::injectUserScript(WKStringRef script)
+{
+#if WK_API_ENABLED
+    auto userScript = adoptNS([[WKUserScript alloc] initWithSource: toWTFString(script) injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]);
+
+    [[globalWebViewConfiguration userContentController] addUserScript: userScript.get()];
+#endif
+}
+
+void TestController::addTestKeyToKeychain(const String& privateKeyBase64, const String& attrLabel, const String& applicationTagBase64)
+{
+    // FIXME(182772)
+#if PLATFORM(IOS_FAMILY)
+    NSDictionary* options = @{
+        (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom,
+        (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+        (id)kSecAttrKeySizeInBits: @256
+    };
+    CFErrorRef errorRef = nullptr;
+    auto key = adoptCF(SecKeyCreateWithData(
+        (__bridge CFDataRef)adoptNS([[NSData alloc] initWithBase64EncodedString:privateKeyBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(),
+        (__bridge CFDictionaryRef)options,
+        &errorRef
+    ));
+    ASSERT(!errorRef);
+
+    NSDictionary* addQuery = @{
+        (id)kSecValueRef: (id)key.get(),
+        (id)kSecClass: (id)kSecClassKey,
+        (id)kSecAttrLabel: attrLabel,
+        (id)kSecAttrApplicationTag: adoptNS([[NSData alloc] initWithBase64EncodedString:applicationTagBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get()
+    };
+    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
+    ASSERT_UNUSED(status, !status);
+#endif
+}
+
+void TestController::cleanUpKeychain(const String& attrLabel)
+{
+    // FIXME(182772)
+#if PLATFORM(IOS_FAMILY)
+    NSDictionary* deleteQuery = @{
+        (id)kSecClass: (id)kSecClassKey,
+        (id)kSecAttrLabel: attrLabel
+    };
+    SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
+#endif
+}
+
+bool TestController::keyExistsInKeychain(const String& attrLabel, const String& applicationTagBase64)
+{
+    // FIXME(182772)
+#if PLATFORM(IOS_FAMILY)
+    NSDictionary *query = @{
+        (id)kSecClass: (id)kSecClassKey,
+        (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate,
+        (id)kSecAttrLabel: attrLabel,
+        (id)kSecAttrApplicationTag: adoptNS([[NSData alloc] initWithBase64EncodedString:applicationTagBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters]).get(),
+    };
+    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
+    if (!status)
+        return true;
+    ASSERT(status == errSecItemNotFound);
+#endif
+    return false;
+}
+
+void TestController::allowCacheStorageQuotaIncrease()
+{
+#if WK_API_ENABLED
+    [globalWebsiteDataStoreDelegateClient setAllowRaisingQuota: true];
+#endif
+}
+
+bool TestController::canDoServerTrustEvaluationInNetworkProcess() const
+{
+#if HAVE(CFNETWORK_NSURLSESSION_STRICTRUSTEVALUATE)
+    return true;
+#else
+    return false;
+#endif
+}
+
+bool TestController::isDoingMediaCapture() const
+{
+#if WK_API_ENABLED
+    return m_mainWebView->platformView()._mediaCaptureState != _WKMediaCaptureStateNone;
+#else
+    return false;
+#endif
+}
+
 } // namespace WTR