blob: 5e9c5f0ff65ff70d5ec47678a3970f52d3ed842c [file]
// Copyright 2025 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_stream/limited_stream.h"
#include <cstddef>
#include "pw_bytes/array.h"
#include "pw_stream/memory_stream.h"
#include "pw_stream/null_stream.h"
#include "pw_unit_test/framework.h"
#define EXPECT_SEQ_EQ(seq1, seq2) \
do { \
EXPECT_EQ(seq1.size(), seq2.size()); \
EXPECT_TRUE( \
std::equal(seq1.begin(), seq1.end(), seq2.begin(), seq2.end())); \
} while (0)
namespace {
using pw::Status;
using pw::bytes::Array;
using pw::stream::LimitedStreamWriter;
using pw::stream::MemoryWriterBuffer;
using pw::stream::NullStream;
using pw::stream::Stream;
TEST(LimitedStreamWriter, DefaultConservativeWriteLimit) {
NullStream stream;
ASSERT_EQ(stream.ConservativeWriteLimit(), Stream::kUnlimited);
LimitedStreamWriter writer(stream); // unlimited
EXPECT_EQ(writer.ConservativeWriteLimit(), Stream::kUnlimited);
}
TEST(LimitedStreamWriter, LimitedConservativeWriteLimit) {
NullStream stream;
ASSERT_EQ(stream.ConservativeWriteLimit(), Stream::kUnlimited);
constexpr size_t kLimit = 123;
LimitedStreamWriter writer(stream, kLimit);
EXPECT_EQ(writer.ConservativeWriteLimit(), kLimit);
}
TEST(LimitedStreamWriter, LimitedConservativeWriteLimitOverUnderlying) {
MemoryWriterBuffer<16> buffer;
ASSERT_EQ(buffer.ConservativeWriteLimit(), buffer.capacity());
constexpr size_t kLimit = 123;
LimitedStreamWriter writer(buffer, kLimit);
// The write limit is the smaller of the writer limit and underlying limit.
EXPECT_EQ(writer.ConservativeWriteLimit(), buffer.capacity());
}
TEST(LimitedStreamWriter, WritesWhenUnlimited) {
MemoryWriterBuffer<16> buffer;
LimitedStreamWriter writer(buffer);
EXPECT_EQ(writer.limit(), Stream::kUnlimited);
constexpr auto kData = Array<1, 2, 3, 4>();
PW_TEST_EXPECT_OK(writer.Write(kData));
EXPECT_SEQ_EQ(buffer, kData);
EXPECT_EQ(writer.bytes_written(), kData.size());
// It respects the underlying stream limit.
EXPECT_EQ(writer.ConservativeWriteLimit(), buffer.capacity() - kData.size());
}
TEST(LimitedStreamWriter, WritesWhenLimited) {
MemoryWriterBuffer<16> buffer;
constexpr size_t kLimit = 8;
LimitedStreamWriter writer(buffer, kLimit);
EXPECT_EQ(writer.limit(), kLimit);
constexpr auto kData = Array<1, 2, 3, 4>();
PW_TEST_EXPECT_OK(writer.Write(kData));
EXPECT_SEQ_EQ(buffer, kData);
EXPECT_EQ(writer.bytes_written(), kData.size());
EXPECT_EQ(writer.ConservativeWriteLimit(), kLimit - kData.size());
}
TEST(LimitedStreamWriter, CanWriteToLimitAndNotAfter) {
MemoryWriterBuffer<16> buffer;
constexpr size_t kLimit = 8;
LimitedStreamWriter writer(buffer, kLimit);
EXPECT_EQ(writer.limit(), kLimit);
constexpr auto kData = Array<1, 2, 3, 4, 5, 6, 7, 8>();
PW_TEST_EXPECT_OK(writer.Write(kData));
EXPECT_SEQ_EQ(buffer, kData);
EXPECT_EQ(writer.bytes_written(), kData.size());
EXPECT_EQ(writer.ConservativeWriteLimit(), 0u);
EXPECT_EQ(writer.Write(kData), Status::OutOfRange()); // Cannot write again
EXPECT_EQ(buffer.bytes_written(), kData.size()); // Nothing more written
}
TEST(LimitedStreamWriter, CannotWritePasteLimit) {
MemoryWriterBuffer<16> buffer;
constexpr size_t kLimit = 4;
LimitedStreamWriter writer(buffer, kLimit);
constexpr auto kData = Array<1, 2, 3, 4, 99, 99, 99>();
EXPECT_EQ(writer.Write(kData), Status::OutOfRange());
// Nothing is written when a Write() would exceed the limit.
EXPECT_EQ(buffer.bytes_written(), 0u);
}
TEST(LimitedStreamWriter, CannotWritePasteLimitAfterChanged) {
MemoryWriterBuffer<16> buffer;
LimitedStreamWriter writer(buffer, 8);
constexpr auto kData = Array<1, 2, 3, 4>();
PW_TEST_EXPECT_OK(writer.Write(kData));
EXPECT_SEQ_EQ(buffer, kData);
// Change the limit to a value less than what was written already.
writer.set_limit(2);
EXPECT_EQ(writer.limit(), 2u);
EXPECT_EQ(writer.ConservativeWriteLimit(), 0u); // Does not underflow
EXPECT_EQ(writer.Write(kData), Status::OutOfRange()); // Cannot write again
EXPECT_EQ(buffer.bytes_written(), kData.size()); // Nothing more written
}
} // namespace