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));
Does series of tests on checked to verify that it is equal to struct returned by defaultS()