Index: Source/web/tests/FrameTestHelpers.cpp |
diff --git a/Source/web/tests/FrameTestHelpers.cpp b/Source/web/tests/FrameTestHelpers.cpp |
index e430f3226674b59e496716d5c98b88f2b20c1bea..df2fdf0d14d83e87a57244c029106c1b4677dca8 100644 |
--- a/Source/web/tests/FrameTestHelpers.cpp |
+++ b/Source/web/tests/FrameTestHelpers.cpp |
@@ -32,6 +32,7 @@ |
#include "web/tests/FrameTestHelpers.h" |
#include "public/platform/Platform.h" |
+#include "public/platform/WebData.h" |
#include "public/platform/WebString.h" |
#include "public/platform/WebThread.h" |
#include "public/platform/WebURLRequest.h" |
@@ -48,6 +49,26 @@ namespace FrameTestHelpers { |
namespace { |
+// The frame test helpers coordinate frame loads in a carefully choreographed |
+// dance. Since the parser is threaded, simply spinning the run loop once is not |
+// enough to ensure completion of a load. Instead, the following pattern is |
+// used to ensure that tests see the final state: |
+// 1. Post a task to trigger a load (LoadTask/LoadHTMLStringTask/ReloadTask). |
+// 2. Enter the run loop. |
+// 3. Posted task triggers the load, and starts pumping pending resource |
+// requests using ServeAsyncRequestsTask. |
+// 4. TestWebFrameClient watches for didStartLoading/didStopLoading calls, |
+// keeping track of how many loads it thinks are in flight. |
+// 5. While ServeAsyncRequestsTask observes TestWebFrameClient to still have |
+// loads in progress, it posts itself back to the run loop. |
+// 6. When ServeAsyncRequestsTask notices there are no more loads in progress, |
+// it exits the run loop. |
+// 7. At this point, all parsing, resource loads, and layout should be finished. |
+TestWebFrameClient* testClientForFrame(WebFrame* frame) |
+{ |
+ return static_cast<TestWebFrameClient*>(toWebLocalFrameImpl(frame)->client()); |
+} |
+ |
class QuitTask : public WebThread::Task { |
public: |
void PostThis(WebCore::Timer<QuitTask>*) |
@@ -65,7 +86,111 @@ public: |
} |
}; |
-WebFrameClient* defaultWebFrameClient() |
+class ServeAsyncRequestsTask : public WebThread::Task { |
+public: |
+ explicit ServeAsyncRequestsTask(TestWebFrameClient* client) |
+ : m_client(client) |
+ { |
+ } |
+ |
+ virtual void run() OVERRIDE |
+ { |
+ Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests(); |
+ if (m_client->isLoading()) |
+ Platform::current()->currentThread()->postTask(new ServeAsyncRequestsTask(m_client)); |
+ else |
+ Platform::current()->currentThread()->exitRunLoop(); |
+ } |
+ |
+private: |
+ TestWebFrameClient* const m_client; |
+}; |
+ |
+void pumpPendingRequests(WebFrame* frame) |
+{ |
+ Platform::current()->currentThread()->postTask(new ServeAsyncRequestsTask(testClientForFrame(frame))); |
+ Platform::current()->currentThread()->enterRunLoop(); |
+} |
+ |
+class LoadTask : public WebThread::Task { |
+public: |
+ LoadTask(WebFrame* frame, const WebURLRequest& request) |
+ : m_frame(frame) |
+ , m_request(request) |
+ { |
+ } |
+ |
+ virtual void run() OVERRIDE |
+ { |
+ m_frame->loadRequest(m_request); |
+ } |
+ |
+private: |
+ WebFrame* const m_frame; |
+ const WebURLRequest m_request; |
+}; |
+ |
+class LoadHTMLStringTask : public WebThread::Task { |
+public: |
+ LoadHTMLStringTask(WebFrame* frame, const std::string& html, const WebURL& baseURL) |
+ : m_frame(frame) |
+ , m_html(html) |
+ , m_baseURL(baseURL) |
+ { |
+ } |
+ |
+ virtual void run() OVERRIDE |
+ { |
+ m_frame->loadHTMLString(WebData(m_html.data(), m_html.size()), m_baseURL); |
+ } |
+ |
+private: |
+ WebFrame* const m_frame; |
+ const std::string m_html; |
+ const WebURL m_baseURL; |
+}; |
+ |
+class LoadHistoryItemTask : public WebThread::Task { |
+public: |
+ LoadHistoryItemTask(WebFrame* frame, const WebHistoryItem& item, WebHistoryLoadType loadType, WebURLRequest::CachePolicy cachePolicy) |
+ : m_frame(frame) |
+ , m_item(item) |
+ , m_loadType(loadType) |
+ , m_cachePolicy(cachePolicy) |
+ { |
+ } |
+ |
+ virtual void run() OVERRIDE |
+ { |
+ m_frame->loadHistoryItem(m_item, m_loadType, m_cachePolicy); |
+ } |
+ |
+private: |
+ WebFrame* const m_frame; |
+ const WebHistoryItem m_item; |
+ const WebHistoryLoadType m_loadType; |
+ const WebURLRequest::CachePolicy m_cachePolicy; |
+}; |
+ |
+class ReloadTask : public WebThread::Task { |
+public: |
+ ReloadTask(WebFrame* frame, bool ignoreCache) |
+ : m_frame(frame) |
+ , m_ignoreCache(ignoreCache) |
+ { |
+ } |
+ |
+ virtual void run() OVERRIDE |
+ { |
+ m_frame->reload(m_ignoreCache); |
+ } |
+ |
+private: |
+ WebFrame* const m_frame; |
+ const bool m_ignoreCache; |
+}; |
+ |
+TestWebFrameClient* defaultWebFrameClient() |
{ |
DEFINE_STATIC_LOCAL(TestWebFrameClient, client, ()); |
return &client; |
@@ -84,9 +209,41 @@ void loadFrame(WebFrame* frame, const std::string& url) |
WebURLRequest urlRequest; |
urlRequest.initialize(); |
urlRequest.setURL(URLTestHelpers::toKURL(url)); |
- frame->loadRequest(urlRequest); |
+ |
+ Platform::current()->currentThread()->postTask(new LoadTask(frame, urlRequest)); |
+ pumpPendingRequests(frame); |
+} |
+ |
+void loadHTMLString(WebFrame* frame, const std::string& html, const WebURL& baseURL) |
+{ |
+ Platform::current()->currentThread()->postTask(new LoadHTMLStringTask(frame, html, baseURL)); |
+ pumpPendingRequests(frame); |
+} |
+ |
+void loadHistoryItem(WebFrame* frame, const WebHistoryItem& item, WebHistoryLoadType loadType, WebURLRequest::CachePolicy cachePolicy) |
+{ |
+ Platform::current()->currentThread()->postTask(new LoadHistoryItemTask(frame, item, loadType, cachePolicy)); |
+ pumpPendingRequests(frame); |
+} |
+ |
+void reloadFrame(WebFrame* frame) |
+{ |
+ Platform::current()->currentThread()->postTask(new ReloadTask(frame, false)); |
+ pumpPendingRequests(frame); |
+} |
+ |
+void reloadFrameIgnoringCache(WebFrame* frame) |
+{ |
+ Platform::current()->currentThread()->postTask(new ReloadTask(frame, true)); |
+ pumpPendingRequests(frame); |
+} |
+ |
+void pumpPendingRequestsDoNotUse(WebFrame* frame) |
+{ |
+ pumpPendingRequests(frame); |
} |
+// FIXME: There's a duplicate implementation in UnitTestHelpers.cpp. Remove one. |
void runPendingTasks() |
{ |
// Pending tasks include Timers that have been scheduled. |
@@ -105,7 +262,7 @@ WebViewHelper::~WebViewHelper() |
reset(); |
} |
-WebViewImpl* WebViewHelper::initialize(bool enableJavascript, WebFrameClient* webFrameClient, WebViewClient* webViewClient, void (*updateSettingsFunc)(WebSettings*)) |
+WebViewImpl* WebViewHelper::initialize(bool enableJavascript, TestWebFrameClient* webFrameClient, WebViewClient* webViewClient, void (*updateSettingsFunc)(WebSettings*)) |
{ |
reset(); |
@@ -127,12 +284,11 @@ WebViewImpl* WebViewHelper::initialize(bool enableJavascript, WebFrameClient* we |
return m_webView; |
} |
-WebViewImpl* WebViewHelper::initializeAndLoad(const std::string& url, bool enableJavascript, WebFrameClient* webFrameClient, WebViewClient* webViewClient, void (*updateSettingsFunc)(WebSettings*)) |
+WebViewImpl* WebViewHelper::initializeAndLoad(const std::string& url, bool enableJavascript, TestWebFrameClient* webFrameClient, WebViewClient* webViewClient, void (*updateSettingsFunc)(WebSettings*)) |
{ |
initialize(enableJavascript, webFrameClient, webViewClient, updateSettingsFunc); |
loadFrame(webView()->mainFrame(), url); |
- Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests(); |
return webViewImpl(); |
} |
@@ -140,11 +296,16 @@ WebViewImpl* WebViewHelper::initializeAndLoad(const std::string& url, bool enabl |
void WebViewHelper::reset() |
{ |
if (m_webView) { |
+ ASSERT(!testClientForFrame(m_webView->mainFrame())->isLoading()); |
m_webView->close(); |
m_webView = 0; |
} |
} |
+TestWebFrameClient::TestWebFrameClient() : m_loadsInProgress(0) |
+{ |
+} |
+ |
WebFrame* TestWebFrameClient::createChildFrame(WebLocalFrame* parent, const WebString& frameName) |
{ |
WebFrame* frame = WebLocalFrame::create(this); |
@@ -159,6 +320,17 @@ void TestWebFrameClient::frameDetached(WebFrame* frame) |
frame->close(); |
} |
+void TestWebFrameClient::didStartLoading(bool) |
+{ |
+ ++m_loadsInProgress; |
+} |
+ |
+void TestWebFrameClient::didStopLoading() |
+{ |
+ ASSERT(m_loadsInProgress > 0); |
+ --m_loadsInProgress; |
+} |
+ |
void TestWebViewClient::initializeLayerTreeView() |
{ |
m_layerTreeView = adoptPtr(Platform::current()->unitTestSupport()->createLayerTreeViewForTesting(WebUnitTestSupport::TestViewTypeUnitTest)); |