Progress on floating point, but not done: a lot more tests, a few bug fixes; also copyright notice for floating point files; also some work on test framework
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index d6fdc58..b259a6c 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -7,11 +7,13 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		E73B574E215713FA0080D658 /* half_precision_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B574D215713FA0080D658 /* half_precision_test.c */; };
 		E776E08F214AE07500E67947 /* qcbor_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08C214AE07400E67947 /* qcbor_encode.c */; };
 		E776E090214AE07500E67947 /* UsefulBuf.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08D214AE07500E67947 /* UsefulBuf.c */; };
 		E776E091214AE07500E67947 /* qcbor_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08E214AE07500E67947 /* qcbor_decode.c */; };
 		E776E097214AE0C700E67947 /* cmd_line_main.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E096214AE0C700E67947 /* cmd_line_main.c */; };
 		E776E09D214AEEEA00E67947 /* basic_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E09C214AEEEA00E67947 /* basic_test.c */; };
+		E776E164214F81EC00E67947 /* ieee754.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E163214F81EC00E67947 /* ieee754.c */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -27,15 +29,19 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		E73B574C215713FA0080D658 /* half_precision_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = half_precision_test.h; path = test/half_precision_test.h; sourceTree = "<group>"; };
+		E73B574D215713FA0080D658 /* half_precision_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = half_precision_test.c; path = test/half_precision_test.c; sourceTree = "<group>"; };
 		E776E07C214ADF7F00E67947 /* QCBOR */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR; sourceTree = BUILT_PRODUCTS_DIR; };
-		E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; };
+		E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; tabWidth = 3; };
 		E776E08D214AE07500E67947 /* UsefulBuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = UsefulBuf.c; path = src/UsefulBuf.c; sourceTree = "<group>"; };
-		E776E08E214AE07500E67947 /* qcbor_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_decode.c; path = src/qcbor_decode.c; sourceTree = "<group>"; };
+		E776E08E214AE07500E67947 /* qcbor_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_decode.c; path = src/qcbor_decode.c; sourceTree = "<group>"; tabWidth = 3; };
 		E776E093214AE08B00E67947 /* qcbor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor.h; path = inc/qcbor.h; sourceTree = "<group>"; };
 		E776E094214AE09700E67947 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/UsefulBuf.h; sourceTree = "<group>"; };
 		E776E096214AE0C700E67947 /* cmd_line_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmd_line_main.c; sourceTree = "<group>"; };
 		E776E09B214AEEEA00E67947 /* basic_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = basic_test.h; path = test/basic_test.h; sourceTree = "<group>"; };
 		E776E09C214AEEEA00E67947 /* basic_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = basic_test.c; path = test/basic_test.c; sourceTree = "<group>"; };
+		E776E162214F81EC00E67947 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = "<group>"; };
+		E776E163214F81EC00E67947 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -71,6 +77,8 @@
 		E776E08B214AE06600E67947 /* src */ = {
 			isa = PBXGroup;
 			children = (
+				E776E163214F81EC00E67947 /* ieee754.c */,
+				E776E162214F81EC00E67947 /* ieee754.h */,
 				E776E08E214AE07500E67947 /* qcbor_decode.c */,
 				E776E08C214AE07400E67947 /* qcbor_encode.c */,
 				E776E08D214AE07500E67947 /* UsefulBuf.c */,
@@ -90,6 +98,8 @@
 		E776E095214AE0B600E67947 /* test */ = {
 			isa = PBXGroup;
 			children = (
+				E73B574D215713FA0080D658 /* half_precision_test.c */,
+				E73B574C215713FA0080D658 /* half_precision_test.h */,
 				E776E09C214AEEEA00E67947 /* basic_test.c */,
 				E776E09B214AEEEA00E67947 /* basic_test.h */,
 			);
@@ -152,8 +162,10 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				E73B574E215713FA0080D658 /* half_precision_test.c in Sources */,
 				E776E08F214AE07500E67947 /* qcbor_encode.c in Sources */,
 				E776E091214AE07500E67947 /* qcbor_decode.c in Sources */,
+				E776E164214F81EC00E67947 /* ieee754.c in Sources */,
 				E776E090214AE07500E67947 /* UsefulBuf.c in Sources */,
 				E776E097214AE0C700E67947 /* cmd_line_main.c in Sources */,
 				E776E09D214AEEEA00E67947 /* basic_test.c in Sources */,
@@ -260,6 +272,7 @@
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
diff --git a/cmd_line_main.c b/cmd_line_main.c
index 54adb50..5a68709 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -1,3 +1,29 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
+
 //
 //  main.c
 //  QCBOR
@@ -9,11 +35,22 @@
 #include <stdio.h>
 
 #include "basic_test.h"
+#include "half_precision_test.h"
+
+
+int fputs_wrapper(const char *szString, void *ctx)
+{
+    return fputs(szString, (FILE *)ctx);
+}
+
 
 int main(int argc, const char * argv[]) {
-    // insert code here...
-    printf("Hello, World! %d\n", basic_test_one());
     
+    half_precision_decode_basic();
     
-    return 0;
+    half_precision_encode_basic();
+    
+    int nNumTestsFailed = run_tests(&fputs_wrapper, stdout, NULL);
+
+    return nNumTestsFailed;
 }
diff --git a/inc/qcbor.h b/inc/qcbor.h
index a5d214d..7c7d6f9 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -896,10 +896,21 @@
  This works the same as QCBOREncode_AddInt64_3() except it is for half-precision floats.
 
  */
+
 void QCBOREncode_AddFloatAsHalf_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum);
 
+#define QCBOREncode_AddFloatAsHalf(pCtx, fNum) \
+      QCBOREncode_AddFloatAsHalf_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsHalfToMap(pCtx, szLabel, fNum) \
+      QCBOREncode_AddFloatAsHalf_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsHalfToMapN(pCtx, nLabel, fNum) \
+      QCBOREncode_AddFloatAsHalf_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, (fNum))
+
+
 /*
- @brief  Add a half-precision floating point number to the encoded output
+ @brief  Add a dynamically sized floating point number to the encoded output
  
  @param[in] pCtx      The encoding context to add the float to.
  @param[in] szLabel   The string map label for this integer value.
@@ -924,11 +935,20 @@
  
  */
 
-
 void QCBOREncode_AddFloatAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum);
 
+#define QCBOREncode_AddFloatAsSmallest(pCtx, fNum) \
+      QCBOREncode_AddFloatAsSmallest_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsSmallestToMap(pCtx, szLabel, fNum) \
+      QCBOREncode_AddFloatAsSmallest_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsSmallestToMapN(pCtx, nLabel, fNum) \
+      QCBOREncode_AddFloatAsSmallest_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, (fNum))
+
+
 /*
- @brief  Add a half-precision floating point number to the encoded output
+ @brief  Add a dynamically sized floating point number to the encoded output
  
  @param[in] pCtx      The encoding context to add the float to.
  @param[in] szLabel   The string map label for this integer value.
@@ -943,9 +963,10 @@
  conversion to single-precision, then it will be converted and encoded. If not, then
  no conversion is performed and it sent as a double.
  
- Half-precision floating point numbers take up 2 bytes, half that of single-precision.
+ Half-precision floating point numbers take up 2 bytes, half that of single-precision,
+ one quarter of double-preceision
  
- This reduces the size of encoded messages a lot, maybe even by four if a lot of values are
+ This reduces the size of encoded messages a lot, maybe even by four if a most of values are
  0, infinity or NaN.
  
  On decode, these will always be represented has float or double. Half-precision values
@@ -954,11 +975,22 @@
  using this approach can / should assume that floats received actually have the precision
  of double. They should probably cast the float received to double.
  
- This works the same as QCBOREncode_AddInt64_3() except it is for half-precision floats.
+ This works the same as QCBOREncode_AddInt64_3() except it is for floating point types.
  
  */
+
 void QCBOREncode_AddDoubleAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, double dNum);
 
+#define QCBOREncode_AddDoubleAsSmallest(pCtx, dNum) \
+      QCBOREncode_AddDoubleAsSmallest_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (dNum))
+
+#define QCBOREncode_AddDoubleAsSmallestToMap(pCtx, szLabel, dNum) \
+      QCBOREncode_AddDoubleAsSmallest_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (dNum))
+
+#define QCBOREncode_AddDoubleAsSmallestToMapN(pCtx, nLabel, dNum) \
+      QCBOREncode_AddDoubleAsSmallest_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, (dNum))
+
+
 
 /**
  
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index d98ebd5..a1305d2 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -241,7 +241,7 @@
    
    /* 3. Slide existing data to the right */
    uint8_t *pSourceOfMove       = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #1
-   size_t   uNumBytesToMove     = me->UB.len - uInsertionPos; // PtrMath #2
+   size_t   uNumBytesToMove     = me->data_len - uInsertionPos; // PtrMath #2
    uint8_t *pDestinationOfMove  = pSourceOfMove + NewData.len; // PtrMath #3
    size_t   uRoomInDestination  = me->UB.len - (uInsertionPos + NewData.len); // PtrMath #4
    
diff --git a/src/ieee754.c b/src/ieee754.c
index a5a65a3..bcad14d 100644
--- a/src/ieee754.c
+++ b/src/ieee754.c
@@ -1,3 +1,29 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
+
 //
 //  ieee754.c
 //  Indefinite
@@ -139,7 +165,7 @@
 
 
 // Public function; see ieee754.h
-int16_t IEEE754_FloatToHalf(float f)
+uint16_t IEEE754_FloatToHalf(float f)
 {
     // Pull the three parts out of the single-precision float
     const uint32_t uSingle = CopyFloatToUint32(f);
@@ -204,7 +230,7 @@
 
 
 // Public function; see ieee754.h
-int16_t IEEE754_DoubleToHalf(double d)
+uint16_t IEEE754_DoubleToHalf(double d)
 {
     // Pull the three parts out of the double-precision float
     const uint64_t uDouble = CopyDoubleToUint64(d);
diff --git a/src/ieee754.h b/src/ieee754.h
index ced4bcb..ba2b030 100644
--- a/src/ieee754.h
+++ b/src/ieee754.h
@@ -1,3 +1,28 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
 //
 //  ieee754.h
 //  Indefinite
@@ -53,11 +78,11 @@
  
  */
 
-int16_t IEEE754_FloatToHalf(float f);
+uint16_t IEEE754_FloatToHalf(float f);
 
 float IEEE754_HalfToFloat(uint16_t uHalfPrecision);
 
-int16_t IEEE754_DoubleToHalf(double d);
+uint16_t IEEE754_DoubleToHalf(double d);
 
 double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
 
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 6aee680..806287d 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -302,11 +302,11 @@
          nReturn = QCBOR_ERR_UNSUPPORTED;
          break;
            
-      case SINGLE_PREC_FLOAT:
+      case HALF_PREC_FLOAT:
          pDecodedItem->val.fnum  = IEEE754_HalfToFloat((uint16_t)uNumber);
          pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
          break;
-      case HALF_PREC_FLOAT:
+      case SINGLE_PREC_FLOAT:
          pDecodedItem->val.fnum = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
          break;
       case DOUBLE_PREC_FLOAT:
diff --git a/test/basic_test.c b/test/basic_test.c
index e5f510c..7df09fc 100644
--- a/test/basic_test.c
+++ b/test/basic_test.c
@@ -1,3 +1,28 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
 //
 //  basic_test.c
 //  QCBOR
@@ -42,3 +67,110 @@
     
     return 0;
 }
+
+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.
+ 
+ This function does pointer math. TODO: test this.
+ */
+const char *NumToString(int32_t nNum, UsefulBuf StringMem)
+{
+    const uint32_t uMax = 1000000000;
+    
+    UsefulOutBuf OutBuf;
+    UsefulOutBuf_Init(&OutBuf, StringMem);
+    
+    if(nNum < 0) {
+        UsefulOutBuf_AppendByte(&OutBuf, '-');
+        nNum = -nNum;
+    }
+    if(nNum > uMax-1) {
+        return "XXX";
+    }
+    
+    bool bDidSomeOutput = false;
+    for(int n = uMax; n > 0; n/=10) {
+        int x = nNum/n;
+        if(x || bDidSomeOutput){
+            bDidSomeOutput = true;
+            UsefulOutBuf_AppendByte(&OutBuf, '0' + x);
+            nNum -= x * n;
+        }
+    }
+    if(!bDidSomeOutput){
+        UsefulOutBuf_AppendByte(&OutBuf, '0');
+    }
+    UsefulOutBuf_AppendByte(&OutBuf, '\0');
+    
+    return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr;
+}
+
+
+
+typedef int (test_fun_t)(void);
+
+#define TEST_ENTRY(test_name)  {#test_name, test_name},
+typedef struct {
+    const char *szTestName;
+    test_fun_t  *test_fun;
+} test_entry;
+
+test_entry s_tests[] = {
+    TEST_ENTRY(basic_test_one)
+    TEST_ENTRY(fail_test)
+};
+
+
+int run_tests(outputstring output, void *poutCtx, int *pNumTestsRun)
+{
+    int nTestsFailed = 0;
+    int nTestsRun = 0;
+    UsefulBuf_MakeStackUB(StringStorage, 5);
+    
+    test_entry *t;
+    const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry);
+    
+    for(t = s_tests; t < s_tests_end; t++) {
+        int x = (t->test_fun)();
+        nTestsRun++;
+        if(output) {
+            (*output)(t->szTestName, poutCtx);
+        }
+        
+        if(x) {
+            if(output) {
+                (*output)(" FAILED (returned ", poutCtx);
+                (*output)(NumToString(x, StringStorage), poutCtx);
+                (*output)(")\n", poutCtx);
+            }
+            nTestsFailed++;
+        } else {
+            if(output) {
+                (*output)( " PASSED\n", poutCtx);
+            }
+        }
+    }
+    
+    if(pNumTestsRun) {
+        *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);
+    }
+    
+    return nTestsFailed;
+}
+
+
diff --git a/test/basic_test.h b/test/basic_test.h
index ef6f396..e71f323 100644
--- a/test/basic_test.h
+++ b/test/basic_test.h
@@ -1,3 +1,28 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
 //
 //  basic_test.h
 //  QCBOR
@@ -5,10 +30,15 @@
 //  Created by Laurence Lundblade on 9/13/18.
 //  Copyright © 2018 Laurence Lundblade. All rights reserved.
 //
+#include <stdio.h>
 
 #ifndef basic_test_h
 #define basic_test_h
 
 int basic_test_one(void);
 
+typedef int (*outputstring)(const char *szString, void *ctx);
+int run_tests(outputstring output, void *poutCtx, int *pNumTestsRun);
+
+
 #endif /* basic_test_h */