blob: 6e47f3cc04133d6848f7aa0efad27feb93830b6c [file] [log] [blame]
/* ==========================================================================
* Copyright (c) 2016-2018, The Linux Foundation.
* Copyright (c) 2018-2024, 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 an empty string */
UsefulOutBuf_AppendUsefulBuf(pUOB, NULLUsefulBufC);
/* Add a zero length string (valid pointer, 0 length) */
UsefulOutBuf_AppendData(pUOB, "xxx", 0);
/* 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";
}
UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB);
if(!UsefulBuf_IsNULLC(O)) {
return "OutUBuf in error should have returned NULL";
}
UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, 100});
if(!UsefulOutBuf_IsBufferNULL(&UOB)) {
return "NULL check failed";
}
UsefulOutBuf_Init(&UOB, outbuf);
UOB.magic = 99; // corrupt the UOB
O = UsefulOutBuf_OutUBuf(&UOB);
if(!UsefulBuf_IsNULLC(O)) {
return "OutUBuf on corrupted should have returned NULL";
}
MakeUsefulBufOnStack(Tmp, 20);
O = UsefulOutBuf_CopyOut(&UOB, Tmp);
if(!UsefulBuf_IsNULLC(O)) {
return "CopyOut on corrupted should have returned NULL";
}
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";
}
if(SIZE_MAX != UsefulBuf_FindBytes(Expected, ExpectedLonger)) {
return "Failed to find 4";
}
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";
}
if(UsefulBuf_OffsetToPointer(Boo, 0) != &pB[0]) {
return "Wrong OffsetToPointer";
}
if(UsefulBuf_OffsetToPointer(Boo, 3) != NULL) {
return "Didn't validate offset correctly";
}
if(UsefulBuf_OffsetToPointer(Boo, 2) != &pB[2]) {
return "Wrong OffsetToPointer 2";
}
if(UsefulBuf_OffsetToPointer(NULLUsefulBufC, 2) != NULL) {
return "Failed OffsetToPtr on NULLUsefulBufC";
}
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 */
if(UsefulInputBuf_GetUint16(&UIB) != 0) {
return "Didn't catch off end with GetUint16";
}
if(UsefulInputBuf_GetUint32(&UIB) !=0 ) {
return "Didn't catch off end with GetUint32";
}
if(UsefulInputBuf_GetUint64(&UIB) !=0 ) {
return "Didn't catch off end with GetUint64";
}
// 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";
}
const uint8_t pB[] = {0x01, 0x02, 0x03};
UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
UsefulInputBuf_Init(&UIB, Boo);
if(UsefulInputBuf_OffsetToPointer(&UIB, 0) != &pB[0]) {
return "OffsetToPointer fail";
}
if(UsefulInputBuf_OffsetToPointer(&UIB, SIZE_MAX) != NULL) {
return "OffsetToPointer SIZE_MAX fail";
}
UsefulInputBuf_Init(&UIB, Boo);
UIB.magic = 88;
size_t uUnc = UsefulInputBuf_BytesUnconsumed(&UIB);
if(uUnc != 0) {
return "Didn't detect corrupted UsefulInputBuf";
}
UsefulInputBuf_Init(&UIB, Boo);
UIB.cursor = 500;
uUnc = UsefulInputBuf_BytesUnconsumed(&UIB);
if(uUnc != 0) {
return "Didn't detect bad UsefulInputBuf cursor";
}
if(!UsefulBuf_IsNULLC(UsefulInputBuf_GetUsefulBuf(&UIB, 5000))) {
return "Didn't detect off-end request of UsefulInputBuf";
}
if(!UsefulInputBuf_GetError(&UIB)) {
return "UIB Error state not reported";
}
UsefulInputBuf_Init(&UIB, Boo);
if(UsefulInputBuf_GetBufferLength(&UIB) != Boo.len) {
return "UIB length wrong";
}
UsefulInputBuf_SetBufferLength(&UIB, 1);
if(UsefulInputBuf_GetBufferLength(&UIB) != 1) {
return "UIB SetBufferLength failed";
}
UsefulBufC CompCheck = UsefulBuf_FROM_SZ_LITERAL("abcd");
UsefulInputBuf_Init(&UIB, CompCheck);
if(UsefulInputBuf_Compare(&UIB, 0, 2, 2, 2) >= 0) {
return "UB 1 compared greater than UB2";
}
if(UsefulInputBuf_Compare(&UIB, 0, 2, 0, 2) != 0) {
return "UB1 and UB2 didn't compare equally";
}
if(UsefulInputBuf_Compare(&UIB, 2, 2, 0, 2) <= 0) {
return "UB2 compared less than UB1";
}
if(UsefulInputBuf_Compare(&UIB, 4, 1, 2, 2) <= 0) {
return "Off-the-end UB1 compared as less than UB2";
}
if(UsefulInputBuf_Compare(&UIB, 0, 5, 2, 2) <= 0) {
return "Off-the-end UB1 compared as less than UB2 (second)";
}
if(UsefulInputBuf_Compare(&UIB, 0, 2, 5, 1) >= 0) {
return "Off-the-end UB2 compared as less than UB2";
}
if(UsefulInputBuf_Compare(&UIB, 0, 2, 2, 3) >= 0) {
return "Off-the-end UB2 compared as less than UB2 (second)";
}
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";
}
// Try to advance in error state
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_Advance(&UOB, 1);
Place = UsefulOutBuf_GetOutPlace(&UOB);
UsefulOutBuf_Advance(&UOB, 1000);
UsefulOutBuf_Advance(&UOB, 1);
UsefulBuf Place2;
Place2 = UsefulOutBuf_GetOutPlace(&UOB);
if(memcmp(&Place, &Place2, sizeof(Place))) {
return "Advance didn't noop in error state";
}
UsefulOutBuf_Reset(&UOB);
UOB.data_len = UOB.UB.len + 1; // React in and corrupt
UsefulOutBuf_Advance(&UOB, 1);
if(!UsefulOutBuf_GetError(&UOB)) {
return "didn't detect corrupted UOB";
}
UsefulOutBuf BadUOB;
memset(&BadUOB, 'x', sizeof(BadUOB));
BadUOB.err = 0;
UsefulOutBuf_Advance(&BadUOB, 1);
if(!UsefulOutBuf_GetError(&BadUOB)) {
return "didn't detect bad UOB";
}
return NULL;
}
const char * UOBExtraTests(void)
{
#define COMPARE_TEST_SIZE 10
UsefulOutBuf_MakeOnStack( UOB, COMPARE_TEST_SIZE);
int nCompare;
UsefulBufC Out;
/* Test UsefulOutBuf_Compare() */
UsefulOutBuf_AppendString(&UOB, "abcabdefab");
nCompare = UsefulOutBuf_Compare(&UOB, 0, 2, 8, 2);
if(nCompare != 0) {
return "ab should compare equal";
}
nCompare = UsefulOutBuf_Compare(&UOB, 0, 3, 3, 3);
if(nCompare != 'd' - 'c') {
return "abc should not equal abd";
}
nCompare = UsefulOutBuf_Compare(&UOB, 3, 2, 8, 2);
if(nCompare != 0) {
return "ab should compare equal";
}
nCompare = UsefulOutBuf_Compare(&UOB, 2, 4, 5, 4);
if(nCompare != 'd' - 'c') {
return "ca should not equal de";
}
nCompare = UsefulOutBuf_Compare(&UOB, 5, 1, 2, 1);
if(nCompare != 'c' - 'd') {
return "de should not equal ca";
}
nCompare = UsefulOutBuf_Compare(&UOB, 7, 2, 8, 2);
if(nCompare != 'a' - 'f') {
return "fa should not equal ab";
}
nCompare = UsefulOutBuf_Compare(&UOB, 0, 10, 0, 10);
if(nCompare != 0) {
return "comparison to self failed";
}
nCompare = UsefulOutBuf_Compare(&UOB, 9, 1, 9, 1);
if(nCompare != 0) {
return "b should compare equal to b";
}
nCompare = UsefulOutBuf_Compare(&UOB, 10, 1, 10, 1);
if(nCompare != 0) {
return "Comparison off the end is equal";
}
nCompare = UsefulOutBuf_Compare(&UOB, 0, 1, 100, 1);
if(nCompare != 0) {
return "Comparison off the end is equal";
}
nCompare = UsefulOutBuf_Compare(&UOB, 100, 1, 0, 1);
if(nCompare != 0) {
return "Comparison off the end is equal";
}
nCompare = UsefulOutBuf_Compare(&UOB, 0, 3, 3, 2);
if(nCompare > 0) {
return "Comparison of unequal lengths incorrect";
}
nCompare = UsefulOutBuf_Compare(&UOB, 8, 2, 0, 3);
if(nCompare < 0) {
return "Comparison of unequal lengths incorrect 2";
}
nCompare = UsefulOutBuf_Compare(&UOB, 0, 2, 2, 3);
if(nCompare != 'c' - 'a') {
return "Inequal lengths, but inequal strings";
}
nCompare = UsefulOutBuf_Compare(&UOB, 1, 3, 4, 2);
if(nCompare != 'd' - 'c') {
return "Inequal lengths, but inequal strings";
}
/* Test UsefulOutBuf_Swap() */
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 0, 4, 8);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("efghabcd"))) {
return "swap fail 1";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 0, 1, 2);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bacdefgh"))) {
return "swap fail 2";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 0, 1, 8);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bcdefgha"))) {
return "swap fail 3";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 0, 3, 4);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("dabcefgh"))) {
return "swap fail 4";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 9, 10, 11);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
return "swap fail 5";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 0, 4, 11);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
return "swap fail 6";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 9, 0, 0);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
return "swap fail 7";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 0, 0, 0);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
return "swap fail 8";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 8, 4, 0);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
return "swap fail 9";
}
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abcdefgh");
UsefulOutBuf_Swap(&UOB, 0, 8, 4);
Out = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
return "swap fail 10";
}
/* Test for UsefulOutBuf_GetOutput() */
UsefulOutBuf_Reset(&UOB);
UsefulOutBuf_AppendString(&UOB, "abc");
UsefulOutBuf_AppendString(&UOB, "xyz");
Out = UsefulOutBuf_OutUBufOffset(&UOB, 0);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcxyz"))) {
return "GetOutput fail 1";
}
Out = UsefulOutBuf_OutUBufOffset(&UOB, 5);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("z"))) {
return "GetOutput fail 2";
}
Out = UsefulOutBuf_OutUBufOffset(&UOB, 1);
if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bcxyz"))) {
return "GetOutput fail 3";
}
Out = UsefulOutBuf_OutUBufOffset(&UOB, 6);
if(!UsefulBuf_IsNULLC(Out)) {
return "GetOutput fail 4";
}
Out = UsefulOutBuf_OutUBufOffset(&UOB, 7);
if(!UsefulBuf_IsNULLC(Out)) {
return "GetOutput fail 5";
}
return NULL;
}