| /* |
| * Copyright (C) 2020 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 "config.h" |
| |
| #if WK_HAVE_C_SPI |
| |
| #import "PlatformUtilities.h" |
| #import "TestWKWebView.h" |
| #import <WebKit/PreferenceObserver.h> |
| |
| #import <wtf/ObjCRuntimeExtras.h> |
| |
| static bool receivedPreferenceNotification = false; |
| |
| @interface WKTestPreferenceObserver : WKPreferenceObserver |
| - (void)preferenceDidChange:(NSString *)domain key:(NSString *)key encodedValue:(NSString *)encodedValue; |
| @end |
| |
| @implementation WKTestPreferenceObserver |
| - (void)preferenceDidChange:(NSString *)domain key:(NSString *)key encodedValue:(NSString *)encodedValue |
| { |
| receivedPreferenceNotification = true; |
| [super preferenceDidChange:domain key:key encodedValue:encodedValue]; |
| } |
| @end |
| |
| static const CFStringRef testKey = CFSTR("testkey"); |
| static const CFStringRef globalDomain = CFSTR("kCFPreferencesAnyApplication"); |
| static const CFStringRef testDomain = CFSTR("com.apple.avfoundation"); |
| |
| static void waitForPreferenceSynchronization() |
| { |
| __block bool didSynchronize = false; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| didSynchronize = true; |
| }); |
| TestWebKitAPI::Util::run(&didSynchronize); |
| } |
| |
| TEST(WebKit, PreferenceObserver) |
| { |
| receivedPreferenceNotification = false; |
| |
| CFPreferencesSetAppValue(testKey, CFSTR("1"), testDomain); |
| |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| CFPreferencesSetAppValue(testKey, CFSTR("2"), testDomain); |
| |
| TestWebKitAPI::Util::run(&receivedPreferenceNotification); |
| } |
| |
| TEST(WebKit, PreferenceObserverArray) |
| { |
| receivedPreferenceNotification = false; |
| |
| NSArray *array = @[@1, @2, @3]; |
| |
| auto userDefaults = adoptNS([[NSUserDefaults alloc] initWithSuiteName:(NSString *)testDomain]); |
| [userDefaults.get() setObject:array forKey:(NSString *)testKey]; |
| |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| NSArray *changedArray = @[@3, @2, @1]; |
| [userDefaults.get() setObject:changedArray forKey:(NSString *)testKey]; |
| |
| TestWebKitAPI::Util::run(&receivedPreferenceNotification); |
| } |
| |
| TEST(WebKit, PreferenceChanges) |
| { |
| CFPreferencesSetAppValue(testKey, CFSTR("0"), testDomain); |
| |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| WKRetainPtr<WKContextRef> context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest")); |
| configuration.get().processPool = (WKProcessPool *)context.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]); |
| [webView synchronouslyLoadTestPageNamed:@"simple"]; |
| |
| receivedPreferenceNotification = false; |
| |
| CFPreferencesSetAppValue(testKey, CFSTR("1"), testDomain); |
| |
| EXPECT_EQ(1, CFPreferencesGetAppIntegerValue(testKey, testDomain, nullptr)); |
| |
| TestWebKitAPI::Util::run(&receivedPreferenceNotification); |
| |
| auto preferenceValue = [&] { |
| waitForPreferenceSynchronization(); |
| NSString *js = [NSString stringWithFormat:@"window.internals.readPreferenceInteger(\"%@\",\"%@\")", (NSString *)testDomain, (NSString *)testKey]; |
| return [webView stringByEvaluatingJavaScript:js].intValue; |
| }; |
| |
| EXPECT_EQ(preferenceValue(), 1); |
| |
| receivedPreferenceNotification = false; |
| |
| CFPreferencesSetAppValue(testKey, CFSTR("2"), testDomain); |
| |
| TestWebKitAPI::Util::run(&receivedPreferenceNotification); |
| |
| EXPECT_EQ(preferenceValue(), 2); |
| } |
| |
| TEST(WebKit, GlobalPreferenceChangesUsingDefaultsWrite) |
| { |
| system([NSString stringWithFormat:@"defaults write %@ %@ 0", (__bridge id)globalDomain, (__bridge id)testKey].UTF8String); |
| |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| WKRetainPtr<WKContextRef> context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest")); |
| configuration.get().processPool = (WKProcessPool *)context.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]); |
| [webView synchronouslyLoadTestPageNamed:@"simple"]; |
| |
| receivedPreferenceNotification = false; |
| |
| system([NSString stringWithFormat:@"defaults write %@ %@ 1", (__bridge id)globalDomain, (__bridge id)testKey].UTF8String); |
| |
| EXPECT_EQ(1, CFPreferencesGetAppIntegerValue(testKey, globalDomain, nullptr)); |
| |
| TestWebKitAPI::Util::run(&receivedPreferenceNotification); |
| |
| auto preferenceValue = [&] { |
| waitForPreferenceSynchronization(); |
| NSString *js = [NSString stringWithFormat:@"window.internals.readPreferenceInteger(\"%@\",\"%@\")", (NSString *)globalDomain, (NSString *)testKey]; |
| return [webView stringByEvaluatingJavaScript:js].intValue; |
| }; |
| |
| EXPECT_EQ(preferenceValue(), 1); |
| |
| receivedPreferenceNotification = false; |
| |
| system([NSString stringWithFormat:@"defaults write %@ %@ 2", (__bridge id)globalDomain, (__bridge id)testKey].UTF8String); |
| |
| TestWebKitAPI::Util::run(&receivedPreferenceNotification); |
| |
| EXPECT_EQ(preferenceValue(), 2); |
| } |
| |
| TEST(WebKit, PreferenceChangesArray) |
| { |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| NSArray *array = @[@1, @2, @3]; |
| |
| auto userDefaults = adoptNS([[NSUserDefaults alloc] initWithSuiteName:(NSString *)testDomain]); |
| [userDefaults.get() setObject:array forKey:(NSString *)testKey]; |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| WKRetainPtr<WKContextRef> context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest")); |
| configuration.get().processPool = (WKProcessPool *)context.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]); |
| |
| auto preferenceValue = [&] { |
| waitForPreferenceSynchronization(); |
| NSString *js = [NSString stringWithFormat:@"window.internals.encodedPreferenceValue(\"%@\",\"%@\")", (NSString *)testDomain, (NSString *)testKey]; |
| return [webView stringByEvaluatingJavaScript:js]; |
| }; |
| |
| preferenceValue(); |
| |
| NSArray *changedArray = @[@3, @2, @1]; |
| [userDefaults.get() setObject:changedArray forKey:(NSString *)testKey]; |
| |
| auto encodedString = preferenceValue(); |
| auto encodedData = adoptNS([[NSData alloc] initWithBase64EncodedString:encodedString options:0]); |
| ASSERT_TRUE(encodedData); |
| NSError *err = nil; |
| auto object = retainPtr([NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:encodedData.get() error:&err]); |
| ASSERT_TRUE(!err); |
| ASSERT_TRUE(object); |
| ASSERT_TRUE([object isEqual:changedArray]); |
| } |
| |
| TEST(WebKit, PreferenceChangesDictionary) |
| { |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| NSDictionary *dict = @{ |
| @"a" : @1, |
| @"b" : @2, |
| }; |
| |
| auto userDefaults = adoptNS([[NSUserDefaults alloc] initWithSuiteName:(NSString *)testDomain]); |
| [userDefaults.get() setObject:dict forKey:(NSString *)testKey]; |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| WKRetainPtr<WKContextRef> context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest")); |
| configuration.get().processPool = (WKProcessPool *)context.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]); |
| |
| auto preferenceValue = [&] { |
| waitForPreferenceSynchronization(); |
| NSString *js = [NSString stringWithFormat:@"window.internals.encodedPreferenceValue(\"%@\",\"%@\")", (NSString *)testDomain, (NSString *)testKey]; |
| return [webView stringByEvaluatingJavaScript:js]; |
| }; |
| |
| preferenceValue(); |
| |
| NSDictionary *changedDict = @{ |
| @"a" : @1, |
| @"b" : @2, |
| @"c" : @3, |
| }; |
| [userDefaults.get() setObject:changedDict forKey:(NSString *)testKey]; |
| |
| auto encodedString = preferenceValue(); |
| auto encodedData = adoptNS([[NSData alloc] initWithBase64EncodedString:encodedString options:0]); |
| ASSERT_TRUE(encodedData); |
| NSError *err = nil; |
| auto object = retainPtr([NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:encodedData.get() error:&err]); |
| ASSERT_TRUE(!err); |
| ASSERT_TRUE(object); |
| ASSERT_TRUE([object isEqual:changedDict]); |
| } |
| |
| TEST(WebKit, PreferenceChangesData) |
| { |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| NSData *data = [NSData dataWithBytes:"abc" length:3]; |
| |
| auto userDefaults = adoptNS([[NSUserDefaults alloc] initWithSuiteName:(NSString *)testDomain]); |
| [userDefaults.get() setObject:data forKey:(NSString *)testKey]; |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| WKRetainPtr<WKContextRef> context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest")); |
| configuration.get().processPool = (WKProcessPool *)context.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]); |
| |
| auto preferenceValue = [&] { |
| waitForPreferenceSynchronization(); |
| NSString *js = [NSString stringWithFormat:@"window.internals.encodedPreferenceValue(\"%@\",\"%@\")", (NSString *)testDomain, (NSString *)testKey]; |
| return [webView stringByEvaluatingJavaScript:js]; |
| }; |
| |
| preferenceValue(); |
| |
| NSData *changedData = [NSData dataWithBytes:"abcd" length:4]; |
| [userDefaults.get() setObject:changedData forKey:(NSString *)testKey]; |
| |
| auto encodedString = preferenceValue(); |
| auto encodedData = adoptNS([[NSData alloc] initWithBase64EncodedString:encodedString options:0]); |
| ASSERT_TRUE(encodedData); |
| NSError *err = nil; |
| auto object = retainPtr([NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:encodedData.get() error:&err]); |
| ASSERT_TRUE(!err); |
| ASSERT_TRUE(object); |
| ASSERT_TRUE([object isEqual:changedData]); |
| } |
| |
| TEST(WebKit, PreferenceChangesDate) |
| { |
| auto observer = adoptNS([[WKTestPreferenceObserver alloc] init]); |
| |
| NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0]; |
| |
| auto userDefaults = adoptNS([[NSUserDefaults alloc] initWithSuiteName:(NSString *)testDomain]); |
| [userDefaults.get() setObject:date forKey:(NSString *)testKey]; |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| WKRetainPtr<WKContextRef> context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest")); |
| configuration.get().processPool = (WKProcessPool *)context.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]); |
| |
| auto preferenceValue = [&] { |
| waitForPreferenceSynchronization(); |
| NSString *js = [NSString stringWithFormat:@"window.internals.encodedPreferenceValue(\"%@\",\"%@\")", (NSString *)testDomain, (NSString *)testKey]; |
| return [webView stringByEvaluatingJavaScript:js]; |
| }; |
| |
| preferenceValue(); |
| |
| NSDate *changedDate = [NSDate dateWithTimeIntervalSinceNow:10]; |
| [userDefaults.get() setObject:changedDate forKey:(NSString *)testKey]; |
| |
| auto encodedString = preferenceValue(); |
| auto encodedData = adoptNS([[NSData alloc] initWithBase64EncodedString:encodedString options:0]); |
| ASSERT_TRUE(encodedData); |
| NSError *err = nil; |
| auto object = retainPtr([NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:encodedData.get() error:&err]); |
| ASSERT_TRUE(!err); |
| ASSERT_TRUE(object); |
| ASSERT_TRUE([object isEqual:changedDate]); |
| } |
| |
| static IMP sharedInstanceMethodOriginal = nil; |
| static bool sharedInstanceCalled = false; |
| |
| static WKPreferenceObserver *sharedInstanceMethodOverride(id self, SEL selector) |
| { |
| WKPreferenceObserver *observer = wtfCallIMP<WKPreferenceObserver *>(sharedInstanceMethodOriginal, self, selector); |
| sharedInstanceCalled = true; |
| return observer; |
| } |
| |
| TEST(WebKit, PreferenceObserverStartedOnActivation) |
| { |
| sharedInstanceCalled = false; |
| Method sharedInstanceMethod = class_getClassMethod(objc_getClass("WKPreferenceObserver"), @selector(sharedInstance)); |
| ASSERT(sharedInstanceMethod); |
| sharedInstanceMethodOriginal = method_setImplementation(sharedInstanceMethod, (IMP)sharedInstanceMethodOverride); |
| ASSERT(sharedInstanceMethodOriginal); |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| WKRetainPtr<WKContextRef> context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest")); |
| configuration.get().processPool = (WKProcessPool *)context.get(); |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]); |
| |
| [webView synchronouslyLoadTestPageNamed:@"simple"]; |
| |
| [[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationDidBecomeActiveNotification object:NSApp userInfo:nil]; |
| |
| TestWebKitAPI::Util::run(&sharedInstanceCalled); |
| } |
| |
| #endif // WK_HAVE_C_SPI |