testS

Does series of tests on checked to verify that it is equal to struct returned by defaultS()

version(unittest)
void
testS

Parameters

checked S

S instance to check for equality

t NamedTest

test to check

Examples

Sanity test for helper functions

auto t = new NamedTest("Sanity");
auto s = defaultS();
testS(t, s);

Standard workflow

auto t = new NamedTest("Basic");
auto s = defaultS();
void[] buffer;

Serializer.serialize(s, buffer);
test!("==")(buffer.length, s.serialized_length);
S.trivialDeserialize(buffer).testNullReferences();
auto cont_S = Deserializer.deserialize!(S)(buffer);
cont_S.enforceIntegrity();
testS(t, *cont_S.ptr);

Standard workflow, copy version

auto t = new NamedTest("Basic + Copy");
auto s = defaultS();
void[] buffer;

Serializer.serialize(s, buffer);
test!("==")(buffer.length, s.serialized_length);
S.trivialDeserialize(buffer).testNullReferences();
Contiguous!(S) destination;
auto cont_S = Deserializer.deserialize(buffer, destination);
cont_S.enforceIntegrity();

t.test(cont_S.ptr is destination.ptr);
testS(t, *cont_S.ptr);

Serialize in-place

auto t = new NamedTest("In-place serialization");
auto s = defaultS();
void[] buffer;

// create Contiguous!(S) instance first
Serializer.serialize(s, buffer);
test!("==")(buffer.length, s.serialized_length);
S.trivialDeserialize(buffer).testNullReferences();
auto cont_S = Deserializer.deserialize!(S)(buffer);

// check that serializations nulls pointers
auto serialized = Serializer.serialize(cont_S);
test!("is")(serialized.ptr, cont_S.ptr);
test!("is")(cont_S.ptr.s4_dynamic_array.ptr, null);
test!("is")(cont_S.ptr.s2.a.ptr, null);
test!("is")(cont_S.ptr.s2.b.ptr, null);

Extra unused bytes in source

auto t = new NamedTest("Basic + Copy");
auto s = defaultS();
void[] buffer;

Serializer.serialize(s, buffer);
test!("==")(buffer.length, s.serialized_length);
S.trivialDeserialize(buffer).testNullReferences();

// emulate left-over bytes from previous deserializations
buffer.length = buffer.length * 2;

Contiguous!(S) destination;
auto cont_S = Deserializer.deserialize(buffer, destination);
cont_S.enforceIntegrity();

t.test(cont_S.ptr is destination.ptr);
testS(t, *cont_S.ptr);

Some arrays set to null

auto t = new NamedTest("Null Arrays");
auto s = defaultS();
s.s2.a = null;
void[] buffer;

Serializer.serialize(s, buffer);
test!("==")(buffer.length, s.serialized_length);
S.trivialDeserialize(buffer).testNullReferences();
auto cont_S = Deserializer.deserialize!(S)(buffer);
cont_S.enforceIntegrity();

t.test!("==")(cont_S.ptr.s2.a.length, 0);
auto s_ = cont_S.ptr;      // hijack the invariant
s_.s2.a = defaultS().s2.a; // revert the difference
testS(t, *s_);             // check the rest

Nested arrays set to null

auto t = new NamedTest("Nested Null Arrays");
auto s = defaultS();
s.s2.b[0] = null;
void[] buffer;

Serializer.serialize(s, buffer);
test!("==")(buffer.length, s.serialized_length);
S.trivialDeserialize(buffer).testNullReferences();
auto cont_S = Deserializer.deserialize!(S)(buffer);
cont_S.enforceIntegrity();

t.test!("==")(cont_S.ptr.s2.b[0].length, 0);
auto s_ = cont_S.ptr;            // hijack the invariant
s_.s2.b[0] = defaultS().s2.b[0]; // revert the difference
testS(t, *s_);                   // check the rest

Recursie static arrays

auto t = new NamedTest("Recursive static");

struct Outer
{
    struct Inner
    {
        char[][] a;
    }

    Inner[2][1][1] a;
}

Outer s;
s.a[0][0][0].a = [ "1".dup, "2".dup, "3".dup ];
s.a[0][0][1].a = [ "1".dup, "2".dup ];

void[] buffer;
Serializer.serialize(s, buffer);

size_t expected_length = s.sizeof;
foreach (a1; s.a)
    foreach (a2; a1)
        foreach (a3; a2)
            expected_length += serialArrayLength(a3.a);
test!("==")(buffer.length, expected_length);

with (*trivialDeserialize!(Outer)(buffer))
    foreach (a1; a)
        foreach (a2; a1)
            foreach (a3; a2)
                testArray!("is")(a3.a, null);

auto cont = Deserializer.deserialize!(Outer)(buffer);

test!("==")(cont.ptr.a[0][0][0].a, s.a[0][0][0].a);
test!("==")(cont.ptr.a[0][0][1].a, s.a[0][0][1].a);

Partial loading of extended struct

Ensures that if struct definition has been extended incrementaly one can still load old definition from the serialized buffer

struct Old
{
    int one;
}

struct New
{
    int one;
    int two;
}

auto input = New(32, 42);
void[] buffer;
Serializer.serialize(input, buffer);
auto output = Deserializer.deserialize!(Old)(buffer);

test!("==")(input.one, output.ptr.one);

Serialization of unions of structs with no dynamic arrays

struct A { int x; }
struct B { int[3] arr; }

struct S
{
    union
    {
        A a;
        B b;
    };
}

void[] buffer;
auto input = S(A(42));
Serializer.serialize(input, buffer);
auto output = Deserializer.deserialize!(S)(buffer);

test!("==")(output.ptr.a, A(42));

input.b.arr[] = [0, 1, 2];
Serializer.serialize(input, buffer);
output = Deserializer.deserialize!(S)(buffer);

test!("==")(output.ptr.b.arr[], [0, 1, 2][]);

Serialization of unions of structs with dynamic arrays (fails)

struct A { int x; }
struct B { int[] arr; }

struct S
{
    union XX
    {
        A a;
        B b;
    };

    XX field;
}

void[] buffer;
S input;

static assert (!is(typeof(Serializer.serialize(input, buffer))));

Allocation Control

auto t = new NamedTest("Memory Usage");
auto s = defaultS();
void[] buffer;

Serializer.serialize(s, buffer);
S.trivialDeserialize(buffer).testNullReferences();
testNoAlloc(Serializer.serialize(s, buffer));
auto cont_s = Deserializer.deserialize!(S)(buffer);
testNoAlloc(Deserializer.deserialize!(S)(buffer));
buffer = buffer.dup;
testNoAlloc(Deserializer.deserialize(buffer, cont_s));

Array of const elements

static struct CS
{
    cstring s;
}

auto cs = CS("Hello world");
void[] buffer;

Serializer.serialize(cs, buffer);
test!("==")(buffer.length, cs.sizeof + serialArrayLength(cs.s));
with (*trivialDeserialize!(CS)(buffer))
    testArray!("is")(s, null);
auto new_s = Deserializer.deserialize!(CS)(buffer);
test!("==")(cs.s, new_s.ptr.s);

Ensure that immutable elements are rejected

static struct IS
{
    istring s;
}

static struct II
{
    immutable(int) s;
}

IS s1 = IS("Hello world");
II s2 = II(42);
void[] buffer1, buffer2;

/*
 * There is no check for the serializer because it is "okay" to
 * serialize immutable data.
 * Obviously they won't be deserializable but that is where
 * we could break the type system.
 */

// Uncomment to check error message
//Deserializer.deserialize!(IS)(buffer1);
//Deserializer.deserialize!(II)(buffer2);

static assert(!is(typeof({Deserializer.deserialize!(IS)(buffer1);})),
    "Serializer should reject a struct with 'istring'");
static assert(!is(typeof({Deserializer.deserialize!(II)(buffer2);})),
    "Deserializer should reject a struct with 'immutable' element");

Ensure that full-const struct can be serialized

static struct S1
{
    mstring s;
}

static struct S2
{
    S1[] nested;
}

auto s = const(S2)([ const(S1)("Hello world") ]);
void[] buffer;

Serializer.serialize(s, buffer);

size_t expected_length = s.sizeof + serialArrayLength(s.nested);
foreach (nested_element; s.nested)
    expected_length += serialArrayLength(nested_element.s);
test!("==")(buffer.length, expected_length);

with (*trivialDeserialize!(S2)(buffer))
    testArray!("is")(nested, null);

auto d = Deserializer.deserialize!(S2)(buffer);
test(deepEquals(*d.ptr, s));

Meta