// Copyright 2021 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_varint/stream.h" #include #include #include #include #include #include "pw_stream/memory_stream.h" #include "pw_unit_test/framework.h" #include "pw_varint/varint.h" namespace pw::varint { namespace { template auto MakeBuffer(const char (&data)[kStringSize]) { constexpr size_t kSizeBytes = kStringSize - 1; static_assert(kSizeBytes <= 10, "Varint arrays never need be larger than 10"); std::array array; std::memcpy(array.data(), data, kSizeBytes); return array; } } // namespace TEST(VarintRead, Signed64_SingleByte) { int64_t value = -1234; { const auto buffer = MakeBuffer("\x00"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, 0); } { const auto buffer = MakeBuffer("\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, -1); } { const auto buffer = MakeBuffer("\x02"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, 1); } { const auto buffer = MakeBuffer("\x03"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, -2); } { const auto buffer = MakeBuffer("\x04"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, 2); } } TEST(VarintRead, Signed64_MultiByte) { int64_t value = -1234; { const auto buffer = MakeBuffer("\x80\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 2u); EXPECT_EQ(value, 64); } { const auto buffer = MakeBuffer("\x81\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 2u); EXPECT_EQ(value, -65); } { const auto buffer = MakeBuffer("\x82\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 2u); EXPECT_EQ(value, 65); } { const auto buffer = MakeBuffer("\xff\xff\xff\xff\x0f"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 5u); EXPECT_EQ(value, std::numeric_limits::min()); } { const auto buffer = MakeBuffer("\xfe\xff\xff\xff\x0f"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 5u); EXPECT_EQ(value, std::numeric_limits::max()); } { const auto buffer = MakeBuffer("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 10u); EXPECT_EQ(value, std::numeric_limits::min()); } { const auto buffer = MakeBuffer("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 10u); EXPECT_EQ(value, std::numeric_limits::max()); } } TEST(VarintRead, Unsigned64_SingleByte) { uint64_t value = 1234; { const auto buffer = MakeBuffer("\x00"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, 0u); } { const auto buffer = MakeBuffer("\x04"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, 4u); } { const auto buffer = MakeBuffer("\x41"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 1u); EXPECT_EQ(value, 65u); } } TEST(VarintRead, Unsigned64_MultiByte) { uint64_t value; { const auto buffer = MakeBuffer("\x80\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 2u); EXPECT_EQ(value, 128u); } { const auto buffer = MakeBuffer("\x81\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 2u); EXPECT_EQ(value, 129u); } { const auto buffer = MakeBuffer("\xfe\xff\xff\xff\x0f"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 5u); EXPECT_EQ(value, std::numeric_limits::max() - 1); } { const auto buffer = MakeBuffer("\xff\xff\xff\xff\x0f"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 5u); EXPECT_EQ(value, std::numeric_limits::max()); } { const auto buffer = MakeBuffer("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 10u); EXPECT_EQ(value, std::numeric_limits::max() - 1); } { const auto buffer = MakeBuffer("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_TRUE(sws.ok()); EXPECT_EQ(sws.size(), 10u); EXPECT_EQ(value, std::numeric_limits::max()); } } TEST(VarintRead, Errors) { uint64_t value; { std::array buffer{}; stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_FALSE(sws.ok()); EXPECT_EQ(sws.status(), Status::OutOfRange()); EXPECT_EQ(sws.size(), buffer.size()); } { const auto buffer = MakeBuffer("\xff\xff"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_FALSE(sws.ok()); EXPECT_EQ(sws.status(), Status::DataLoss()); EXPECT_EQ(sws.size(), buffer.size()); } { std::array buffer{}; for (auto& b : buffer) { b = std::byte{0xff}; } stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value); EXPECT_FALSE(sws.ok()); EXPECT_EQ(sws.status(), Status::DataLoss()); EXPECT_EQ(sws.size(), varint::kMaxVarint64SizeBytes); } } TEST(VarintRead, SizeLimit) { uint64_t value; { // buffer contains a valid varint, but we limit the read length to ensure // that the final byte is not read, turning it into an error. const auto buffer = MakeBuffer("\xff\xff\xff\xff\x0f"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value, 4); EXPECT_FALSE(sws.ok()); EXPECT_EQ(sws.status(), Status::DataLoss()); EXPECT_EQ(sws.size(), 4u); EXPECT_EQ(reader.Tell(), 4u); } { // If we tell varint::Read() to read zero bytes, it should always return // OutOfRange() without moving the reader. const auto buffer = MakeBuffer("\xff\xff\xff\xff\x0f"); stream::MemoryReader reader(buffer); const auto sws = Read(reader, &value, 0); EXPECT_FALSE(sws.ok()); EXPECT_EQ(sws.status(), Status::OutOfRange()); EXPECT_EQ(sws.size(), 0u); EXPECT_EQ(reader.Tell(), 0u); } } } // namespace pw::varint