blob: e729ff139ffb8555753b3341c39559c145939ca1 [file] [log] [blame]
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018-2022, Laurence Lundblade.
Copyright (c) 2021, Arm Limited.
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"
/* This calls the main methods to add stuff to a UsefulOutBuf.
* The result in the UsefulOutBuf is "heffalump unbounce bluster hunny bear"
*/
const char *AddStuffToUOB(UsefulOutBuf *pUOB)
{
const char *szReturn = NULL;
if(!UsefulOutBuf_AtStart(pUOB)) {
szReturn = "Not at start";
goto Done;
}
/* Put 7 bytes at beginning of buf */
UsefulOutBuf_AppendData(pUOB, "bluster", 7);
if(UsefulOutBuf_AtStart(pUOB)) {
szReturn = "At start";
goto Done;
}
/* add a space to end */
UsefulOutBuf_AppendByte(pUOB, ' ');
/* Add 6 bytes to the end */
UsefulBufC UBC = {"hunny ", 6};
UsefulOutBuf_AppendUsefulBuf(pUOB, UBC);
/* Insert 9 bytes at the beginning, slide the previous stuff right */
UsefulOutBuf_InsertData(pUOB, "heffalump", 9, 0);
UsefulOutBuf_InsertByte(pUOB, ' ', 9);
/* Put 9 bytes in at position 10 -- just after "heffalump " */
UsefulBufC UBC2 = {"unbounce ", 9};
UsefulOutBuf_InsertUsefulBuf(pUOB, UBC2, 10);
/* Add 4 bytes to the end, by accessing the buffer directly and then advancing it */
UsefulBuf UB = UsefulOutBuf_GetOutPlace(pUOB);
if (!UsefulBuf_IsNULL(UB)) {
memcpy(UB.ptr, "bear", UB.len < 4 ? UB.len : 4);
}
UsefulOutBuf_Advance(pUOB, 4);
Done:
return szReturn;
}
/* Basic exercise of a UsefulOutBuf
*
* Call all the main public functions.
*
* Binary compare the result to the expected.
*
* There is nothing adversarial in this test
*/
const char * UOBTest_NonAdversarial(void)
{
const char *szReturn = NULL;
UsefulBuf_MAKE_STACK_UB(outbuf, 50);
UsefulOutBuf UOB;
UsefulOutBuf_Init(&UOB, outbuf);
szReturn = AddStuffToUOB(&UOB);
if(szReturn) {
goto Done;
}
const UsefulBufC Expected = UsefulBuf_FROM_SZ_LITERAL("heffalump unbounce bluster hunny bear");
UsefulBufC U = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_IsNULLC(U) ||
UsefulBuf_Compare(Expected, U) ||
UsefulOutBuf_GetError(&UOB)) {
szReturn = "OutUBuf";
goto Done;
}
UsefulBuf_MAKE_STACK_UB(buf, 50);
UsefulBufC Out = UsefulOutBuf_CopyOut(&UOB, buf);
if(UsefulBuf_IsNULLC(Out) || UsefulBuf_Compare(Expected, Out)) {
szReturn = "CopyOut";
goto Done;
}
/* Now test the size calculation mode */
UsefulOutBuf_Init(&UOB, SizeCalculateUsefulBuf);
szReturn = AddStuffToUOB(&UOB);
if(szReturn) {
goto Done;
}
U = UsefulOutBuf_OutUBuf(&UOB);
if(U.len != Expected.len || U.ptr != NULL) {
szReturn = "size calculation failed";
}
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(void)
{
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";
}
UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, 100});
if(!UsefulOutBuf_IsBufferNULL(&UOB)) {
return "NULL check failed";
}
return NULL;
}
// Test function to get size and magic number check
const char *TestBasicSanity(void)
{
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(void)
{
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 *String = "string"; // Intentionally not const
UsefulBuf B = (UsefulBuf){(void *)String, strlen(String)};
UsefulBufC BC = UsefulBuf_Const(B);
if(BC.len != strlen(String) || BC.ptr != String)
return "UsefulBufConst failed";
return NULL;
}
const char *UBUtilTests(void)
{
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";
}
if(UsefulBuf_IsValue(ExpectedShorter, '+') != SIZE_MAX) {
return "IsValue failed to match all";
}
if(UsefulBuf_IsValue(ExpectedShorter, '-') != 0) {
return "IsValue should have failed right away";
}
if(UsefulBuf_IsValue(NULLUsefulBufC, 0x00) != 0) {
return "IsValue failed on NULLUsefulBufC";
}
if(UsefulBuf_IsValue((UsefulBufC){(uint8_t[]){0x00}, 1}, 0x00) != SIZE_MAX) {
return "IsValue failed finding 0 in one byte of 0";
}
if(UsefulBuf_IsValue((UsefulBufC){(uint8_t[]){0x00}, 1}, 0x01) != 0) {
return "IsValue failed not finding 1 in one byte of 0";
}
if(UsefulBuf_IsValue(ExpectedSmaller, '+') != ExpectedSmaller.len -1) {
return "IsValue failed to find final *";
}
// 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";
}
const uint8_t pB[] = {0x01, 0x02, 0x03};
UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
// Try to map a pointer before
if(UsefulBuf_PointerToOffset(Boo, pB-1) != SIZE_MAX) {
return "Didn't error on pointer before";
}
// Try to map a pointer after
if(UsefulBuf_PointerToOffset(Boo, pB+sizeof(pB)) != SIZE_MAX) {
return "Didn't error on pointer after";
}
// Try to map a pointer inside
if(UsefulBuf_PointerToOffset(Boo, pB+1) != 1) {
return "Incorrect pointer offset";
}
// Try to map a pointer at the start
if(UsefulBuf_PointerToOffset(Boo, pB) != 0) {
return "Incorrect pointer offset for start";
}
// Try to map a pointer at the end
if(UsefulBuf_PointerToOffset(Boo, pB + sizeof(pB)-1) != 2) {
return "Incorrect pointer offset for end";
}
// Try to map a pointer on a NULL UB
if(UsefulBuf_PointerToOffset(NULLUsefulBufC, pB ) != SIZE_MAX) {
return "Incorrect pointer offset for start";
}
return NULL;
}
const char * UIBTest_IntegerFormat(void)
{
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;
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
const float f = (float)314.15;
const double d = 2.1e10;
#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
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);
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat
UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble
#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
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";
}
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
if(UsefulInputBuf_GetFloat(&UIB) != f) {
return "float out then in failed";
}
if(UsefulInputBuf_GetDouble(&UIB) != d) {
return "double out then in failed";
}
#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
// 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";
}
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
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";
}
#else /* USEFULBUF_DISABLE_ALL_FLOAT */
if(UsefulInputBuf_BytesUnconsumed(&UIB) != 11){
return "Wrong number of unconsumed bytes";
}
if(!UsefulInputBuf_BytesAvailable(&UIB, 11)){
return "Wrong number of bytes available I";
}
if(UsefulInputBuf_BytesAvailable(&UIB, 12)){
return "Wrong number of bytes available II";
}
#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
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";
}
if(UsefulInputBuf_PointerToOffset(&UIB, O.ptr) != 0) {
return "PointerToOffset not working";
}
return NULL;
}
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
const char *UBUTest_CopyUtil(void)
{
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;
}
#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
const char *UBAdvanceTest(void)
{
#define ADVANCE_TEST_SIZE 10
UsefulOutBuf_MakeOnStack(UOB, ADVANCE_TEST_SIZE);
UsefulBuf Place = UsefulOutBuf_GetOutPlace(&UOB);
if(Place.len != 10) {
return "GetOutPlace wrong size";
}
memset(Place.ptr, 'x', Place.len/2);
UsefulOutBuf_Advance(&UOB, Place.len/2);
UsefulOutBuf_AppendByte(&UOB, 'y');
Place = UsefulOutBuf_GetOutPlace(&UOB);
if(Place.len != ADVANCE_TEST_SIZE/2 -1 ) {
return "GetOutPlace wrong size 2";
}
memset(Place.ptr, 'z', Place.len);
UsefulOutBuf_Advance(&UOB, Place.len);
UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB);
UsefulBuf_Compare(O, UsefulBuf_FROM_SZ_LITERAL("xxxxxyzzzz"));
Place = UsefulOutBuf_GetOutPlace(&UOB);
if(Place.len != 0 || Place.ptr != NULL) {
return "GetOutPlace not null";
}
if(UsefulOutBuf_GetError(&UOB)) {
return "GetOutPlace error set";
}
UsefulOutBuf_Advance(&UOB, 1);
if(!UsefulOutBuf_GetError(&UOB)) {
return "Advance off end didn't set error";
}
return NULL;
}