Index: Source/web/tests/DocumentLoaderTest.cpp |
diff --git a/Source/web/tests/DocumentLoaderTest.cpp b/Source/web/tests/DocumentLoaderTest.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..71da5854b900e726c15a736f6b91b3e9f911fdf9 |
--- /dev/null |
+++ b/Source/web/tests/DocumentLoaderTest.cpp |
@@ -0,0 +1,169 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+ |
+#include "platform/testing/URLTestHelpers.h" |
+#include "public/platform/Platform.h" |
+#include "public/platform/WebURLLoaderClient.h" |
+#include "public/platform/WebUnitTestSupport.h" |
+#include "web/WebLocalFrameImpl.h" |
+#include "web/tests/FrameTestHelpers.h" |
+#include "wtf/TemporaryChange.h" |
+#include <gtest/gtest.h> |
+#include <queue> |
+#include <vector> |
+ |
+namespace blink { |
+ |
+class DocumentLoaderTest : public ::testing::Test { |
Nate Chapin
2015/08/11 17:36:36
It feels wrong to put this in web/ given the name.
dcheng
2015/08/11 17:41:37
It does. The problem is:
- I can't put this test i
Nate Chapin
2015/08/12 21:10:53
Ideally, we'd have enough of FrameTestHelpers in c
dcheng
2015/08/12 22:06:40
Done.
|
+protected: |
+ void SetUp() override |
+ { |
+ m_webViewHelper.initialize(); |
+ URLTestHelpers::registerMockedURLLoad(URLTestHelpers::toKURL( |
+ "https://example.com/foo.html"), "foo.html"); |
+ } |
+ |
+ void TearDown() override |
+ { |
+ Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); |
+ } |
+ |
+ WebLocalFrameImpl* mainFrame() |
+ { |
+ return m_webViewHelper.webViewImpl()->mainFrameImpl(); |
+ } |
+ |
+ FrameTestHelpers::WebViewHelper m_webViewHelper; |
+}; |
+ |
+TEST_F(DocumentLoaderTest, SingleChunk) |
+{ |
+ class TestDelegate : public WebURLLoaderTestDelegate { |
+ public: |
+ void didReceiveData(WebURLLoaderClient* originalClient, WebURLLoader* loader, const char* data, int dataLength, int encodedDataLength) override |
+ { |
+ EXPECT_EQ(34, dataLength) << "foo.html was not served in a single chunk"; |
+ originalClient->didReceiveData(loader, data, dataLength, encodedDataLength); |
+ } |
+ } delegate; |
Nate Chapin
2015/08/11 17:36:36
What does this syntax do? I'm not familiar with it
dcheng
2015/08/11 17:41:37
I just collapsed the definition of the class and t
|
+ |
+ Platform::current()->unitTestSupport()->setLoaderDelegate(&delegate); |
+ FrameTestHelpers::loadFrame(mainFrame(), "https://example.com/foo.html"); |
+ Platform::current()->unitTestSupport()->setLoaderDelegate(nullptr); |
+ |
+ // TODO(dcheng): How should the test verify that the original callback is |
+ // invoked? The test currently still passes even if the test delegate |
+ // forgets to invoke the callback. |
+} |
+ |
+// Test normal case of DocumentLoader::dataReceived(): data in multiple chunks, |
+// with no reentrancy. |
+TEST_F(DocumentLoaderTest, MultiChunkNoReentrancy) |
+{ |
+ class TestDelegate : public WebURLLoaderTestDelegate { |
+ public: |
+ void didReceiveData(WebURLLoaderClient* originalClient, WebURLLoader* loader, const char* data, int dataLength, int encodedDataLength) override |
+ { |
+ EXPECT_EQ(34, dataLength) << "foo.html was not served in a single chunk"; |
+ // Chunk the reply into one byte chunks. |
+ for (int i = 0; i < dataLength; ++i) |
+ originalClient->didReceiveData(loader, &data[i], 1, 1); |
+ } |
+ } delegate; |
+ |
+ Platform::current()->unitTestSupport()->setLoaderDelegate(&delegate); |
+ FrameTestHelpers::loadFrame(mainFrame(), "https://example.com/foo.html"); |
+ Platform::current()->unitTestSupport()->setLoaderDelegate(nullptr); |
+} |
+ |
+// Finally, test reentrant callbacks to DocumentLoader::dataReceived(). |
+TEST_F(DocumentLoaderTest, MultiChunkWithReentrancy) |
+{ |
+ // This test delegate chunks the response stage into three distinct stages: |
+ // 1. The first dataReceived() callback, which triggers frame detach due to |
+ // commiting a provisional load. |
+ // 2. The middle part of the response, which is dispatched to |
+ // dataReceived() reentrantly. |
+ // 3. The final chunk, which is dispatched normally at the top-level. |
+ class TestDelegate |
+ : public WebURLLoaderTestDelegate, public FrameTestHelpers::TestWebFrameClient { |
+ public: |
+ TestDelegate() : m_loaderClient(nullptr), m_loader(nullptr), m_dispatchingDidReceiveData(false), m_servedReentrantly(false) { } |
+ |
+ // WebURLLoaderTestDelegate overrides: |
+ void didReceiveData(WebURLLoaderClient* originalClient, WebURLLoader* loader, const char* data, int dataLength, int encodedDataLength) override |
+ { |
+ EXPECT_EQ(34, dataLength) << "foo.html was not served in a single chunk"; |
+ |
+ m_loaderClient = originalClient; |
+ m_loader = loader; |
+ for (int i = 0; i < dataLength; ++i) |
+ m_data.push(data[i]); |
+ |
+ { |
+ // Serve the first byte to the real WebURLLoaderCLient, which |
+ // should trigger frameDetach() due to committing a provisional |
+ // load. |
+ TemporaryChange<bool> dispatching(m_dispatchingDidReceiveData, true); |
+ dispatchOneByte(); |
+ } |
+ // Serve the remaining bytes to complete the load. |
+ EXPECT_FALSE(m_data.empty()); |
+ while (!m_data.empty()) |
+ dispatchOneByte(); |
+ } |
+ |
+ // WebFrameClient overrides: |
+ void frameDetached(WebFrame* frame, DetachType detachType) override |
+ { |
+ if (m_dispatchingDidReceiveData) { |
+ // This should be called by the first didReceiveData() call, since |
+ // it should commit the provisional load. |
+ EXPECT_GT(m_data.size(), 10u); |
+ // Dispatch dataReceived() callbacks for part of the remaining |
+ // data, saving the rest to be dispatched at the top-level as |
+ // normal. |
+ while (m_data.size() > 10) |
+ dispatchOneByte(); |
+ m_servedReentrantly = true; |
+ } |
+ TestWebFrameClient::frameDetached(frame, detachType); |
+ } |
+ |
+ void dispatchOneByte() |
+ { |
+ char c = m_data.front(); |
+ m_data.pop(); |
+ m_loaderClient->didReceiveData(m_loader, &c, 1, 1); |
+ } |
+ |
+ bool servedReentrantly() const { return m_servedReentrantly; } |
+ |
+ private: |
+ WebURLLoaderClient* m_loaderClient; |
+ WebURLLoader* m_loader; |
+ std::queue<char> m_data; |
+ bool m_dispatchingDidReceiveData; |
+ bool m_servedReentrantly; |
+ } delegate; |
+ m_webViewHelper.initialize(false, &delegate); |
+ |
+ // This doesn't go through the mocked URL load path: it's just intended to |
+ // setup a situation where didReceiveData() can be invoked reentrantly. |
+ FrameTestHelpers::loadHTMLString(mainFrame(), "<iframe></iframe>", URLTestHelpers::toKURL("about:blank")); |
+ |
+ Platform::current()->unitTestSupport()->setLoaderDelegate(&delegate); |
+ FrameTestHelpers::loadFrame(mainFrame(), "https://example.com/foo.html"); |
+ Platform::current()->unitTestSupport()->setLoaderDelegate(nullptr); |
+ |
+ EXPECT_TRUE(delegate.servedReentrantly()); |
+ |
+ // delegate is a WebFrameClient and stack-allocated, so manually reset() the |
+ // WebViewHelper here. |
+ m_webViewHelper.reset(); |
+} |
+ |
+} // namespace blink |