/* Copyright (c) 2014 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #include "serialization/TestSerializationContext.h" #include "utilities/IOUtilities.h" #include "utilities/printfFormats.h" #include #include #include #include #define stemobject_implementation TestSerializationContext stemobject_vtable_begin(); stemobject_vtable_entry(dispose); stemobject_vtable_entry(beginStructure); stemobject_vtable_entry(beginDictionary); stemobject_vtable_entry(beginArray); stemobject_vtable_entry(endStructure); stemobject_vtable_entry(endDictionary); stemobject_vtable_entry(endArray); stemobject_vtable_entry(writeBoolean); stemobject_vtable_entry(writeInt8); stemobject_vtable_entry(writeUInt8); stemobject_vtable_entry(writeInt16); stemobject_vtable_entry(writeUInt16); stemobject_vtable_entry(writeInt32); stemobject_vtable_entry(writeUInt32); stemobject_vtable_entry(writeInt64); stemobject_vtable_entry(writeUInt64); stemobject_vtable_entry(writeFloat); stemobject_vtable_entry(writeDouble); stemobject_vtable_entry(writeFixed16_16); stemobject_vtable_entry(writeEnumeration); stemobject_vtable_entry(writeEnumeration8); stemobject_vtable_entry(writeEnumeration16); stemobject_vtable_entry(writeEnumeration32); stemobject_vtable_entry(writeBitfield8); stemobject_vtable_entry(writeBitfield16); stemobject_vtable_entry(writeBitfield32); stemobject_vtable_entry(writeBitfield64); stemobject_vtable_entry(writeString); stemobject_vtable_entry(writeStringNullable); stemobject_vtable_entry(writeBlob); stemobject_vtable_entry(expectCall); stemobject_vtable_entry(failNthCall); stemobject_vtable_entry(finish); stemobject_vtable_entry(rewind); stemobject_vtable_end(); TestSerializationContext * TestSerializationContext_create(jmp_buf * sequenceBreakJmpEnv) { stemobject_create_implementation(init, sequenceBreakJmpEnv) } bool TestSerializationContext_init(TestSerializationContext * self, jmp_buf * sequenceBreakJmpEnv) { call_super(init, self); self->sequenceBreakJmpEnv = sequenceBreakJmpEnv; self->error[0] = '\x00'; self->callIndexToFail = UINT_MAX; self->failStatus = 0; self->expectedCalls = NULL; self->numExpectedCalls = 0; self->nextExpectedCallIndex = 0; return true; } void TestSerializationContext_dispose(TestSerializationContext * self) { unsigned int expectedCallIndex; for (expectedCallIndex = 0; expectedCallIndex < self->numExpectedCalls; expectedCallIndex++) { free(self->expectedCalls[expectedCallIndex].additionalArgs); } free(self->expectedCalls); call_super(dispose, self); } static char * functionNameForPtr(TestSerializationContext * self, void * functionPtr) { #define tryFunctionName(function) if (functionPtr == self->vtable->function) {return #function;} tryFunctionName(beginStructure) tryFunctionName(beginDictionary) tryFunctionName(beginArray) tryFunctionName(endStructure) tryFunctionName(endDictionary) tryFunctionName(endArray) tryFunctionName(writeBoolean) tryFunctionName(writeInt8) tryFunctionName(writeUInt8) tryFunctionName(writeInt16) tryFunctionName(writeUInt16) tryFunctionName(writeInt32) tryFunctionName(writeUInt32) tryFunctionName(writeInt64) tryFunctionName(writeUInt64) tryFunctionName(writeFloat) tryFunctionName(writeDouble) tryFunctionName(writeFixed16_16) tryFunctionName(writeEnumeration) tryFunctionName(writeEnumeration8) tryFunctionName(writeEnumeration16) tryFunctionName(writeEnumeration32) tryFunctionName(writeBitfield8) tryFunctionName(writeBitfield16) tryFunctionName(writeBitfield32) tryFunctionName(writeBitfield64) tryFunctionName(writeString) tryFunctionName(writeStringNullable) tryFunctionName(writeBlob) #undef tryFunctionName return ""; } #define BLOB_STRING_MAX 256 static void verifyCallIsInSequence(TestSerializationContext * self, void * functionPtr, ...) { if (self->nextExpectedCallIndex >= self->numExpectedCalls) { snprintf_safe(self->error, sizeof(self->error), "Additional function %s called after expected end of calls", functionNameForPtr(self, functionPtr)); longjmp(*self->sequenceBreakJmpEnv, 1); } if (self->expectedCalls[self->nextExpectedCallIndex].functionPtr != functionPtr) { snprintf_safe(self->error, sizeof(self->error), "Function %s called when %s was expected (index %u, line %u)", functionNameForPtr(self, functionPtr), functionNameForPtr(self, self->expectedCalls[self->nextExpectedCallIndex].functionPtr), self->nextExpectedCallIndex, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 2); } va_list args; va_start(args, functionPtr); if (functionPtr != self->vtable->endStructure && functionPtr != self->vtable->endDictionary && functionPtr != self->vtable->endArray) { char * key = va_arg(args, char *); if (((self->expectedCalls[self->nextExpectedCallIndex].key == NULL || key == NULL) && self->expectedCalls[self->nextExpectedCallIndex].key != key) || (self->expectedCalls[self->nextExpectedCallIndex].key != NULL && key != NULL && strcmp(self->expectedCalls[self->nextExpectedCallIndex].key, key))) { snprintf_safe(self->error, sizeof(self->error), "Arg 2 to call %d (%s) was expected to be \"%s\", but was \"%s\" instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].key, key, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } if (functionPtr == self->vtable->writeInt8) { int8_t int8Value = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.int8Value != int8Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %d, but was %d instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.int8Value, int8Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeUInt8 || functionPtr == self->vtable->writeBitfield8) { uint8_t uint8Value = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.uint8Value != uint8Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %u, but was %u instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.uint8Value, uint8Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeInt16) { int16_t int16Value = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.int16Value != int16Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %d, but was %d instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.int16Value, int16Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeUInt16 || functionPtr == self->vtable->writeBitfield16) { uint16_t uint16Value = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.uint16Value != uint16Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %u, but was %u instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.uint16Value, uint16Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeInt32) { int32_t int32Value = va_arg(args, int32_t); if (self->expectedCalls[self->nextExpectedCallIndex].value.int32Value != int32Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %d, but was %d instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.int32Value, int32Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeUInt32 || functionPtr == self->vtable->writeBitfield32) { uint32_t uint32Value = va_arg(args, uint32_t); if (self->expectedCalls[self->nextExpectedCallIndex].value.uint32Value != uint32Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %u, but was %u instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.uint32Value, uint32Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeInt64) { int64_t int64Value = va_arg(args, int64_t); if (self->expectedCalls[self->nextExpectedCallIndex].value.int64Value != int64Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be " INT64_FORMAT ", but was " INT64_FORMAT " instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.int64Value, int64Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeUInt64 || functionPtr == self->vtable->writeBitfield64) { uint64_t uint64Value = va_arg(args, uint64_t); if (self->expectedCalls[self->nextExpectedCallIndex].value.uint64Value != uint64Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be " UINT64_FORMAT ", but was " UINT64_FORMAT " instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.uint64Value, uint64Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeFloat) { float floatValue = va_arg(args, double); if (self->expectedCalls[self->nextExpectedCallIndex].value.floatValue != floatValue) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %f, but was %f instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.floatValue, floatValue, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeDouble) { double doubleValue = va_arg(args, double); if (self->expectedCalls[self->nextExpectedCallIndex].value.doubleValue != doubleValue) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %f, but was %f instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.doubleValue, doubleValue, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeFixed16_16) { fixed16_16 fixed16_16Value = va_arg(args, fixed16_16); if (self->expectedCalls[self->nextExpectedCallIndex].value.fixed16_16Value != fixed16_16Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be 0x%05X, but was 0x%05X instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.fixed16_16Value, fixed16_16Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeString) { char * stringValue = va_arg(args, char *); if (strcmp(self->expectedCalls[self->nextExpectedCallIndex].value.stringValue, stringValue)) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be \"%s\", but was \"%s\" instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.stringValue, stringValue, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeStringNullable) { char * stringValue = va_arg(args, char *); if (((stringValue == NULL) != (self->expectedCalls[self->nextExpectedCallIndex].value.stringValue == NULL)) || (stringValue != NULL && strcmp(self->expectedCalls[self->nextExpectedCallIndex].value.stringValue, stringValue))) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be \"%s\", but was \"%s\" instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.stringValue, stringValue, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeBlob) { void * blobValue = va_arg(args, void *); size_t length = va_arg(args, size_t); if (length != self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[0].length) { snprintf_safe(self->error, sizeof(self->error), "Arg 4 to call %d (%s) was expected to be " SIZE_T_FORMAT ", but was " SIZE_T_FORMAT " instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[0].length, length, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } if (memcmp(self->expectedCalls[self->nextExpectedCallIndex].value.blobValue, blobValue, length)) { char blobString1[256], blobString2[256]; snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %s, but was %s instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), printHexString(self->expectedCalls[self->nextExpectedCallIndex].value.blobValue, length, blobString1, sizeof(blobString1)), printHexString(blobValue, length, blobString2, sizeof(blobString2)), self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeBoolean) { bool boolValue = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.boolValue != boolValue) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %s, but was %s instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.boolValue ? "true" : "false", boolValue ? "true" : "false", self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeEnumeration) { int intValue = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.intValue != intValue) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %d, but was %d instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.intValue, intValue, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeEnumeration8) { int8_t int8Value = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.int8Value != int8Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %d, but was %d instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.int8Value, int8Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeEnumeration16) { int16_t int16Value = va_arg(args, int); if (self->expectedCalls[self->nextExpectedCallIndex].value.int16Value != int16Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %d, but was %d instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.int16Value, int16Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } else if (functionPtr == self->vtable->writeEnumeration32) { int32_t int32Value = va_arg(args, int32_t); if (self->expectedCalls[self->nextExpectedCallIndex].value.int32Value != int32Value) { snprintf_safe(self->error, sizeof(self->error), "Arg 3 to call %d (%s) was expected to be %d, but was %d instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].value.int32Value, int32Value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } if (functionPtr == self->vtable->writeEnumeration || functionPtr == self->vtable->writeEnumeration8 || functionPtr == self->vtable->writeEnumeration16 || functionPtr == self->vtable->writeEnumeration32) { unsigned int valueCount = va_arg(args, unsigned int); Serialization_enumKeyValue * values = va_arg(args, Serialization_enumKeyValue *); if (self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[0].count != valueCount) { snprintf(self->error, sizeof(self->error), "Arg 2 to call %d (%s) was expected to be %u, but was %u instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[0].count, valueCount, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } Serialization_enumKeyValue * expectedValues = self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[1].values; for (unsigned int valueIndex = 0; valueIndex < valueCount; valueIndex++) { if (expectedValues[valueIndex].value != values[valueIndex].value || values[valueIndex].key == NULL || strcmp(expectedValues[valueIndex].key, values[valueIndex].key)) { snprintf(self->error, sizeof(self->error), "Enumeration key/value mismatch at index %u in call %d (%s); expected {\"%s\", %d} but got {\"%s\", %d} (line %u)", valueIndex, self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), expectedValues[valueIndex].key, expectedValues[valueIndex].value, values[valueIndex].key, values[valueIndex].value, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } } else if (functionPtr == self->vtable->writeBitfield8 || functionPtr == self->vtable->writeBitfield16 || functionPtr == self->vtable->writeBitfield32 || functionPtr == self->vtable->writeBitfield64) { unsigned int bitCount = va_arg(args, unsigned int); Serialization_bitName * bitNames = va_arg(args, Serialization_bitName *); if (self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[0].count != bitCount) { snprintf(self->error, sizeof(self->error), "Arg 2 to call %d (%s) was expected to be %u, but was %u instead (line %u)", self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[0].count, bitCount, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } Serialization_bitName * expectedBitNames = self->expectedCalls[self->nextExpectedCallIndex].additionalArgs[1].bitNames; for (unsigned int bitIndex = 0; bitIndex < bitCount; bitIndex++) { if (expectedBitNames[bitIndex].index != bitNames[bitIndex].index || bitNames[bitIndex].name == NULL || strcmp(expectedBitNames[bitIndex].name, bitNames[bitIndex].name)) { snprintf(self->error, sizeof(self->error), "Bit name/index mismatch at index %u in call %d (%s); expected {\"%s\", %d} but got {\"%s\", %d} (line %u)", bitIndex, self->nextExpectedCallIndex, functionNameForPtr(self, functionPtr), expectedBitNames[bitIndex].name, expectedBitNames[bitIndex].index, bitNames[bitIndex].name, bitNames[bitIndex].index, self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 3); } } } va_end(args); self->nextExpectedCallIndex++; } static void failIfRequested(TestSerializationContext * self) { if (self->nextExpectedCallIndex - 1 == self->callIndexToFail) { self->status = self->failStatus; if (self->jmpBuf != NULL) { longjmp(*self->jmpBuf, self->status); } } } void TestSerializationContext_beginStructure(TestSerializationContext * self, const char * key) { verifyCallIsInSequence(self, self->vtable->beginStructure, key); failIfRequested(self); } void TestSerializationContext_beginDictionary(TestSerializationContext * self, const char * key) { verifyCallIsInSequence(self, self->vtable->beginDictionary, key); failIfRequested(self); } void TestSerializationContext_beginArray(TestSerializationContext * self, const char * key) { verifyCallIsInSequence(self, self->vtable->beginArray, key); failIfRequested(self); } void TestSerializationContext_endStructure(TestSerializationContext * self) { verifyCallIsInSequence(self, self->vtable->endStructure); failIfRequested(self); } void TestSerializationContext_endDictionary(TestSerializationContext * self) { verifyCallIsInSequence(self, self->vtable->endDictionary); failIfRequested(self); } void TestSerializationContext_endArray(TestSerializationContext * self) { verifyCallIsInSequence(self, self->vtable->endArray); failIfRequested(self); } void TestSerializationContext_writeBoolean(TestSerializationContext * self, const char * key, bool value) { verifyCallIsInSequence(self, self->vtable->writeBoolean, key, value); failIfRequested(self); } void TestSerializationContext_writeInt8(TestSerializationContext * self, const char * key, int8_t value) { verifyCallIsInSequence(self, self->vtable->writeInt8, key, value); failIfRequested(self); } void TestSerializationContext_writeUInt8(TestSerializationContext * self, const char * key, uint8_t value) { verifyCallIsInSequence(self, self->vtable->writeUInt8, key, value); failIfRequested(self); } void TestSerializationContext_writeInt16(TestSerializationContext * self, const char * key, int16_t value) { verifyCallIsInSequence(self, self->vtable->writeInt16, key, value); failIfRequested(self); } void TestSerializationContext_writeUInt16(TestSerializationContext * self, const char * key, uint16_t value) { verifyCallIsInSequence(self, self->vtable->writeUInt16, key, value); failIfRequested(self); } void TestSerializationContext_writeInt32(TestSerializationContext * self, const char * key, int32_t value) { verifyCallIsInSequence(self, self->vtable->writeInt32, key, value); failIfRequested(self); } void TestSerializationContext_writeUInt32(TestSerializationContext * self, const char * key, uint32_t value) { verifyCallIsInSequence(self, self->vtable->writeUInt32, key, value); failIfRequested(self); } void TestSerializationContext_writeInt64(TestSerializationContext * self, const char * key, int64_t value) { verifyCallIsInSequence(self, self->vtable->writeInt64, key, value); failIfRequested(self); } void TestSerializationContext_writeUInt64(TestSerializationContext * self, const char * key, uint64_t value) { verifyCallIsInSequence(self, self->vtable->writeUInt64, key, value); failIfRequested(self); } void TestSerializationContext_writeFloat(TestSerializationContext * self, const char * key, float value) { verifyCallIsInSequence(self, self->vtable->writeFloat, key, value); failIfRequested(self); } void TestSerializationContext_writeDouble(TestSerializationContext * self, const char * key, double value) { verifyCallIsInSequence(self, self->vtable->writeDouble, key, value); failIfRequested(self); } void TestSerializationContext_writeFixed16_16(TestSerializationContext * self, const char * key, fixed16_16 value) { verifyCallIsInSequence(self, self->vtable->writeFixed16_16, key, value); failIfRequested(self); } void TestSerializationContext_writeEnumeration(TestSerializationContext * self, const char * key, int value, unsigned int valueCount, Serialization_enumKeyValue * values) { verifyCallIsInSequence(self, self->vtable->writeEnumeration, key, value, valueCount, values); failIfRequested(self); } void TestSerializationContext_writeEnumeration8(TestSerializationContext * self, const char * key, int8_t value, unsigned int valueCount, Serialization_enumKeyValue * values) { verifyCallIsInSequence(self, self->vtable->writeEnumeration8, key, value, valueCount, values); failIfRequested(self); } void TestSerializationContext_writeEnumeration16(TestSerializationContext * self, const char * key, int16_t value, unsigned int valueCount, Serialization_enumKeyValue * values) { verifyCallIsInSequence(self, self->vtable->writeEnumeration16, key, value, valueCount, values); failIfRequested(self); } void TestSerializationContext_writeEnumeration32(TestSerializationContext * self, const char * key, int32_t value, unsigned int valueCount, Serialization_enumKeyValue * values) { verifyCallIsInSequence(self, self->vtable->writeEnumeration32, key, value, valueCount, values); failIfRequested(self); } void TestSerializationContext_writeBitfield8(TestSerializationContext * self, const char * key, uint8_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { verifyCallIsInSequence(self, self->vtable->writeBitfield8, key, value, bitNameCount, bitNames); failIfRequested(self); } void TestSerializationContext_writeBitfield16(TestSerializationContext * self, const char * key, uint16_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { verifyCallIsInSequence(self, self->vtable->writeBitfield16, key, value, bitNameCount, bitNames); failIfRequested(self); } void TestSerializationContext_writeBitfield32(TestSerializationContext * self, const char * key, uint32_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { verifyCallIsInSequence(self, self->vtable->writeBitfield32, key, value, bitNameCount, bitNames); failIfRequested(self); } void TestSerializationContext_writeBitfield64(TestSerializationContext * self, const char * key, uint64_t value, unsigned int bitNameCount, Serialization_bitName * bitNames) { verifyCallIsInSequence(self, self->vtable->writeBitfield64, key, value, bitNameCount, bitNames); failIfRequested(self); } void TestSerializationContext_writeString(TestSerializationContext * self, const char * key, const char * value) { verifyCallIsInSequence(self, self->vtable->writeString, key, value); failIfRequested(self); } void TestSerializationContext_writeStringNullable(TestSerializationContext * self, const char * key, const char * value) { verifyCallIsInSequence(self, self->vtable->writeStringNullable, key, value); failIfRequested(self); } void TestSerializationContext_writeBlob(TestSerializationContext * self, const char * key, const void * value, size_t length) { verifyCallIsInSequence(self, self->vtable->writeBlob, key, value, length); failIfRequested(self); } void TestSerializationContext_expectCall(TestSerializationContext * self, unsigned int lineNumber, void * functionPtr, ...) { va_list args; self->expectedCalls = realloc(self->expectedCalls, sizeof(struct TestSerializationContext_expectedCall) * (self->numExpectedCalls + 1)); self->expectedCalls[self->numExpectedCalls].functionPtr = functionPtr; self->expectedCalls[self->numExpectedCalls].lineNumber = lineNumber; self->expectedCalls[self->numExpectedCalls].additionalArgs = NULL; va_start(args, functionPtr); if (functionPtr != self->vtable->endStructure && functionPtr != self->vtable->endDictionary && functionPtr != self->vtable->endArray) { self->expectedCalls[self->numExpectedCalls].key = va_arg(args, char *); } if (functionPtr == self->vtable->writeBoolean) { self->expectedCalls[self->numExpectedCalls].value.boolValue = va_arg(args, int); } else if (functionPtr == self->vtable->writeInt8) { self->expectedCalls[self->numExpectedCalls].value.int8Value = va_arg(args, int); } else if (functionPtr == self->vtable->writeUInt8 || functionPtr == self->vtable->writeBitfield8) { self->expectedCalls[self->numExpectedCalls].value.uint8Value = va_arg(args, int); } else if (functionPtr == self->vtable->writeInt16) { self->expectedCalls[self->numExpectedCalls].value.int16Value = va_arg(args, int); } else if (functionPtr == self->vtable->writeUInt16 || functionPtr == self->vtable->writeBitfield16) { self->expectedCalls[self->numExpectedCalls].value.uint16Value = va_arg(args, int); } else if (functionPtr == self->vtable->writeInt32) { self->expectedCalls[self->numExpectedCalls].value.int32Value = va_arg(args, int32_t); } else if (functionPtr == self->vtable->writeUInt32 || functionPtr == self->vtable->writeBitfield32) { self->expectedCalls[self->numExpectedCalls].value.uint32Value = va_arg(args, uint32_t); } else if (functionPtr == self->vtable->writeInt64) { self->expectedCalls[self->numExpectedCalls].value.int64Value = va_arg(args, int64_t); } else if (functionPtr == self->vtable->writeUInt64 || functionPtr == self->vtable->writeBitfield64) { self->expectedCalls[self->numExpectedCalls].value.uint64Value = va_arg(args, uint64_t); } else if (functionPtr == self->vtable->writeFloat) { self->expectedCalls[self->numExpectedCalls].value.floatValue = va_arg(args, double); } else if (functionPtr == self->vtable->writeDouble) { self->expectedCalls[self->numExpectedCalls].value.doubleValue = va_arg(args, double); } else if (functionPtr == self->vtable->writeFixed16_16) { self->expectedCalls[self->numExpectedCalls].value.fixed16_16Value = va_arg(args, fixed16_16); } else if (functionPtr == self->vtable->writeEnumeration) { self->expectedCalls[self->numExpectedCalls].value.intValue = va_arg(args, int); } else if (functionPtr == self->vtable->writeEnumeration8) { self->expectedCalls[self->numExpectedCalls].value.int8Value = va_arg(args, int); } else if (functionPtr == self->vtable->writeEnumeration16) { self->expectedCalls[self->numExpectedCalls].value.int16Value = va_arg(args, int); } else if (functionPtr == self->vtable->writeEnumeration32) { self->expectedCalls[self->numExpectedCalls].value.int32Value = va_arg(args, int32_t); } else if (functionPtr == self->vtable->writeString) { self->expectedCalls[self->numExpectedCalls].value.stringValue = va_arg(args, const char *); } else if (functionPtr == self->vtable->writeStringNullable) { self->expectedCalls[self->numExpectedCalls].value.stringValue = va_arg(args, const char *); } else if (functionPtr == self->vtable->writeBlob) { self->expectedCalls[self->numExpectedCalls].value.blobValue = va_arg(args, const void *); self->expectedCalls[self->numExpectedCalls].additionalArgs = malloc(sizeof(union TestSerializationContext_additionalArg)); self->expectedCalls[self->numExpectedCalls].additionalArgs[0].length = va_arg(args, size_t); } if (functionPtr == self->vtable->writeEnumeration || functionPtr == self->vtable->writeEnumeration8 || functionPtr == self->vtable->writeEnumeration16 || functionPtr == self->vtable->writeEnumeration32) { self->expectedCalls[self->numExpectedCalls].additionalArgs = malloc(sizeof(union TestSerializationContext_additionalArg) * 2); self->expectedCalls[self->numExpectedCalls].additionalArgs[0].count = va_arg(args, unsigned int); self->expectedCalls[self->numExpectedCalls].additionalArgs[1].values = va_arg(args, Serialization_enumKeyValue *); } else if (functionPtr == self->vtable->writeBitfield8 || functionPtr == self->vtable->writeBitfield16 || functionPtr == self->vtable->writeBitfield32 || functionPtr == self->vtable->writeBitfield64) { self->expectedCalls[self->numExpectedCalls].additionalArgs = malloc(sizeof(union TestSerializationContext_additionalArg) * 2); self->expectedCalls[self->numExpectedCalls].additionalArgs[0].count = va_arg(args, unsigned int); self->expectedCalls[self->numExpectedCalls].additionalArgs[1].bitNames = va_arg(args, Serialization_bitName *); } va_end(args); self->numExpectedCalls++; } void TestSerializationContext_failNthCall(TestSerializationContext * self, unsigned int callIndex, int status) { self->callIndexToFail = callIndex; self->failStatus = status; } void TestSerializationContext_finish(TestSerializationContext * self) { if (self->nextExpectedCallIndex < self->numExpectedCalls) { snprintf_safe(self->error, sizeof(self->error), "%d expected call%s still left in queue at end (next expected call is %s, line %u)", self->numExpectedCalls - self->nextExpectedCallIndex, self->numExpectedCalls - self->nextExpectedCallIndex == 1 ? "" : "s", functionNameForPtr(self, self->expectedCalls[self->nextExpectedCallIndex].functionPtr), self->expectedCalls[self->nextExpectedCallIndex].lineNumber); longjmp(*self->sequenceBreakJmpEnv, 4); } } void TestSerializationContext_rewind(TestSerializationContext * self) { self->nextExpectedCallIndex = 0; self->error[0] = '\x00'; self->status = SERIALIZATION_ERROR_OK; }