| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "modules/fetch/BytesConsumerTestUtil.h" |
| 6 |
| 7 #include "core/dom/ExecutionContext.h" |
| 8 #include "core/dom/TaskRunnerHelper.h" |
| 9 #include "platform/testing/UnitTestHelpers.h" |
| 10 #include "public/platform/WebTaskRunner.h" |
| 11 #include "wtf/Assertions.h" |
| 12 #include "wtf/Functional.h" |
| 13 |
| 14 namespace blink { |
| 15 |
| 16 using Result = BytesConsumer::Result; |
| 17 |
| 18 BytesConsumerTestUtil::ReplayingBytesConsumer::ReplayingBytesConsumer(ExecutionC
ontext* executionContext) |
| 19 : m_executionContext(executionContext) |
| 20 { |
| 21 } |
| 22 |
| 23 BytesConsumerTestUtil::ReplayingBytesConsumer::~ReplayingBytesConsumer() |
| 24 { |
| 25 } |
| 26 |
| 27 Result BytesConsumerTestUtil::ReplayingBytesConsumer::beginRead(const char** buf
fer, size_t* available) |
| 28 { |
| 29 ++m_notificationToken; |
| 30 if (m_commands.isEmpty()) { |
| 31 switch (m_state) { |
| 32 case BytesConsumer::InternalState::Readable: |
| 33 case BytesConsumer::InternalState::Waiting: |
| 34 return Result::ShouldWait; |
| 35 case BytesConsumer::InternalState::Closed: |
| 36 return Result::Done; |
| 37 case BytesConsumer::InternalState::Errored: |
| 38 return Result::Error; |
| 39 } |
| 40 } |
| 41 const Command& command = m_commands[0]; |
| 42 switch (command.getName()) { |
| 43 case Command::Data: |
| 44 DCHECK_LE(m_offset, command.body().size()); |
| 45 *buffer = command.body().data() + m_offset; |
| 46 *available = command.body().size() - m_offset; |
| 47 return Result::Ok; |
| 48 case Command::Done: |
| 49 m_commands.removeFirst(); |
| 50 close(); |
| 51 return Result::Done; |
| 52 case Command::Error: { |
| 53 Error e(String::fromUTF8(command.body().data(), command.body().size())); |
| 54 m_commands.removeFirst(); |
| 55 error(std::move(e)); |
| 56 return Result::Error; |
| 57 } |
| 58 case Command::Wait: |
| 59 m_commands.removeFirst(); |
| 60 m_state = InternalState::Waiting; |
| 61 TaskRunnerHelper::get(TaskType::Networking, m_executionContext)->postTas
k( |
| 62 BLINK_FROM_HERE, |
| 63 WTF::bind(&ReplayingBytesConsumer::notifyAsReadable, wrapPersistent(
this), m_notificationToken)); |
| 64 return Result::ShouldWait; |
| 65 } |
| 66 NOTREACHED(); |
| 67 return Result::Error; |
| 68 } |
| 69 |
| 70 Result BytesConsumerTestUtil::ReplayingBytesConsumer::endRead(size_t read) |
| 71 { |
| 72 DCHECK(!m_commands.isEmpty()); |
| 73 const Command& command = m_commands[0]; |
| 74 DCHECK_EQ(Command::Data, command.getName()); |
| 75 m_offset += read; |
| 76 DCHECK_LE(m_offset, command.body().size()); |
| 77 if (m_offset < command.body().size()) |
| 78 return Result::Ok; |
| 79 |
| 80 m_offset = 0; |
| 81 m_commands.removeFirst(); |
| 82 return Result::Ok; |
| 83 } |
| 84 |
| 85 void BytesConsumerTestUtil::ReplayingBytesConsumer::setClient(Client* client) |
| 86 { |
| 87 DCHECK(!m_client); |
| 88 DCHECK(client); |
| 89 m_client = client; |
| 90 ++m_notificationToken; |
| 91 } |
| 92 |
| 93 void BytesConsumerTestUtil::ReplayingBytesConsumer::clearClient() |
| 94 { |
| 95 DCHECK(m_client); |
| 96 m_client = nullptr; |
| 97 ++m_notificationToken; |
| 98 } |
| 99 |
| 100 void BytesConsumerTestUtil::ReplayingBytesConsumer::cancel() |
| 101 { |
| 102 close(); |
| 103 m_isCancelled = true; |
| 104 } |
| 105 |
| 106 BytesConsumer::PublicState BytesConsumerTestUtil::ReplayingBytesConsumer::getPub
licState() const |
| 107 { |
| 108 return getPublicStateFromInternalState(m_state); |
| 109 } |
| 110 |
| 111 BytesConsumer::Error BytesConsumerTestUtil::ReplayingBytesConsumer::getError() c
onst |
| 112 { |
| 113 return m_error; |
| 114 } |
| 115 |
| 116 void BytesConsumerTestUtil::ReplayingBytesConsumer::notifyAsReadable(int notific
ationToken) |
| 117 { |
| 118 if (m_notificationToken != notificationToken) { |
| 119 // The notification is cancelled. |
| 120 return; |
| 121 } |
| 122 DCHECK(m_client); |
| 123 DCHECK_NE(InternalState::Closed, m_state); |
| 124 DCHECK_NE(InternalState::Errored, m_state); |
| 125 m_client->onStateChange(); |
| 126 } |
| 127 |
| 128 void BytesConsumerTestUtil::ReplayingBytesConsumer::close() |
| 129 { |
| 130 m_commands.clear(); |
| 131 m_offset = 0; |
| 132 m_state = InternalState::Closed; |
| 133 ++m_notificationToken; |
| 134 } |
| 135 |
| 136 void BytesConsumerTestUtil::ReplayingBytesConsumer::error(const Error& e) |
| 137 { |
| 138 m_commands.clear(); |
| 139 m_offset = 0; |
| 140 m_error = e; |
| 141 m_state = InternalState::Errored; |
| 142 ++m_notificationToken; |
| 143 } |
| 144 |
| 145 DEFINE_TRACE(BytesConsumerTestUtil::ReplayingBytesConsumer) |
| 146 { |
| 147 visitor->trace(m_executionContext); |
| 148 visitor->trace(m_client); |
| 149 BytesConsumer::trace(visitor); |
| 150 } |
| 151 |
| 152 BytesConsumerTestUtil::Reader::Reader(BytesConsumer* consumer) |
| 153 : m_consumer(consumer) |
| 154 { |
| 155 m_consumer->setClient(this); |
| 156 } |
| 157 |
| 158 void BytesConsumerTestUtil::Reader::onStateChange() |
| 159 { |
| 160 while (true) { |
| 161 // We choose 3 here because of the following reasons. |
| 162 // - We want to split a string with multiple chunks, so we need to |
| 163 // choose a small number. |
| 164 // - An odd number is preferable to check an out-of-range error. |
| 165 // - With 1, every chunk consists of one byte it's too simple. |
| 166 char buffer[3]; |
| 167 size_t read = 0; |
| 168 switch (m_consumer->read(buffer, sizeof(buffer), &read)) { |
| 169 case BytesConsumer::Result::Ok: |
| 170 m_data.append(buffer, read); |
| 171 break; |
| 172 case BytesConsumer::Result::ShouldWait: |
| 173 return; |
| 174 case BytesConsumer::Result::Done: |
| 175 m_result = BytesConsumer::Result::Done; |
| 176 return; |
| 177 case BytesConsumer::Result::Error: |
| 178 m_result = BytesConsumer::Result::Error; |
| 179 return; |
| 180 } |
| 181 } |
| 182 } |
| 183 |
| 184 std::pair<BytesConsumer::Result, Vector<char>> BytesConsumerTestUtil::Reader::ru
n() |
| 185 { |
| 186 onStateChange(); |
| 187 while (m_result != BytesConsumer::Result::Done && m_result != BytesConsumer:
:Result::Error) |
| 188 testing::runPendingTasks(); |
| 189 testing::runPendingTasks(); |
| 190 return std::make_pair(m_result, std::move(m_data)); |
| 191 } |
| 192 |
| 193 BytesConsumerTestUtil::TwoPhaseReader::TwoPhaseReader(BytesConsumer* consumer) |
| 194 : m_consumer(consumer) |
| 195 { |
| 196 m_consumer->setClient(this); |
| 197 } |
| 198 |
| 199 |
| 200 void BytesConsumerTestUtil::TwoPhaseReader::onStateChange() |
| 201 { |
| 202 while (true) { |
| 203 const char* buffer = nullptr; |
| 204 size_t available = 0; |
| 205 switch (m_consumer->beginRead(&buffer, &available)) { |
| 206 case BytesConsumer::Result::Ok: { |
| 207 // We don't use |available| as-is to test cases where endRead |
| 208 // is called with a number smaller than |available|. We choose 3 |
| 209 // because of the same reasons as Reader::onStateChange. |
| 210 size_t read = std::max(static_cast<size_t>(3), available); |
| 211 m_data.append(buffer, read); |
| 212 m_consumer->endRead(read); |
| 213 break; |
| 214 } |
| 215 case BytesConsumer::Result::ShouldWait: |
| 216 return; |
| 217 case BytesConsumer::Result::Done: |
| 218 m_result = BytesConsumer::Result::Done; |
| 219 return; |
| 220 case BytesConsumer::Result::Error: |
| 221 m_result = BytesConsumer::Result::Error; |
| 222 return; |
| 223 } |
| 224 } |
| 225 } |
| 226 |
| 227 std::pair<BytesConsumer::Result, Vector<char>> BytesConsumerTestUtil::TwoPhaseRe
ader::run() |
| 228 { |
| 229 onStateChange(); |
| 230 while (m_result != BytesConsumer::Result::Done && m_result != BytesConsumer:
:Result::Error) |
| 231 testing::runPendingTasks(); |
| 232 testing::runPendingTasks(); |
| 233 return std::make_pair(m_result, std::move(m_data)); |
| 234 } |
| 235 |
| 236 } // namespace blink |
| OLD | NEW |