Path: blob/master/src/common-tests/binary_reader_writer_tests.cpp
7197 views
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <[email protected]>1// SPDX-License-Identifier: CC-BY-NC-ND-4.023#include "common/binary_reader_writer.h"4#include "common/small_string.h"56#include <array>7#include <cstring>8#include <gtest/gtest.h>9#include <optional>10#include <string>11#include <string_view>1213using namespace std::string_view_literals;1415//////////////////////////////////////////////////////////////////////////16// Global test data17//////////////////////////////////////////////////////////////////////////1819// Buffer with various primitive types20alignas(8) static constexpr std::array<u8, 32> g_primitive_buffer = {{210x01, // u8: 1220xFE, // s8: -2230x34, 0x12, // u16: 0x1234 (little endian)240xCD, 0xAB, // s16: -0x5433 (little endian)250x78, 0x56, 0x34, 0x12, // u32: 0x12345678260x88, 0xA9, 0xCB, 0xED, // s32: -0x12345678270xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, // u64: 0x0123456789ABCDEF280x00, 0x00, 0x80, 0x3F, // float: 1.0f290x00, 0x00, 0x00, 0x00 // padding30}};3132// Buffer with C-strings (null-terminated)33static constexpr std::array<u8, 16> g_cstring_buffer = {{34'H', 'e', 'l', 'l', 'o', '\0', // "Hello"35'W', 'o', 'r', 'l', 'd', '\0', // "World"36'\0', // empty string37'A', 'B', 'C' // "ABC" without null terminator (truncated)38}};3940// Buffer with size-prefixed strings (u32 length + data)41static constexpr std::array<u8, 25> g_size_prefixed_buffer = {420x05, 0x00, 0x00, 0x00, // length: 543'H', 'e', 'l', 'l', 'o', // "Hello"440x00, 0x00, 0x00, 0x00, // length: 0 (empty string)450x04, 0x00, 0x00, 0x00, // length: 446'T', 'e', 's', 't', // "Test"470xFF, 0xFF, 0xFF, 0xFF // invalid length (overflow)48};4950//////////////////////////////////////////////////////////////////////////51// BinarySpanReader Tests52//////////////////////////////////////////////////////////////////////////5354TEST(BinarySpanReader, DefaultConstructor)55{56BinarySpanReader reader;57EXPECT_FALSE(reader.IsValid());58EXPECT_EQ(reader.GetBufferRemaining(), 0u);59EXPECT_EQ(reader.GetBufferConsumed(), 0u);60}6162TEST(BinarySpanReader, SpanConstructor)63{64BinarySpanReader reader(g_primitive_buffer);65EXPECT_TRUE(reader.IsValid());66EXPECT_EQ(reader.GetBufferRemaining(), g_primitive_buffer.size());67EXPECT_EQ(reader.GetBufferConsumed(), 0u);68}6970TEST(BinarySpanReader, MoveConstructor)71{72BinarySpanReader original(g_primitive_buffer);73original.ReadU8();74original.ReadU8();7576BinarySpanReader moved(std::move(original));77EXPECT_TRUE(moved.IsValid());78EXPECT_EQ(moved.GetBufferConsumed(), 2u);79EXPECT_EQ(original.GetBufferConsumed(), 0u);80}8182TEST(BinarySpanReader, MoveAssignment)83{84BinarySpanReader original(g_primitive_buffer);85original.ReadU8();8687BinarySpanReader moved;88moved = std::move(original);89EXPECT_TRUE(moved.IsValid());90EXPECT_EQ(moved.GetBufferConsumed(), 1u);91EXPECT_EQ(original.GetBufferConsumed(), 0u);92}9394TEST(BinarySpanReader, GetSpan)95{96BinarySpanReader reader(g_primitive_buffer);97auto span = reader.GetSpan();98EXPECT_EQ(span.size(), g_primitive_buffer.size());99EXPECT_EQ(span.data(), g_primitive_buffer.data());100}101102TEST(BinarySpanReader, CheckRemaining)103{104BinarySpanReader reader(g_primitive_buffer);105EXPECT_TRUE(reader.CheckRemaining(g_primitive_buffer.size()));106EXPECT_TRUE(reader.CheckRemaining(1));107EXPECT_FALSE(reader.CheckRemaining(g_primitive_buffer.size() + 1));108}109110TEST(BinarySpanReader, ReadU8)111{112BinarySpanReader reader(g_primitive_buffer);113u8 val;114EXPECT_TRUE(reader.ReadU8(&val));115EXPECT_EQ(val, 0x01u);116EXPECT_EQ(reader.GetBufferConsumed(), 1u);117}118119TEST(BinarySpanReader, ReadS8)120{121BinarySpanReader reader(g_primitive_buffer);122reader.IncrementPosition(1);123s8 val;124EXPECT_TRUE(reader.ReadS8(&val));125EXPECT_EQ(val, static_cast<s8>(0xFE));126EXPECT_EQ(reader.GetBufferConsumed(), 2u);127}128129TEST(BinarySpanReader, ReadU16)130{131BinarySpanReader reader(g_primitive_buffer);132reader.IncrementPosition(2);133u16 val;134EXPECT_TRUE(reader.ReadU16(&val));135EXPECT_EQ(val, 0x1234u);136}137138TEST(BinarySpanReader, ReadS16)139{140BinarySpanReader reader(g_primitive_buffer);141reader.IncrementPosition(4);142s16 val;143EXPECT_TRUE(reader.ReadS16(&val));144EXPECT_EQ(val, static_cast<s16>(0xABCD));145}146147TEST(BinarySpanReader, ReadU32)148{149BinarySpanReader reader(g_primitive_buffer);150reader.IncrementPosition(6);151u32 val;152EXPECT_TRUE(reader.ReadU32(&val));153EXPECT_EQ(val, 0x12345678u);154}155156TEST(BinarySpanReader, ReadS32)157{158BinarySpanReader reader(g_primitive_buffer);159reader.IncrementPosition(10);160s32 val;161EXPECT_TRUE(reader.ReadS32(&val));162EXPECT_EQ(val, static_cast<s32>(0xEDCBA988));163}164165TEST(BinarySpanReader, ReadU64)166{167BinarySpanReader reader(g_primitive_buffer);168reader.IncrementPosition(14);169u64 val;170EXPECT_TRUE(reader.ReadU64(&val));171EXPECT_EQ(val, 0x0123456789ABCDEFull);172}173174TEST(BinarySpanReader, ReadFloat)175{176BinarySpanReader reader(g_primitive_buffer);177reader.IncrementPosition(22);178float val;179EXPECT_TRUE(reader.ReadFloat(&val));180EXPECT_FLOAT_EQ(val, 1.0f);181}182183TEST(BinarySpanReader, ReadBool)184{185std::array<u8, 2> buf = {0x00, 0x01};186BinarySpanReader reader(buf);187bool val;188EXPECT_TRUE(reader.ReadBool(&val));189EXPECT_FALSE(val);190EXPECT_TRUE(reader.ReadBool(&val));191EXPECT_TRUE(val);192}193194TEST(BinarySpanReader, ReadTReturningValue)195{196BinarySpanReader reader(g_primitive_buffer);197EXPECT_EQ(reader.ReadU8(), 0x01u);198EXPECT_EQ(reader.ReadS8(), static_cast<s8>(0xFE));199EXPECT_EQ(reader.ReadU16(), 0x1234u);200EXPECT_EQ(reader.ReadS16(), static_cast<s16>(0xABCD));201EXPECT_EQ(reader.ReadU32(), 0x12345678u);202EXPECT_EQ(reader.ReadS32(), static_cast<s32>(0xEDCBA988));203EXPECT_EQ(reader.ReadU64(), 0x0123456789ABCDEFull);204EXPECT_FLOAT_EQ(reader.ReadFloat(), 1.0f);205}206207TEST(BinarySpanReader, ReadBoolReturningValue)208{209std::array<u8, 3> buf = {0x00, 0x01, 0xFF};210BinarySpanReader reader(buf);211EXPECT_FALSE(reader.ReadBool());212EXPECT_TRUE(reader.ReadBool());213EXPECT_TRUE(reader.ReadBool()); // any non-zero is true214}215216TEST(BinarySpanReader, ReadCStringToString)217{218BinarySpanReader reader(g_cstring_buffer);219std::string val;220EXPECT_TRUE(reader.ReadCString(&val));221EXPECT_EQ(val, "Hello");222EXPECT_EQ(reader.GetBufferConsumed(), 6u);223}224225TEST(BinarySpanReader, ReadCStringToStringView)226{227BinarySpanReader reader(g_cstring_buffer);228std::string_view val;229EXPECT_TRUE(reader.ReadCString(&val));230EXPECT_EQ(val, "Hello"sv);231}232233TEST(BinarySpanReader, ReadCStringToSmallString)234{235BinarySpanReader reader(g_cstring_buffer);236SmallString val;237EXPECT_TRUE(reader.ReadCString(&val));238EXPECT_STREQ(val.c_str(), "Hello");239}240241TEST(BinarySpanReader, ReadCStringReturningValue)242{243BinarySpanReader reader(g_cstring_buffer);244EXPECT_EQ(reader.ReadCString(), "Hello"sv);245EXPECT_EQ(reader.ReadCString(), "World"sv);246EXPECT_EQ(reader.ReadCString(), ""sv);247}248249TEST(BinarySpanReader, ReadCStringWithoutNullTerminator)250{251// Buffer ending without null terminator252std::array<u8, 3> buf = {'A', 'B', 'C'};253BinarySpanReader reader(buf);254std::string val;255EXPECT_FALSE(reader.ReadCString(&val));256}257258TEST(BinarySpanReader, ReadSizePrefixedStringToString)259{260BinarySpanReader reader(g_size_prefixed_buffer);261std::string val;262EXPECT_TRUE(reader.ReadSizePrefixedString(&val));263EXPECT_EQ(val, "Hello");264EXPECT_EQ(reader.GetBufferConsumed(), 9u);265}266267TEST(BinarySpanReader, ReadSizePrefixedStringToStringView)268{269BinarySpanReader reader(g_size_prefixed_buffer);270std::string_view val;271EXPECT_TRUE(reader.ReadSizePrefixedString(&val));272EXPECT_EQ(val, "Hello"sv);273}274275TEST(BinarySpanReader, ReadSizePrefixedStringToSmallString)276{277BinarySpanReader reader(g_size_prefixed_buffer);278SmallString val;279EXPECT_TRUE(reader.ReadSizePrefixedString(&val));280EXPECT_STREQ(val.c_str(), "Hello");281}282283TEST(BinarySpanReader, ReadSizePrefixedStringReturningValue)284{285BinarySpanReader reader(g_size_prefixed_buffer);286EXPECT_EQ(reader.ReadSizePrefixedString(), "Hello"sv);287EXPECT_EQ(reader.ReadSizePrefixedString(), ""sv);288EXPECT_EQ(reader.ReadSizePrefixedString(), "Test"sv);289}290291TEST(BinarySpanReader, ReadSizePrefixedStringEmpty)292{293BinarySpanReader reader(g_size_prefixed_buffer);294reader.IncrementPosition(9);295std::string val;296EXPECT_TRUE(reader.ReadSizePrefixedString(&val));297EXPECT_TRUE(val.empty());298}299300TEST(BinarySpanReader, PeekU8)301{302BinarySpanReader reader(g_primitive_buffer);303u8 val;304EXPECT_TRUE(reader.PeekU8(&val));305EXPECT_EQ(val, 0x01u);306EXPECT_EQ(reader.GetBufferConsumed(), 0u); // position unchanged307}308309TEST(BinarySpanReader, PeekU16)310{311BinarySpanReader reader(g_primitive_buffer);312reader.IncrementPosition(2);313u16 val;314EXPECT_TRUE(reader.PeekU16(&val));315EXPECT_EQ(val, 0x1234u);316EXPECT_EQ(reader.GetBufferConsumed(), 2u); // position unchanged after peek317}318319TEST(BinarySpanReader, PeekU32)320{321BinarySpanReader reader(g_primitive_buffer);322reader.IncrementPosition(6);323u32 val;324EXPECT_TRUE(reader.PeekU32(&val));325EXPECT_EQ(val, 0x12345678u);326EXPECT_EQ(reader.GetBufferConsumed(), 6u);327}328329TEST(BinarySpanReader, PeekU64)330{331BinarySpanReader reader(g_primitive_buffer);332reader.IncrementPosition(14);333u64 val;334EXPECT_TRUE(reader.PeekU64(&val));335EXPECT_EQ(val, 0x0123456789ABCDEFull);336EXPECT_EQ(reader.GetBufferConsumed(), 14u);337}338339TEST(BinarySpanReader, PeekFloat)340{341BinarySpanReader reader(g_primitive_buffer);342reader.IncrementPosition(22);343float val;344EXPECT_TRUE(reader.PeekFloat(&val));345EXPECT_FLOAT_EQ(val, 1.0f);346EXPECT_EQ(reader.GetBufferConsumed(), 22u);347}348349TEST(BinarySpanReader, PeekBool)350{351std::array<u8, 2> buf = {0x00, 0x01};352BinarySpanReader reader(buf);353bool val;354EXPECT_TRUE(reader.PeekBool(&val));355EXPECT_FALSE(val);356EXPECT_EQ(reader.GetBufferConsumed(), 0u);357}358359TEST(BinarySpanReader, PeekCString)360{361BinarySpanReader reader(g_cstring_buffer);362std::string_view val;363EXPECT_TRUE(reader.PeekCString(&val));364EXPECT_EQ(val, "Hello"sv);365EXPECT_EQ(reader.GetBufferConsumed(), 0u); // position unchanged366}367368TEST(BinarySpanReader, PeekSizePrefixedString)369{370BinarySpanReader reader(g_size_prefixed_buffer);371std::string_view val;372EXPECT_TRUE(reader.PeekSizePrefixedString(&val));373EXPECT_EQ(val, "Hello"sv);374EXPECT_EQ(reader.GetBufferConsumed(), 0u); // position unchanged375}376377TEST(BinarySpanReader, StreamOperators)378{379BinarySpanReader reader(g_primitive_buffer);380u8 u8val;381s8 s8val;382u16 u16val;383s16 s16val;384u32 u32val;385s32 s32val;386u64 u64val;387float fval;388389reader >> u8val >> s8val >> u16val >> s16val >> u32val >> s32val >> u64val >> fval;390391EXPECT_EQ(u8val, 0x01u);392EXPECT_EQ(s8val, static_cast<s8>(0xFE));393EXPECT_EQ(u16val, 0x1234u);394EXPECT_EQ(s16val, static_cast<s16>(0xABCD));395EXPECT_EQ(u32val, 0x12345678u);396EXPECT_EQ(s32val, static_cast<s32>(0xEDCBA988));397EXPECT_EQ(u64val, 0x0123456789ABCDEFull);398EXPECT_FLOAT_EQ(fval, 1.0f);399}400401TEST(BinarySpanReader, StreamOperatorCString)402{403BinarySpanReader reader(g_cstring_buffer);404std::string_view val;405reader >> val;406EXPECT_EQ(val, "Hello"sv);407}408409TEST(BinarySpanReader, ReadOptionalTWithValue)410{411std::array<u8, 5> buf = {0x01, 0x78, 0x56, 0x34, 0x12}; // has_value=true, value=0x12345678412BinarySpanReader reader(buf);413std::optional<u32> val;414EXPECT_TRUE(reader.ReadOptionalT(&val));415EXPECT_TRUE(val.has_value());416EXPECT_EQ(val.value(), 0x12345678u);417}418419TEST(BinarySpanReader, ReadOptionalTWithoutValue)420{421std::array<u8, 5> buf = {0x00, 0x00, 0x00, 0x00, 0x00}; // has_value=false422BinarySpanReader reader(buf);423std::optional<u32> val = 123u; // preset to non-empty424EXPECT_TRUE(reader.ReadOptionalT(&val));425EXPECT_FALSE(val.has_value());426}427428TEST(BinarySpanReader, GetRemainingSpan)429{430BinarySpanReader reader(g_primitive_buffer);431reader.IncrementPosition(10);432auto remaining = reader.GetRemainingSpan();433EXPECT_EQ(remaining.size(), g_primitive_buffer.size() - 10);434}435436TEST(BinarySpanReader, GetRemainingSpanWithSize)437{438BinarySpanReader reader(g_primitive_buffer);439reader.IncrementPosition(10);440auto remaining = reader.GetRemainingSpan(5);441EXPECT_EQ(remaining.size(), 5u);442}443444TEST(BinarySpanReader, ReadBeyondBuffer)445{446std::array<u8, 2> buf = {0x01, 0x02};447BinarySpanReader reader(buf);448u32 val;449EXPECT_FALSE(reader.ReadU32(&val));450}451452TEST(BinarySpanReader, PeekBeyondBuffer)453{454std::array<u8, 2> buf = {0x01, 0x02};455BinarySpanReader reader(buf);456u32 val;457EXPECT_FALSE(reader.PeekU32(&val));458}459460//////////////////////////////////////////////////////////////////////////461// BinarySpanWriter Tests462//////////////////////////////////////////////////////////////////////////463464TEST(BinarySpanWriter, DefaultConstructor)465{466BinarySpanWriter writer;467EXPECT_FALSE(writer.IsValid());468EXPECT_EQ(writer.GetBufferRemaining(), 0u);469EXPECT_EQ(writer.GetBufferWritten(), 0u);470}471472TEST(BinarySpanWriter, SpanConstructor)473{474std::array<u8, 32> buf = {};475BinarySpanWriter writer(buf);476EXPECT_TRUE(writer.IsValid());477EXPECT_EQ(writer.GetBufferRemaining(), buf.size());478EXPECT_EQ(writer.GetBufferWritten(), 0u);479}480481TEST(BinarySpanWriter, MoveConstructor)482{483std::array<u8, 32> buf = {};484BinarySpanWriter original(buf);485original.WriteU8(0x01);486original.WriteU8(0x02);487488BinarySpanWriter moved(std::move(original));489EXPECT_TRUE(moved.IsValid());490EXPECT_EQ(moved.GetBufferWritten(), 2u);491EXPECT_EQ(original.GetBufferWritten(), 0u);492}493494TEST(BinarySpanWriter, MoveAssignment)495{496std::array<u8, 32> buf = {};497BinarySpanWriter original(buf);498original.WriteU8(0x01);499500BinarySpanWriter moved;501moved = std::move(original);502EXPECT_TRUE(moved.IsValid());503EXPECT_EQ(moved.GetBufferWritten(), 1u);504EXPECT_EQ(original.GetBufferWritten(), 0u);505}506507TEST(BinarySpanWriter, GetSpan)508{509std::array<u8, 32> buf = {};510BinarySpanWriter writer(buf);511auto span = writer.GetSpan();512EXPECT_EQ(span.size(), buf.size());513EXPECT_EQ(span.data(), buf.data());514}515516TEST(BinarySpanWriter, WriteU8)517{518std::array<u8, 4> buf = {};519BinarySpanWriter writer(buf);520EXPECT_TRUE(writer.WriteU8(0xAB));521EXPECT_EQ(buf[0], 0xABu);522EXPECT_EQ(writer.GetBufferWritten(), 1u);523}524525TEST(BinarySpanWriter, WriteS8)526{527std::array<u8, 4> buf = {};528BinarySpanWriter writer(buf);529EXPECT_TRUE(writer.WriteS8(-5));530EXPECT_EQ(static_cast<s8>(buf[0]), -5);531}532533TEST(BinarySpanWriter, WriteU16)534{535std::array<u8, 4> buf = {};536BinarySpanWriter writer(buf);537EXPECT_TRUE(writer.WriteU16(0x1234));538EXPECT_EQ(buf[0], 0x34u);539EXPECT_EQ(buf[1], 0x12u);540}541542TEST(BinarySpanWriter, WriteS16)543{544std::array<u8, 4> buf = {};545BinarySpanWriter writer(buf);546EXPECT_TRUE(writer.WriteS16(-1000));547s16 val;548std::memcpy(&val, buf.data(), sizeof(val));549EXPECT_EQ(val, -1000);550}551552TEST(BinarySpanWriter, WriteU32)553{554std::array<u8, 4> buf = {};555BinarySpanWriter writer(buf);556EXPECT_TRUE(writer.WriteU32(0x12345678));557EXPECT_EQ(buf[0], 0x78u);558EXPECT_EQ(buf[1], 0x56u);559EXPECT_EQ(buf[2], 0x34u);560EXPECT_EQ(buf[3], 0x12u);561}562563TEST(BinarySpanWriter, WriteS32)564{565std::array<u8, 4> buf = {};566BinarySpanWriter writer(buf);567EXPECT_TRUE(writer.WriteS32(-123456789));568s32 val;569std::memcpy(&val, buf.data(), sizeof(val));570EXPECT_EQ(val, -123456789);571}572573TEST(BinarySpanWriter, WriteU64)574{575std::array<u8, 8> buf = {};576BinarySpanWriter writer(buf);577EXPECT_TRUE(writer.WriteU64(0x0123456789ABCDEFull));578EXPECT_EQ(buf[0], 0xEFu);579EXPECT_EQ(buf[7], 0x01u);580}581582TEST(BinarySpanWriter, WriteS64)583{584std::array<u8, 8> buf = {};585BinarySpanWriter writer(buf);586EXPECT_TRUE(writer.WriteS64(-1234567890123456789ll));587s64 val;588std::memcpy(&val, buf.data(), sizeof(val));589EXPECT_EQ(val, -1234567890123456789ll);590}591592TEST(BinarySpanWriter, WriteFloat)593{594std::array<u8, 4> buf = {};595BinarySpanWriter writer(buf);596EXPECT_TRUE(writer.WriteFloat(1.0f));597float val;598std::memcpy(&val, buf.data(), sizeof(val));599EXPECT_FLOAT_EQ(val, 1.0f);600}601602TEST(BinarySpanWriter, WriteBool)603{604std::array<u8, 2> buf = {};605BinarySpanWriter writer(buf);606EXPECT_TRUE(writer.WriteBool(false));607EXPECT_TRUE(writer.WriteBool(true));608EXPECT_EQ(buf[0], 0x00u);609EXPECT_EQ(buf[1], 0x01u);610}611612TEST(BinarySpanWriter, WriteCString)613{614std::array<u8, 16> buf = {};615BinarySpanWriter writer(buf);616EXPECT_TRUE(writer.WriteCString("Hello"));617EXPECT_EQ(buf[0], 'H');618EXPECT_EQ(buf[4], 'o');619EXPECT_EQ(buf[5], '\0');620EXPECT_EQ(writer.GetBufferWritten(), 6u);621}622623TEST(BinarySpanWriter, WriteCStringEmpty)624{625std::array<u8, 16> buf = {};626BinarySpanWriter writer(buf);627EXPECT_TRUE(writer.WriteCString(""));628EXPECT_EQ(buf[0], '\0');629EXPECT_EQ(writer.GetBufferWritten(), 1u);630}631632TEST(BinarySpanWriter, WriteSizePrefixedString)633{634std::array<u8, 16> buf = {};635BinarySpanWriter writer(buf);636EXPECT_TRUE(writer.WriteSizePrefixedString("Test"));637638u32 length;639std::memcpy(&length, buf.data(), sizeof(length));640EXPECT_EQ(length, 4u);641EXPECT_EQ(buf[4], 'T');642EXPECT_EQ(buf[7], 't');643EXPECT_EQ(writer.GetBufferWritten(), 8u);644}645646TEST(BinarySpanWriter, WriteSizePrefixedStringEmpty)647{648std::array<u8, 16> buf = {};649BinarySpanWriter writer(buf);650EXPECT_TRUE(writer.WriteSizePrefixedString(""));651652u32 length;653std::memcpy(&length, buf.data(), sizeof(length));654EXPECT_EQ(length, 0u);655EXPECT_EQ(writer.GetBufferWritten(), 4u);656}657658TEST(BinarySpanWriter, StreamOperators)659{660std::array<u8, 32> buf = {};661BinarySpanWriter writer(buf);662663writer << static_cast<u8>(0x01) << static_cast<s8>(0xFE) << static_cast<u16>(0x1234) << static_cast<s16>(0xABCD)664<< static_cast<u32>(0x12345678) << static_cast<s32>(0xEDCBA988) << static_cast<u64>(0x0123456789ABCDEFull)665<< 1.0f;666667EXPECT_EQ(writer.GetBufferWritten(), 26u);668669// Verify by reading back670BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));671EXPECT_EQ(reader.ReadU8(), 0x01u);672EXPECT_EQ(reader.ReadS8(), static_cast<s8>(0xFE));673EXPECT_EQ(reader.ReadU16(), 0x1234u);674EXPECT_EQ(reader.ReadS16(), static_cast<s16>(0xABCD));675EXPECT_EQ(reader.ReadU32(), 0x12345678u);676EXPECT_EQ(reader.ReadS32(), static_cast<s32>(0xEDCBA988));677EXPECT_EQ(reader.ReadU64(), 0x0123456789ABCDEFull);678EXPECT_FLOAT_EQ(reader.ReadFloat(), 1.0f);679}680681TEST(BinarySpanWriter, StreamOperatorCString)682{683std::array<u8, 16> buf = {};684BinarySpanWriter writer(buf);685writer << "Hello"sv;686687BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));688EXPECT_EQ(reader.ReadCString(), "Hello"sv);689}690691TEST(BinarySpanWriter, WriteOptionalTWithValue)692{693std::array<u8, 8> buf = {};694BinarySpanWriter writer(buf);695std::optional<u32> val = 0x12345678u;696EXPECT_TRUE(writer.WriteOptionalT(val));697EXPECT_EQ(writer.GetBufferWritten(), 5u);698699BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));700EXPECT_TRUE(reader.ReadBool());701EXPECT_EQ(reader.ReadU32(), 0x12345678u);702}703704TEST(BinarySpanWriter, WriteOptionalTWithoutValue)705{706std::array<u8, 8> buf = {};707BinarySpanWriter writer(buf);708std::optional<u32> val;709EXPECT_TRUE(writer.WriteOptionalT(val));710EXPECT_EQ(writer.GetBufferWritten(), 1u);711712BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));713EXPECT_FALSE(reader.ReadBool());714}715716TEST(BinarySpanWriter, GetRemainingSpan)717{718std::array<u8, 32> buf = {};719BinarySpanWriter writer(buf);720writer.IncrementPosition(10);721auto remaining = writer.GetRemainingSpan();722EXPECT_EQ(remaining.size(), buf.size() - 10);723}724725TEST(BinarySpanWriter, GetRemainingSpanWithSize)726{727std::array<u8, 32> buf = {};728BinarySpanWriter writer(buf);729writer.IncrementPosition(10);730auto remaining = writer.GetRemainingSpan(5);731EXPECT_EQ(remaining.size(), 5u);732}733734TEST(BinarySpanWriter, WriteBeyondBuffer)735{736std::array<u8, 2> buf = {};737BinarySpanWriter writer(buf);738EXPECT_FALSE(writer.WriteU32(0x12345678));739}740741TEST(BinarySpanWriter, WriteCStringBeyondBuffer)742{743std::array<u8, 4> buf = {};744BinarySpanWriter writer(buf);745EXPECT_FALSE(writer.WriteCString("Hello")); // needs 6 bytes746}747748TEST(BinarySpanWriter, WriteSizePrefixedStringBeyondBuffer)749{750std::array<u8, 4> buf = {};751BinarySpanWriter writer(buf);752EXPECT_FALSE(writer.WriteSizePrefixedString("Test")); // needs 8 bytes753}754755//////////////////////////////////////////////////////////////////////////756// Round-trip Tests (Writer -> Reader)757//////////////////////////////////////////////////////////////////////////758759TEST(BinarySpanRoundTrip, AllPrimitiveTypes)760{761std::array<u8, 64> buf = {};762BinarySpanWriter writer(buf);763764writer.WriteU8(0xAB);765writer.WriteS8(-42);766writer.WriteU16(0x1234);767writer.WriteS16(-1000);768writer.WriteU32(0xDEADBEEF);769writer.WriteS32(-123456789);770writer.WriteU64(0xFEDCBA9876543210ull);771writer.WriteS64(-876543210123456789ll);772writer.WriteFloat(3.14159f);773writer.WriteBool(true);774775BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));776EXPECT_EQ(reader.ReadU8(), 0xABu);777EXPECT_EQ(reader.ReadS8(), -42);778EXPECT_EQ(reader.ReadU16(), 0x1234u);779EXPECT_EQ(reader.ReadS16(), -1000);780EXPECT_EQ(reader.ReadU32(), 0xDEADBEEFu);781EXPECT_EQ(reader.ReadS32(), -123456789);782EXPECT_EQ(reader.ReadU64(), 0xFEDCBA9876543210ull);783EXPECT_EQ(reader.ReadS64(), -876543210123456789ll);784EXPECT_FLOAT_EQ(reader.ReadFloat(), 3.14159f);785EXPECT_TRUE(reader.ReadBool());786}787788TEST(BinarySpanRoundTrip, CStrings)789{790std::array<u8, 64> buf = {};791BinarySpanWriter writer(buf);792793writer.WriteCString("Hello");794writer.WriteCString("");795writer.WriteCString("World!");796797BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));798EXPECT_EQ(reader.ReadCString(), "Hello"sv);799EXPECT_EQ(reader.ReadCString(), ""sv);800EXPECT_EQ(reader.ReadCString(), "World!"sv);801}802803TEST(BinarySpanRoundTrip, SizePrefixedStrings)804{805std::array<u8, 64> buf = {};806BinarySpanWriter writer(buf);807808writer.WriteSizePrefixedString("Testing");809writer.WriteSizePrefixedString("");810writer.WriteSizePrefixedString("123");811812BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));813EXPECT_EQ(reader.ReadSizePrefixedString(), "Testing"sv);814EXPECT_EQ(reader.ReadSizePrefixedString(), ""sv);815EXPECT_EQ(reader.ReadSizePrefixedString(), "123"sv);816}817818TEST(BinarySpanRoundTrip, OptionalValues)819{820std::array<u8, 32> buf = {};821BinarySpanWriter writer(buf);822823std::optional<u32> val1 = 12345u;824std::optional<u32> val2;825std::optional<u16> val3 = u16(9999);826827writer.WriteOptionalT(val1);828writer.WriteOptionalT(val2);829writer.WriteOptionalT(val3);830831BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));832833std::optional<u32> read1, read2;834std::optional<u16> read3;835836EXPECT_TRUE(reader.ReadOptionalT(&read1));837EXPECT_TRUE(reader.ReadOptionalT(&read2));838EXPECT_TRUE(reader.ReadOptionalT(&read3));839840EXPECT_TRUE(read1.has_value());841EXPECT_EQ(read1.value(), 12345u);842EXPECT_FALSE(read2.has_value());843EXPECT_TRUE(read3.has_value());844EXPECT_EQ(read3.value(), 9999u);845}846847TEST(BinarySpanRoundTrip, MixedContent)848{849std::array<u8, 128> buf = {};850BinarySpanWriter writer(buf);851852writer.WriteU32(0x12345678);853writer.WriteCString("Header");854writer.WriteU16(100);855writer.WriteSizePrefixedString("Payload");856writer.WriteFloat(2.5f);857writer.WriteBool(false);858859BinarySpanReader reader(std::span<const u8>(buf.data(), writer.GetBufferWritten()));860861EXPECT_EQ(reader.ReadU32(), 0x12345678u);862EXPECT_EQ(reader.ReadCString(), "Header"sv);863EXPECT_EQ(reader.ReadU16(), 100u);864EXPECT_EQ(reader.ReadSizePrefixedString(), "Payload"sv);865EXPECT_FLOAT_EQ(reader.ReadFloat(), 2.5f);866EXPECT_FALSE(reader.ReadBool());867}868869