Unreviewed, temporarily disable the data interaction unit tests.
[WebKit.git] / Tools / TestWebKitAPI / Tests / ios / DataInteractionTests.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 0
29
30 #import "DataInteractionSimulator.h"
31 #import "PlatformUtilities.h"
32 #import "TestWKWebView.h"
33 #import "WKWebViewConfigurationExtras.h"
34 #import <MobileCoreServices/MobileCoreServices.h>
35 #import <UIKit/NSString+UIItemProvider.h>
36 #import <UIKit/NSURL+UIItemProvider.h>
37 #import <UIKit/UIImage+UIItemProvider.h>
38 #import <UIKit/UIItemProvider_Private.h>
39 #import <WebKit/WKPreferencesPrivate.h>
40 #import <WebKit/WKWebViewConfigurationPrivate.h>
41 #import <WebKit/_WKProcessPoolConfiguration.h>
42
43 typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
44 typedef void (^DataLoadCompletionBlock)(NSData *, NSError *);
45
46 static UIImage *testIconImage()
47 {
48     return [UIImage imageNamed:@"TestWebKitAPI.resources/icon.png"];
49 }
50
51 static NSURL *temporaryURLForDataInteractionFileLoad(NSString *temporaryFileName)
52 {
53     NSString *temporaryDirectoryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"data-interaction"];
54     if (![[NSFileManager defaultManager] fileExistsAtPath:temporaryDirectoryPath])
55         [[NSFileManager defaultManager] createDirectoryAtPath:temporaryDirectoryPath withIntermediateDirectories:YES attributes:nil error:nil];
56     return [NSURL fileURLWithPath:[temporaryDirectoryPath stringByAppendingPathComponent:temporaryFileName]];
57 }
58
59 static void cleanUpDataInteractionTemporaryPath()
60 {
61     NSArray *temporaryDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSURL fileURLWithPath:NSTemporaryDirectory()] includingPropertiesForKeys:nil options:0 error:nil];
62     for (NSURL *url in temporaryDirectoryContents) {
63         if ([url.lastPathComponent rangeOfString:@"data-interaction"].location != NSNotFound)
64             [[NSFileManager defaultManager] removeItemAtURL:url error:nil];
65     }
66 }
67
68 @implementation UIItemProvider (DataInteractionTests)
69
70 - (void)registerFileRepresentationForTypeIdentifier:(NSString *)typeIdentifier withData:(NSData *)data filename:(NSString *)filename
71 {
72     RetainPtr<NSData> retainedData = data;
73     RetainPtr<NSURL> retainedTemporaryURL = temporaryURLForDataInteractionFileLoad(filename);
74     [self registerFileRepresentationForTypeIdentifier:typeIdentifier fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler: [retainedData, retainedTemporaryURL] (FileLoadCompletionBlock block) -> NSProgress * {
75         [retainedData writeToFile:[retainedTemporaryURL path] atomically:YES];
76         dispatch_async(dispatch_get_main_queue(), [retainedTemporaryURL, capturedBlock = makeBlockPtr(block)] {
77             capturedBlock(retainedTemporaryURL.get(), NO, nil);
78         });
79         return nil;
80     }];
81 }
82
83 - (void)registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier withData:(NSData *)data
84 {
85     RetainPtr<NSData> retainedData = data;
86     [self registerDataRepresentationForTypeIdentifier:typeIdentifier visibility:NSItemProviderRepresentationVisibilityAll loadHandler: [retainedData] (DataLoadCompletionBlock block) -> NSProgress * {
87         block(retainedData.get(), nil);
88         return [NSProgress discreteProgressWithTotalUnitCount:100];
89     }];
90 }
91
92 @end
93
94 @implementation TestWKWebView (DataInteractionTests)
95
96 - (BOOL)editorContainsImageElement
97 {
98     return [self stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"].boolValue;
99 }
100
101 - (NSString *)editorValue
102 {
103     return [self stringByEvaluatingJavaScript:@"editor.value"];
104 }
105
106 @end
107
108 static NSValue *makeCGRectValue(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
109 {
110     return [NSValue valueWithCGRect:CGRectMake(x, y, width, height)];
111 }
112
113 static void checkSelectionRectsWithLogging(NSArray *expected, NSArray *observed)
114 {
115     if (![expected isEqualToArray:observed])
116         NSLog(@"Expected selection rects: %@ but observed: %@", expected, observed);
117     EXPECT_TRUE([expected isEqualToArray:observed]);
118 }
119
120 static void checkTypeIdentifierPrecedesOtherTypeIdentifier(DataInteractionSimulator *simulator, NSString *firstType, NSString *secondType)
121 {
122     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
123     EXPECT_TRUE([registeredTypes containsObject:firstType]);
124     EXPECT_TRUE([registeredTypes containsObject:secondType]);
125     EXPECT_TRUE([registeredTypes indexOfObject:firstType] < [registeredTypes indexOfObject:secondType]);
126 }
127
128 namespace TestWebKitAPI {
129
130 TEST(DataInteractionTests, ImageToContentEditable)
131 {
132     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
133     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
134
135     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
136     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
137
138     EXPECT_TRUE([webView editorContainsImageElement]);
139
140     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
141     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
142     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
143     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
144     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
145     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
146 }
147
148 TEST(DataInteractionTests, ImageToTextarea)
149 {
150     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
151     [webView synchronouslyLoadTestPageNamed:@"image-and-textarea"];
152
153     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
154     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
155
156     NSURL *imageURL = [NSURL fileURLWithPath:[webView editorValue]];
157     EXPECT_WK_STREQ("icon.png", imageURL.lastPathComponent);
158
159     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
160     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
161     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
162     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
163
164     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
165 }
166
167 TEST(DataInteractionTests, ImageInLinkToInput)
168 {
169     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
170     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
171
172     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
173     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
174
175     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
176     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
177 }
178
179 TEST(DataInteractionTests, ImageInLinkWithoutHREFToInput)
180 {
181     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
182     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
183     [webView stringByEvaluatingJavaScript:@"link.href = ''"];
184
185     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
186     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
187
188     NSURL *imageURL = [NSURL fileURLWithPath:[webView editorValue]];
189     EXPECT_WK_STREQ("icon.png", imageURL.lastPathComponent);
190 }
191
192 TEST(DataInteractionTests, ContentEditableToContentEditable)
193 {
194     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
195     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
196
197     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
198     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
199
200     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
201     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
202
203     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
204     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
205     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
206     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
207     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 961, 227) ], [dataInteractionSimulator finalSelectionRects]);
208     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
209 }
210
211 TEST(DataInteractionTests, ContentEditableToTextarea)
212 {
213     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
214     [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-textarea"];
215
216     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
217     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
218
219     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
220     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
221
222     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
223     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
224     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
225     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
226     checkSelectionRectsWithLogging(@[ makeCGRectValue(6, 203, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
227     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
228 }
229
230 TEST(DataInteractionTests, TextAreaToInput)
231 {
232     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
233     [webView synchronouslyLoadTestPageNamed:@"textarea-to-input"];
234
235     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
236     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
237
238     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
239     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
240     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
241 }
242
243 TEST(DataInteractionTests, LinkToInput)
244 {
245     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
246     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
247
248     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
249     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
250
251     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
252
253     __block bool doneLoadingURL = false;
254     UIItemProvider *sourceItemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
255     [sourceItemProvider loadObjectOfClass:[NSURL class] completionHandler:^(NSURL *url, NSError *error) {
256         EXPECT_WK_STREQ("Hello world", url._title.UTF8String ?: "");
257         doneLoadingURL = true;
258     }];
259     TestWebKitAPI::Util::run(&doneLoadingURL);
260
261     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
262     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
263     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
264     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
265     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 273, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
266     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, (NSString *)kUTTypeUTF8PlainText);
267 }
268
269 TEST(DataInteractionTests, BackgroundImageLinkToInput)
270 {
271     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
272     [webView synchronouslyLoadTestPageNamed:@"background-image-link-and-input"];
273
274     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
275     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
276
277     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
278
279     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
280     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
281     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
282     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
283     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
284     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, (NSString *)kUTTypeUTF8PlainText);
285 }
286
287 TEST(DataInteractionTests, CanPreventStart)
288 {
289     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
290     [webView synchronouslyLoadTestPageNamed:@"prevent-start"];
291
292     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
293     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
294
295     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
296     EXPECT_FALSE([webView editorContainsImageElement]);
297
298     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
299     EXPECT_FALSE([observedEventNames containsObject:DataInteractionEnterEventName]);
300     EXPECT_FALSE([observedEventNames containsObject:DataInteractionOverEventName]);
301     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
302 }
303
304 TEST(DataInteractionTests, CanPreventOperation)
305 {
306     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
307     [webView synchronouslyLoadTestPageNamed:@"prevent-operation"];
308
309     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
310     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
311
312     EXPECT_FALSE([webView editorContainsImageElement]);
313
314     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
315     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
316     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
317     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
318 }
319
320 TEST(DataInteractionTests, EnterAndLeaveEvents)
321 {
322     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
323     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
324
325     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
326     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 450)];
327
328     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
329
330     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
331     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
332     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
333     EXPECT_TRUE([observedEventNames containsObject:DataInteractionLeaveEventName]);
334     EXPECT_FALSE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
335     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
336 }
337
338 TEST(DataInteractionTests, ExternalSourceJSONToFileInput)
339 {
340     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
341     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
342
343     RetainPtr<UIItemProvider> simulatedJSONItemProvider = adoptNS([[UIItemProvider alloc] init]);
344     NSData *jsonData = [@"{ \"foo\": \"bar\",  \"bar\": \"baz\" }" dataUsingEncoding:NSUTF8StringEncoding];
345     [simulatedJSONItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJSON withData:jsonData filename:@"data.json"];
346
347     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
348     [dataInteractionSimulator setExternalItemProviders:@[ simulatedJSONItemProvider.get() ]];
349     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
350
351     EXPECT_WK_STREQ("application/json", [webView stringByEvaluatingJavaScript:@"output.value"]);
352     cleanUpDataInteractionTemporaryPath();
353 }
354
355 TEST(DataInteractionTests, ExternalSourceImageToFileInput)
356 {
357     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
358     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
359
360     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
361     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
362     [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
363
364     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
365     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get() ]];
366     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
367
368     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
369     EXPECT_WK_STREQ("image/jpeg", outputValue.UTF8String);
370
371     cleanUpDataInteractionTemporaryPath();
372 }
373
374 TEST(DataInteractionTests, ExternalSourceHTMLToUploadArea)
375 {
376     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
377     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
378
379     RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
380     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
381     [simulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData filename:@"index.html"];
382
383     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
384     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
385     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
386
387     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
388     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
389
390     cleanUpDataInteractionTemporaryPath();
391 }
392
393 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToSingleFileInput)
394 {
395     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
396     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
397
398     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
399     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
400     [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
401
402     RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
403     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
404     [simulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData filename:@"index.html"];
405
406     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
407     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
408     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
409
410     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
411     EXPECT_WK_STREQ("", outputValue.UTF8String);
412
413     cleanUpDataInteractionTemporaryPath();
414 }
415
416 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToMultipleFileInput)
417 {
418     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
419     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
420     [webView stringByEvaluatingJavaScript:@"input.setAttribute('multiple', '')"];
421
422     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
423     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
424     [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
425
426     RetainPtr<UIItemProvider> simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
427     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
428     [simulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData filename:@"index.html"];
429
430     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
431     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
432     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
433
434     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
435     EXPECT_WK_STREQ("image/jpeg, text/html", outputValue.UTF8String);
436
437     cleanUpDataInteractionTemporaryPath();
438 }
439
440 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToUploadArea)
441 {
442     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
443     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
444
445     RetainPtr<UIItemProvider> simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
446     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
447     [simulatedImageItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData filename:@"image.png"];
448
449     RetainPtr<UIItemProvider> firstSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
450     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
451     [firstSimulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData filename:@"index.html"];
452
453     RetainPtr<UIItemProvider> secondSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
454     NSData *secondHTMLData = [@"<html><body>hello world</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
455     [secondSimulatedHTMLItemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:secondHTMLData filename:@"index.html"];
456
457     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
458     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), firstSimulatedHTMLItemProvider.get(), secondSimulatedHTMLItemProvider.get() ]];
459     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
460
461     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
462     EXPECT_WK_STREQ("image/jpeg, text/html, text/html", outputValue.UTF8String);
463
464     cleanUpDataInteractionTemporaryPath();
465 }
466
467 TEST(DataInteractionTests, RespectsExternalSourceFidelityRankings)
468 {
469     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
470     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
471     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
472
473     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
474
475     // Here, our source item provider vends two representations: plain text, and then an image. If we don't respect the
476     // fidelity order requested by the source, we'll end up assuming that the image is a higher fidelity representation
477     // than the plain text, and erroneously insert the image. If we respect source fidelities, we'll insert text rather
478     // than an image.
479     auto simulatedItemProviderWithTextFirst = adoptNS([[UIItemProvider alloc] init]);
480     [simulatedItemProviderWithTextFirst registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll];
481     [simulatedItemProviderWithTextFirst registerObject:testIconImage() visibility:NSItemProviderRepresentationVisibilityAll];
482     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithTextFirst.get() ]];
483
484     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
485     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
486     EXPECT_FALSE([webView editorContainsImageElement]);
487     [webView stringByEvaluatingJavaScript:@"editor.innerHTML = ''"];
488
489     // Now we register the item providers in reverse, and expect the image to be inserted instead of text.
490     auto simulatedItemProviderWithImageFirst = adoptNS([[UIItemProvider alloc] init]);
491     [simulatedItemProviderWithImageFirst registerObject:testIconImage() visibility:NSItemProviderRepresentationVisibilityAll];
492     [simulatedItemProviderWithImageFirst registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll];
493     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithImageFirst.get() ]];
494
495     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
496     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
497     EXPECT_TRUE([webView editorContainsImageElement]);
498 }
499
500 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
501 {
502     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
503     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
504
505     NSString *textPayload = @"Ceci n'est pas une string";
506     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
507     RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
508     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
509     {
510         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
511         return [NSProgress discreteProgressWithTotalUnitCount:100];
512     }];
513     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
514     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
515     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
516     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
517 }
518
519 TEST(DataInteractionTests, ExternalSourceJPEGOnly)
520 {
521     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
522     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
523
524     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
525     RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
526     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeJPEG options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
527     {
528         completionBlock(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
529         return [NSProgress discreteProgressWithTotalUnitCount:100];
530     }];
531     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
532     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
533     EXPECT_TRUE([webView editorContainsImageElement]);
534     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
535 }
536
537 TEST(DataInteractionTests, ExternalSourceTitledNSURL)
538 {
539     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
540     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
541     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
542
543     NSURL *titledURL = [NSURL URLWithString:@"https://www.apple.com"];
544     titledURL._title = @"Apple";
545     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
546     [simulatedItemProvider registerObject:titledURL visibility:NSItemProviderRepresentationVisibilityAll];
547
548     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
549     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
550     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
551
552     EXPECT_WK_STREQ("Apple", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').textContent"]);
553     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
554 }
555
556 TEST(DataInteractionTests, OverrideDataInteractionOperation)
557 {
558     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
559     [webView synchronouslyLoadTestPageNamed:@"simple"];
560
561     RetainPtr<UIItemProvider> simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
562     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:[@"<body></body>" dataUsingEncoding:NSUTF8StringEncoding]];
563
564     __block bool finishedLoadingData = false;
565     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
566     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
567     [dataInteractionSimulator setOverrideDataInteractionOperationBlock:^NSUInteger(NSUInteger operation, id session)
568     {
569         EXPECT_EQ(0U, operation);
570         return 1;
571     }];
572     [dataInteractionSimulator setDataInteractionOperationCompletionBlock:^(BOOL handled, NSArray *itemProviders) {
573         EXPECT_FALSE(handled);
574         [itemProviders.firstObject loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) {
575             NSString *text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
576             EXPECT_WK_STREQ("<body></body>", text.UTF8String);
577             EXPECT_FALSE(!!error);
578             finishedLoadingData = true;
579         }];
580     }];
581     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
582     TestWebKitAPI::Util::run(&finishedLoadingData);
583 }
584
585 TEST(DataInteractionTests, AttachmentElementItemProviders)
586 {
587     RetainPtr<WKWebViewConfiguration> configuration = [WKWebViewConfiguration testwebkitapi_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
588     [configuration _setAttachmentElementEnabled:YES];
589     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get()]);
590     [webView synchronouslyLoadTestPageNamed:@"attachment-element"];
591
592     NSString *injectedTypeIdentifier = @"org.webkit.data";
593     __block RetainPtr<NSString> injectedString;
594     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
595     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(NSArray *originalItemProviders)
596     {
597         for (UIItemProvider *provider in originalItemProviders) {
598             NSData *injectedData = [provider copyDataRepresentationForTypeIdentifier:injectedTypeIdentifier error:nil];
599             if (!injectedData.length)
600                 continue;
601             injectedString = adoptNS([[NSString alloc] initWithData:injectedData encoding:NSUTF8StringEncoding]);
602             break;
603         }
604         return originalItemProviders;
605     }];
606
607     [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400)];
608
609     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
610 }
611
612 TEST(DataInteractionTests, LargeImageToTargetDiv)
613 {
614     auto testWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
615     [[testWebViewConfiguration preferences] _setLargeImageAsyncDecodingEnabled:NO];
616
617     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:testWebViewConfiguration.get()]);
618     [webView synchronouslyLoadTestPageNamed:@"div-and-large-image"];
619
620     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
621     [dataInteractionSimulator runFrom:CGPointMake(200, 400) to:CGPointMake(200, 150)];
622     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
623     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
624 }
625
626 TEST(DataInteractionTests, LinkWithEmptyHREF)
627 {
628     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
629     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
630     [webView stringByEvaluatingJavaScript:@"document.querySelector('a').href = ''"];
631
632     RetainPtr<DataInteractionSimulator> dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
633     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
634
635     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
636     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
637 }
638
639 TEST(DataInteractionTests, CustomActionSheetPopover)
640 {
641     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
642     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
643
644     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
645     [dataInteractionSimulator setShouldEnsureUIApplication:YES];
646
647     __block BOOL didInvokeCustomActionSheet = NO;
648     [dataInteractionSimulator setShowCustomActionSheetBlock:^BOOL(_WKActivatedElementInfo *element)
649     {
650         EXPECT_EQ(_WKActivatedElementTypeLink, element.type);
651         EXPECT_WK_STREQ("Hello world", element.title.UTF8String);
652         didInvokeCustomActionSheet = YES;
653         return YES;
654     }];
655     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
656     EXPECT_TRUE(didInvokeCustomActionSheet);
657     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
658 }
659
660 TEST(DataInteractionTests, UnresponsivePageDoesNotHangUI)
661 {
662     _WKProcessPoolConfiguration *processPoolConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
663     processPoolConfiguration.ignoreSynchronousMessagingTimeoutsForTesting = YES;
664
665     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:[[[WKWebViewConfiguration alloc] init] autorelease] processPoolConfiguration:processPoolConfiguration]);
666     [webView synchronouslyLoadTestPageNamed:@"simple"];
667     [webView evaluateJavaScript:@"while(1);" completionHandler:nil];
668
669     // The test passes if we can prepare for data interaction without timing out.
670     [webView _simulatePrepareForDataInteractionSession:nil completion:^() { }];
671 }
672
673 } // namespace TestWebKitAPI
674
675 #endif // ENABLE(DATA_INTERACTION)