Title: [234976] trunk/Tools
Revision
234976
Author
[email protected]
Date
2018-08-16 21:58:49 -0700 (Thu, 16 Aug 2018)

Log Message

[macOS] [WK2] Add infrastructure to test receiving file promises on drop
https://bugs.webkit.org/show_bug.cgi?id=188583

Reviewed by Andy Estes.

Enable testing file promise drop handling on the WebKit2 port of macOS by introducing a subclass of
NSFilePromiseReceiver and implementing `-enumerateDraggingItemsWithOptions:forView:…` on TestDraggingInfo (the
concrete NSDraggingInfo implementation used by DragAndDropSimulator) using the mock file receiver. Also
introduces 3 new macOS tests. See below for more details.

A large portion of this logic is ported over from DumpRenderTree testing infrastructure added in r229297. In a
future patch, we should introduce a way to write code common to both API tests, WebKitTestRunner and
DumpRenderTree, and make this code shared among all three testing harnesses.

Tests:  DragAndDropTests.DragImageElementIntoFileUpload
        DragAndDropTests.DragPromisedImageFileIntoFileUpload
        DragAndDropTests.DragImageFileIntoFileUpload

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm:
(TEST):

Drive-by fix: Replace NSMakePoint with CGPointMake.

* TestWebKitAPI/Tests/WebKitCocoa/image-and-file-upload.html:

Add a new test page consisting of an image and a "file upload" area that updates exercises DataTransfer API to
load the dropped image.

* TestWebKitAPI/Tests/mac/DragAndDropTestsMac.mm:
(waitForConditionWithLogging):

Add a helper function to wait for a condition to evaluate to true. To make failures more informative,
additionally add a mechanism to log a warning message after a given timeout, if the condition has yet to be met.

(TEST):

Add new tests to exercise a few cases of file upload in WebKit, including: (1) dragging from an image element,
(2) dragging files written to the pasteboard as promises, and (3) files written to the pasteboard as file URLs.

* TestWebKitAPI/cocoa/DragAndDropSimulator.h:

Surface the new functionality provided by the file promise receiver mock via two new methods on
DragAndDropSimulator to (1) write files as file promises to the pasteboard, and (2) write files as file paths
directly to the pasteboard.

* TestWebKitAPI/mac/DragAndDropSimulatorMac.mm:
(-[DragAndDropSimulator performDragInWebView:atLocation:withImage:pasteboard:source:]):
(-[DragAndDropSimulator externalPromisedFiles]):
(getFilePathsAndTypeIdentifiers):
(-[DragAndDropSimulator writePromisedFiles:]):
(-[DragAndDropSimulator writeFiles:]):
* TestWebKitAPI/mac/TestDraggingInfo.h:
* TestWebKitAPI/mac/TestDraggingInfo.mm:
(-[TestDraggingInfo initWithDragAndDropSimulator:]):
(-[TestDraggingInfo filePromiseReceivers]):
(-[TestDraggingInfo enumerateDraggingItemsWithOptions:forView:classes:searchOptions:usingBlock:]):

Implement this by invoking the given block with a TestFilePromiseReceiver. While all other classes are
unhandled by this testing code, WebKit only calls into this with [NSFilePromiseReceiver class], this is
currently sufficient for testing purposes.

* TestWebKitAPI/mac/TestFilePromiseReceiver.h: Copied from Tools/TestWebKitAPI/mac/TestDraggingInfo.h.
* TestWebKitAPI/mac/TestFilePromiseReceiver.mm: Added.
(-[TestFilePromiseReceiver initWithPromisedTypeIdentifiers:dragAndDropSimulator:]):
(-[TestFilePromiseReceiver fileTypes]):
(-[TestFilePromiseReceiver fileNames]):
(-[TestFilePromiseReceiver dealloc]):
(-[TestFilePromiseReceiver draggingSource]):
(-[TestFilePromiseReceiver setDraggingSource:]):
(fileNameWithNumericSuffix):
(copyFile):

Add a helper to copy a file into a destination directory. Used to implement the main functionality of our
NSFilePromiseReceiver subclass, which copies the files specified by test code into the directory determined by
WebKit.

(-[TestFilePromiseReceiver receivePromisedFilesAtDestination:options:operationQueue:reader:]):

Modified Paths

Added Paths

Diff

Modified: trunk/Tools/ChangeLog (234975 => 234976)


--- trunk/Tools/ChangeLog	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/ChangeLog	2018-08-17 04:58:49 UTC (rev 234976)
@@ -1,3 +1,84 @@
+2018-08-16  Wenson Hsieh  <[email protected]>
+
+        [macOS] [WK2] Add infrastructure to test receiving file promises on drop
+        https://bugs.webkit.org/show_bug.cgi?id=188583
+
+        Reviewed by Andy Estes.
+
+        Enable testing file promise drop handling on the WebKit2 port of macOS by introducing a subclass of
+        NSFilePromiseReceiver and implementing `-enumerateDraggingItemsWithOptions:forView:…` on TestDraggingInfo (the
+        concrete NSDraggingInfo implementation used by DragAndDropSimulator) using the mock file receiver. Also
+        introduces 3 new macOS tests. See below for more details.
+
+        A large portion of this logic is ported over from DumpRenderTree testing infrastructure added in r229297. In a
+        future patch, we should introduce a way to write code common to both API tests, WebKitTestRunner and
+        DumpRenderTree, and make this code shared among all three testing harnesses.
+
+        Tests:  DragAndDropTests.DragImageElementIntoFileUpload
+                DragAndDropTests.DragPromisedImageFileIntoFileUpload
+                DragAndDropTests.DragImageFileIntoFileUpload
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm:
+        (TEST):
+
+        Drive-by fix: Replace NSMakePoint with CGPointMake.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/image-and-file-upload.html:
+
+        Add a new test page consisting of an image and a "file upload" area that updates exercises DataTransfer API to
+        load the dropped image.
+
+        * TestWebKitAPI/Tests/mac/DragAndDropTestsMac.mm:
+        (waitForConditionWithLogging):
+
+        Add a helper function to wait for a condition to evaluate to true. To make failures more informative,
+        additionally add a mechanism to log a warning message after a given timeout, if the condition has yet to be met.
+
+        (TEST):
+
+        Add new tests to exercise a few cases of file upload in WebKit, including: (1) dragging from an image element,
+        (2) dragging files written to the pasteboard as promises, and (3) files written to the pasteboard as file URLs.
+
+        * TestWebKitAPI/cocoa/DragAndDropSimulator.h:
+
+        Surface the new functionality provided by the file promise receiver mock via two new methods on
+        DragAndDropSimulator to (1) write files as file promises to the pasteboard, and (2) write files as file paths
+        directly to the pasteboard.
+
+        * TestWebKitAPI/mac/DragAndDropSimulatorMac.mm:
+        (-[DragAndDropSimulator performDragInWebView:atLocation:withImage:pasteboard:source:]):
+        (-[DragAndDropSimulator externalPromisedFiles]):
+        (getFilePathsAndTypeIdentifiers):
+        (-[DragAndDropSimulator writePromisedFiles:]):
+        (-[DragAndDropSimulator writeFiles:]):
+        * TestWebKitAPI/mac/TestDraggingInfo.h:
+        * TestWebKitAPI/mac/TestDraggingInfo.mm:
+        (-[TestDraggingInfo initWithDragAndDropSimulator:]):
+        (-[TestDraggingInfo filePromiseReceivers]):
+        (-[TestDraggingInfo enumerateDraggingItemsWithOptions:forView:classes:searchOptions:usingBlock:]):
+
+        Implement this by invoking the given block with a TestFilePromiseReceiver. While all other classes are
+        unhandled by this testing code, WebKit only calls into this with [NSFilePromiseReceiver class], this is
+        currently sufficient for testing purposes.
+
+        * TestWebKitAPI/mac/TestFilePromiseReceiver.h: Copied from Tools/TestWebKitAPI/mac/TestDraggingInfo.h.
+        * TestWebKitAPI/mac/TestFilePromiseReceiver.mm: Added.
+        (-[TestFilePromiseReceiver initWithPromisedTypeIdentifiers:dragAndDropSimulator:]):
+        (-[TestFilePromiseReceiver fileTypes]):
+        (-[TestFilePromiseReceiver fileNames]):
+        (-[TestFilePromiseReceiver dealloc]):
+        (-[TestFilePromiseReceiver draggingSource]):
+        (-[TestFilePromiseReceiver setDraggingSource:]):
+        (fileNameWithNumericSuffix):
+        (copyFile):
+
+        Add a helper to copy a file into a destination directory. Used to implement the main functionality of our
+        NSFilePromiseReceiver subclass, which copies the files specified by test code into the directory determined by
+        WebKit.
+
+        (-[TestFilePromiseReceiver receivePromisedFilesAtDestination:options:operationQueue:reader:]):
+
 2018-08-16  Alex Christensen  <[email protected]>
 
         Add entitlement to MiniBrowser to allow it to communicate with com.apple.Safari.SafeBrowsing.Service

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (234975 => 234976)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-08-17 04:58:49 UTC (rev 234976)
@@ -842,9 +842,11 @@
 		F4D5E4E81F0C5D38008C1A49 /* dragstart-clear-selection.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4D5E4E71F0C5D27008C1A49 /* dragstart-clear-selection.html */; };
 		F4D65DA81F5E4704009D8C27 /* selected-text-image-link-and-editable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4D65DA71F5E46C0009D8C27 /* selected-text-image-link-and-editable.html */; };
 		F4DEF6ED1E9B4DB60048EF61 /* image-in-link-and-input.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4DEF6EC1E9B4D950048EF61 /* image-in-link-and-input.html */; };
-		F4E0A296211FC5FB00AF7C7F /* selected-text-and-textarea.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4E0A295211FC5A300AF7C7F /* selected-text-and-textarea.html */; };
 		F4E0A28B211E4A2B00AF7C7F /* full-page-dropzone.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F46128D8211E496300D9FADB /* full-page-dropzone.html */; };
 		F4E0A28F211E5D5B00AF7C7F /* DragAndDropTestsMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4E0A28E211E5D5B00AF7C7F /* DragAndDropTestsMac.mm */; };
+		F4E0A296211FC5FB00AF7C7F /* selected-text-and-textarea.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4E0A295211FC5A300AF7C7F /* selected-text-and-textarea.html */; };
+		F4E0A2B42122402B00AF7C7F /* image-and-file-upload.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4E0A2B321223F2D00AF7C7F /* image-and-file-upload.html */; };
+		F4E0A2B82122847400AF7C7F /* TestFilePromiseReceiver.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4E0A2B72122847400AF7C7F /* TestFilePromiseReceiver.mm */; };
 		F4E3D80820F70BB9007B58C5 /* significant-text-milestone-article.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4E3D80720F708E4007B58C5 /* significant-text-milestone-article.html */; };
 		F4F137921D9B683E002BEC57 /* large-video-test-now-playing.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4F137911D9B6832002BEC57 /* large-video-test-now-playing.html */; };
 		F4F405BC1D4C0D1C007A9707 /* full-size-autoplaying-video-with-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4F405BA1D4C0CF8007A9707 /* full-size-autoplaying-video-with-audio.html */; };
@@ -1042,6 +1044,7 @@
 				510477741D298DDD009747EB /* IDBDeleteRecovery.sqlite3-wal in Copy Resources */,
 				5110FCF11E01CD64006F8D0B /* IDBIndexUpgradeToV2.html in Copy Resources */,
 				F41AB9A41EF4696B0083FA08 /* image-and-contenteditable.html in Copy Resources */,
+				F4E0A2B42122402B00AF7C7F /* image-and-file-upload.html in Copy Resources */,
 				F41AB9A51EF4696B0083FA08 /* image-and-textarea.html in Copy Resources */,
 				F4DEF6ED1E9B4DB60048EF61 /* image-in-link-and-input.html in Copy Resources */,
 				F45B63FB1F197F4A009D38B9 /* image-map.html in Copy Resources */,
@@ -2088,8 +2091,11 @@
 		F4D5E4E71F0C5D27008C1A49 /* dragstart-clear-selection.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "dragstart-clear-selection.html"; sourceTree = "<group>"; };
 		F4D65DA71F5E46C0009D8C27 /* selected-text-image-link-and-editable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "selected-text-image-link-and-editable.html"; sourceTree = "<group>"; };
 		F4DEF6EC1E9B4D950048EF61 /* image-in-link-and-input.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "image-in-link-and-input.html"; sourceTree = "<group>"; };
+		F4E0A28E211E5D5B00AF7C7F /* DragAndDropTestsMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropTestsMac.mm; sourceTree = "<group>"; };
 		F4E0A295211FC5A300AF7C7F /* selected-text-and-textarea.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "selected-text-and-textarea.html"; sourceTree = "<group>"; };
-		F4E0A28E211E5D5B00AF7C7F /* DragAndDropTestsMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropTestsMac.mm; sourceTree = "<group>"; };
+		F4E0A2B321223F2D00AF7C7F /* image-and-file-upload.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "image-and-file-upload.html"; sourceTree = "<group>"; };
+		F4E0A2B62122847400AF7C7F /* TestFilePromiseReceiver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestFilePromiseReceiver.h; sourceTree = "<group>"; };
+		F4E0A2B72122847400AF7C7F /* TestFilePromiseReceiver.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TestFilePromiseReceiver.mm; sourceTree = "<group>"; };
 		F4E3D80720F708E4007B58C5 /* significant-text-milestone-article.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "significant-text-milestone-article.html"; sourceTree = "<group>"; };
 		F4F137911D9B6832002BEC57 /* large-video-test-now-playing.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-test-now-playing.html"; sourceTree = "<group>"; };
 		F4F405BA1D4C0CF8007A9707 /* full-size-autoplaying-video-with-audio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-size-autoplaying-video-with-audio.html"; sourceTree = "<group>"; };
@@ -2662,6 +2668,7 @@
 				510477711D298D85009747EB /* IDBDeleteRecovery.sqlite3-wal */,
 				5110FCF01E01CD53006F8D0B /* IDBIndexUpgradeToV2.html */,
 				F41AB9991EF4692C0083FA08 /* image-and-contenteditable.html */,
+				F4E0A2B321223F2D00AF7C7F /* image-and-file-upload.html */,
 				F41AB9931EF4692C0083FA08 /* image-and-textarea.html */,
 				F4DEF6EC1E9B4D950048EF61 /* image-in-link-and-input.html */,
 				F45B63FA1F197F33009D38B9 /* image-map.html */,
@@ -3147,6 +3154,8 @@
 				29AB8AA2164C7A9300D49BEC /* TestBrowsingContextLoadDelegate.mm */,
 				F46128C9211D475100D9FADB /* TestDraggingInfo.h */,
 				F46128CA211D475100D9FADB /* TestDraggingInfo.mm */,
+				F4E0A2B62122847400AF7C7F /* TestFilePromiseReceiver.h */,
+				F4E0A2B72122847400AF7C7F /* TestFilePromiseReceiver.mm */,
 				C08587BE13FE956C001EF4E5 /* WebKitAgnosticTest.h */,
 				C08587BD13FE956C001EF4E5 /* WebKitAgnosticTest.mm */,
 			);
@@ -3962,6 +3971,7 @@
 				7CCE7F161A411AE600447C4C /* TerminateTwice.cpp in Sources */,
 				7CCE7EA91A411A1D00447C4C /* TestBrowsingContextLoadDelegate.mm in Sources */,
 				F46128CB211D475100D9FADB /* TestDraggingInfo.mm in Sources */,
+				F4E0A2B82122847400AF7C7F /* TestFilePromiseReceiver.mm in Sources */,
 				F45E15762112CE6200307E82 /* TestInputDelegate.mm in Sources */,
 				2D1C04A71D76298B000A6816 /* TestNavigationDelegate.mm in Sources */,
 				A14FC5901B8AE36F00D107EB /* TestProtocol.mm in Sources */,

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm (234975 => 234976)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DragAndDropTests.mm	2018-08-17 04:58:49 UTC (rev 234976)
@@ -34,7 +34,7 @@
 {
     auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:CGRectMake(0, 0, 400, 400)]);
     [[simulator webView] synchronouslyLoadTestPageNamed:@"link-in-iframe-and-input"];
-    [simulator runFrom:NSMakePoint(200, 375) to:NSMakePoint(200, 125)];
+    [simulator runFrom:CGPointMake(200, 375) to:CGPointMake(200, 125)];
 
     EXPECT_WK_STREQ("https://www.apple.com/", [[simulator webView] stringByEvaluatingJavaScript:@"document.querySelector('input').value"]);
 

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/image-and-file-upload.html (0 => 234976)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/image-and-file-upload.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/image-and-file-upload.html	2018-08-17 04:58:49 UTC (rev 234976)
@@ -0,0 +1,47 @@
+<DOCTYPE !html>
+<html>
+<head>
+<meta charset="utf8">
+<meta name="viewport" content="width=device-width">
+<style>
+    body {
+        width: 100%;
+        height: 100%;
+        margin: 0;
+    }
+
+    #source, #destination {
+        width: 200px;
+        height: 200px;
+    }
+
+    #destination {
+        border: red 1px solid;
+    }
+</style>
+<script>
+    function runTest() {
+        destination.addEventListener("dragenter", event => event.preventDefault());
+        destination.addEventListener("dragover", event => event.preventDefault());
+        destination.addEventListener("drop", event => {
+            filecount.textContent = event.dataTransfer.files.length;
+            destination.setAttribute("src", URL.createObjectURL(event.dataTransfer.files[0]));
+            event.preventDefault();
+        });
+    }
+
+    function destinationLoaded() {
+        imageload.textContent = "true";
+        imageload.style.color = "green";
+    }
+</script>
+</head>
+<body _onload_="runTest()">
+    <div><img id="source" src=""
+    <img _onload_="destinationLoaded()" src="" id="destination"></img>
+    <div id="output">
+        <div>Number of files: <span id="filecount">N/A</span></div>
+        <div>Image loaded? <span style="color: red" id="imageload">false</span></div>
+    </div>
+</body>
+</html>

Modified: trunk/Tools/TestWebKitAPI/Tests/mac/DragAndDropTestsMac.mm (234975 => 234976)


--- trunk/Tools/TestWebKitAPI/Tests/mac/DragAndDropTestsMac.mm	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/DragAndDropTestsMac.mm	2018-08-17 04:58:49 UTC (rev 234976)
@@ -30,6 +30,25 @@
 
 #if WK_API_ENABLED && ENABLE(DRAG_SUPPORT) && PLATFORM(MAC)
 
+static void waitForConditionWithLogging(BOOL(^condition)(), NSTimeInterval loggingTimeout, NSString *message, ...)
+{
+    NSDate *startTime = [NSDate date];
+    BOOL exceededLoggingTimeout = NO;
+    while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]) {
+        if (condition())
+            break;
+
+        if (exceededLoggingTimeout || [[NSDate date] timeIntervalSinceDate:startTime] < loggingTimeout)
+            continue;
+
+        va_list args;
+        va_start(args, message);
+        NSLogv(message, args);
+        va_end(args);
+        exceededLoggingTimeout = YES;
+    }
+}
+
 TEST(DragAndDropTests, NumberOfValidItemsForDrop)
 {
     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
@@ -39,10 +58,6 @@
     auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:NSMakeRect(0, 0, 400, 400)]);
     TestWKWebView *webView = [simulator webView];
     [simulator setExternalDragPasteboard:pasteboard];
-
-    auto hostWindow = adoptNS([[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 400, 400) styleMask:0 backing:NSBackingStoreBuffered defer:NO]);
-    [hostWindow setFrameOrigin:NSMakePoint(0, 0)];
-    [[hostWindow contentView] addSubview:webView];
     [webView synchronouslyLoadTestPageNamed:@"full-page-dropzone"];
 
     NSInteger numberOfValidItemsForDrop = 0;
@@ -75,4 +90,49 @@
 }
 #endif // ENABLE(INPUT_TYPE_COLOR)
 
+TEST(DragAndDropTests, DragImageElementIntoFileUpload)
+{
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:NSMakeRect(0, 0, 400, 400)]);
+    TestWKWebView *webView = [simulator webView];
+    [webView synchronouslyLoadTestPageNamed:@"image-and-file-upload"];
+    [simulator runFrom:NSMakePoint(100, 100) to:NSMakePoint(100, 300)];
+
+    waitForConditionWithLogging([&] () -> BOOL {
+        return [webView stringByEvaluatingJavaScript:@"imageload.textContent"].boolValue;
+    }, 2, @"Expected image to finish loading.");
+    EXPECT_EQ(1, [webView stringByEvaluatingJavaScript:@"filecount.textContent"].integerValue);
+}
+
+TEST(DragAndDropTests, DragPromisedImageFileIntoFileUpload)
+{
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:NSMakeRect(0, 0, 400, 400)]);
+    TestWKWebView *webView = [simulator webView];
+    [webView synchronouslyLoadTestPageNamed:@"image-and-file-upload"];
+
+    NSURL *imageURL = [NSBundle.mainBundle URLForResource:@"apple" withExtension:@"gif" subdirectory:@"TestWebKitAPI.resources"];
+    [simulator writePromisedFiles:@[ imageURL ]];
+    [simulator runFrom:NSMakePoint(100, 100) to:NSMakePoint(100, 300)];
+
+    waitForConditionWithLogging([&] () -> BOOL {
+        return [webView stringByEvaluatingJavaScript:@"imageload.textContent"].boolValue;
+    }, 2, @"Expected image to finish loading.");
+    EXPECT_EQ(1, [webView stringByEvaluatingJavaScript:@"filecount.textContent"].integerValue);
+}
+
+TEST(DragAndDropTests, DragImageFileIntoFileUpload)
+{
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebViewFrame:NSMakeRect(0, 0, 400, 400)]);
+    TestWKWebView *webView = [simulator webView];
+    [webView synchronouslyLoadTestPageNamed:@"image-and-file-upload"];
+
+    NSURL *imageURL = [NSBundle.mainBundle URLForResource:@"apple" withExtension:@"gif" subdirectory:@"TestWebKitAPI.resources"];
+    [simulator writeFiles:@[ imageURL ]];
+    [simulator runFrom:NSMakePoint(100, 100) to:NSMakePoint(100, 300)];
+
+    waitForConditionWithLogging([&] () -> BOOL {
+        return [webView stringByEvaluatingJavaScript:@"imageload.textContent"].boolValue;
+    }, 2, @"Expected image to finish loading.");
+    EXPECT_EQ(1, [webView stringByEvaluatingJavaScript:@"filecount.textContent"].integerValue);
+}
+
 #endif // WK_API_ENABLED && ENABLE(DRAG_SUPPORT) && PLATFORM(MAC)

Modified: trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h (234975 => 234976)


--- trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h	2018-08-17 04:58:49 UTC (rev 234976)
@@ -116,8 +116,12 @@
 @property (nonatomic, readonly) NSDragOperation currentDragOperation;
 @property (nonatomic, strong) NSPasteboard *externalDragPasteboard;
 @property (nonatomic, strong) NSImage *externalDragImage;
+@property (nonatomic, readonly) NSArray<NSURL *> *externalPromisedFiles;
 @property (nonatomic, copy) dispatch_block_t willEndDraggingHandler;
 
+- (void)writePromisedFiles:(NSArray<NSURL *> *)fileURLs;
+- (void)writeFiles:(NSArray<NSURL *> *)fileURLs;
+
 #endif // PLATFORM(MAC)
 
 @end

Modified: trunk/Tools/TestWebKitAPI/mac/DragAndDropSimulatorMac.mm (234975 => 234976)


--- trunk/Tools/TestWebKitAPI/mac/DragAndDropSimulatorMac.mm	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/TestWebKitAPI/mac/DragAndDropSimulatorMac.mm	2018-08-17 04:58:49 UTC (rev 234976)
@@ -84,6 +84,7 @@
     RetainPtr<TestDraggingInfo> _draggingInfo;
     RetainPtr<NSPasteboard> _externalDragPasteboard;
     RetainPtr<NSImage> _externalDragImage;
+    RetainPtr<NSArray<NSURL *>> _externalPromisedFiles;
     BlockPtr<void()> _willEndDraggingHandler;
     NSPoint _startLocationInWindow;
     NSPoint _endLocationInWindow;
@@ -160,7 +161,7 @@
 - (void)performDragInWebView:(DragAndDropTestWKWebView *)webView atLocation:(NSPoint)viewLocation withImage:(NSImage *)image pasteboard:(NSPasteboard *)pasteboard source:(id)source
 {
     _initialDragImageLocationInView = viewLocation;
-    _draggingInfo = adoptNS([[TestDraggingInfo alloc] init]);
+    _draggingInfo = adoptNS([[TestDraggingInfo alloc] initWithDragAndDropSimulator:self]);
     [_draggingInfo setDraggedImage:image];
     [_draggingInfo setDraggingPasteboard:pasteboard];
     [_draggingInfo setDraggingSource:source];
@@ -245,6 +246,68 @@
     _willEndDraggingHandler = makeBlockPtr(willEndDraggingHandler);
 }
 
+- (NSArray<NSURL *> *)externalPromisedFiles
+{
+    return _externalPromisedFiles.get();
+}
+
+static BOOL getFilePathsAndTypeIdentifiers(NSArray<NSURL *> *fileURLs, NSArray<NSString *> **outFilePaths, NSArray<NSString *> **outTypeIdentifiers)
+{
+    NSMutableArray *filePaths = [NSMutableArray arrayWithCapacity:fileURLs.count];
+    NSMutableArray *typeIdentifiers = [NSMutableArray arrayWithCapacity:fileURLs.count];
+    for (NSURL *url in fileURLs) {
+        NSString *typeIdentifier = nil;
+        NSError *error = nil;
+        BOOL foundUTI = [url getResourceValue:&typeIdentifier forKey:NSURLTypeIdentifierKey error:&error];
+        if (!foundUTI || error) {
+            [NSException raise:@"DragAndDropSimulator" format:@"Failed to get UTI for promised file: %@ with error: %@", url, error];
+            continue;
+        }
+        [typeIdentifiers addObject:typeIdentifier];
+        [filePaths addObject:url.path];
+    }
+
+    if (fileURLs.count != filePaths.count)
+        return NO;
+
+    if (outTypeIdentifiers)
+        *outTypeIdentifiers = typeIdentifiers;
+
+    if (outFilePaths)
+        *outFilePaths = filePaths;
+
+    return YES;
+}
+
+- (void)writePromisedFiles:(NSArray<NSURL *> *)fileURLs
+{
+    NSArray *paths = nil;
+    NSArray *types = nil;
+    if (!getFilePathsAndTypeIdentifiers(fileURLs, &paths, &types))
+        return;
+
+    NSMutableArray *names = [NSMutableArray arrayWithCapacity:paths.count];
+    for (NSString *path in paths)
+        [names addObject:path.lastPathComponent];
+
+    _externalPromisedFiles = fileURLs;
+    _externalDragPasteboard = [NSPasteboard pasteboardWithUniqueName];
+    [_externalDragPasteboard declareTypes:@[NSFilesPromisePboardType, NSFilenamesPboardType] owner:nil];
+    [_externalDragPasteboard setPropertyList:types forType:NSFilesPromisePboardType];
+    [_externalDragPasteboard setPropertyList:names forType:NSFilenamesPboardType];
+}
+
+- (void)writeFiles:(NSArray<NSURL *> *)fileURLs
+{
+    NSArray *paths = nil;
+    if (!getFilePathsAndTypeIdentifiers(fileURLs, &paths, nil))
+        return;
+
+    _externalDragPasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+    [_externalDragPasteboard declareTypes:@[NSFilenamesPboardType] owner:nil];
+    [_externalDragPasteboard setPropertyList:paths forType:NSFilenamesPboardType];
+}
+
 @end
 
 #endif // ENABLE(DRAG_SUPPORT) && PLATFORM(MAC) && WK_API_ENABLED

Modified: trunk/Tools/TestWebKitAPI/mac/TestDraggingInfo.h (234975 => 234976)


--- trunk/Tools/TestWebKitAPI/mac/TestDraggingInfo.h	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/TestWebKitAPI/mac/TestDraggingInfo.h	2018-08-17 04:58:49 UTC (rev 234976)
@@ -29,8 +29,13 @@
 
 #import <AppKit/NSDragging.h>
 
+@class DragAndDropSimulator;
+
 @interface TestDraggingInfo : NSObject <NSDraggingInfo>
 
+- (instancetype)initWithDragAndDropSimulator:(DragAndDropSimulator *)simulator NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
 @property (nonatomic) NSPoint draggingLocation;
 @property (nonatomic) NSPoint draggedImageLocation;
 @property (nonatomic) NSInteger draggingSequenceNumber;
@@ -38,6 +43,7 @@
 @property (nonatomic, strong) NSPasteboard *draggingPasteboard;
 @property (nonatomic, strong) NSImage *draggedImage;
 @property (nonatomic, weak) id draggingSource;
+@property (nonatomic, readonly) NSArray<NSFilePromiseReceiver *> *filePromiseReceivers;
 
 @end
 

Modified: trunk/Tools/TestWebKitAPI/mac/TestDraggingInfo.mm (234975 => 234976)


--- trunk/Tools/TestWebKitAPI/mac/TestDraggingInfo.mm	2018-08-17 03:06:40 UTC (rev 234975)
+++ trunk/Tools/TestWebKitAPI/mac/TestDraggingInfo.mm	2018-08-17 04:58:49 UTC (rev 234976)
@@ -28,19 +28,41 @@
 
 #if ENABLE(DRAG_SUPPORT) && PLATFORM(MAC) && WK_API_ENABLED
 
+#import "DragAndDropSimulator.h"
+#import "TestFilePromiseReceiver.h"
 #import <wtf/WeakObjCPtr.h>
 
+@interface NSDraggingItem ()
+@property (nonatomic, strong) id item;
+@end
+
 @implementation TestDraggingInfo {
     WeakObjCPtr<id> _source;
+    WeakObjCPtr<DragAndDropSimulator> _dragAndDropSimulator;
     RetainPtr<NSPasteboard> _pasteboard;
     RetainPtr<NSImage> _draggedImage;
+    RetainPtr<NSMutableArray<NSFilePromiseReceiver *>> _filePromiseReceivers;
 }
 
+- (instancetype)initWithDragAndDropSimulator:(DragAndDropSimulator *)simulator
+{
+    if (self = [super init]) {
+        _filePromiseReceivers = adoptNS([NSMutableArray new]);
+        _dragAndDropSimulator = simulator;
+    }
+    return self;
+}
+
 @synthesize draggingSourceOperationMask=_draggingSourceOperationMask;
 @synthesize draggingLocation=_draggingLocation;
 @synthesize draggingFormation=_draggingFormation;
 @synthesize numberOfValidItemsForDrop=_numberOfValidItemsForDrop;
 
+- (NSArray<NSFilePromiseReceiver *> *)filePromiseReceivers
+{
+    return _filePromiseReceivers.get();
+}
+
 - (NSPasteboard *)draggingPasteboard
 {
     return _pasteboard.get();
@@ -61,9 +83,45 @@
     _source = draggingSource;
 }
 
-- (void)enumerateDraggingItemsWithOptions:(NSDraggingItemEnumerationOptions)enumOpts forView:(NSView *)view classes:(NSArray<Class> *)classArray searchOptions:(NSDictionary<NSString *, id> *)searchOptions usingBlock:(void (^)(NSDraggingItem *, NSInteger, BOOL *))block
+- (void)enumerateDraggingItemsWithOptions:(NSDraggingItemEnumerationOptions)enumerationOptions forView:(NSView *)view classes:(NSArray<Class> *)classes searchOptions:(NSDictionary<NSString *, id> *)searchOptions usingBlock:(void (^)(NSDraggingItem *, NSInteger, BOOL *))block
 {
-    // FIXME: Implement this to test file promise drop handling.
+    // FIXME: Much of this can be shared with existing drag and drop testing code in DumpRenderTree.
+
+    if (enumerationOptions) {
+        [NSException raise:@"DragAndDropSimulator" format:@"Dragging item enumeration options are currently unsupported. (got: %tu)", enumerationOptions];
+        return;
+    }
+
+    if (searchOptions.count) {
+        [NSException raise:@"DragAndDropSimulator" format:@"Search options are currently unsupported. (got: %@)", searchOptions];
+        return;
+    }
+
+    BOOL stop = NO;
+    for (Class classObject in classes) {
+        if (classObject != NSFilePromiseReceiver.class)
+            continue;
+
+        id promisedTypeIdentifiers = [_pasteboard propertyListForType:NSFilesPromisePboardType];
+        if (![promisedTypeIdentifiers isKindOfClass:NSArray.class])
+            break;
+
+        for (id object in promisedTypeIdentifiers) {
+            if (![object isKindOfClass:NSString.class])
+                break;
+        }
+
+        auto receiver = adoptNS([[TestFilePromiseReceiver alloc] initWithPromisedTypeIdentifiers:promisedTypeIdentifiers dragAndDropSimulator:_dragAndDropSimulator.getAutoreleased()]);
+        [receiver setDraggingSource:_source.get().get()];
+        [_filePromiseReceivers addObject:receiver.get()];
+
+        auto item = adoptNS([NSDraggingItem new]);
+        [item setItem:receiver.get()];
+
+        block(item.get(), 0, &stop);
+        if (stop)
+            break;
+    }
 }
 
 // The following methods are not currently used by WebKit.

Copied: trunk/Tools/TestWebKitAPI/mac/TestFilePromiseReceiver.h (from rev 234975, trunk/Tools/TestWebKitAPI/mac/TestDraggingInfo.h) (0 => 234976)


--- trunk/Tools/TestWebKitAPI/mac/TestFilePromiseReceiver.h	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/mac/TestFilePromiseReceiver.h	2018-08-17 04:58:49 UTC (rev 234976)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#if PLATFORM(MAC) && WK_API_ENABLED
+
+#import <AppKit/NSFilePromiseReceiver.h>
+
+@class DragAndDropSimulator;
+
+@interface TestFilePromiseReceiver : NSFilePromiseReceiver
+
+- (instancetype)initWithPromisedTypeIdentifiers:(NSArray<NSString *> *)promisedTypeIdentifiers dragAndDropSimulator:(DragAndDropSimulator *)simulator NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
+@property (nonatomic, weak) id draggingSource;
+
+@end
+
+#endif

Added: trunk/Tools/TestWebKitAPI/mac/TestFilePromiseReceiver.mm (0 => 234976)


--- trunk/Tools/TestWebKitAPI/mac/TestFilePromiseReceiver.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/mac/TestFilePromiseReceiver.mm	2018-08-17 04:58:49 UTC (rev 234976)
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 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"
+#import "TestFilePromiseReceiver.h"
+
+#if PLATFORM(MAC) && WK_API_ENABLED
+
+#import "DragAndDropSimulator.h"
+#import <wtf/RetainPtr.h>
+#import <wtf/WeakObjCPtr.h>
+
+@implementation TestFilePromiseReceiver {
+    RetainPtr<NSArray<NSString *>> _promisedTypeIdentifiers;
+    RetainPtr<NSMutableArray<NSURL *>> _destinationURLs;
+    WeakObjCPtr<id> _draggingSource;
+    WeakObjCPtr<DragAndDropSimulator> _dragAndDropSimulator;
+}
+
+- (instancetype)initWithPromisedTypeIdentifiers:(NSArray<NSString *> *)promisedTypeIdentifiers dragAndDropSimulator:(DragAndDropSimulator *)simulator
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _dragAndDropSimulator = simulator;
+    _promisedTypeIdentifiers = adoptNS([promisedTypeIdentifiers copy]);
+    _destinationURLs = adoptNS([NSMutableArray new]);
+    return self;
+}
+
+- (NSArray<NSString *> *)fileTypes
+{
+    return _promisedTypeIdentifiers.get();
+}
+
+- (NSArray<NSString *> *)fileNames
+{
+    NSMutableArray *fileNames = [NSMutableArray arrayWithCapacity:[_destinationURLs count]];
+    for (NSURL *url in _destinationURLs.get())
+        [fileNames addObject:url.lastPathComponent];
+    return fileNames;
+}
+
+- (void)dealloc
+{
+    for (NSURL *destinationURL in _destinationURLs.get())
+        [[NSFileManager defaultManager] removeItemAtURL:destinationURL error:nil];
+
+    [super dealloc];
+}
+
+- (id)draggingSource
+{
+    return _draggingSource.get().get();
+}
+
+- (void)setDraggingSource:(id)draggingSource
+{
+    _draggingSource = draggingSource;
+}
+
+static NSString *fileNameWithNumericSuffix(NSString *fileName, NSUInteger suffix)
+{
+    return [NSString stringWithFormat:@"%@ %zu.%@", fileName.stringByDeletingPathExtension, suffix, fileName.pathExtension];
+}
+
+static NSURL *copyFile(NSURL *sourceURL, NSURL *destinationDirectory, NSError **outError)
+{
+    NSUInteger suffix = 0;
+    NSString *fileName = sourceURL.lastPathComponent;
+    NSURL *destinationURL = [NSURL fileURLWithPath:fileName relativeToURL:destinationDirectory];
+    NSError *error;
+    while (![NSFileManager.defaultManager copyItemAtURL:sourceURL toURL:destinationURL error:&error]) {
+        if (error.domain != NSCocoaErrorDomain || error.code != NSFileWriteFileExistsError) {
+            if (outError)
+                *outError = error;
+            return nil;
+        }
+        destinationURL = [NSURL fileURLWithPath:fileNameWithNumericSuffix(fileName, ++suffix) relativeToURL:destinationDirectory];
+    }
+    return destinationURL;
+}
+
+- (void)receivePromisedFilesAtDestination:(NSURL *)destinationDirectory options:(NSDictionary *)options operationQueue:(NSOperationQueue *)queue reader:(void (^)(NSURL *, NSError *))reader
+{
+    for (NSURL *sourceURL in [_dragAndDropSimulator externalPromisedFiles]) {
+        [queue addOperationWithBlock:^{
+            NSError *error = nil;
+            NSURL *destination = copyFile(sourceURL, destinationDirectory, &error);
+            if (destination) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    [_destinationURLs addObject:destination];
+                });
+            }
+            reader(destination, error);
+        }];
+    }
+}
+
+@end
+
+#endif // PLATFORM(MAC) && WK_API_ENABLED
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to