mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-10 01:27:15 +00:00
1321 lines
34 KiB
C++
1321 lines
34 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2017-2018 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "serialiser.h"
|
|
|
|
#if ENABLED(ENABLE_UNIT_TESTS)
|
|
|
|
#include "3rdparty/catch/catch.hpp"
|
|
|
|
void WriteAllBasicTypes(WriteSerialiser &ser)
|
|
{
|
|
int64_t a = -1;
|
|
uint64_t b = 2;
|
|
int32_t c = -3;
|
|
uint32_t d = 4;
|
|
int16_t e = -5;
|
|
uint16_t f = 6;
|
|
int8_t g = -7;
|
|
uint8_t h = 8;
|
|
|
|
bool i = true;
|
|
|
|
char j = 'j';
|
|
|
|
double k = 11.11011011;
|
|
float l = 12.12012012f;
|
|
|
|
std::string m = "mmmm";
|
|
char n[5] = "nnnn";
|
|
const char *s = "ssss";
|
|
|
|
int t[4] = {20, 20, 20, 20};
|
|
|
|
SERIALISE_ELEMENT(a);
|
|
SERIALISE_ELEMENT(b);
|
|
SERIALISE_ELEMENT(c);
|
|
SERIALISE_ELEMENT(d);
|
|
SERIALISE_ELEMENT(e);
|
|
SERIALISE_ELEMENT(f);
|
|
SERIALISE_ELEMENT(g);
|
|
SERIALISE_ELEMENT(h);
|
|
SERIALISE_ELEMENT(i);
|
|
SERIALISE_ELEMENT(j);
|
|
SERIALISE_ELEMENT(k);
|
|
SERIALISE_ELEMENT(l);
|
|
SERIALISE_ELEMENT(m);
|
|
SERIALISE_ELEMENT(n);
|
|
SERIALISE_ELEMENT(s);
|
|
SERIALISE_ELEMENT(t);
|
|
}
|
|
|
|
TEST_CASE("Read/write basic types", "[serialiser][structured]")
|
|
{
|
|
StreamWriter *buf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
// write basic types, verify that we didn't write too much (rough factor of total data size +
|
|
// overhead - it's OK to update this value if serialisation changed as long as it's incremental).
|
|
{
|
|
WriteSerialiser ser(buf, Ownership::Nothing);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CHUNK(5);
|
|
|
|
WriteAllBasicTypes(ser);
|
|
}
|
|
|
|
CHECK(buf->GetOffset() <= 128);
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
uint32_t chunkID = ser.ReadChunk<uint32_t>();
|
|
|
|
CHECK(chunkID == 5);
|
|
|
|
int64_t a;
|
|
uint64_t b;
|
|
int32_t c;
|
|
uint32_t d;
|
|
int16_t e;
|
|
uint16_t f;
|
|
int8_t g;
|
|
uint8_t h;
|
|
|
|
bool i;
|
|
|
|
char j;
|
|
|
|
double k;
|
|
float l;
|
|
|
|
std::string m;
|
|
char n[5];
|
|
const char *s;
|
|
|
|
int t[4] = {0, 0, 0, 0};
|
|
|
|
SERIALISE_ELEMENT(a);
|
|
SERIALISE_ELEMENT(b);
|
|
SERIALISE_ELEMENT(c);
|
|
SERIALISE_ELEMENT(d);
|
|
SERIALISE_ELEMENT(e);
|
|
SERIALISE_ELEMENT(f);
|
|
SERIALISE_ELEMENT(g);
|
|
SERIALISE_ELEMENT(h);
|
|
SERIALISE_ELEMENT(i);
|
|
SERIALISE_ELEMENT(j);
|
|
SERIALISE_ELEMENT(k);
|
|
SERIALISE_ELEMENT(l);
|
|
SERIALISE_ELEMENT(m);
|
|
SERIALISE_ELEMENT(n);
|
|
SERIALISE_ELEMENT(s);
|
|
SERIALISE_ELEMENT(t);
|
|
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
|
|
CHECK(a == -1);
|
|
CHECK(b == 2);
|
|
CHECK(c == -3);
|
|
CHECK(d == 4);
|
|
CHECK(e == -5);
|
|
CHECK(f == 6);
|
|
CHECK(g == -7);
|
|
CHECK(h == 8);
|
|
|
|
CHECK(i == true);
|
|
|
|
CHECK(j == 'j');
|
|
|
|
CHECK(k == 11.11011011);
|
|
CHECK(l == 12.12012012f);
|
|
|
|
CHECK(m == "mmmm");
|
|
CHECK(std::string(n) == "nnnn");
|
|
CHECK(std::string(s) == "ssss");
|
|
|
|
CHECK(t[0] == 20);
|
|
CHECK(t[1] == 20);
|
|
CHECK(t[2] == 20);
|
|
CHECK(t[3] == 20);
|
|
}
|
|
|
|
delete buf;
|
|
};
|
|
|
|
TEST_CASE("Read/write via structured of basic types", "[serialiser]")
|
|
{
|
|
StreamWriter *buf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
// write basic types, verify that we didn't write too much (rough factor of total data size +
|
|
// overhead - it's OK to update this value if serialisation changed as long as it's incremental).
|
|
{
|
|
WriteSerialiser ser(buf, Ownership::Nothing);
|
|
ser.WriteChunk(5);
|
|
WriteAllBasicTypes(ser);
|
|
ser.EndChunk();
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
ChunkLookup testChunkLoop = [](uint32_t) -> std::string { return "TestChunk"; };
|
|
|
|
ser.ConfigureStructuredExport(testChunkLoop, true);
|
|
|
|
int64_t a;
|
|
uint64_t b;
|
|
int32_t c;
|
|
uint32_t d;
|
|
int16_t e;
|
|
uint16_t f;
|
|
int8_t g;
|
|
uint8_t h;
|
|
|
|
bool i;
|
|
|
|
char j;
|
|
|
|
double k;
|
|
float l;
|
|
|
|
std::string m;
|
|
char n[5];
|
|
const char *s;
|
|
|
|
int t[4];
|
|
|
|
ser.ReadChunk<uint32_t>();
|
|
|
|
SERIALISE_ELEMENT(a);
|
|
SERIALISE_ELEMENT(b);
|
|
SERIALISE_ELEMENT(c);
|
|
SERIALISE_ELEMENT(d);
|
|
SERIALISE_ELEMENT(e);
|
|
SERIALISE_ELEMENT(f);
|
|
SERIALISE_ELEMENT(g);
|
|
SERIALISE_ELEMENT(h);
|
|
SERIALISE_ELEMENT(i);
|
|
SERIALISE_ELEMENT(j);
|
|
SERIALISE_ELEMENT(k);
|
|
SERIALISE_ELEMENT(l);
|
|
SERIALISE_ELEMENT(m);
|
|
SERIALISE_ELEMENT(n);
|
|
SERIALISE_ELEMENT(s);
|
|
SERIALISE_ELEMENT(t);
|
|
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
|
|
const SDFile &structFile = ser.GetStructuredFile();
|
|
|
|
CHECK(structFile.chunks.size() == 1);
|
|
CHECK(structFile.buffers.size() == 0);
|
|
|
|
REQUIRE(structFile.chunks[0]);
|
|
|
|
const SDChunk &chunk = *structFile.chunks[0];
|
|
|
|
CHECK(chunk.name == testChunkLoop(0));
|
|
CHECK(chunk.metadata.chunkID == 5);
|
|
CHECK(chunk.metadata.length == chunk.type.byteSize);
|
|
CHECK(chunk.metadata.length < ser.GetReader()->GetSize());
|
|
CHECK(chunk.type.basetype == SDBasic::Chunk);
|
|
CHECK(chunk.type.name == "Chunk");
|
|
CHECK(chunk.data.children.size() == 16);
|
|
|
|
for(SDObject *o : chunk.data.children)
|
|
REQUIRE(o);
|
|
|
|
int childIdx = 0;
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "a");
|
|
CHECK(o.type.name == "int64_t");
|
|
CHECK(o.type.basetype == SDBasic::SignedInteger);
|
|
CHECK(o.type.byteSize == 8);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.i == -1);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "b");
|
|
CHECK(o.type.name == "uint64_t");
|
|
CHECK(o.type.basetype == SDBasic::UnsignedInteger);
|
|
CHECK(o.type.byteSize == 8);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.u == 2);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "c");
|
|
CHECK(o.type.name == "int32_t");
|
|
CHECK(o.type.basetype == SDBasic::SignedInteger);
|
|
CHECK(o.type.byteSize == 4);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.i == -3);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "d");
|
|
CHECK(o.type.name == "uint32_t");
|
|
CHECK(o.type.basetype == SDBasic::UnsignedInteger);
|
|
CHECK(o.type.byteSize == 4);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.u == 4);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "e");
|
|
CHECK(o.type.name == "int16_t");
|
|
CHECK(o.type.basetype == SDBasic::SignedInteger);
|
|
CHECK(o.type.byteSize == 2);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.i == -5);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "f");
|
|
CHECK(o.type.name == "uint16_t");
|
|
CHECK(o.type.basetype == SDBasic::UnsignedInteger);
|
|
CHECK(o.type.byteSize == 2);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.u == 6);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "g");
|
|
CHECK(o.type.name == "int8_t");
|
|
CHECK(o.type.basetype == SDBasic::SignedInteger);
|
|
CHECK(o.type.byteSize == 1);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.i == -7);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "h");
|
|
CHECK(o.type.name == "uint8_t");
|
|
CHECK(o.type.basetype == SDBasic::UnsignedInteger);
|
|
CHECK(o.type.byteSize == 1);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.u == 8);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "i");
|
|
CHECK(o.type.name == "bool");
|
|
CHECK(o.type.basetype == SDBasic::Boolean);
|
|
CHECK(o.type.byteSize == 1);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.b == true);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "j");
|
|
CHECK(o.type.name == "char");
|
|
CHECK(o.type.basetype == SDBasic::Character);
|
|
CHECK(o.type.byteSize == 1);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.c == 'j');
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "k");
|
|
CHECK(o.type.name == "double");
|
|
CHECK(o.type.basetype == SDBasic::Float);
|
|
CHECK(o.type.byteSize == 8);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.d == 11.11011011);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "l");
|
|
CHECK(o.type.name == "float");
|
|
CHECK(o.type.basetype == SDBasic::Float);
|
|
CHECK(o.type.byteSize == 4);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.basic.d == Approx(12.12012012));
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "m");
|
|
CHECK(o.type.name == "string");
|
|
CHECK(o.type.basetype == SDBasic::String);
|
|
CHECK(o.type.byteSize == 4);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.str == "mmmm");
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "n");
|
|
CHECK(o.type.name == "string");
|
|
CHECK(o.type.basetype == SDBasic::String);
|
|
CHECK(o.type.byteSize == 4);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.str == "nnnn");
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "s");
|
|
CHECK(o.type.name == "string");
|
|
CHECK(o.type.basetype == SDBasic::String);
|
|
CHECK(o.type.byteSize == 4);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(o.data.str == "ssss");
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "t");
|
|
CHECK(o.type.name == "int32_t");
|
|
CHECK(o.type.basetype == SDBasic::Array);
|
|
CHECK(o.type.byteSize == 4);
|
|
CHECK(o.type.flags == SDTypeFlags::FixedArray);
|
|
|
|
CHECK(o.data.children.size() == 4);
|
|
|
|
CHECK(o.data.children[0]->data.basic.i == 20);
|
|
CHECK(o.data.children[1]->data.basic.c == 20);
|
|
CHECK(o.data.children[2]->data.basic.c == 20);
|
|
CHECK(o.data.children[3]->data.basic.c == 20);
|
|
}
|
|
|
|
StreamWriter *rewriteBuf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
{
|
|
WriteSerialiser rewrite(rewriteBuf, Ownership::Nothing);
|
|
|
|
rewrite.WriteStructuredFile(structFile, NULL);
|
|
}
|
|
|
|
// must be bitwise identical to the original serialised data.
|
|
REQUIRE(rewriteBuf->GetOffset() == buf->GetOffset());
|
|
CHECK_FALSE(memcmp(rewriteBuf->GetData(), buf->GetData(), (size_t)rewriteBuf->GetOffset()));
|
|
|
|
delete rewriteBuf;
|
|
}
|
|
|
|
delete buf;
|
|
};
|
|
|
|
TEST_CASE("Read/write chunk metadata", "[serialiser]")
|
|
{
|
|
StreamWriter *buf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
// write basic types, verify that we didn't write too much (rough factor of total data size +
|
|
// overhead - it's OK to update this value if serialisation changed as long as it's incremental).
|
|
{
|
|
WriteSerialiser ser(buf, Ownership::Nothing);
|
|
|
|
ser.SetChunkMetadataRecording(WriteSerialiser::ChunkCallstack | WriteSerialiser::ChunkDuration |
|
|
WriteSerialiser::ChunkThreadID | WriteSerialiser::ChunkTimestamp);
|
|
|
|
ser.ChunkMetadata().threadID = 12345ULL;
|
|
ser.ChunkMetadata().durationMicro = 445566ULL;
|
|
ser.ChunkMetadata().timestampMicro = 987654321ULL;
|
|
ser.ChunkMetadata().callstack.resize(4);
|
|
ser.ChunkMetadata().callstack[0] = 101;
|
|
ser.ChunkMetadata().callstack[1] = 102;
|
|
ser.ChunkMetadata().callstack[2] = 103;
|
|
ser.ChunkMetadata().callstack[3] = 104;
|
|
|
|
ser.WriteChunk(1);
|
|
|
|
uint32_t dummy = 99;
|
|
ser.Serialise("dummy", dummy);
|
|
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
ser.ReadChunk<uint32_t>();
|
|
|
|
CHECK(ser.ChunkMetadata().threadID == 12345ULL);
|
|
CHECK(ser.ChunkMetadata().durationMicro == 445566ULL);
|
|
CHECK(ser.ChunkMetadata().timestampMicro == 987654321ULL);
|
|
REQUIRE(ser.ChunkMetadata().callstack.size() == 4);
|
|
CHECK(ser.ChunkMetadata().callstack[0] == 101);
|
|
CHECK(ser.ChunkMetadata().callstack[1] == 102);
|
|
CHECK(ser.ChunkMetadata().callstack[2] == 103);
|
|
CHECK(ser.ChunkMetadata().callstack[3] == 104);
|
|
|
|
ser.SkipCurrentChunk();
|
|
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
ChunkLookup testChunkLoop = [](uint32_t) -> std::string { return "TestChunk"; };
|
|
|
|
ser.ConfigureStructuredExport(testChunkLoop, true);
|
|
|
|
ser.ReadChunk<uint32_t>();
|
|
|
|
uint32_t dummy;
|
|
ser.Serialise("dummy", dummy);
|
|
|
|
ser.EndChunk();
|
|
|
|
SDChunkMetaData &md = ser.GetStructuredFile().chunks[0]->metadata;
|
|
|
|
CHECK(md.threadID == 12345ULL);
|
|
CHECK(md.durationMicro == 445566ULL);
|
|
CHECK(md.timestampMicro == 987654321ULL);
|
|
REQUIRE(md.callstack.size() == 4);
|
|
CHECK(md.callstack[0] == 101);
|
|
CHECK(md.callstack[1] == 102);
|
|
CHECK(md.callstack[2] == 103);
|
|
CHECK(md.callstack[3] == 104);
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
}
|
|
|
|
delete buf;
|
|
};
|
|
|
|
TEST_CASE("Verify multiple chunks can be merged", "[serialiser][chunks]")
|
|
{
|
|
StreamWriter *buf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
enum ChunkType
|
|
{
|
|
FLOAT4 = 5,
|
|
TWO_INTS,
|
|
BOOL_INT_FLOAT,
|
|
STRING_AND_INT,
|
|
};
|
|
|
|
// write some chunks individually
|
|
std::vector<Chunk *> chunks;
|
|
{
|
|
WriteSerialiser ser(new StreamWriter(StreamWriter::DefaultScratchSize), Ownership::Stream);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CHUNK(TWO_INTS);
|
|
|
|
int first = 123;
|
|
int second = 456;
|
|
|
|
SERIALISE_ELEMENT(first);
|
|
SERIALISE_ELEMENT(second);
|
|
|
|
chunks.push_back(scope.Get());
|
|
REQUIRE(chunks.back());
|
|
}
|
|
|
|
{
|
|
SCOPED_SERIALISE_CHUNK(STRING_AND_INT);
|
|
|
|
string s = "string in STRING_AND_INT";
|
|
int i = 4096;
|
|
|
|
SERIALISE_ELEMENT(s);
|
|
SERIALISE_ELEMENT(i);
|
|
|
|
chunks.push_back(scope.Get());
|
|
REQUIRE(chunks.back());
|
|
}
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
REQUIRE(chunks.size() == 2);
|
|
}
|
|
|
|
// now write the previous chunks, then some more in-line
|
|
{
|
|
WriteSerialiser ser(buf, Ownership::Nothing);
|
|
|
|
for(Chunk *c : chunks)
|
|
c->Write(ser);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CHUNK(BOOL_INT_FLOAT);
|
|
|
|
bool flag = false;
|
|
int data = 10000;
|
|
float value = 3.141592f;
|
|
|
|
SERIALISE_ELEMENT(flag);
|
|
SERIALISE_ELEMENT(data);
|
|
SERIALISE_ELEMENT(value);
|
|
}
|
|
|
|
{
|
|
SCOPED_SERIALISE_CHUNK(FLOAT4);
|
|
|
|
float vec4[4] = {1.1f, 2.2f, 3.3f, 4.4f};
|
|
|
|
SERIALISE_ELEMENT(vec4);
|
|
}
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
CHECK(buf->GetOffset() <= 256);
|
|
}
|
|
|
|
for(Chunk *c : chunks)
|
|
delete c;
|
|
|
|
// now read the data "dynamically" and ensure it's all correct
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
while(!ser.GetReader()->AtEnd())
|
|
{
|
|
uint32_t chunkID = ser.ReadChunk<uint32_t>();
|
|
ChunkType chunk = (ChunkType)chunkID;
|
|
|
|
switch(chunk)
|
|
{
|
|
case FLOAT4:
|
|
{
|
|
float vec4[4];
|
|
|
|
SERIALISE_ELEMENT(vec4);
|
|
|
|
CHECK(vec4[0] == 1.1f);
|
|
CHECK(vec4[1] == 2.2f);
|
|
CHECK(vec4[2] == 3.3f);
|
|
CHECK(vec4[3] == 4.4f);
|
|
break;
|
|
}
|
|
case TWO_INTS:
|
|
{
|
|
int first = 0;
|
|
int second = 0;
|
|
|
|
SERIALISE_ELEMENT(first);
|
|
SERIALISE_ELEMENT(second);
|
|
|
|
CHECK(first == 123);
|
|
CHECK(second == 456);
|
|
break;
|
|
}
|
|
case BOOL_INT_FLOAT:
|
|
{
|
|
bool flag = true;
|
|
int data = 0;
|
|
float value = 0.0f;
|
|
|
|
SERIALISE_ELEMENT(flag);
|
|
SERIALISE_ELEMENT(data);
|
|
SERIALISE_ELEMENT(value);
|
|
|
|
CHECK(flag == false);
|
|
CHECK(data == 10000);
|
|
CHECK(value == 3.141592f);
|
|
break;
|
|
}
|
|
case STRING_AND_INT:
|
|
{
|
|
string s;
|
|
int i = 0;
|
|
|
|
SERIALISE_ELEMENT(s);
|
|
SERIALISE_ELEMENT(i);
|
|
|
|
CHECK(s == "string in STRING_AND_INT");
|
|
CHECK(i == 4096);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
CAPTURE(chunkID);
|
|
FAIL("Unexpected chunk type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
ser.EndChunk();
|
|
}
|
|
}
|
|
|
|
delete buf;
|
|
};
|
|
|
|
TEST_CASE("Read/write container types", "[serialiser][structured]")
|
|
{
|
|
StreamWriter *buf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
// write basic types, verify that we didn't write too much (rough factor of total data size +
|
|
// overhead - it's OK to update this value if serialisation changed as long as it's incremental).
|
|
{
|
|
WriteSerialiser ser(buf, Ownership::Nothing);
|
|
|
|
{
|
|
SCOPED_SERIALISE_CHUNK(5);
|
|
|
|
std::vector<int> v;
|
|
std::pair<float, string> p;
|
|
std::list<uint16_t> l;
|
|
|
|
v.push_back(1);
|
|
v.push_back(1);
|
|
v.push_back(2);
|
|
v.push_back(3);
|
|
v.push_back(5);
|
|
v.push_back(8);
|
|
|
|
p = std::make_pair(3.14159f, "M_PI");
|
|
|
|
l.push_back(2U);
|
|
l.push_back(3U);
|
|
l.push_back(5U);
|
|
l.push_back(7U);
|
|
l.push_back(11U);
|
|
l.push_back(13U);
|
|
|
|
SERIALISE_ELEMENT(v);
|
|
SERIALISE_ELEMENT(p);
|
|
SERIALISE_ELEMENT(l);
|
|
}
|
|
|
|
CHECK(buf->GetOffset() <= 128);
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
uint32_t chunkID = ser.ReadChunk<uint32_t>();
|
|
|
|
CHECK(chunkID == 5);
|
|
|
|
std::vector<int> v;
|
|
std::pair<float, string> p;
|
|
std::list<uint16_t> l;
|
|
|
|
SERIALISE_ELEMENT(v);
|
|
SERIALISE_ELEMENT(p);
|
|
SERIALISE_ELEMENT(l);
|
|
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
|
|
REQUIRE(v.size() == 6);
|
|
REQUIRE(l.size() == 6);
|
|
|
|
CHECK(v[0] == 1);
|
|
CHECK(v[1] == 1);
|
|
CHECK(v[2] == 2);
|
|
CHECK(v[3] == 3);
|
|
CHECK(v[4] == 5);
|
|
CHECK(v[5] == 8);
|
|
|
|
CHECK(p.first == 3.14159f);
|
|
CHECK(p.second == "M_PI");
|
|
|
|
auto it = l.begin();
|
|
|
|
CHECK(*it == 2U);
|
|
++it;
|
|
CHECK(*it == 3U);
|
|
++it;
|
|
CHECK(*it == 5U);
|
|
++it;
|
|
CHECK(*it == 7U);
|
|
++it;
|
|
CHECK(*it == 11U);
|
|
++it;
|
|
CHECK(*it == 13U);
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
ser.ConfigureStructuredExport([](uint32_t) -> std::string { return "TestChunk"; }, true);
|
|
|
|
ser.ReadChunk<uint32_t>();
|
|
{
|
|
std::vector<int32_t> v;
|
|
std::pair<float, string> p;
|
|
std::list<uint16_t> l;
|
|
|
|
SERIALISE_ELEMENT(v);
|
|
SERIALISE_ELEMENT(p);
|
|
SERIALISE_ELEMENT(l);
|
|
}
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
|
|
const SDFile &structData = ser.GetStructuredFile();
|
|
|
|
CHECK(structData.chunks.size() == 1);
|
|
CHECK(structData.buffers.size() == 0);
|
|
|
|
REQUIRE(structData.chunks[0]);
|
|
|
|
const SDChunk &chunk = *structData.chunks[0];
|
|
|
|
CHECK(chunk.data.children.size() == 3);
|
|
|
|
for(SDObject *o : chunk.data.children)
|
|
REQUIRE(o);
|
|
|
|
int childIdx = 0;
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "v");
|
|
CHECK(o.type.basetype == SDBasic::Array);
|
|
CHECK(o.type.byteSize == 6);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
CHECK(o.data.children.size() == 6);
|
|
|
|
for(SDObject *child : o.data.children)
|
|
{
|
|
CHECK(child->type.basetype == SDBasic::SignedInteger);
|
|
CHECK(child->type.byteSize == 4);
|
|
}
|
|
|
|
CHECK(o.data.children[0]->data.basic.i == 1);
|
|
CHECK(o.data.children[1]->data.basic.i == 1);
|
|
CHECK(o.data.children[2]->data.basic.i == 2);
|
|
CHECK(o.data.children[3]->data.basic.i == 3);
|
|
CHECK(o.data.children[4]->data.basic.i == 5);
|
|
CHECK(o.data.children[5]->data.basic.i == 8);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "p");
|
|
CHECK(o.type.name == "pair");
|
|
CHECK(o.type.basetype == SDBasic::Struct);
|
|
CHECK(o.type.byteSize == 2);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
CHECK(o.data.children.size() == 2);
|
|
|
|
{
|
|
SDObject &first = *o.data.children[0];
|
|
|
|
CHECK(first.name == "first");
|
|
CHECK(first.type.name == "float");
|
|
CHECK(first.type.basetype == SDBasic::Float);
|
|
CHECK(first.type.byteSize == 4);
|
|
CHECK(first.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(first.data.basic.d == 3.14159f);
|
|
}
|
|
|
|
{
|
|
SDObject &second = *o.data.children[1];
|
|
|
|
CHECK(second.name == "second");
|
|
CHECK(second.type.name == "string");
|
|
CHECK(second.type.basetype == SDBasic::String);
|
|
CHECK(second.type.byteSize == 4);
|
|
CHECK(second.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(second.data.str == "M_PI");
|
|
}
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "l");
|
|
CHECK(o.type.basetype == SDBasic::Array);
|
|
CHECK(o.type.byteSize == 6);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
CHECK(o.data.children.size() == 6);
|
|
|
|
for(SDObject *child : o.data.children)
|
|
{
|
|
CHECK(child->type.basetype == SDBasic::UnsignedInteger);
|
|
CHECK(child->type.byteSize == 2);
|
|
}
|
|
|
|
CHECK(o.data.children[0]->data.basic.u == 2U);
|
|
CHECK(o.data.children[1]->data.basic.u == 3U);
|
|
CHECK(o.data.children[2]->data.basic.u == 5U);
|
|
CHECK(o.data.children[3]->data.basic.u == 7U);
|
|
CHECK(o.data.children[4]->data.basic.u == 11U);
|
|
CHECK(o.data.children[5]->data.basic.u == 13U);
|
|
}
|
|
|
|
StreamWriter *rewriteBuf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
{
|
|
WriteSerialiser rewrite(rewriteBuf, Ownership::Nothing);
|
|
|
|
rewrite.WriteStructuredFile(structData, NULL);
|
|
}
|
|
|
|
// must be bitwise identical to the original serialised data.
|
|
REQUIRE(rewriteBuf->GetOffset() == buf->GetOffset());
|
|
CHECK_FALSE(memcmp(rewriteBuf->GetData(), buf->GetData(), (size_t)rewriteBuf->GetOffset()));
|
|
|
|
delete rewriteBuf;
|
|
}
|
|
|
|
delete buf;
|
|
};
|
|
|
|
struct struct1
|
|
{
|
|
struct1() : x(0.0f), y(0.0f), width(0.0f), height(0.0f) {}
|
|
struct1(float X, float Y, float W, float H) : x(X), y(Y), width(W), height(H) {}
|
|
float x, y, width, height;
|
|
};
|
|
|
|
DECLARE_REFLECTION_STRUCT(struct1);
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, struct1 &el)
|
|
{
|
|
SERIALISE_MEMBER(x);
|
|
SERIALISE_MEMBER(y);
|
|
SERIALISE_MEMBER(width);
|
|
SERIALISE_MEMBER(height);
|
|
}
|
|
|
|
struct struct2
|
|
{
|
|
string name;
|
|
std::vector<float> floats;
|
|
std::vector<struct1> viewports;
|
|
};
|
|
|
|
DECLARE_REFLECTION_STRUCT(struct2);
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, struct2 &el)
|
|
{
|
|
SERIALISE_MEMBER(name);
|
|
SERIALISE_MEMBER(floats);
|
|
SERIALISE_MEMBER(viewports);
|
|
}
|
|
|
|
enum MySpecialEnum
|
|
{
|
|
FirstEnumValue,
|
|
SecondEnumValue,
|
|
AnotherEnumValue,
|
|
TheLastEnumValue,
|
|
};
|
|
|
|
DECLARE_REFLECTION_ENUM(MySpecialEnum);
|
|
|
|
template <>
|
|
std::string DoStringise(const MySpecialEnum &el)
|
|
{
|
|
BEGIN_ENUM_STRINGISE(MySpecialEnum);
|
|
{
|
|
STRINGISE_ENUM(FirstEnumValue);
|
|
STRINGISE_ENUM(SecondEnumValue);
|
|
STRINGISE_ENUM(AnotherEnumValue);
|
|
STRINGISE_ENUM(TheLastEnumValue);
|
|
}
|
|
END_ENUM_STRINGISE();
|
|
}
|
|
|
|
TEST_CASE("Read/write complex types", "[serialiser][structured]")
|
|
{
|
|
StreamWriter *buf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
{
|
|
WriteSerialiser ser(buf, Ownership::Nothing);
|
|
|
|
SCOPED_SERIALISE_CHUNK(5);
|
|
|
|
MySpecialEnum enumVal = AnotherEnumValue;
|
|
|
|
SERIALISE_ELEMENT(enumVal);
|
|
|
|
std::vector<struct1> sparseStructArray;
|
|
|
|
sparseStructArray.resize(10);
|
|
|
|
sparseStructArray[5] = struct1(1.0f, 2.0f, 3.0f, 4.0f);
|
|
sparseStructArray[8] = struct1(10.0f, 20.0f, 30.0f, 40.0f);
|
|
|
|
SERIALISE_ELEMENT(sparseStructArray);
|
|
|
|
struct2 complex;
|
|
complex.name = "A complex object";
|
|
complex.floats = {1.2f, 3.4f, 5.6f};
|
|
complex.viewports.resize(4);
|
|
complex.viewports[0] = struct1(512.0f, 0.0f, 256.0f, 256.0f);
|
|
|
|
SERIALISE_ELEMENT(complex);
|
|
|
|
const struct1 *inputParam1 = new struct1(9.0f, 9.9f, 9.99f, 9.999f);
|
|
const struct1 *inputParam2 = NULL;
|
|
|
|
SERIALISE_ELEMENT_OPT(inputParam1);
|
|
SERIALISE_ELEMENT_OPT(inputParam2);
|
|
|
|
CHECK(buf->GetOffset() <= 512);
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
delete inputParam1;
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
uint32_t chunkID = ser.ReadChunk<uint32_t>();
|
|
|
|
CHECK(chunkID == 5);
|
|
|
|
MySpecialEnum enumVal;
|
|
|
|
SERIALISE_ELEMENT(enumVal);
|
|
|
|
std::vector<struct1> sparseStructArray;
|
|
|
|
SERIALISE_ELEMENT(sparseStructArray);
|
|
|
|
struct2 complex;
|
|
|
|
SERIALISE_ELEMENT(complex);
|
|
|
|
const struct1 *inputParam1;
|
|
const struct1 *inputParam2;
|
|
|
|
SERIALISE_ELEMENT_OPT(inputParam1);
|
|
SERIALISE_ELEMENT_OPT(inputParam2);
|
|
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
|
|
CHECK(enumVal == AnotherEnumValue);
|
|
|
|
CHECK(sparseStructArray[0].x == 0.0f);
|
|
CHECK(sparseStructArray[0].y == 0.0f);
|
|
CHECK(sparseStructArray[0].width == 0.0f);
|
|
CHECK(sparseStructArray[0].height == 0.0f);
|
|
|
|
CHECK(sparseStructArray[5].x == 1.0f);
|
|
CHECK(sparseStructArray[5].y == 2.0f);
|
|
CHECK(sparseStructArray[5].width == 3.0f);
|
|
CHECK(sparseStructArray[5].height == 4.0f);
|
|
|
|
CHECK(sparseStructArray[8].x == 10.0f);
|
|
CHECK(sparseStructArray[8].y == 20.0f);
|
|
CHECK(sparseStructArray[8].width == 30.0f);
|
|
CHECK(sparseStructArray[8].height == 40.0f);
|
|
|
|
CHECK(complex.name == "A complex object");
|
|
REQUIRE(complex.floats.size() == 3);
|
|
CHECK(complex.floats[0] == 1.2f);
|
|
CHECK(complex.floats[1] == 3.4f);
|
|
CHECK(complex.floats[2] == 5.6f);
|
|
REQUIRE(complex.viewports.size() == 4);
|
|
|
|
CHECK(complex.viewports[0].x == 512.0f);
|
|
CHECK(complex.viewports[0].y == 0.0f);
|
|
CHECK(complex.viewports[0].width == 256.0f);
|
|
CHECK(complex.viewports[0].height == 256.0f);
|
|
|
|
CHECK(inputParam1->x == 9.0f);
|
|
CHECK(inputParam1->y == 9.9f);
|
|
CHECK(inputParam1->width == 9.99f);
|
|
CHECK(inputParam1->height == 9.999f);
|
|
|
|
CHECK(inputParam2 == NULL);
|
|
}
|
|
|
|
{
|
|
ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream);
|
|
|
|
ser.ConfigureStructuredExport([](uint32_t) -> std::string { return "TestChunk"; }, true);
|
|
|
|
ser.ReadChunk<uint32_t>();
|
|
{
|
|
MySpecialEnum enumVal;
|
|
|
|
SERIALISE_ELEMENT(enumVal);
|
|
|
|
std::vector<struct1> sparseStructArray;
|
|
|
|
SERIALISE_ELEMENT(sparseStructArray);
|
|
|
|
struct2 complex;
|
|
|
|
SERIALISE_ELEMENT(complex);
|
|
|
|
const struct1 *inputParam1;
|
|
const struct1 *inputParam2;
|
|
|
|
SERIALISE_ELEMENT_OPT(inputParam1);
|
|
SERIALISE_ELEMENT_OPT(inputParam2);
|
|
}
|
|
ser.EndChunk();
|
|
|
|
REQUIRE_FALSE(ser.IsErrored());
|
|
|
|
CHECK(ser.GetReader()->AtEnd());
|
|
|
|
const SDFile &structData = ser.GetStructuredFile();
|
|
|
|
CHECK(structData.chunks.size() == 1);
|
|
CHECK(structData.buffers.size() == 0);
|
|
|
|
REQUIRE(structData.chunks[0]);
|
|
|
|
const SDChunk &chunk = *structData.chunks[0];
|
|
|
|
CHECK(chunk.data.children.size() == 5);
|
|
|
|
for(SDObject *o : chunk.data.children)
|
|
REQUIRE(o);
|
|
|
|
int childIdx = 0;
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "enumVal");
|
|
CHECK(o.type.basetype == SDBasic::Enum);
|
|
CHECK(o.type.flags == SDTypeFlags::HasCustomString);
|
|
|
|
CHECK(o.data.basic.u == AnotherEnumValue);
|
|
CHECK(o.data.str == "AnotherEnumValue");
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "sparseStructArray");
|
|
CHECK(o.type.basetype == SDBasic::Array);
|
|
CHECK(o.type.byteSize == 10);
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
CHECK(o.data.children.size() == 10);
|
|
|
|
for(SDObject *child : o.data.children)
|
|
{
|
|
CHECK(child->type.basetype == SDBasic::Struct);
|
|
CHECK(child->type.name == "struct1");
|
|
CHECK(child->type.byteSize == sizeof(struct1));
|
|
CHECK(child->data.children.size() == 4);
|
|
CHECK(child->data.children[0]->type.basetype == SDBasic::Float);
|
|
CHECK(child->data.children[0]->type.byteSize == 4);
|
|
CHECK(child->data.children[0]->name == "x");
|
|
CHECK(child->data.children[1]->type.basetype == SDBasic::Float);
|
|
CHECK(child->data.children[1]->type.byteSize == 4);
|
|
CHECK(child->data.children[1]->name == "y");
|
|
CHECK(child->data.children[2]->type.basetype == SDBasic::Float);
|
|
CHECK(child->data.children[2]->type.byteSize == 4);
|
|
CHECK(child->data.children[2]->name == "width");
|
|
CHECK(child->data.children[3]->type.basetype == SDBasic::Float);
|
|
CHECK(child->data.children[3]->type.byteSize == 4);
|
|
CHECK(child->data.children[3]->name == "height");
|
|
}
|
|
|
|
CHECK(o.data.children[0]->data.children[0]->data.basic.d == 0.0f);
|
|
CHECK(o.data.children[0]->data.children[1]->data.basic.d == 0.0f);
|
|
CHECK(o.data.children[0]->data.children[2]->data.basic.d == 0.0f);
|
|
CHECK(o.data.children[0]->data.children[3]->data.basic.d == 0.0f);
|
|
|
|
CHECK(o.data.children[5]->data.children[0]->data.basic.d == 1.0f);
|
|
CHECK(o.data.children[5]->data.children[1]->data.basic.d == 2.0f);
|
|
CHECK(o.data.children[5]->data.children[2]->data.basic.d == 3.0f);
|
|
CHECK(o.data.children[5]->data.children[3]->data.basic.d == 4.0f);
|
|
|
|
CHECK(o.data.children[8]->data.children[0]->data.basic.d == 10.0f);
|
|
CHECK(o.data.children[8]->data.children[1]->data.basic.d == 20.0f);
|
|
CHECK(o.data.children[8]->data.children[2]->data.basic.d == 30.0f);
|
|
CHECK(o.data.children[8]->data.children[3]->data.basic.d == 40.0f);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "complex");
|
|
CHECK(o.type.name == "struct2");
|
|
CHECK(o.type.basetype == SDBasic::Struct);
|
|
CHECK(o.type.byteSize == sizeof(struct2));
|
|
CHECK(o.type.flags == SDTypeFlags::NoFlags);
|
|
CHECK(o.data.children.size() == 3);
|
|
|
|
{
|
|
SDObject &c = *o.data.children[0];
|
|
|
|
CHECK(c.name == "name");
|
|
CHECK(c.type.name == "string");
|
|
CHECK(c.type.basetype == SDBasic::String);
|
|
CHECK(c.type.flags == SDTypeFlags::NoFlags);
|
|
|
|
CHECK(c.data.str == "A complex object");
|
|
}
|
|
|
|
{
|
|
SDObject &c = *o.data.children[1];
|
|
|
|
CHECK(c.name == "floats");
|
|
CHECK(c.type.basetype == SDBasic::Array);
|
|
CHECK(c.type.flags == SDTypeFlags::NoFlags);
|
|
CHECK(c.data.children.size() == 3);
|
|
for(SDObject *ch : c.data.children)
|
|
{
|
|
CHECK(ch->type.basetype == SDBasic::Float);
|
|
CHECK(ch->type.byteSize == 4);
|
|
}
|
|
|
|
CHECK(c.data.children[0]->data.basic.d == 1.2f);
|
|
CHECK(c.data.children[1]->data.basic.d == 3.4f);
|
|
CHECK(c.data.children[2]->data.basic.d == 5.6f);
|
|
}
|
|
|
|
{
|
|
SDObject &c = *o.data.children[2];
|
|
|
|
CHECK(c.name == "viewports");
|
|
CHECK(c.type.basetype == SDBasic::Array);
|
|
CHECK(c.type.flags == SDTypeFlags::NoFlags);
|
|
CHECK(c.data.children.size() == 4);
|
|
for(SDObject *ch : c.data.children)
|
|
{
|
|
CHECK(ch->type.basetype == SDBasic::Struct);
|
|
CHECK(ch->type.name == "struct1");
|
|
}
|
|
|
|
CHECK(c.data.children[0]->data.children[0]->data.basic.d == 512.0f);
|
|
CHECK(c.data.children[0]->data.children[1]->data.basic.d == 0.0f);
|
|
CHECK(c.data.children[0]->data.children[2]->data.basic.d == 256.0f);
|
|
CHECK(c.data.children[0]->data.children[3]->data.basic.d == 256.0f);
|
|
}
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "inputParam1");
|
|
CHECK(o.type.basetype == SDBasic::Struct);
|
|
CHECK(o.type.flags == SDTypeFlags::Nullable);
|
|
|
|
CHECK(o.data.children[0]->data.basic.d == 9.0f);
|
|
CHECK(o.data.children[1]->data.basic.d == 9.9f);
|
|
CHECK(o.data.children[2]->data.basic.d == 9.99f);
|
|
CHECK(o.data.children[3]->data.basic.d == 9.999f);
|
|
}
|
|
|
|
{
|
|
SDObject &o = *chunk.data.children[childIdx++];
|
|
|
|
CHECK(o.name == "inputParam2");
|
|
CHECK(o.type.basetype == SDBasic::Null);
|
|
CHECK(o.type.flags == SDTypeFlags::Nullable);
|
|
}
|
|
|
|
StreamWriter *rewriteBuf = new StreamWriter(StreamWriter::DefaultScratchSize);
|
|
|
|
{
|
|
WriteSerialiser rewrite(rewriteBuf, Ownership::Nothing);
|
|
|
|
rewrite.WriteStructuredFile(structData, NULL);
|
|
}
|
|
|
|
// must be bitwise identical to the original serialised data.
|
|
REQUIRE(rewriteBuf->GetOffset() == buf->GetOffset());
|
|
CHECK_FALSE(memcmp(rewriteBuf->GetData(), buf->GetData(), (size_t)rewriteBuf->GetOffset()));
|
|
|
|
delete rewriteBuf;
|
|
}
|
|
|
|
delete buf;
|
|
};
|
|
|
|
#endif // ENABLED(ENABLE_UNIT_TESTS)
|