blob: 167b90e95d5516428123e074ad56a4a4819bb3b0 [file] [log] [blame]
// Copyright 2024 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 "quiche/web_transport/test_tools/in_memory_stream.h"
#include <cstddef>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "quiche/common/platform/api/quiche_logging.h"
#include "quiche/common/platform/api/quiche_test.h"
#include "quiche/common/quiche_mem_slice.h"
#include "quiche/common/quiche_stream.h"
#include "quiche/common/vectorized_io_utils.h"
#include "quiche/web_transport/web_transport.h"
namespace webtransport::test {
quiche::ReadStream::ReadResult InMemoryStream::Read(absl::Span<char> output) {
std::vector<absl::string_view> chunks;
for (absl::string_view chunk : buffer_.Chunks()) {
chunks.push_back(chunk);
}
size_t bytes_read = quiche::GatherStringViewSpan(chunks, output);
buffer_.RemovePrefix(bytes_read);
return ReadResult{bytes_read, buffer_.empty() && fin_received_};
}
quiche::ReadStream::ReadResult InMemoryStream::Read(std::string* output) {
ReadResult result;
result.bytes_read = buffer_.size();
result.fin = fin_received_;
absl::AppendCordToString(buffer_, output);
buffer_.Clear();
return result;
}
size_t InMemoryStream::ReadableBytes() const { return buffer_.size(); }
quiche::ReadStream::PeekResult InMemoryStream::PeekNextReadableRegion() const {
if (buffer_.empty()) {
return PeekResult{"", fin_received_, fin_received_};
}
absl::string_view next_chunk = *buffer_.Chunks().begin();
if (peek_one_byte_at_a_time_) {
return PeekResult{next_chunk.substr(0, 1), false, fin_received_};
}
return PeekResult{next_chunk, false, fin_received_};
}
bool InMemoryStream::SkipBytes(size_t bytes) {
buffer_.RemovePrefix(bytes);
return buffer_.empty() && fin_received_;
}
absl::Status InMemoryStream::Writev(absl::Span<quiche::QuicheMemSlice> data,
const quiche::StreamWriteOptions& options) {
absl::Status status = GetWriteStatusWithExtraChecks();
if (!status.ok()) {
return status;
}
std::string merged_data;
for (const quiche::QuicheMemSlice& slice : data) {
merged_data.append(slice.AsStringView());
}
OnWrite(merged_data);
if (options.send_fin()) {
OnFin();
fin_sent_ = true;
}
return absl::OkStatus();
}
void InMemoryStream::Receive(absl::string_view data, bool fin) {
QUICHE_DCHECK(!abruptly_terminated_);
buffer_.Append(data);
fin_received_ |= fin;
if (visitor_ != nullptr) {
visitor_->OnCanRead();
}
}
void InMemoryStream::Terminate() {
abruptly_terminated_ = true;
buffer_.Clear();
fin_received_ = false;
}
absl::Status InMemoryStream::GetWriteStatus() const {
return absl::UnimplementedError(
"Writing not implemented; use InMemoryStreamWithMockWrite");
}
absl::Status InMemoryStream::GetWriteStatusWithExtraChecks() const {
if (fin_sent_) {
return absl::FailedPreconditionError(
"Can't write on a stream with FIN sent.");
}
return GetWriteStatus();
}
InMemoryStreamWithMockWrite::InMemoryStreamWithMockWrite(StreamId id)
: InMemoryStream(id) {
ON_CALL(*this, GetWriteStatus)
.WillByDefault(testing::Return(absl::OkStatus()));
}
} // namespace webtransport::test