Remove malloc dependency in tests. Give list of tests to run on command line. Describe tests in README.md
diff --git a/README.md b/README.md
index 00d458d..2e1efd3 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,8 @@
## Characteristics
**Implemented in C with minimal dependecy** – Only dependencies are
-C99, stdint.h, stddef.h, stdbool.h and string.h making it highly
-portable. There are no #ifdefs.
+C99, <stdint.h>, <stddef.h>, <stdbool.h> and <string.h> making it highly
+portable. There are no #ifdefs to be configured at all.
**Focused on C / native data representation** – Simpler code because
there is no support for encoding/decoding to/from JSON, pretty
@@ -28,13 +28,13 @@
length strings is not supported, but is also not necessary or
preferred.
-**Extensible and General** – Provides a way to handle data types that
+**Extensible and general** – Provides a way to handle data types that
are not directly supported.
-**Secure Coding Style** – Uses a construct called UsefulBuf as a
+**Secure coding style** – Uses a construct called UsefulBuf as a
discipline for very safe coding the handling of binary data.
-**Small Code Size** – When optimized for size using the compiler -Os
+**Small code size** – When optimized for size using the compiler -Os
option, x86 code is less than 5KB (~1.1B encode, ~2.8KB decode,
~0.4KB common).
@@ -42,6 +42,11 @@
separated from the implementation. It can be put to use without
reading the source.
+ **Comprehensive test suite** – Easy to verify on a new platform
+ or OS with the test suite. The test suite dependencies are also
+ minimal, only additionally requiring <math.h> for floating point
+ tests.
+
## Code Status
QCBOR was originally developed by Qualcomm. It was [open sourced
diff --git a/cmd_line_main.c b/cmd_line_main.c
index 927beee..29b8488 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -1,5 +1,7 @@
/*==============================================================================
- cmd_line_mainc.c -- basic tests for qcbor encoder / decoder
+ cmd_line_mainc.c -- Runs tests for QCBOR encoder / decoder
+
+ Created on 9/13/18.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
@@ -30,49 +32,30 @@
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==============================================================================*/
-// Created by Laurence Lundblade on 9/13/18.
+
#include <stdio.h>
#include "run_tests.h"
-#include "qcbor.h" // just to print sizes of the structures.
-int fputs_wrapper(const char *szString, void *ctx)
+/*
+ This is an implementation of OutputStringCB built using stdio. If
+ you don't have stdio, replaces this is
+ */
+static void fputs_wrapper(const char *szString, void *ctx)
{
- return fputs(szString, (FILE *)ctx);
-}
-
-
-static void PrintSize(const char *szWhat, uint32_t uSize)
-{
- UsefulBuf_MAKE_STACK_UB(foo, 20);
-
- fputs_wrapper(szWhat, stdout);
- fputs_wrapper(" ", stdout);
- fputs_wrapper(NumToString(uSize,foo), stdout);
- fputs_wrapper("\n", stdout);
+ fputs(szString, (FILE *)ctx);
}
int main(int argc, const char * argv[])
{
- // Type and size of return from sizeof() varies. These will never be large so cast is safe
- PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting));
- PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting));
- PrintSize("sizeof(QCBOREncodeContext)", (uint32_t)sizeof(QCBOREncodeContext));
- PrintSize("sizeof(QCBORDecodeContext)", (uint32_t)sizeof(QCBORDecodeContext));
- PrintSize("sizeof(QCBORDecodeNesting)", (uint32_t)sizeof(QCBORDecodeNesting));
- PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem));
- PrintSize("sizeof(QCBORStringAllocator)", (uint32_t)sizeof(QCBORStringAllocator));
- fputs_wrapper("\n", stdout);
+ (void)argc; // Avoid unused parameter error
- int nNumTestsFailed = 0;
+ // This call prints out sizes of data structures to remind us
+ // to keep them small.
+ PrintSizes(&fputs_wrapper, stdout);
- if(argc > 1) {
- nNumTestsFailed += run_tests(argv[1], &fputs_wrapper, stdout, NULL);
- } else {
- nNumTestsFailed += run_tests(NULL, &fputs_wrapper, stdout, NULL);
- }
-
- return nNumTestsFailed;
+ // This runs all the tests
+ return RunTests(argv+1, &fputs_wrapper, stdout, NULL);
}
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 3fe705c..021c150 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -30,11 +30,11 @@
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==============================================================================*/
-#include "qcbor.h"
#include "qcbor_decode_tests.h"
+#include "qcbor.h"
#include <string.h>
#include <math.h> // for fabs()
-#include <stdlib.h>
+
#ifdef PRINT_FUNCTIONS_FOR_DEBUGGING
#include <stdio.h>
@@ -44,14 +44,14 @@
if(szLabel) {
printf("%s ", szLabel);
}
-
+
size_t i;
for(i = 0; i < Buf.len; i++) {
uint8_t Z = ((uint8_t *)Buf.ptr)[i];
printf("%02x ", Z);
}
printf("\n");
-
+
fflush(stdout);
}
@@ -444,6 +444,8 @@
*/
+static uint8_t spSimpleArrayBuffer[50];
+
static int CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen)
{
QCBOREncodeContext ECtx;
@@ -453,7 +455,7 @@
*pEncodedLen = INT32_MAX;
// loop runs CBOR encoding twice. First with no buffer to
- // calucate the length so buffer can be allocated correctly,
+ // calculate the length so buffer can be allocated correctly,
// and last with the buffer to do the actual encoding
do {
QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen});
@@ -464,25 +466,24 @@
QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"haven token", 11}));
QCBOREncode_CloseArray(&ECtx);
- UsefulBufC Encoded;
- if(QCBOREncode_Finish(&ECtx, &Encoded))
+ if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen))
goto Done;
if(*pEncoded != NULL) {
- *pEncodedLen = Encoded.len;
nReturn = 0;
goto Done;
}
- *pEncoded = malloc(Encoded.len);
- if(*pEncoded == NULL) {
- nReturn = -1;
+
+ // Use static buffer to avoid dependency on malloc()
+ if(*pEncodedLen > sizeof(spSimpleArrayBuffer)) {
goto Done;
}
+ *pEncoded = spSimpleArrayBuffer;
} while(1);
-Done:
- return (nReturn);
+Done:
+ return nReturn;
}
@@ -1418,12 +1419,12 @@
if(nLen >= nLenMax) {
return;
}
-
+
for(int inputByte = 0; inputByte < 256; inputByte++) {
// Set up the input
pBuf[nLen] = inputByte;
const UsefulBufC Input = {pBuf, nLen+1};
-
+
// Get ready to parse
QCBORDecodeContext DCtx;
QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL);
@@ -1472,9 +1473,9 @@
// the others so as to no slow down the use
// of them as a very frequent regression.
uint8_t pBuf[3]; //
-
+
ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf));
-
+
return 0;
}
@@ -2679,7 +2680,7 @@
const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded));
QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL);
- UsefulBuf_Set(Pool, '/');
+ UsefulBuf_Set(Pool, '/');
QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying.
QCBORItem Item1, Item2, Item3, Item4;
diff --git a/test/run_tests.c b/test/run_tests.c
index ef5a16f..0297de9 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -1,8 +1,9 @@
-
/*==============================================================================
run_tests.c -- test aggregator and results reporting
- Copyright (c) 2018, Laurence Lundblade.
+ Created on 9/30/18
+
+ Copyright (c) 2018-2019, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -30,7 +31,6 @@
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==============================================================================*/
-// Created by Laurence Lundblade on 9/30/18.
#include "run_tests.h"
@@ -42,13 +42,17 @@
#include "qcbor_encode_tests.h"
#include "UsefulBuf_Tests.h"
-// Used to test the test runner
+
+
+// Used to test RunTests
int fail_test()
{
return -44;
}
+
+
/*
Convert a number up to 999999999 to a string. This is so sprintf doesn't
have to be linked in so as to minimized dependencies even in test code.
@@ -87,6 +91,7 @@
+
typedef int (test_fun_t)(void);
typedef const char * (test_fun2_t)(void);
@@ -163,7 +168,7 @@
};
-int run_tests(const char *szTestName, outputstring output, void *poutCtx, int *pNumTestsRun)
+int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx, int *pNumTestsRun)
{
int nTestsFailed = 0;
int nTestsRun = 0;
@@ -173,30 +178,43 @@
const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2);
for(t2 = s_tests2; t2 < s_tests2_end; t2++) {
- if(!t2->bEnabled && !szTestName) {
- // Don't run disabled tests when all tests are being run
- // as indicated by no specific test name being given
- continue;
+ if(szTestNames[0]) {
+ // Some tests have been named
+ const char **szRequestedNames;
+ for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) {
+ if(!strcmp(t2->szTestName, *szRequestedNames)) {
+ break; // Name matched
+ }
+ }
+ if(*szRequestedNames == NULL) {
+ // Didn't match this test
+ continue;
+ }
+ } else {
+ // no tests named, but don't run "disabled" tests
+ if(!t2->bEnabled) {
+ // Don't run disabled tests when all tests are being run
+ // as indicated by no specific test names being given
+ continue;
+ }
}
- if(szTestName && strcmp(szTestName, t2->szTestName)) {
- continue;
- }
+
const char * szTestResult = (t2->test_fun)();
nTestsRun++;
- if(output) {
- (*output)(t2->szTestName, poutCtx);
+ if(pfOutput) {
+ (*pfOutput)(t2->szTestName, poutCtx);
}
if(szTestResult) {
- if(output) {
- (*output)(" FAILED (returned ", poutCtx);
- (*output)(szTestResult, poutCtx);
- (*output)(")\n", poutCtx);
+ if(pfOutput) {
+ (*pfOutput)(" FAILED (returned ", poutCtx);
+ (*pfOutput)(szTestResult, poutCtx);
+ (*pfOutput)(")\n", poutCtx);
}
nTestsFailed++;
} else {
- if(output) {
- (*output)( " PASSED\n", poutCtx);
+ if(pfOutput) {
+ (*pfOutput)( " PASSED\n", poutCtx);
}
}
}
@@ -206,30 +224,43 @@
const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry);
for(t = s_tests; t < s_tests_end; t++) {
- if(!t->bEnabled && !szTestName) {
- // Don't run disabled tests when all tests are being run
- // as indicated by no specific test name being given
- continue;
+ if(szTestNames[0]) {
+ // Some tests have been named
+ const char **szRequestedNames;
+ for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) {
+ if(!strcmp(t->szTestName, *szRequestedNames)) {
+ break; // Name matched
+ }
+ }
+ if(*szRequestedNames == NULL) {
+ // Didn't match this test
+ continue;
+ }
+ } else {
+ // no tests named, but don't run "disabled" tests
+ if(!t->bEnabled) {
+ // Don't run disabled tests when all tests are being run
+ // as indicated by no specific test names being given
+ continue;
+ }
}
- if(szTestName && strcmp(szTestName, t->szTestName)) {
- continue;
- }
+
int nTestResult = (t->test_fun)();
nTestsRun++;
- if(output) {
- (*output)(t->szTestName, poutCtx);
+ if(pfOutput) {
+ (*pfOutput)(t->szTestName, poutCtx);
}
if(nTestResult) {
- if(output) {
- (*output)(" FAILED (returned ", poutCtx);
- (*output)(NumToString(nTestResult, StringStorage), poutCtx);
- (*output)(")\n", poutCtx);
+ if(pfOutput) {
+ (*pfOutput)(" FAILED (returned ", poutCtx);
+ (*pfOutput)(NumToString(nTestResult, StringStorage), poutCtx);
+ (*pfOutput)(")\n", poutCtx);
}
nTestsFailed++;
} else {
- if(output) {
- (*output)( " PASSED\n", poutCtx);
+ if(pfOutput) {
+ (*pfOutput)( " PASSED\n", poutCtx);
}
}
}
@@ -238,13 +269,40 @@
*pNumTestsRun = nTestsRun;
}
- if(output) {
- (*output)( "SUMMARY: ", poutCtx);
- (*output)( NumToString(nTestsRun, StringStorage), poutCtx);
- (*output)( " tests run; ", poutCtx);
- (*output)( NumToString(nTestsFailed, StringStorage), poutCtx);
- (*output)( " tests failed\n", poutCtx);
+ if(pfOutput) {
+ (*pfOutput)( "SUMMARY: ", poutCtx);
+ (*pfOutput)( NumToString(nTestsRun, StringStorage), poutCtx);
+ (*pfOutput)( " tests run; ", poutCtx);
+ (*pfOutput)( NumToString(nTestsFailed, StringStorage), poutCtx);
+ (*pfOutput)( " tests failed\n", poutCtx);
}
return nTestsFailed;
}
+
+
+
+
+static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutput, void *pOutCtx)
+{
+ UsefulBuf_MAKE_STACK_UB(foo, 20);
+
+ (*pfOutput)(szWhat, pOutCtx);
+ (*pfOutput)(" ", pOutCtx);
+ (*pfOutput)(NumToString(uSize,foo), pOutCtx);
+ (*pfOutput)("\n", pOutCtx);
+}
+
+void PrintSizes(OutputStringCB pfOutput, void *pOutCtx)
+{
+ // Type and size of return from sizeof() varies. These will never be large so cast is safe
+ PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBOREncodeContext)", (uint32_t)sizeof(QCBOREncodeContext), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORDecodeNesting)", (uint32_t)sizeof(QCBORDecodeNesting), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORDecodeContext)", (uint32_t)sizeof(QCBORDecodeContext), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORStringAllocator)", (uint32_t)sizeof(QCBORStringAllocator), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx);
+ (*pfOutput)("\n", pOutCtx);
+}
diff --git a/test/run_tests.h b/test/run_tests.h
index 431ef22..91d6c65 100644
--- a/test/run_tests.h
+++ b/test/run_tests.h
@@ -2,6 +2,8 @@
/*==============================================================================
run_tests.c -- test aggregator and results reporting
+ Created 9/30/18.
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
@@ -30,14 +32,41 @@
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==============================================================================*/
-// Created by Laurence Lundblade on 9/30/18.
-typedef int (*outputstring)(const char *szString, void *ctx);
-
-int run_tests(const char *szTestName, outputstring output, void *poutCtx, int *pNumTestsRun);
-#include <stdint.h>
-#include "UsefulBuf.h"
+/**
+ @brief Type for function to output a text string
-const char *NumToString(int32_t nNum, UsefulBuf StringMem);
+ @param[in] szString The string to output
+ @param[in] pOutCtx A context pointer; NULL if not needed
+
+ This is a prototype of a function to be passed to run_tests() to
+ output text strings. This can be implemented with stdio (if
+ available) using a straight call to fputs() where the FILE *
+ is passed as the ctx.
+*/
+typedef void (*OutputStringCB)(const char *szString, void *pOutCtx);
+
+
+/**
+ @brief Runs the QCBOR tests
+
+ @param[in] szTestNames An argv-style list of test names to run. If
+ empty, all are run.
+ @param[in] pfOutput Function that is called to output text strings.
+ @param[in] pOutCtx Context pointer passed to output function.
+ @param[out] pNumTestsRun Returns the number of tests run. May be NULL.
+
+ @return The number of tests that failed. Zero means overall success.
+ */
+int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *pOutCtx, int *pNumTestsRun);
+
+
+/**
+ @brief Print sizes of encoder / decoder contexts.
+
+ @param[in] pfOutput Function that is called to output text strings.
+ @param[in] pOutCtx Context pointer passed to output function.
+ */
+void PrintSizes(OutputStringCB pfOutput, void *pOutCtx);