// 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_protobuf/stream_decoder.h"

#include <array>

#include "pw_status/status.h"
#include "pw_status/status_with_size.h"
#include "pw_stream/memory_stream.h"
#include "pw_stream/stream.h"
#include "pw_unit_test/framework.h"

namespace pw::protobuf {
namespace {
// Non-seekable wrapper for MemoryReader for testing behavior when seeking is
// not available.
class NonSeekableMemoryReader : public stream::NonSeekableReader {
 public:
  explicit NonSeekableMemoryReader(stream::MemoryReader& reader)
      : reader_(reader) {}

  size_t bytes_read() const { return reader_.bytes_read(); }
  const std::byte* data() const { return reader_.data(); }

 private:
  StatusWithSize DoRead(ByteSpan destination) override {
    const pw::Result<pw::ByteSpan> result = reader_.Read(destination);
    if (!result.ok()) {
      return StatusWithSize(result.status(), 0);
    }
    return StatusWithSize(result.value().size_bytes());
  }

  stream::MemoryReader& reader_;
};

TEST(StreamDecoder, Decode) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,
    // type=sint32, k=2, v=-13
    0x10, 0x19,
    // type=bool, k=3, v=false
    0x18, 0x00,
    // type=double, k=4, v=3.14159
    0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
    // type=fixed32, k=5, v=0xdeadbeef
    0x2d, 0xef, 0xbe, 0xad, 0xde,
    // type=string, k=6, v="Hello world"
    0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
    // type=sfixed32, k=7, v=-50
    0x3d, 0xce, 0xff, 0xff, 0xff,
    // type=sfixed64, k=8, v=-1647993274
    0x41, 0x46, 0x9e, 0xc5, 0x9d, 0xff, 0xff, 0xff, 0xff,
    // type=float, k=9, v=2.718
    0x4d, 0xb6, 0xf3, 0x2d, 0x40,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  Result<int32_t> int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), OkStatus());
  EXPECT_EQ(int32.value(), 42);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 2u);
  Result<int32_t> sint32 = decoder.ReadSint32();
  ASSERT_EQ(sint32.status(), OkStatus());
  EXPECT_EQ(sint32.value(), -13);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 3u);
  Result<bool> boolean = decoder.ReadBool();
  ASSERT_EQ(boolean.status(), OkStatus());
  EXPECT_FALSE(boolean.value());

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 4u);
  Result<double> dbl = decoder.ReadDouble();
  ASSERT_EQ(dbl.status(), OkStatus());
  EXPECT_EQ(dbl.value(), 3.14159);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 5u);
  Result<uint32_t> fixed32 = decoder.ReadFixed32();
  ASSERT_EQ(fixed32.status(), OkStatus());
  EXPECT_EQ(fixed32.value(), 0xdeadbeef);

  char buffer[16];
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 6u);
  StatusWithSize sws = decoder.ReadString(buffer);
  ASSERT_EQ(sws.status(), OkStatus());
  buffer[sws.size()] = '\0';
  EXPECT_STREQ(buffer, "Hello world");

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 7u);
  Result<int32_t> sfixed32 = decoder.ReadSfixed32();
  ASSERT_EQ(sfixed32.status(), OkStatus());
  EXPECT_EQ(sfixed32.value(), -50);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 8u);
  Result<int64_t> sfixed64 = decoder.ReadSfixed64();
  ASSERT_EQ(sfixed64.status(), OkStatus());
  EXPECT_EQ(sfixed64.value(), -1647993274);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 9u);
  Result<float> flt = decoder.ReadFloat();
  ASSERT_EQ(flt.status(), OkStatus());
  EXPECT_EQ(flt.value(), 2.718f);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_SkipsUnusedFields) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,
    // type=sint32, k=2, v=-13
    0x10, 0x19,
    // type=bool, k=3, v=false
    0x18, 0x00,
    // type=double, k=4, v=3.14159
    0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
    // type=fixed32, k=5, v=0xdeadbeef
    0x2d, 0xef, 0xbe, 0xad, 0xde,
    // type=string, k=6, v="Hello world"
    0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  // Don't process any fields except for the fourth. Next should still iterate
  // correctly despite field values not being consumed.
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 4u);
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_NonSeekable_SkipsUnusedFields) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,
    // type=sint32, k=2, v=-13
    0x10, 0x19,
    // type=bool, k=3, v=false
    0x18, 0x00,
    // type=double, k=4, v=3.14159
    0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
    // type=fixed32, k=5, v=0xdeadbeef
    0x2d, 0xef, 0xbe, 0xad, 0xde,
    // type=string, k=6, v="Hello world"
    0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
  };
  // clang-format on

  // Test with a non-seekable memory reader
  stream::MemoryReader wrapped_reader(as_bytes(span(encoded_proto)));
  NonSeekableMemoryReader reader(wrapped_reader);
  StreamDecoder decoder(reader);

  // Don't process any fields except for the fourth. Next should still iterate
  // correctly despite field values not being consumed.
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 4u);
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_BadData) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,
    // type=sint32, k=2, value... missing
    0x10,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);
  Result<int32_t> int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), OkStatus());
  EXPECT_EQ(int32.value(), 42);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 2u);
  EXPECT_EQ(decoder.ReadSint32().status(), Status::DataLoss());

  EXPECT_EQ(decoder.Next(), Status::DataLoss());
}

TEST(StreamDecoder, Decode_MissingDelimitedLength) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,
    // Submessage (bytes) key=8, length=... missing
    0x32,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);
  Result<int32_t> int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), OkStatus());
  EXPECT_EQ(int32.value(), 42);

  EXPECT_EQ(decoder.Next(), Status::DataLoss());
}

TEST(StreamDecoder, Decode_VarintTooBig) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=uint32, k=1, v=>uint32_t::max
    0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
    // type=int32, k=2, v=>int32_t::max
    0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
    // type=int32, k=3, v<=int32_t::min
    0x18, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff, 0xff, 0xff, 0xff, 0x01,
    // type=sint32, k=4, v=>int32_t::max
    0x20, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0f,
    // type=sint32, k=5, v<=int32_t::max
    0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);
  Result<uint32_t> uint32 = decoder.ReadUint32();
  ASSERT_EQ(uint32.status(), Status::FailedPrecondition());

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 2u);
  Result<int32_t> int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), Status::FailedPrecondition());

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 3u);
  int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), Status::FailedPrecondition());

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 4u);
  Result<int32_t> sint32 = decoder.ReadSint32();
  ASSERT_EQ(sint32.status(), Status::FailedPrecondition());

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 5u);
  sint32 = decoder.ReadSint32();
  ASSERT_EQ(sint32.status(), Status::FailedPrecondition());

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(Decoder, Decode_SkipsBadFieldNumbers) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,
    // type=int32, k=19001, v=42 (invalid field number)
    0xc8, 0xa3, 0x09, 0x2a,
    // type=bool, k=3, v=false
    0x18, 0x00,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(*decoder.FieldNumber(), 1u);
  Result<int32_t> int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), OkStatus());
  EXPECT_EQ(int32.value(), 42);

  // Bad field.
  EXPECT_EQ(decoder.Next(), Status::DataLoss());
  EXPECT_EQ(decoder.FieldNumber().status(), Status::FailedPrecondition());

  EXPECT_EQ(decoder.Next(), Status::DataLoss());
}

TEST(StreamDecoder, Decode_Nested) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,

    // Submessage (bytes) key=8, length=4
    0x32, 0x04,
    // type=uint32, k=1, v=2
    0x08, 0x02,
    // type=uint32, k=2, v=7
    0x10, 0x07,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);
  Result<int32_t> int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), OkStatus());
  EXPECT_EQ(int32.value(), 42);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 6u);
  {
    StreamDecoder nested = decoder.GetNestedDecoder();

    EXPECT_EQ(nested.Next(), OkStatus());
    ASSERT_EQ(*nested.FieldNumber(), 1u);
    Result<uint32_t> uint32 = nested.ReadUint32();
    ASSERT_EQ(uint32.status(), OkStatus());
    EXPECT_EQ(uint32.value(), 2u);

    EXPECT_EQ(nested.Next(), OkStatus());
    ASSERT_EQ(*nested.FieldNumber(), 2u);
    uint32 = nested.ReadUint32();
    ASSERT_EQ(uint32.status(), OkStatus());
    EXPECT_EQ(uint32.value(), 7u);

    ASSERT_EQ(nested.Next(), Status::OutOfRange());
  }

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 2u);
  Result<int32_t> sint32 = decoder.ReadSint32();
  ASSERT_EQ(sint32.status(), OkStatus());
  EXPECT_EQ(sint32.value(), -13);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_Nested_SeeksToNextFieldOnDestruction) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,

    // Submessage (bytes) key=8, length=4
    0x32, 0x04,
    // type=uint32, k=1, v=2
    0x08, 0x02,
    // type=uint32, k=2, v=7
    0x10, 0x07,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  // Create a nested encoder for the nested field, but don't use it.
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 6u);
  {
    StreamDecoder nested = decoder.GetNestedDecoder();
  }

  // The root decoder should still advance to the next field after the nested
  // decoder is closed.
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 2u);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder,
     Decode_Nested_NonSeekable_AdvancesToNextFieldOnDestruction) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,

    // Submessage (bytes) key=8, length=4
    0x32, 0x04,
    // type=uint32, k=1, v=2
    0x08, 0x02,
    // type=uint32, k=2, v=7
    0x10, 0x07,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  // Test with a non-seekable memory reader
  stream::MemoryReader wrapped_reader(as_bytes(span(encoded_proto)));
  NonSeekableMemoryReader reader(wrapped_reader);
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  // Create a nested encoder for the nested field, but don't use it.
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 6u);
  {
    StreamDecoder nested = decoder.GetNestedDecoder();
  }

  // The root decoder should still advance to the next field after the nested
  // decoder is closed.
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 2u);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_Nested_LastField) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,

    // Submessage (bytes) key=8, length=4
    0x32, 0x04,
    // type=uint32, k=1, v=2
    0x08, 0x02,
    // type=uint32, k=2, v=7
    0x10, 0x07,
    // End submessage and proto
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  // Create a nested encoder for the nested field, which is the last field in
  // the root proto.
  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 6u);
  {
    StreamDecoder nested = decoder.GetNestedDecoder();
  }

  // Root decoder should correctly terminate after the nested decoder is closed.
  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_Nested_MultiLevel) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=4
    0x0a, 0x04,

    // Sub-submessage key=1, length=2
    0x0a, 0x02,
    // type=uint32, k=2, v=7
    0x10, 0x07,
    // End sub-submessage

    // End submessage
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);
  {
    StreamDecoder nested = decoder.GetNestedDecoder();

    EXPECT_EQ(nested.Next(), OkStatus());
    ASSERT_EQ(*nested.FieldNumber(), 1u);

    {
      StreamDecoder double_nested = nested.GetNestedDecoder();

      EXPECT_EQ(double_nested.Next(), OkStatus());
      ASSERT_EQ(*double_nested.FieldNumber(), 2u);
      Result<uint32_t> result = double_nested.ReadUint32();
      ASSERT_EQ(result.status(), OkStatus());
      EXPECT_EQ(result.value(), 7u);

      EXPECT_EQ(double_nested.Next(), Status::OutOfRange());
    }

    EXPECT_EQ(nested.Next(), Status::OutOfRange());
  }

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_Nested_InvalidField) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=4
    0x0a, 0x04,

    // Oops. No data!
  };

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);
  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), Status::DataLoss());
  }

  EXPECT_EQ(decoder.Next(), Status::DataLoss());
}

TEST(StreamDecoder, Decode_Nested_InvalidFieldKey) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=2
    0x0a, 0x02,
    // type=invalid...
    0xff, 0xff,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), Status::DataLoss());

    // Make sure that the nested decoder didn't run off the end of the
    // submessage.
    ASSERT_EQ(reader.Tell(), 4u);
  }
}

TEST(StreamDecoder, Decode_Nested_MissingDelimitedLength) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=1
    0x0a, 0x01,
    // Delimited field (bytes) key=1, length=missing...
    0x0a,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), Status::DataLoss());

    // Make sure that the nested decoder didn't run off the end of the
    // submessage.
    ASSERT_EQ(reader.Tell(), 3u);
  }
}

TEST(StreamDecoder, Decode_Nested_InvalidDelimitedLength) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=2
    0x0a, 0x02,
    // Delimited field (bytes) key=1, length=invalid...
    0x0a, 0xff,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), Status::DataLoss());

    // Make sure that the nested decoder didn't run off the end of the
    // submessage.
    ASSERT_EQ(reader.Tell(), 4u);
  }
}

TEST(StreamDecoder, Decode_Nested_InvalidVarint) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=2
    0x0a, 0x02,
    // type=uint32 key=1, value=invalid...
    0x08, 0xff,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), OkStatus());
    ASSERT_EQ(*nested.FieldNumber(), 1u);

    Result<uint32_t> uint32 = nested.ReadUint32();
    EXPECT_EQ(uint32.status(), Status::DataLoss());

    // Make sure that the nested decoder didn't run off the end of the
    // submessage.
    ASSERT_EQ(reader.Tell(), 4u);
  }
}

TEST(StreamDecoder, Decode_Nested_SkipInvalidVarint) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=2
    0x0a, 0x02,
    // type=uint32 key=1, value=invalid...
    0x08, 0xff,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), OkStatus());
    ASSERT_EQ(*nested.FieldNumber(), 1u);

    // Skip without reading.
    EXPECT_EQ(nested.Next(), Status::DataLoss());

    // Make sure that the nested decoder didn't run off the end of the
    // submessage.
    ASSERT_EQ(reader.Tell(), 4u);
  }
}

TEST(StreamDecoder, Decode_Nested_TruncatedFixed) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=2
    0x0a, 0x03,
    // type=fixed32 key=1, value=truncated...
    0x0d, 0x42, 0x00,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), OkStatus());
    ASSERT_EQ(*nested.FieldNumber(), 1u);

    Result<uint32_t> uint32 = nested.ReadFixed32();
    EXPECT_EQ(uint32.status(), Status::DataLoss());

    // Make sure that the nested decoder didn't run off the end of the
    // submessage. Note that this will not read the data at all in this case.
    ASSERT_EQ(reader.Tell(), 3u);
  }
}

TEST(StreamDecoder, Decode_Nested_SkipTruncatedFixed) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // Submessage key=1, length=2
    0x0a, 0x03,
    // type=fixed32 key=1, value=truncated...
    0x0d, 0x42, 0x00,
    // End submessage

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);

  {
    StreamDecoder nested = decoder.GetNestedDecoder();
    EXPECT_EQ(nested.Next(), OkStatus());
    ASSERT_EQ(*nested.FieldNumber(), 1u);

    // Skip without reading.
    EXPECT_EQ(nested.Next(), Status::DataLoss());

    // Make sure that the nested decoder didn't run off the end of the
    // submessage. Note that this will be unable to skip the field without
    // exceeding the range of the nested decoder, so it won't move the cursor.
    ASSERT_EQ(reader.Tell(), 3u);
  }
}

TEST(StreamDecoder, Decode_BytesReader) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // bytes key=1, length=14
    0x0a, 0x0e,

    0x00, 0x01, 0x02, 0x03,
    0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b,
    0x0c, 0x0d,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(*decoder.FieldNumber(), 1u);
  {
    StreamDecoder::BytesReader bytes = decoder.GetBytesReader();
    EXPECT_EQ(bytes.field_size(), 14u);

    std::byte buffer[7];
    EXPECT_EQ(bytes.Read(buffer).status(), OkStatus());
    EXPECT_EQ(std::memcmp(buffer, encoded_proto + 2, sizeof(buffer)), 0);

    EXPECT_EQ(bytes.Read(buffer).status(), OkStatus());
    EXPECT_EQ(std::memcmp(buffer, encoded_proto + 9, sizeof(buffer)), 0);

    EXPECT_EQ(bytes.Read(buffer).status(), Status::OutOfRange());
  }

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_BytesReader_Seek) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // bytes key=1, length=14
    0x0a, 0x0e,

    0x00, 0x01, 0x02, 0x03,
    0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b,
    0x0c, 0x0d,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(*decoder.FieldNumber(), 1u);
  {
    StreamDecoder::BytesReader bytes = decoder.GetBytesReader();

    std::byte buffer[2];

    ASSERT_EQ(bytes.Seek(3), OkStatus());

    EXPECT_EQ(bytes.Read(buffer).status(), OkStatus());
    EXPECT_EQ(std::memcmp(buffer, encoded_proto + 5, sizeof(buffer)), 0);

    // Bad seek offset (absolute).
    ASSERT_EQ(bytes.Seek(15), Status::OutOfRange());

    // Seek back from current position.
    ASSERT_EQ(bytes.Seek(-4, stream::Stream::kCurrent), OkStatus());

    EXPECT_EQ(bytes.Read(buffer).status(), OkStatus());
    EXPECT_EQ(std::memcmp(buffer, encoded_proto + 3, sizeof(buffer)), 0);

    // Bad seek offset (relative).
    ASSERT_EQ(bytes.Seek(-4, stream::Stream::kCurrent), Status::OutOfRange());

    // Seek from the end of the bytes field.
    ASSERT_EQ(bytes.Seek(-2, stream::Stream::kEnd), OkStatus());

    EXPECT_EQ(bytes.Read(buffer).status(), OkStatus());
    EXPECT_EQ(std::memcmp(buffer, encoded_proto + 14, sizeof(buffer)), 0);

    // Bad seek offset (end).
    ASSERT_EQ(bytes.Seek(-15, stream::Stream::kEnd), Status::OutOfRange());
  }

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_BytesReader_Close) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // bytes key=1, length=14
    0x0a, 0x0e,

    0x00, 0x01, 0x02, 0x03,
    0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b,
    0x0c, 0x0d,
    // End bytes

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(*decoder.FieldNumber(), 1u);
  {
    // Partially consume the bytes field.
    StreamDecoder::BytesReader bytes = decoder.GetBytesReader();

    std::byte buffer[2];
    EXPECT_EQ(bytes.Read(buffer).status(), OkStatus());
    EXPECT_EQ(std::memcmp(buffer, encoded_proto + 2, sizeof(buffer)), 0);
  }

  // Continue reading the top-level message.
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(*decoder.FieldNumber(), 2u);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_BytesReader_NonSeekable_Close) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // bytes key=1, length=14
    0x0a, 0x0e,

    0x00, 0x01, 0x02, 0x03,
    0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b,
    0x0c, 0x0d,
    // End bytes

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  // Test with a non-seekable memory reader
  stream::MemoryReader wrapped_reader(as_bytes(span(encoded_proto)));
  NonSeekableMemoryReader reader(wrapped_reader);
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(*decoder.FieldNumber(), 1u);
  {
    // Partially consume the bytes field.
    StreamDecoder::BytesReader bytes = decoder.GetBytesReader();

    std::byte buffer[2];
    EXPECT_EQ(bytes.Read(buffer).status(), OkStatus());
    EXPECT_EQ(std::memcmp(buffer, encoded_proto + 2, sizeof(buffer)), 0);
  }

  // Continue reading the top-level message.
  EXPECT_EQ(decoder.Next(), OkStatus());
  EXPECT_EQ(*decoder.FieldNumber(), 2u);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_BytesReader_InvalidField) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // bytes key=1, length=4
    0x0a, 0x04,

    // Oops. No data!
  };

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(*decoder.FieldNumber(), 1u);
  {
    StreamDecoder::BytesReader bytes = decoder.GetBytesReader();
    EXPECT_EQ(bytes.Seek(0), Status::DataLoss());

    std::byte buffer[2];
    EXPECT_EQ(bytes.Read(buffer).status(), Status::DataLoss());
  }

  EXPECT_EQ(decoder.Next(), Status::DataLoss());
}

TEST(StreamDecoder, GetLengthDelimitedPayloadBounds) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // bytes key=1, length=14
    0x0a, 0x0e,

    0x00, 0x01, 0x02, 0x03,
    0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b,
    0x0c, 0x0d,
    // End bytes

    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  ASSERT_EQ(OkStatus(), decoder.Next());
  Result<StreamDecoder::Bounds> field_bound =
      decoder.GetLengthDelimitedPayloadBounds();
  ASSERT_EQ(OkStatus(), field_bound.status());
  ASSERT_EQ(field_bound.value().low, 2ULL);
  ASSERT_EQ(field_bound.value().high, 16ULL);

  ASSERT_EQ(OkStatus(), decoder.Next());
  ASSERT_EQ(Status::NotFound(),
            decoder.GetLengthDelimitedPayloadBounds().status());
}

TEST(StreamDecoder, ReadDelimitedField_DoesntOverConsume) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=string, k=1, v="Hello world"
    0x0a, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
    // type=int32, k=2, v=42
    0x10, 0x2a,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  ASSERT_EQ(OkStatus(), decoder.Next());

  // This buffer is much larger than the string.
  char buffer[128];
  const StatusWithSize size = decoder.ReadString(buffer);
  EXPECT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 11u);

  // Make sure we can still read the next field.
  ASSERT_EQ(OkStatus(), decoder.Next());
  const pw::Result<int32_t> result = decoder.ReadInt32();
  EXPECT_EQ(result.status(), OkStatus());
  EXPECT_EQ(result.value(), 42);
}

TEST(StreamDecoder, Decode_WithLength) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=int32, k=1, v=42
    0x08, 0x2a,
    // This field is beyond the range of the protobuf:
    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader, /*length=*/2u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  Result<int32_t> int32 = decoder.ReadInt32();
  ASSERT_EQ(int32.status(), OkStatus());
  EXPECT_EQ(int32.value(), 42);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, Decode_WithLength_SkipsToEnd) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=string, k=1, v="Hello world"
    0x08, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
    // This field is beyond the range of the protobuf:
    // type=sint32, k=2, v=-13
    0x10, 0x19,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  {
    StreamDecoder decoder(reader, /*length=*/13u);

    EXPECT_EQ(decoder.Next(), OkStatus());
    ASSERT_EQ(decoder.FieldNumber().value(), 1u);
    // Don't read the value out, or advance further. Destructing the object
    // should advance to the end of the length given.
  }

  EXPECT_EQ(reader.Tell(), 13u);
}

TEST(StreamDecoder, RepeatedField) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=uint32, k=1, v=0
    0x08, 0x00,
    // type=uint32, k=1, v=50
    0x08, 0x32,
    // type=uint32, k=1, v=100
    0x08, 0x64,
    // type=uint32, k=1, v=150
    0x08, 0x96, 0x01,
    // type=uint32, k=1, v=200
    0x08, 0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  Result<uint32_t> uint32 = decoder.ReadUint32();
  ASSERT_EQ(uint32.status(), OkStatus());
  EXPECT_EQ(uint32.value(), 0u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  uint32 = decoder.ReadUint32();
  ASSERT_EQ(uint32.status(), OkStatus());
  EXPECT_EQ(uint32.value(), 50u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  uint32 = decoder.ReadUint32();
  ASSERT_EQ(uint32.status(), OkStatus());
  EXPECT_EQ(uint32.value(), 100u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  uint32 = decoder.ReadUint32();
  ASSERT_EQ(uint32.status(), OkStatus());
  EXPECT_EQ(uint32.value(), 150u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  uint32 = decoder.ReadUint32();
  ASSERT_EQ(uint32.status(), OkStatus());
  EXPECT_EQ(uint32.value(), 200u);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, RepeatedFieldVector) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=uint32, k=1, v=0
    0x08, 0x00,
    // type=uint32, k=1, v=50
    0x08, 0x32,
    // type=uint32, k=1, v=100
    0x08, 0x64,
    // type=uint32, k=1, v=150
    0x08, 0x96, 0x01,
    // type=uint32, k=1, v=200
    0x08, 0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  pw::Vector<uint32_t, 8> uint32{};

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  Status status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 1u);
  EXPECT_EQ(uint32[0], 0u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 2u);
  EXPECT_EQ(uint32[1], 50u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 3u);
  EXPECT_EQ(uint32[2], 100u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 4u);
  EXPECT_EQ(uint32[3], 150u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 5u);
  EXPECT_EQ(uint32[4], 200u);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, RepeatedFieldVectorFull) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=uint32, k=1, v=0
    0x08, 0x00,
    // type=uint32, k=1, v=50
    0x08, 0x32,
    // type=uint32, k=1, v=100
    0x08, 0x64,
    // type=uint32, k=1, v=150
    0x08, 0x96, 0x01,
    // type=uint32, k=1, v=200
    0x08, 0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  pw::Vector<uint32_t, 2> uint32{};

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  Status status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 1u);
  EXPECT_EQ(uint32[0], 0u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 2u);
  EXPECT_EQ(uint32[1], 50u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, Status::ResourceExhausted());
  EXPECT_EQ(uint32.size(), 2u);
}

TEST(StreamDecoder, PackedVarint) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=uint32[], k=1, v={0, 50, 100, 150, 200}
    0x0a, 0x07,
    0x00,
    0x32,
    0x64,
    0x96, 0x01,
    0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  std::array<uint32_t, 8> uint32{};
  StatusWithSize size = decoder.ReadPackedUint32(uint32);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 5u);

  EXPECT_EQ(uint32[0], 0u);
  EXPECT_EQ(uint32[1], 50u);
  EXPECT_EQ(uint32[2], 100u);
  EXPECT_EQ(uint32[3], 150u);
  EXPECT_EQ(uint32[4], 200u);
}

TEST(StreamDecoder, PackedVarintInsufficientSpace) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=uint32[], k=1, v={0, 50, 100, 150, 200}
    0x0a, 0x07,
    0x00,
    0x32,
    0x64,
    0x96, 0x01,
    0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  std::array<uint32_t, 2> uint32{};
  StatusWithSize size = decoder.ReadPackedUint32(uint32);
  ASSERT_EQ(size.status(), Status::ResourceExhausted());
  EXPECT_EQ(size.size(), 2u);

  // Still returns values in case of error.
  EXPECT_EQ(uint32[0], 0u);
  EXPECT_EQ(uint32[1], 50u);
}

TEST(StreamDecoder, PackedVarintVector) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=uint32[], k=1, v={0, 50, 100, 150, 200}
    0x0a, 0x07,
    0x00,
    0x32,
    0x64,
    0x96, 0x01,
    0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  pw::Vector<uint32_t, 8> uint32{};
  Status status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(uint32.size(), 5u);

  EXPECT_EQ(uint32[0], 0u);
  EXPECT_EQ(uint32[1], 50u);
  EXPECT_EQ(uint32[2], 100u);
  EXPECT_EQ(uint32[3], 150u);
  EXPECT_EQ(uint32[4], 200u);
}

TEST(StreamDecoder, PackedVarintVectorFull) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=uint32[], k=1, v={0, 50, 100, 150, 200}
    0x0a, 0x07,
    0x00,
    0x32,
    0x64,
    0x96, 0x01,
    0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  pw::Vector<uint32_t, 2> uint32{};
  Status status = decoder.ReadRepeatedUint32(uint32);
  ASSERT_EQ(status, Status::ResourceExhausted());
  EXPECT_EQ(uint32.size(), 2u);

  // Still returns values in case of error.
  EXPECT_EQ(uint32[0], 0u);
  EXPECT_EQ(uint32[1], 50u);
}

TEST(StreamDecoder, PackedZigZag) {
  // clang-format off
  constexpr uint8_t encoded_proto[] = {
    // type=sint32[], k=1, v={-100, -25, -1, 0, 1, 25, 100}
    0x0a, 0x09,
    0xc7, 0x01,
    0x31,
    0x01,
    0x00,
    0x02,
    0x32,
    0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  std::array<int32_t, 8> sint32{};
  StatusWithSize size = decoder.ReadPackedSint32(sint32);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 7u);

  EXPECT_EQ(sint32[0], -100);
  EXPECT_EQ(sint32[1], -25);
  EXPECT_EQ(sint32[2], -1);
  EXPECT_EQ(sint32[3], 0);
  EXPECT_EQ(sint32[4], 1);
  EXPECT_EQ(sint32[5], 25);
  EXPECT_EQ(sint32[6], 100);
}

TEST(StreamDecoder, PackedZigZagVector) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=sint32[], k=1, v={-100, -25, -1, 0, 1, 25, 100}
    0x0a, 0x09,
    0xc7, 0x01,
    0x31,
    0x01,
    0x00,
    0x02,
    0x32,
    0xc8, 0x01
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  pw::Vector<int32_t, 8> sint32{};
  Status status = decoder.ReadRepeatedSint32(sint32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(sint32.size(), 7u);

  EXPECT_EQ(sint32[0], -100);
  EXPECT_EQ(sint32[1], -25);
  EXPECT_EQ(sint32[2], -1);
  EXPECT_EQ(sint32[3], 0);
  EXPECT_EQ(sint32[4], 1);
  EXPECT_EQ(sint32[5], 25);
  EXPECT_EQ(sint32[6], 100);
}

TEST(StreamDecoder, PackedFixed) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=fixed32[], k=1, v={0, 50, 100, 150, 200}
    0x0a, 0x14,
    0x00, 0x00, 0x00, 0x00,
    0x32, 0x00, 0x00, 0x00,
    0x64, 0x00, 0x00, 0x00,
    0x96, 0x00, 0x00, 0x00,
    0xc8, 0x00, 0x00, 0x00,
    // type=fixed64[], v=2, v={0x0102030405060708}
    0x12, 0x08,
    0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
    // type=sfixed32[], k=3, v={0, -50, 100, -150, 200}
    0x1a, 0x14,
    0x00, 0x00, 0x00, 0x00,
    0xce, 0xff, 0xff, 0xff,
    0x64, 0x00, 0x00, 0x00,
    0x6a, 0xff, 0xff, 0xff,
    0xc8, 0x00, 0x00, 0x00,
    // type=sfixed64[], v=4, v={-1647993274}
    0x22, 0x08,
    0x46, 0x9e, 0xc5, 0x9d, 0xff, 0xff, 0xff, 0xff,
    // type=double[], k=5, v=3.14159
    0x2a, 0x08,
    0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
    // type=float[], k=6, v=2.718
    0x32, 0x04,
    0xb6, 0xf3, 0x2d, 0x40,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  std::array<uint32_t, 8> fixed32{};
  StatusWithSize size = decoder.ReadPackedFixed32(fixed32);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 5u);

  EXPECT_EQ(fixed32[0], 0u);
  EXPECT_EQ(fixed32[1], 50u);
  EXPECT_EQ(fixed32[2], 100u);
  EXPECT_EQ(fixed32[3], 150u);
  EXPECT_EQ(fixed32[4], 200u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 2u);
  std::array<uint64_t, 8> fixed64{};
  size = decoder.ReadPackedFixed64(fixed64);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 1u);

  EXPECT_EQ(fixed64[0], 0x0102030405060708u);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 3u);
  std::array<int32_t, 8> sfixed32{};
  size = decoder.ReadPackedSfixed32(sfixed32);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 5u);

  EXPECT_EQ(sfixed32[0], 0);
  EXPECT_EQ(sfixed32[1], -50);
  EXPECT_EQ(sfixed32[2], 100);
  EXPECT_EQ(sfixed32[3], -150);
  EXPECT_EQ(sfixed32[4], 200);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 4u);
  std::array<int64_t, 8> sfixed64{};
  size = decoder.ReadPackedSfixed64(sfixed64);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 1u);

  EXPECT_EQ(sfixed64[0], -1647993274);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 5u);
  std::array<double, 8> dbl{};
  size = decoder.ReadPackedDouble(dbl);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 1u);

  EXPECT_EQ(dbl[0], 3.14159);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 6u);
  std::array<float, 8> flt{};
  size = decoder.ReadPackedFloat(flt);
  ASSERT_EQ(size.status(), OkStatus());
  EXPECT_EQ(size.size(), 1u);

  EXPECT_EQ(flt[0], 2.718f);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, PackedFixedInsufficientSpace) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=fixed32[], k=1, v={0, 50, 100, 150, 200}
    0x0a, 0x14,
    0x00, 0x00, 0x00, 0x00,
    0x32, 0x00, 0x00, 0x00,
    0x64, 0x00, 0x00, 0x00,
    0x96, 0x00, 0x00, 0x00,
    0xc8, 0x00, 0x00, 0x00,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  std::array<uint32_t, 2> fixed32{};
  StatusWithSize size = decoder.ReadPackedFixed32(fixed32);
  ASSERT_EQ(size.status(), Status::ResourceExhausted());
}

TEST(StreamDecoder, PackedFixedVector) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=sfixed32[], k=1, v={0, -50, 100, -150, 200}
    0x0a, 0x14,
    0x00, 0x00, 0x00, 0x00,
    0xce, 0xff, 0xff, 0xff,
    0x64, 0x00, 0x00, 0x00,
    0x6a, 0xff, 0xff, 0xff,
    0xc8, 0x00, 0x00, 0x00,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  pw::Vector<int32_t, 8> sfixed32{};
  Status status = decoder.ReadRepeatedSfixed32(sfixed32);
  ASSERT_EQ(status, OkStatus());
  EXPECT_EQ(sfixed32.size(), 5u);

  EXPECT_EQ(sfixed32[0], 0);
  EXPECT_EQ(sfixed32[1], -50);
  EXPECT_EQ(sfixed32[2], 100);
  EXPECT_EQ(sfixed32[3], -150);
  EXPECT_EQ(sfixed32[4], 200);

  EXPECT_EQ(decoder.Next(), Status::OutOfRange());
}

TEST(StreamDecoder, PackedFixedVectorFull) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    // type=sfixed32[], k=1, v={0, -50, 100, -150, 200}
    0x0a, 0x14,
    0x00, 0x00, 0x00, 0x00,
    0xce, 0xff, 0xff, 0xff,
    0x64, 0x00, 0x00, 0x00,
    0x6a, 0xff, 0xff, 0xff,
    0xc8, 0x00, 0x00, 0x00,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  ASSERT_EQ(decoder.FieldNumber().value(), 1u);
  pw::Vector<int32_t, 2> sfixed32{};
  Status status = decoder.ReadRepeatedSfixed32(sfixed32);
  ASSERT_EQ(status, Status::ResourceExhausted());
  EXPECT_EQ(sfixed32.size(), 0u);
}

// See b/314803709.
TEST(StreamDecoder, NestedIncompleteVarint) {
  // clang-format off
  static constexpr const uint8_t encoded_proto[] = {
    0x4a, 0x02, 0x20, 0xff,
  };
  // clang-format on

  stream::MemoryReader reader(as_bytes(span(encoded_proto)));
  StreamDecoder decoder(reader);

  EXPECT_EQ(decoder.Next(), OkStatus());
  StreamDecoder nested_decoder = decoder.GetNestedDecoder();

  EXPECT_EQ(nested_decoder.Next(), OkStatus());
  EXPECT_EQ(nested_decoder.ReadInt32().status(), Status::DataLoss());
}

}  // namespace
}  // namespace pw::protobuf
