QCBOR: Add CBOR encoder / decoder library
QCBOR supports encoding and decoding of most
of the CBOR standard, RFC 7049. QCBOR is open
source maintained at
https://github.com/laurencelundblade/QCBOR
Change-Id: I5632379e4a1fdb16e0df7f03dfa2374160b7ed7f
Signed-off-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/lib/ext/qcbor/test/UsefulBuf_Tests.c b/lib/ext/qcbor/test/UsefulBuf_Tests.c
new file mode 100644
index 0000000..cfa1262
--- /dev/null
+++ b/lib/ext/qcbor/test/UsefulBuf_Tests.c
@@ -0,0 +1,700 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2019, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ==============================================================================*/
+
+#include "UsefulBuf.h"
+
+
+/* Basic exercise...
+
+ Call all the main public functions.
+
+ Binary compare the result to the expected.
+
+ There is nothing adversarial in this test
+ */
+const char * UOBTest_NonAdversarial()
+{
+ const char *szReturn = NULL;
+
+ UsefulBuf_MAKE_STACK_UB(outbuf,50);
+
+ UsefulOutBuf UOB;
+
+ UsefulOutBuf_Init(&UOB, outbuf);
+
+ if(!UsefulOutBuf_AtStart(&UOB)) {
+ szReturn = "Not at start";
+ goto Done;
+ }
+
+ // Put 7 bytes at beginning of buf
+ UsefulOutBuf_AppendData(&UOB, "bluster", 7);
+
+ if(UsefulOutBuf_AtStart(&UOB)) {
+ szReturn = "At start";
+ goto Done;
+ }
+
+ // add a space to end
+ UsefulOutBuf_AppendByte(&UOB, ' ');
+
+ // Add 5 bytes to the end
+ UsefulBufC UBC = {"hunny", 5};
+ UsefulOutBuf_AppendUsefulBuf(&UOB, UBC);
+
+ // Insert 9 bytes at the beginning, slide the previous stuff right
+ UsefulOutBuf_InsertData(&UOB, "heffalump", 9, 0);
+ UsefulOutBuf_InsertByte(&UOB, ' ', 9);
+
+ // Put 9 bytes in at position 10 -- just after "heffalump "
+ UsefulBufC UBC2 = {"unbounce ", 9};
+ UsefulOutBuf_InsertUsefulBuf(&UOB, UBC2, 10);
+
+ // Make it a null terminated string (because all the appends and inserts above not strcpy !)
+ UsefulOutBuf_AppendByte(&UOB, '\0');
+
+
+ UsefulBufC U = UsefulOutBuf_OutUBuf(&UOB);
+
+ const char *expected = "heffalump unbounce bluster hunny";
+
+ if(UsefulBuf_IsNULLC(U) || U.len-1 != strlen(expected) || strcmp(expected, U.ptr) || UsefulOutBuf_GetError(&UOB)) {
+ szReturn = "OutUBuf";
+ }
+
+ UsefulBuf_MAKE_STACK_UB(buf, 50);
+ UsefulBufC Out = UsefulOutBuf_CopyOut(&UOB, buf);
+
+ if(UsefulBuf_IsNULLC(Out) || Out.len-1 != strlen(expected) || strcmp(expected, Out.ptr)) {
+ szReturn = "CopyOut";
+ }
+
+Done:
+ return szReturn;
+}
+
+
+/*
+ Append test utility.
+ pUOB is the buffer to append too
+ num is the amount to append
+ expected is the expected return code, 0 or 1
+
+ returns 0 if test passed
+
+ */
+static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected)
+{
+ //reset
+ UsefulOutBuf_Reset(pUOB);
+
+ // check status first
+ if(UsefulOutBuf_GetError(pUOB))
+ return 1;
+
+ // append the bytes
+ UsefulOutBuf_AppendData(pUOB, (const uint8_t *)"bluster", num);
+
+ // check error status after
+ if(UsefulOutBuf_GetError(pUOB) != expected)
+ return 1;
+
+ return 0;
+}
+
+
+/*
+ Same as append, but takes a position param too
+ */
+static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected)
+{
+ // reset
+ UsefulOutBuf_Reset(pUOB);
+
+ // check
+ if(UsefulOutBuf_GetError(pUOB))
+ return 1;
+
+ UsefulOutBuf_InsertData(pUOB, (const uint8_t *)"bluster", num, pos);
+
+ if(UsefulOutBuf_GetError(pUOB) != expected)
+ return 1;
+
+ return 0;
+}
+
+
+/*
+ Boundary conditions to test
+ - around 0
+ - around the buffer size
+ - around MAX size_t
+
+
+ Test these for the buffer size and the cursor, the insert amount, the append amount and the insert position
+
+ */
+
+const char *UOBTest_BoundaryConditionsTest()
+{
+ UsefulBuf_MAKE_STACK_UB(outbuf,2);
+
+ UsefulOutBuf UOB;
+
+ UsefulOutBuf_Init(&UOB, outbuf);
+
+ // append 0 byte to a 2 byte buffer --> success
+ if(AppendTest(&UOB, 0, 0))
+ return "Append 0 bytes failed";
+
+ // append 1 byte to a 2 byte buffer --> success
+ if(AppendTest(&UOB, 1, 0))
+ return "Append of 1 byte failed";
+
+ // append 2 byte to a 2 byte buffer --> success
+ if(AppendTest(&UOB, 2, 0))
+ return "Append to fill buffer failed";
+
+ // append 3 bytes to a 2 byte buffer --> failure
+ if(AppendTest(&UOB, 3, 1))
+ return "Overflow of buffer not caught";
+
+ // append max size_t to a 2 byte buffer --> failure
+ if(AppendTest(&UOB, SIZE_MAX, 1))
+ return "Append of SIZE_MAX error not caught";
+
+ if(InsertTest(&UOB, 1, 0, 0))
+ return "Insert 1 byte at start failed";
+
+ if(InsertTest(&UOB, 2, 0, 0))
+ return "Insert 2 bytes at start failed";
+
+ if(InsertTest(&UOB, 3, 0, 1))
+ return "Insert overflow not caught";
+
+ if(InsertTest(&UOB, 1, 1, 1))
+ return "Bad insertion point not caught";
+
+
+ UsefulBuf_MAKE_STACK_UB(outBuf2,10);
+
+ UsefulOutBuf_Init(&UOB, outBuf2);
+
+ UsefulOutBuf_Reset(&UOB);
+ // put data in the buffer
+ UsefulOutBuf_AppendString(&UOB, "abc123");
+
+ UsefulOutBuf_InsertString(&UOB, "xyz*&^", 0);
+
+ if(!UsefulOutBuf_GetError(&UOB)) {
+ return "insert with data should have failed";
+ }
+
+
+ UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
+ UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -6);
+ if(UsefulOutBuf_GetError(&UOB)) {
+ return "insert in huge should have succeeded";
+ }
+
+ UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
+ UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -5);
+ if(UsefulOutBuf_GetError(&UOB)) {
+ return "insert in huge should have succeeded";
+ }
+
+ UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
+ UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX - 4);
+ if(!UsefulOutBuf_GetError(&UOB)) {
+ return "lengths near max size";
+ }
+
+ return NULL;
+}
+
+
+
+
+
+// Test function to get size and magic number check
+
+const char *TestBasicSanity()
+{
+ UsefulBuf_MAKE_STACK_UB(outbuf,10);
+
+ UsefulOutBuf UOB;
+
+ // First -- make sure that the room left function returns the right amount
+ UsefulOutBuf_Init(&UOB, outbuf);
+
+ if(UsefulOutBuf_RoomLeft(&UOB) != 10)
+ return "room left failed";
+
+ if(!UsefulOutBuf_WillItFit(&UOB, 9)) {
+ return "it did not fit";
+ }
+
+ if(UsefulOutBuf_WillItFit(&UOB, 11)) {
+ return "it should have not fit";
+ }
+
+
+ // Next -- make sure that the magic number checking is working right
+ UOB.magic = 8888; // make magic bogus
+
+ UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7);
+
+ if(!UsefulOutBuf_GetError(&UOB))
+ return "magic corruption check failed";
+
+
+
+ // Next make sure that the valid data length check is working right
+ UsefulOutBuf_Init(&UOB, outbuf);
+
+ UOB.data_len = UOB.UB.len+1; // make size bogus
+
+ UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7);
+ if(!UsefulOutBuf_GetError(&UOB))
+ return "valid data check failed";
+
+ return NULL;
+}
+
+
+
+const char *UBMacroConversionsTest()
+{
+ char *szFoo = "foo";
+
+ UsefulBufC Foo = UsefulBuf_FromSZ(szFoo);
+ if(Foo.len != 3 || strncmp(Foo.ptr, szFoo, 3))
+ return "SZToUsefulBufC failed";
+
+ UsefulBufC Too = UsefulBuf_FROM_SZ_LITERAL("Toooo");
+ if(Too.len != 5 || strncmp(Too.ptr, "Toooo", 5))
+ return "UsefulBuf_FROM_SZ_LITERAL failed";
+
+ uint8_t pB[] = {0x42, 0x6f, 0x6f};
+ UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
+ if(Boo.len != 3 || strncmp(Boo.ptr, "Boo", 3))
+ return "UsefulBuf_FROM_BYTE_ARRAY_LITERAL failed";
+
+ char *sz = "not const"; // some data for the test
+ UsefulBuf B = (UsefulBuf){sz, sizeof(sz)};
+ UsefulBufC BC = UsefulBuf_Const(B);
+ if(BC.len != sizeof(sz) || BC.ptr != sz)
+ return "UsefulBufConst failed";
+
+ return NULL;
+}
+
+
+const char *UBUtilTests()
+{
+ UsefulBuf UB = NULLUsefulBuf;
+
+ if(!UsefulBuf_IsNULL(UB)){
+ return "IsNull failed";
+ }
+
+ if(!UsefulBuf_IsEmpty(UB)){
+ return "IsEmpty failed";
+ }
+
+ if(!UsefulBuf_IsNULLOrEmpty(UB)) {
+ return "IsNULLOrEmpty failed";
+ }
+
+ const UsefulBufC UBC = UsefulBuf_Const(UB);
+
+ if(!UsefulBuf_IsNULLC(UBC)){
+ return "IsNull const failed";
+ }
+
+ if(!UsefulBuf_IsEmptyC(UBC)){
+ return "IsEmptyC failed";
+ }
+
+ if(!UsefulBuf_IsNULLOrEmptyC(UBC)){
+ return "IsNULLOrEmptyC failed";
+ }
+
+ const UsefulBuf UB2 = UsefulBuf_Unconst(UBC);
+ if(!UsefulBuf_IsEmpty(UB2)) {
+ return "Back to UB is Empty failed";
+ }
+
+ UB.ptr = "x"; // just some valid pointer
+
+ if(UsefulBuf_IsNULL(UB)){
+ return "IsNull failed";
+ }
+
+ if(!UsefulBuf_IsEmptyC(UBC)){
+ return "IsEmpty failed";
+ }
+
+ // test the Unconst.
+ if(UsefulBuf_Unconst(UBC).ptr != NULL) {
+ return "Unconst failed";
+ }
+
+ // Set 100 bytes of '+'; validated a few tests later
+ UsefulBuf_MAKE_STACK_UB(Temp, 100);
+ const UsefulBufC TempC = UsefulBuf_Set(Temp, '+');
+
+ // Try to copy into a buf that is too small and see failure
+ UsefulBuf_MAKE_STACK_UB(Temp2, 99);
+ if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp2, TempC))) {
+ return "Copy should have failed";
+ }
+
+ if(UsefulBuf_IsNULLC(UsefulBuf_CopyPtr(Temp2, "xx", 2))) {
+ return "CopyPtr failed";
+ }
+
+ UsefulBufC xxyy = UsefulBuf_CopyOffset(Temp2, 2, UsefulBuf_FROM_SZ_LITERAL("yy"));
+ if(UsefulBuf_IsNULLC(xxyy)) {
+ return "CopyOffset Failed";
+ }
+
+ if(UsefulBuf_Compare(UsefulBuf_Head(xxyy, 3), UsefulBuf_FROM_SZ_LITERAL("xxy"))) {
+ return "head failed";
+ }
+
+ if(UsefulBuf_Compare(UsefulBuf_Tail(xxyy, 1), UsefulBuf_FROM_SZ_LITERAL("xyy"))) {
+ return "tail failed";
+ }
+
+ if(!UsefulBuf_IsNULLC(UsefulBuf_Head(xxyy, 5))) {
+ return "head should have failed";
+ }
+
+ if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(xxyy, 5))) {
+ return "tail should have failed";
+ }
+
+ if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(NULLUsefulBufC, 0))) {
+ return "tail of NULLUsefulBufC is not NULLUsefulBufC";
+ }
+
+ const UsefulBufC TailResult = UsefulBuf_Tail((UsefulBufC){NULL, 100}, 99);
+ if(TailResult.ptr != NULL || TailResult.len != 1) {
+ return "tail of NULL and length incorrect";
+ }
+
+ if(!UsefulBuf_IsNULLC(UsefulBuf_CopyOffset(Temp2, 100, UsefulBuf_FROM_SZ_LITERAL("yy")))) {
+ return "Copy Offset should have failed";
+ }
+
+ // Try to copy into a NULL/empty buf and see failure
+ const UsefulBuf UBNull = NULLUsefulBuf;
+ if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(UBNull, TempC))) {
+ return "Copy to NULL should have failed";
+ }
+
+
+ // Try to set a NULL/empty buf; nothing should happen
+ UsefulBuf_Set(UBNull, '+'); // This will crash on failure
+
+ // Copy successfully to a buffer
+ UsefulBuf_MAKE_STACK_UB(Temp3, 101);
+ if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp3, TempC))) {
+ return "Copy should not have failed";
+ }
+
+ static const uint8_t pExpected[] = {
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ };
+ UsefulBufC Expected = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpected);
+ // This validates comparison for equality and the UsefulBuf_Set
+ if(UsefulBuf_Compare(Expected, TempC)) {
+ return "Set / Copy / Compare failed";
+ }
+
+ // Compare two empties and expect success
+ if(UsefulBuf_Compare(NULLUsefulBufC, NULLUsefulBufC)){
+ return "Compare Empties failed";
+ }
+
+ // Compare with empty and expect the first to be larger
+ if(UsefulBuf_Compare(Expected, NULLUsefulBufC) <= 0){
+ return "Compare with empty failed";
+ }
+
+
+ static const uint8_t pExpectedBigger[] = {
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', ',',
+ };
+ const UsefulBufC ExpectedBigger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedBigger);
+
+ // Expect -1 when the first arg is smaller
+ if(UsefulBuf_Compare(Expected, ExpectedBigger) >= 0){
+ return "Compare with bigger";
+ }
+
+
+ static const uint8_t pExpectedSmaller[] = {
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '*',
+ };
+ const UsefulBufC ExpectedSmaller = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedSmaller);
+ // Expect +1 when the first arg is larger
+ if(UsefulBuf_Compare(Expected, ExpectedSmaller) <= 0){
+ return "Compare with smaller";
+ }
+
+
+ static const uint8_t pExpectedLonger[] = {
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+'
+ };
+ const UsefulBufC ExpectedLonger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedLonger);
+
+ // Expect -1 when the first arg is smaller
+ if(UsefulBuf_Compare(Expected, ExpectedLonger) >= 0){
+ return "Compare with longer";
+ }
+
+
+ static const uint8_t pExpectedShorter[] = {
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ '+', '+', '+', '+', '+', '+', '+', '+', '+',
+ };
+ const UsefulBufC ExpectedShorter = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedShorter);
+ // Expect +1 with the first arg is larger
+ if(UsefulBuf_Compare(Expected, ExpectedShorter) <= 0){
+ return "Compare with shorter";
+ }
+
+
+ if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp, NULLUsefulBufC))) {
+ return "Copy null/empty failed";
+ }
+
+ // Look for +++++... in +++++... and find it at the beginning
+ if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedShorter)){
+ return "Failed to find";
+ }
+
+ // look for ++* in ....++* and find it at the end
+ static const uint8_t pToFind[] = {'+', '+', '*'};
+ const UsefulBufC ToBeFound = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pToFind);
+
+ if(97 != UsefulBuf_FindBytes(ExpectedSmaller, ToBeFound)){
+ return "Failed to find 2";
+ }
+
+ // look for ++* in ....++, and find it near the end
+ if(SIZE_MAX != UsefulBuf_FindBytes(ExpectedBigger, ToBeFound)){
+ return "Failed to not find";
+ }
+
+ // Look for the whole buffer in itself and succeed.
+ if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedLonger)){
+ return "Failed to find 3";
+ }
+
+ return NULL;
+}
+
+
+const char * UIBTest_IntegerFormat()
+{
+ UsefulOutBuf_MakeOnStack(UOB,100);
+
+ const uint32_t u32 = 0x0A0B0C0D; // from https://en.wikipedia.org/wiki/Endianness
+ const uint64_t u64 = 1984738472938472;
+ const uint16_t u16 = 40000;
+ const uint8_t u8 = 9;
+ const float f = (float)314.15;
+ const double d = 2.1e10;
+
+
+ UsefulOutBuf_AppendUint32(&UOB, u32); // Also tests UsefulOutBuf_InsertUint64 and UsefulOutBuf_GetEndPosition
+ UsefulOutBuf_AppendUint64(&UOB, u64); // Also tests UsefulOutBuf_InsertUint32
+ UsefulOutBuf_AppendUint16(&UOB, u16); // Also tests UsefulOutBuf_InsertUint16
+ UsefulOutBuf_AppendByte(&UOB, u8);
+ UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat
+ UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble
+
+ const UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_IsNULLC(O))
+ return "Couldn't output integers";
+
+ // from https://en.wikipedia.org/wiki/Endianness
+ const uint8_t pExpectedNetworkOrder[4] = {0x0A, 0x0B, 0x0C, 0x0D};
+ if(memcmp(O.ptr, pExpectedNetworkOrder, 4)) {
+ return "not in network order";
+ }
+
+ UsefulInputBuf UIB;
+
+ UsefulInputBuf_Init(&UIB, O);
+
+ if(UsefulInputBuf_Tell(&UIB) != 0) {
+ return "UsefulInputBuf_Tell failed";
+ }
+
+ if(UsefulInputBuf_GetUint32(&UIB) != u32) {
+ return "u32 out then in failed";
+ }
+ if(UsefulInputBuf_GetUint64(&UIB) != u64) {
+ return "u64 out then in failed";
+ }
+ if(UsefulInputBuf_GetUint16(&UIB) != u16) {
+ return "u16 out then in failed";
+ }
+ if(UsefulInputBuf_GetByte(&UIB) != u8) {
+ return "u8 out then in failed";
+ }
+ if(UsefulInputBuf_GetFloat(&UIB) != f) {
+ return "float out then in failed";
+ }
+ if(UsefulInputBuf_GetDouble(&UIB) != d) {
+ return "double out then in failed";
+ }
+
+ // Reset and go again for a few more tests
+ UsefulInputBuf_Init(&UIB, O);
+
+ const UsefulBufC Four = UsefulInputBuf_GetUsefulBuf(&UIB, 4);
+ if(UsefulBuf_IsNULLC(Four)) {
+ return "Four is NULL";
+ }
+ if(UsefulBuf_Compare(Four, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedNetworkOrder))) {
+ return "Four compare failed";
+ }
+
+ if(UsefulInputBuf_BytesUnconsumed(&UIB) != 23){
+ return "Wrong number of unconsumed bytes";
+ }
+
+ if(!UsefulInputBuf_BytesAvailable(&UIB, 23)){
+ return "Wrong number of bytes available I";
+ }
+
+ if(UsefulInputBuf_BytesAvailable(&UIB, 24)){
+ return "Wrong number of bytes available II";
+ }
+
+ UsefulInputBuf_Seek(&UIB, 0);
+
+ if(UsefulInputBuf_GetError(&UIB)) {
+ return "unexpected error after seek";
+ }
+
+ const uint8_t *pGetBytes = (const uint8_t *)UsefulInputBuf_GetBytes(&UIB, 4);
+ if(pGetBytes == NULL) {
+ return "GetBytes returns NULL";
+ }
+
+ if(memcmp(pGetBytes, pExpectedNetworkOrder, 4)) {
+ return "Got wrong bytes";
+ }
+
+ UsefulInputBuf_Seek(&UIB, 28);
+
+ if(!UsefulInputBuf_GetError(&UIB)) {
+ return "expected error after seek";
+ }
+
+ return NULL;
+}
+
+
+const char *UBUTest_CopyUtil()
+{
+ if(UsefulBufUtil_CopyFloatToUint32(65536.0F) != 0x47800000) {
+ return "CopyFloatToUint32 failed";
+ }
+
+ if(UsefulBufUtil_CopyDoubleToUint64(4e-40F) != 0X37C16C2800000000ULL) {
+ return "CopyDoubleToUint64 failed";
+ }
+
+ if(UsefulBufUtil_CopyUint64ToDouble(0X37C16C2800000000ULL) != 4e-40F) {
+ return "CopyUint64ToDouble failed";
+ }
+
+ if(UsefulBufUtil_CopyUint32ToFloat(0x47800000) != 65536.0F) {
+ return "CopyUint32ToFloat failed";
+ }
+
+ return NULL;
+}
+
+
+