| Index: third_party/WebKit/Source/modules/fetch/FormDataBytesConsumerTest.cpp
|
| diff --git a/third_party/WebKit/Source/modules/fetch/FormDataBytesConsumerTest.cpp b/third_party/WebKit/Source/modules/fetch/FormDataBytesConsumerTest.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..94ac06429a0525753bc56e077e34be7d4b305546
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/modules/fetch/FormDataBytesConsumerTest.cpp
|
| @@ -0,0 +1,385 @@
|
| +// Copyright 2016 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 "modules/fetch/FormDataBytesConsumer.h"
|
| +
|
| +#include "core/dom/DOMArrayBuffer.h"
|
| +#include "core/dom/DOMTypedArray.h"
|
| +#include "core/dom/Document.h"
|
| +#include "core/html/FormData.h"
|
| +#include "core/testing/DummyPageHolder.h"
|
| +#include "modules/fetch/BytesConsumerTestUtil.h"
|
| +#include "platform/blob/BlobData.h"
|
| +#include "platform/network/EncodedFormData.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "wtf/RefPtr.h"
|
| +#include "wtf/Vector.h"
|
| +#include "wtf/text/WTFString.h"
|
| +
|
| +namespace blink {
|
| +namespace {
|
| +
|
| +using Result = BytesConsumer::Result;
|
| +using ::testing::_;
|
| +using ::testing::DoAll;
|
| +using ::testing::InSequence;
|
| +using ::testing::Return;
|
| +using Checkpoint = ::testing::StrictMock<::testing::MockFunction<void(int)>>;
|
| +
|
| +String toString(const Vector<char>& v)
|
| +{
|
| + return String(v.data(), v.size());
|
| +}
|
| +
|
| +PassRefPtr<EncodedFormData> complexFormData()
|
| +{
|
| + RefPtr<EncodedFormData> data = EncodedFormData::create();
|
| +
|
| + data->appendData("foo", 3);
|
| + data->appendFileRange("/foo/bar/baz", 3, 4, 5);
|
| + data->appendFileSystemURLRange(KURL(KURL(), "file:///foo/bar/baz"), 6, 7, 8);
|
| + std::unique_ptr<BlobData> blobData = BlobData::create();
|
| + blobData->appendText("hello", false);
|
| + auto size = blobData->length();
|
| + RefPtr<BlobDataHandle> blobDataHandle = BlobDataHandle::create(std::move(blobData), size);
|
| + data->appendBlob(blobDataHandle->uuid(), blobDataHandle);
|
| + Vector<char> boundary;
|
| + boundary.append("\0", 1);
|
| + data->setBoundary(boundary);
|
| + return data.release();
|
| +}
|
| +
|
| +class NoopClient final : public GarbageCollectedFinalized<NoopClient>, public BytesConsumer::Client {
|
| + USING_GARBAGE_COLLECTED_MIXIN(NoopClient);
|
| +public:
|
| + void onStateChange() override {}
|
| +};
|
| +
|
| +class MockBytesConsumer : public BytesConsumer {
|
| +public:
|
| + static MockBytesConsumer* create() { return new ::testing::StrictMock<MockBytesConsumer>(); }
|
| +
|
| + MOCK_METHOD2(beginRead, Result(const char**, size_t*));
|
| + MOCK_METHOD1(endRead, Result(size_t));
|
| + MOCK_METHOD1(setClient, void(Client*));
|
| + MOCK_METHOD0(clearClient, void());
|
| + MOCK_METHOD0(cancel, void());
|
| + MOCK_CONST_METHOD0(getPublicState, PublicState());
|
| + MOCK_CONST_METHOD0(getError, Error());
|
| +
|
| + String debugName() const override { return "MockBytesConsumer"; }
|
| +
|
| +protected:
|
| + MockBytesConsumer() = default;
|
| +};
|
| +
|
| +class FormDataBytesConsumerTest : public ::testing::Test {
|
| +public:
|
| + FormDataBytesConsumerTest() : m_page(DummyPageHolder::create()) {}
|
| +
|
| +protected:
|
| + Document* getDocument() { return &m_page->document(); }
|
| +
|
| + std::unique_ptr<DummyPageHolder> m_page;
|
| +};
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromString)
|
| +{
|
| + auto result = (new BytesConsumerTestUtil::TwoPhaseReader(new FormDataBytesConsumer("hello, world")))->run();
|
| + EXPECT_EQ(Result::Done, result.first);
|
| + EXPECT_EQ("hello, world", toString(result.second));
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromStringNonLatin)
|
| +{
|
| + constexpr UChar cs[] = {0x3042, 0};
|
| + auto result = (new BytesConsumerTestUtil::TwoPhaseReader(new FormDataBytesConsumer(String(cs))))->run();
|
| + EXPECT_EQ(Result::Done, result.first);
|
| + EXPECT_EQ("\xe3\x81\x82", toString(result.second));
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromArrayBuffer)
|
| +{
|
| + constexpr unsigned char data[] = { 0x21, 0xfe, 0x00, 0x00, 0xff, 0xa3, 0x42, 0x30, 0x42, 0x99, 0x88 };
|
| + DOMArrayBuffer* buffer = DOMArrayBuffer::create(data, WTF_ARRAY_LENGTH(data));
|
| + auto result = (new BytesConsumerTestUtil::TwoPhaseReader(new FormDataBytesConsumer(buffer)))->run();
|
| + Vector<char> expected;
|
| + expected.append(data, WTF_ARRAY_LENGTH(data));
|
| +
|
| + EXPECT_EQ(Result::Done, result.first);
|
| + EXPECT_EQ(expected, result.second);
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromArrayBufferView)
|
| +{
|
| + constexpr unsigned char data[] = { 0x21, 0xfe, 0x00, 0x00, 0xff, 0xa3, 0x42, 0x30, 0x42, 0x99, 0x88 };
|
| + constexpr size_t offset = 1, size = 4;
|
| + DOMArrayBuffer* buffer = DOMArrayBuffer::create(data, WTF_ARRAY_LENGTH(data));
|
| + auto result = (new BytesConsumerTestUtil::TwoPhaseReader(new FormDataBytesConsumer(DOMUint8Array::create(buffer, offset, size))))->run();
|
| + Vector<char> expected;
|
| + expected.append(data + offset, size);
|
| +
|
| + EXPECT_EQ(Result::Done, result.first);
|
| + EXPECT_EQ(expected, result.second);
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromSimpleFormData)
|
| +{
|
| + RefPtr<EncodedFormData> data = EncodedFormData::create();
|
| + data->appendData("foo", 3);
|
| + data->appendData("hoge", 4);
|
| +
|
| + auto result = (new BytesConsumerTestUtil::TwoPhaseReader(new FormDataBytesConsumer(getDocument(), data)))->run();
|
| + EXPECT_EQ(Result::Done, result.first);
|
| + EXPECT_EQ("foohoge", toString(result.second));
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromComplexFormData)
|
| +{
|
| + RefPtr<EncodedFormData> data = complexFormData();
|
| + MockBytesConsumer* underlying = MockBytesConsumer::create();
|
| + BytesConsumer* consumer = FormDataBytesConsumer::createForTesting(getDocument(), data, underlying);
|
| + Checkpoint checkpoint;
|
| +
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| +
|
| + InSequence s;
|
| + EXPECT_CALL(checkpoint, Call(1));
|
| + EXPECT_CALL(*underlying, beginRead(&buffer, &available)).WillOnce(Return(Result::Ok));
|
| + EXPECT_CALL(checkpoint, Call(2));
|
| + EXPECT_CALL(*underlying, endRead(0)).WillOnce(Return(Result::Ok));
|
| + EXPECT_CALL(checkpoint, Call(3));
|
| +
|
| + checkpoint.Call(1);
|
| + ASSERT_EQ(Result::Ok, consumer->beginRead(&buffer, &available));
|
| + checkpoint.Call(2);
|
| + EXPECT_EQ(Result::Ok, consumer->endRead(0));
|
| + checkpoint.Call(3);
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, EndReadCanReturnDone)
|
| +{
|
| + BytesConsumer* consumer = new FormDataBytesConsumer("hello, world");
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + ASSERT_EQ(Result::Ok, consumer->beginRead(&buffer, &available));
|
| + ASSERT_EQ(12u, available);
|
| + EXPECT_EQ("hello, world", String(buffer, available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::ReadableOrWaiting, consumer->getPublicState());
|
| + EXPECT_EQ(Result::Done, consumer->endRead(available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsBlobDataHandleFromString)
|
| +{
|
| + BytesConsumer* consumer = new FormDataBytesConsumer("hello, world");
|
| + RefPtr<BlobDataHandle> blobDataHandle = consumer->drainAsBlobDataHandle();
|
| + ASSERT_TRUE(blobDataHandle);
|
| +
|
| + EXPECT_EQ(String(), blobDataHandle->type());
|
| + EXPECT_EQ(12u, blobDataHandle->size());
|
| + EXPECT_FALSE(consumer->drainAsFormData());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsBlobDataHandleFromArrayBuffer)
|
| +{
|
| + BytesConsumer* consumer = new FormDataBytesConsumer(DOMArrayBuffer::create("foo", 3));
|
| + RefPtr<BlobDataHandle> blobDataHandle = consumer->drainAsBlobDataHandle();
|
| + ASSERT_TRUE(blobDataHandle);
|
| +
|
| + EXPECT_EQ(String(), blobDataHandle->type());
|
| + EXPECT_EQ(3u, blobDataHandle->size());
|
| + EXPECT_FALSE(consumer->drainAsFormData());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsBlobDataHandleFromSimpleFormData)
|
| +{
|
| + FormData* data = FormData::create(UTF8Encoding());
|
| + data->append("name1", "value1");
|
| + data->append("name2", "value2");
|
| + RefPtr<EncodedFormData> inputFormData = data->encodeMultiPartFormData();
|
| +
|
| + BytesConsumer* consumer = new FormDataBytesConsumer(getDocument(), inputFormData);
|
| + RefPtr<BlobDataHandle> blobDataHandle = consumer->drainAsBlobDataHandle();
|
| + ASSERT_TRUE(blobDataHandle);
|
| +
|
| + EXPECT_EQ(String(), blobDataHandle->type());
|
| + EXPECT_EQ(inputFormData->flattenToString().utf8().length(), blobDataHandle->size());
|
| + EXPECT_FALSE(consumer->drainAsFormData());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsBlobDataHandleFromComplexFormData)
|
| +{
|
| + RefPtr<EncodedFormData> inputFormData = complexFormData();
|
| +
|
| + BytesConsumer* consumer = new FormDataBytesConsumer(getDocument(), inputFormData);
|
| + RefPtr<BlobDataHandle> blobDataHandle = consumer->drainAsBlobDataHandle();
|
| + ASSERT_TRUE(blobDataHandle);
|
| +
|
| + EXPECT_FALSE(consumer->drainAsFormData());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsFormDataFromString)
|
| +{
|
| + BytesConsumer* consumer = new FormDataBytesConsumer("hello, world");
|
| + RefPtr<EncodedFormData> formData = consumer->drainAsFormData();
|
| + ASSERT_TRUE(formData);
|
| + EXPECT_EQ("hello, world", formData->flattenToString());
|
| +
|
| + EXPECT_FALSE(consumer->drainAsBlobDataHandle());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsFormDataFromArrayBuffer)
|
| +{
|
| + BytesConsumer* consumer = new FormDataBytesConsumer(DOMArrayBuffer::create("foo", 3));
|
| + RefPtr<EncodedFormData> formData = consumer->drainAsFormData();
|
| + ASSERT_TRUE(formData);
|
| + EXPECT_TRUE(formData->isSafeToSendToAnotherThread());
|
| + EXPECT_EQ("foo", formData->flattenToString());
|
| +
|
| + EXPECT_FALSE(consumer->drainAsBlobDataHandle());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsFormDataFromSimpleFormData)
|
| +{
|
| + FormData* data = FormData::create(UTF8Encoding());
|
| + data->append("name1", "value1");
|
| + data->append("name2", "value2");
|
| + RefPtr<EncodedFormData> inputFormData = data->encodeMultiPartFormData();
|
| +
|
| + BytesConsumer* consumer = new FormDataBytesConsumer(getDocument(), inputFormData);
|
| + EXPECT_EQ(inputFormData, consumer->drainAsFormData());
|
| + EXPECT_FALSE(consumer->drainAsBlobDataHandle());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, DrainAsFormDataFromComplexFormData)
|
| +{
|
| + RefPtr<EncodedFormData> inputFormData = complexFormData();
|
| +
|
| + BytesConsumer* consumer = new FormDataBytesConsumer(getDocument(), inputFormData);
|
| + EXPECT_EQ(inputFormData, consumer->drainAsFormData());
|
| + EXPECT_FALSE(consumer->drainAsBlobDataHandle());
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ(BytesConsumer::PublicState::Closed, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, BeginReadAffectsDraining)
|
| +{
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + BytesConsumer* consumer = new FormDataBytesConsumer("hello, world");
|
| + ASSERT_EQ(Result::Ok, consumer->beginRead(&buffer, &available));
|
| + EXPECT_EQ("hello, world", String(buffer, available));
|
| +
|
| + ASSERT_EQ(Result::Ok, consumer->endRead(0));
|
| + EXPECT_FALSE(consumer->drainAsFormData());
|
| + EXPECT_FALSE(consumer->drainAsBlobDataHandle());
|
| + EXPECT_EQ(BytesConsumer::PublicState::ReadableOrWaiting, consumer->getPublicState());
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, BeginReadAffectsDrainingWithComplexFormData)
|
| +{
|
| + MockBytesConsumer* underlying = MockBytesConsumer::create();
|
| + BytesConsumer* consumer = FormDataBytesConsumer::createForTesting(getDocument(), complexFormData(), underlying);
|
| +
|
| + const char* buffer = nullptr;
|
| + size_t available = 0;
|
| + Checkpoint checkpoint;
|
| +
|
| + InSequence s;
|
| + EXPECT_CALL(checkpoint, Call(1));
|
| + EXPECT_CALL(*underlying, beginRead(&buffer, &available)).WillOnce(Return(Result::Ok));
|
| + EXPECT_CALL(*underlying, endRead(0)).WillOnce(Return(Result::Ok));
|
| + EXPECT_CALL(checkpoint, Call(2));
|
| + // drainAsFormData / drainAsBlobDataHandle should not be called here.
|
| + EXPECT_CALL(checkpoint, Call(3));
|
| + // |consumer| delegates the getPublicState call to |underlying|.
|
| + EXPECT_CALL(*underlying, getPublicState()).WillOnce(Return(BytesConsumer::PublicState::ReadableOrWaiting));
|
| + EXPECT_CALL(checkpoint, Call(4));
|
| +
|
| + checkpoint.Call(1);
|
| + ASSERT_EQ(Result::Ok, consumer->beginRead(&buffer, &available));
|
| + ASSERT_EQ(Result::Ok, consumer->endRead(0));
|
| + checkpoint.Call(2);
|
| + EXPECT_FALSE(consumer->drainAsFormData());
|
| + EXPECT_FALSE(consumer->drainAsBlobDataHandle());
|
| + checkpoint.Call(3);
|
| + EXPECT_EQ(BytesConsumer::PublicState::ReadableOrWaiting, consumer->getPublicState());
|
| + checkpoint.Call(4);
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, SetClientWithComplexFormData)
|
| +{
|
| + RefPtr<EncodedFormData> inputFormData = complexFormData();
|
| +
|
| + MockBytesConsumer* underlying = MockBytesConsumer::create();
|
| + BytesConsumer* consumer = FormDataBytesConsumer::createForTesting(getDocument(), inputFormData, underlying);
|
| + Checkpoint checkpoint;
|
| +
|
| + InSequence s;
|
| + EXPECT_CALL(checkpoint, Call(1));
|
| + EXPECT_CALL(*underlying, setClient(_));
|
| + EXPECT_CALL(checkpoint, Call(2));
|
| + EXPECT_CALL(*underlying, clearClient());
|
| + EXPECT_CALL(checkpoint, Call(3));
|
| +
|
| + checkpoint.Call(1);
|
| + consumer->setClient(new NoopClient());
|
| + checkpoint.Call(2);
|
| + consumer->clearClient();
|
| + checkpoint.Call(3);
|
| +}
|
| +
|
| +TEST_F(FormDataBytesConsumerTest, CancelWithComplexFormData)
|
| +{
|
| + RefPtr<EncodedFormData> inputFormData = complexFormData();
|
| +
|
| + MockBytesConsumer* underlying = MockBytesConsumer::create();
|
| + BytesConsumer* consumer = FormDataBytesConsumer::createForTesting(getDocument(), inputFormData, underlying);
|
| + Checkpoint checkpoint;
|
| +
|
| + InSequence s;
|
| + EXPECT_CALL(checkpoint, Call(1));
|
| + EXPECT_CALL(*underlying, cancel());
|
| + EXPECT_CALL(checkpoint, Call(2));
|
| +
|
| + checkpoint.Call(1);
|
| + consumer->cancel();
|
| + checkpoint.Call(2);
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace blink
|
|
|