REGRESSION(r226396) DataInteractionTests: ContentEditableToContentEditable and Conten...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / ios / UIPasteboardTests.mm
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if PLATFORM(IOS) && WK_API_ENABLED
29
30 #import "PlatformUtilities.h"
31 #import "TestWKWebView.h"
32 #import "UIKitSPI.h"
33 #import <MobileCoreServices/MobileCoreServices.h>
34 #import <UIKit/UIPasteboard.h>
35 #import <WebKit/WKPreferencesPrivate.h>
36 #import <WebKit/WKWebViewPrivate.h>
37 #import <wtf/SoftLinking.h>
38
39 typedef void (^DataLoadCompletionBlock)(NSData *, NSError *);
40
41 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
42
43 static void checkJSONWithLogging(NSString *jsonString, NSDictionary *expected)
44 {
45     BOOL success = TestWebKitAPI::Util::jsonMatchesExpectedValues(jsonString, expected);
46     EXPECT_TRUE(success);
47     if (!success)
48         NSLog(@"Expected JSON: %@ to match values: %@", jsonString, expected);
49 }
50
51 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
52
53 namespace TestWebKitAPI {
54
55 NSData *dataForPasteboardType(CFStringRef type)
56 {
57     return [[UIPasteboard generalPasteboard] dataForPasteboardType:(NSString *)type inItemSet:[NSIndexSet indexSetWithIndex:0]].firstObject;
58 }
59
60 RetainPtr<TestWKWebView> setUpWebViewForPasteboardTests(NSString *pageName)
61 {
62     // UIPasteboard's type coercion codepaths only take effect when the UIApplication has been initialized.
63     UIApplicationInitialize();
64
65     [UIPasteboard generalPasteboard].items = @[];
66     EXPECT_TRUE(!dataForPasteboardType(kUTTypeUTF8PlainText).length);
67     EXPECT_TRUE(!dataForPasteboardType(kUTTypeUTF16PlainText).length);
68
69     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
70     WKPreferences *preferences = [webView configuration].preferences;
71     preferences._javaScriptCanAccessClipboard = YES;
72     preferences._domPasteAllowed = YES;
73     [webView synchronouslyLoadTestPageNamed:pageName];
74     return webView;
75 }
76
77 TEST(UIPasteboardTests, CopyPlainTextWritesConcreteTypes)
78 {
79     auto webView = setUpWebViewForPasteboardTests(@"rich-and-plain-text");
80     [webView stringByEvaluatingJavaScript:@"selectPlainText()"];
81     [webView stringByEvaluatingJavaScript:@"document.execCommand('copy')"];
82
83     auto utf8Result = adoptNS([[NSString alloc] initWithData:dataForPasteboardType(kUTTypeUTF8PlainText) encoding:NSUTF8StringEncoding]);
84     EXPECT_WK_STREQ("Hello world", [utf8Result UTF8String]);
85 }
86
87 TEST(UIPasteboardTests, CopyRichTextWritesConcreteTypes)
88 {
89     auto webView = setUpWebViewForPasteboardTests(@"rich-and-plain-text");
90     [webView stringByEvaluatingJavaScript:@"selectRichText()"];
91     [webView stringByEvaluatingJavaScript:@"document.execCommand('copy')"];
92
93     auto utf8Result = adoptNS([[NSString alloc] initWithData:dataForPasteboardType(kUTTypeUTF8PlainText) encoding:NSUTF8StringEncoding]);
94     EXPECT_WK_STREQ("Hello world", [utf8Result UTF8String]);
95 }
96
97 TEST(UIPasteboardTests, DoNotPastePlainTextAsURL)
98 {
99     auto webView = setUpWebViewForPasteboardTests(@"rich-and-plain-text");
100
101     NSString *testString = @"[helloworld]";
102     [UIPasteboard generalPasteboard].string = testString;
103
104     [webView stringByEvaluatingJavaScript:@"selectPlainText()"];
105     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
106     EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"plain.value"]);
107
108     [webView stringByEvaluatingJavaScript:@"selectRichText()"];
109     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
110     EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"rich.textContent"]);
111     EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"!!rich.querySelector('a')"].boolValue);
112 }
113
114 TEST(UIPasteboardTests, PastePlainTextAsURL)
115 {
116     auto webView = setUpWebViewForPasteboardTests(@"rich-and-plain-text");
117
118     NSString *testString = @"https://www.apple.com/iphone";
119     [UIPasteboard generalPasteboard].string = testString;
120
121     [webView stringByEvaluatingJavaScript:@"selectPlainText()"];
122     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
123     EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"plain.value"]);
124
125     [webView stringByEvaluatingJavaScript:@"selectRichText()"];
126     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
127     EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"rich.textContent"]);
128     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!rich.querySelector('a')"].boolValue);
129 }
130
131 TEST(UIPasteboardTests, PasteURLWithPlainTextAsURL)
132 {
133     auto webView = setUpWebViewForPasteboardTests(@"rich-and-plain-text");
134
135     NSString *testString = @"thisisdefinitelyaurl";
136     [UIPasteboard generalPasteboard].URL = [NSURL URLWithString:testString];
137
138     [webView stringByEvaluatingJavaScript:@"selectPlainText()"];
139     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
140     EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"plain.value"]);
141
142     [webView stringByEvaluatingJavaScript:@"selectRichText()"];
143     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
144     EXPECT_WK_STREQ(testString, [webView stringByEvaluatingJavaScript:@"rich.textContent"]);
145     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!rich.querySelector('a')"].boolValue);
146 }
147
148 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
149
150 TEST(UIPasteboardTests, DataTransferGetDataWhenPastingURL)
151 {
152     auto webView = setUpWebViewForPasteboardTests(@"dump-datatransfer-types");
153
154     NSString *testURLString = @"https://www.apple.com/";
155     [UIPasteboard generalPasteboard].URL = [NSURL URLWithString:testURLString];
156
157     [webView stringByEvaluatingJavaScript:@"destination.focus()"];
158     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
159     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
160         @"paste" : @{
161             @"text/plain" : testURLString,
162             @"text/uri-list" : testURLString
163         }
164     });
165 }
166
167 TEST(UIPasteboardTests, DataTransferGetDataWhenPastingPlatformRepresentations)
168 {
169     auto webView = setUpWebViewForPasteboardTests(@"dump-datatransfer-types");
170
171     // This simulates how a native app on iOS might write to the pasteboard when copying.
172     RetainPtr<NSURL> testURL = [NSURL URLWithString:@"https://www.apple.com/"];
173     RetainPtr<NSString> testPlainTextString = @"WebKit";
174     RetainPtr<NSString> testMarkupString = @"<a href='https://www.webkit.org/'>The WebKit Project</a>";
175     auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
176     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(DataLoadCompletionBlock completionHandler)
177     {
178         completionHandler([testMarkupString dataUsingEncoding:NSUTF8StringEncoding], nil);
179         return nil;
180     }];
181     [itemProvider registerObject:testURL.get() visibility:NSItemProviderRepresentationVisibilityAll];
182     [itemProvider registerObject:testPlainTextString.get() visibility:NSItemProviderRepresentationVisibilityAll];
183
184     [UIPasteboard generalPasteboard].itemProviders = @[ itemProvider.get() ];
185     [webView stringByEvaluatingJavaScript:@"destination.focus()"];
186     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
187     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
188         @"paste" : @{
189             @"text/plain" : testPlainTextString.get(),
190             @"text/uri-list" : [testURL absoluteString],
191             @"text/html" : testMarkupString.get()
192         }
193     });
194 }
195
196 TEST(UIPasteboardTests, DataTransferSetDataCannotWritePlatformTypes)
197 {
198     auto webView = setUpWebViewForPasteboardTests(@"dump-datatransfer-types");
199
200     [webView stringByEvaluatingJavaScript:@"customData = { 'text/plain' : '年年年', '年年年年年年' : 'test', 'com.adobe.pdf' : '🔥🔥🔥', 'text/rtf' : 'not actually rich text!' }"];
201     [webView stringByEvaluatingJavaScript:@"writeCustomData = true"];
202     [webView stringByEvaluatingJavaScript:@"select(rich)"];
203     [webView stringByEvaluatingJavaScript:@"document.execCommand('copy')"];
204     [webView stringByEvaluatingJavaScript:@"destination.focus()"];
205     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
206     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
207         @"paste": @{
208             @"text/plain": @"年年年",
209             @"年年年年年年": @"test",
210             @"com.adobe.pdf": @"🔥🔥🔥",
211             @"text/rtf": @"not actually rich text!"
212         }
213     });
214
215     // Most importantly, the system pasteboard should not contain the PDF UTI.
216     NSData *pdfData = [[UIPasteboard generalPasteboard] dataForPasteboardType:(NSString *)kUTTypePDF];
217     EXPECT_EQ(0UL, pdfData.length);
218
219     // However, the system pasteboard should contain a plain text string.
220     EXPECT_WK_STREQ("年年年", [UIPasteboard generalPasteboard].string);
221 }
222
223 TEST(UIPasteboardTests, DataTransferGetDataCannotReadArbitraryPlatformTypes)
224 {
225     auto webView = setUpWebViewForPasteboardTests(@"dump-datatransfer-types");
226     auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
227     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeMP3 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(DataLoadCompletionBlock completionHandler)
228     {
229         completionHandler([@"this is a test" dataUsingEncoding:NSUTF8StringEncoding], nil);
230         return nil;
231     }];
232     [itemProvider registerDataRepresentationForTypeIdentifier:@"org.WebKit.TestWebKitAPI.custom-pasteboard-type" visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(DataLoadCompletionBlock completionHandler)
233     {
234         completionHandler([@"this is another test" dataUsingEncoding:NSUTF8StringEncoding], nil);
235         return nil;
236     }];
237
238     [webView stringByEvaluatingJavaScript:@"destination.focus()"];
239     [webView stringByEvaluatingJavaScript:@"document.execCommand('paste')"];
240     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
241         @"paste": @{ }
242     });
243 }
244
245 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
246
247 } // namespace TestWebKitAPI
248
249 #endif