Encode/UB test coverage 100%; fix bugs in UsefulOutBuf_Compare and sorting

UsefulBuf test coverage back up to 100% (filled out coverage for new v2 features)

UsefulOutBuf_Compare() bugs for unequal length comparisons and comparisons off the end of the buffer

Improve UsefulOutBuf magic number check

UsefulOutBuf_OutSubString renamed to UsefulOutBuf_SubString for consistency. Old name still supported.



* Useful test coverage; UsefulOutBuf_Compare fixes

* Improve sort error handling; encode test coverage 100%

* Fix ifdef test fan out

* revert error codes

* Add diverse labels test

---------

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index f3b86da..888891d 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -1,6 +1,6 @@
 /* =========================================================================
  * Copyright (c) 2016-2018, The Linux Foundation.
- * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2018-2025, Laurence Lundblade.
  * Copyright (c) 2021, Arm Limited. All rights reserved.
  * All rights reserved.
  *
@@ -43,6 +43,8 @@
 
  when         who             what, where, why
  --------     ----            --------------------------------------------------
+ 02/21/2025   llundblade      Correct documentaion for UsefulOutBuf_Compare()
+ 02/21/2025   llundblade      Rename to UsefulOutBuf_OutSubString().
  12/31/2024   llundblade      Minor documentation tweaks for Doxygen.
  08/31/2024   llundblade      Add UsefulBufC_NTH_BYTE().
  08/14/2024   llundblade      Add UsefulOutBuf_RetrieveOutputStorage().
@@ -1452,9 +1454,9 @@
  * substring. @c NULLUsefulBufC is returned if the requested substring
  * is off the end of the output bytes or if in error state.
  */
-UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pUOutBuf,
-                                  const size_t  uStart,
-                                  const size_t  uLen);
+UsefulBufC UsefulOutBuf_OutSubString(UsefulOutBuf *pUOutBuf,
+                                     const size_t  uStart,
+                                     const size_t  uLen);
 
 
 /**
@@ -1483,26 +1485,28 @@
  * @return  0 for equality, positive if uStart1 is lexographically larger,
  *          negative if uStart2 is lexographically larger.
  *
- * This looks into bytes that have been output at the offsets @c start1
- * and @c start2. It compares bytes at those two starting points until
- * they are not equal or @c uLen1 or @c uLen2 is reached. If the
- * length of the string given is off the end of the output data, the
- * string will be effectively truncated to the data in the output
- * buffer for the comparison.
+ * This looks into bytes that have been output at the offsets
+ * @c start1 and @c start2. It compares bytes at those two starting
+ * points until they are not equal or @c uLen1 or @c uLen2 is
+ * reached. If the length of the string given is off the end of the
+ * output data, the string will be effectively (not actually)
+ * truncated to the data in the output buffer for the comparison.
  *
- * This returns positive when @c uStart1 lexographically sorts ahead
- * of @c uStart2 and vice versa.  Zero is returned if the strings
- * compare equally.
+ * This function returns a positive value if the first string
+ * lexicographically precedes the second and a negative value if the
+ * second precedes the first. If the strings are equal, it returns
+ * zero.
  *
- * If lengths are unequal and the first bytes are an exact subset of
- * the second string, then a positve value will be returned and vice
- * versa.
+ * If one string is a substring of the other, the shorter string is
+ * considered smaller. For example, if the first string is "ab" and
+ * the second is "abc", a positive value is returned. The empty string
+ * is always the smallest and sorts ahead of all others.
  *
- * If either start is past the end of data in the output buffer, 0
- * will be returned. It is the caller's responsibility to make sure
- * the offsets are not off the end so that a comparison is actually
- * being made. No data will ever be read off the end of the buffer so
- * this safe no matter what offsets are passed.
+ * If either starting offset is beyond the end of the output buffer,
+ * the function returns zero.  It is the caller’s responsibility to
+ * ensure that offsets are within bounds so that a valid comparison is
+ * performed. No data will ever be read beyond the buffer’s end,
+ * making the function safe regardless of the provided offsets.
  *
  * This is a relatively odd function in that it works on data in the
  * output buffer. It is employed by QCBOR to sort CBOR-encoded maps
@@ -2477,6 +2481,8 @@
     * or was never initialized.
     */
    if(pMe->magic != UIB_MAGIC) {
+      /* Strangely gcov thinks the line is not covered by tests even
+       * though it clearly is (tested with break point and printf) */
       return 0;
    }
 
@@ -2711,6 +2717,12 @@
 }
 
 
+/* For backwards compatibility */
+static inline UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe, const size_t uStart, const size_t uLen)
+{
+   return UsefulOutBuf_OutSubString(pMe, uStart, uLen);
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/inc/qcbor/qcbor_main_encode.h b/inc/qcbor/qcbor_main_encode.h
index 00e6b33..abcb955 100644
--- a/inc/qcbor/qcbor_main_encode.h
+++ b/inc/qcbor/qcbor_main_encode.h
@@ -215,7 +215,7 @@
     * set when trying to encode non-preferred big numbers with
     * QCBOREncode_AddTBigNumberNoPreferred() or
     * QCBOREncode_AddTBigNumberRaw(). */
-   QCBOR_ENCODE_CONFIG_ONLY_PREFERRED_BIG_NUMBERS = 0x40, // TODO: test this one
+   QCBOR_ENCODE_CONFIG_ONLY_PREFERRED_BIG_NUMBERS = 0x40,
 
 
    /**
@@ -1042,8 +1042,8 @@
  * raw CBOR added here to have indefinite lengths.
  *
  * The raw CBOR added here is not checked in anyway. If it is not
- * conforming or has open arrays or such, the final encoded CBOR
- * will probably be wrong or not what was intended.
+ * well-formed or has open arrays or such, the final encoded CBOR
+ * will not be well-formed.
  *
  * If the encoded CBOR being added here contains multiple items, they
  * must be enclosed in a map or array. At the top level the raw
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index 46b66c6..6e99c43 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -1,6 +1,6 @@
 /*==============================================================================
  * Copyright (c) 2016-2018, The Linux Foundation.
- * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2018-2025, Laurence Lundblade.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,9 @@
 
  when        who          what, where, why
  --------    ----         ---------------------------------------------------
+ 02/21/2025  llundblade   Improve magic number to detect lack of initialization.
+ 02/21/2025  llundblade   Bug fixes to UsefulOutBuf_Compare().
+ 02/21/2025  llundblade   Rename to UsefulOutBuf_OutSubString().
  08/08/2024  llundblade   Add UsefulOutBuf_SubString().
  21/05/2024  llundblade   Comment formatting and some code tidiness.
  1/7/2024    llundblade   Add UsefulInputBuf_Compare().
@@ -246,11 +249,6 @@
  */
 void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos)
 {
-   if(pMe->err) {
-      /* Already in error state. */
-      return;
-   }
-
    /* 0. Sanity check the UsefulOutBuf structure
     * A "counter measure". If magic number is not the right number it
     * probably means pMe was not initialized or it was corrupted. Attackers
@@ -262,6 +260,11 @@
       return;  /* Magic number is wrong due to uninitalization or corrption */
    }
 
+   if(pMe->err) {
+      /* Already in error state. */
+      return;
+   }
+
    /* Make sure valid data is less than buffer size. This would only occur
     * if there was corruption of me, but it is also part of the checks to
     * be sure there is no pointer arithmatic under/overflow.
@@ -358,11 +361,6 @@
     * rarely used.
     */
 
-   if(pMe->err) {
-      /* Already in error state. */
-      return;
-   }
-
    /* 0. Sanity check the UsefulOutBuf structure
     *
     * A "counter measure". If magic number is not the right number it
@@ -375,6 +373,11 @@
       return;  /* Magic number is wrong due to uninitalization or corrption */
    }
 
+   if(pMe->err) {
+      /* Already in error state. */
+      return;
+   }
+
    /* Make sure valid data is less than buffer size. This would only
     * occur if there was corruption of me, but it is also part of the
     * checks to be sure there is no pointer arithmatic
@@ -409,12 +412,12 @@
  */
 UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe)
 {
-   if(pMe->err) {
+   if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
+      pMe->err = 1;
       return NULLUsefulBufC;
    }
 
-   if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
-      pMe->err = 1;
+   if(pMe->err) {
       return NULLUsefulBufC;
    }
 
@@ -442,9 +445,9 @@
  *
  * Code Reviewers: THIS FUNCTION DOES POINTER MATH
  */
-UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe,
-                                  const size_t  uStart,
-                                  const size_t  uLen)
+UsefulBufC UsefulOutBuf_OutSubString(UsefulOutBuf *pMe,
+                                     const size_t  uStart,
+                                     const size_t  uLen)
 {
    const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe);
 
@@ -544,34 +547,53 @@
    const uint8_t *pEnd;
    const uint8_t *p1;
    const uint8_t *p2;
+   const uint8_t *p1Start;
+   const uint8_t *p2Start;
    const uint8_t *p1End;
    const uint8_t *p2End;
    int            uComparison;
+   size_t         uComparedLen1;
+   size_t         uComparedLen2;
 
-   pBase = pMe->UB.ptr;
-   pEnd = (const uint8_t *)pBase + pMe->data_len;
-   p1   = pBase + uStart1;
-   p2   = pBase + uStart2;
-   p1End = p1 + uLen1;
-   p2End = p2 + uLen2;
+   pBase   = pMe->UB.ptr;
+   pEnd    = (const uint8_t *)pBase + pMe->data_len;
+   p1Start = pBase + uStart1;
+   p2Start = pBase + uStart2;
+   p1End   = p1Start + uLen1;
+   p2End   = p2Start + uLen2;
 
    uComparison = 0;
-   while(p1 < pEnd && p2 < pEnd && p1 < p1End && p2 < p2End) {
+   for(p1 = p1Start, p2 = p2Start;
+       p1 < pEnd && p2 < pEnd && p1 < p1End && p2 < p2End;
+       p1++, p2++) {
       uComparison = *p2 - *p1;
       if(uComparison != 0) {
-         break;;
+         break;
       }
-      p1++;
-      p2++;
    }
 
-   if(uComparison == 0 && p1 != p1End && p2 != p2End) {
-      if(uLen1 > uLen2) {
+   /* Loop might have terminated because strings were off
+    * the end of the buffer. Compute actual lengths compared.
+    */
+   uComparedLen1 = uLen1;
+   if(p1 >= pEnd) {
+      uComparedLen1 = (size_t)(p1 - p1Start);
+   }
+   uComparedLen2 = uLen2;
+   if(p2 >= pEnd) {
+      uComparedLen2 = (size_t)(p2 - p2Start);
+   }
+
+   if(uComparison == 0) {
+      /* All bytes were equal, now check the lengths */
+      if(uComparedLen2 > uComparedLen1) {
+         /* string 1 is a substring of string 2 */
          uComparison = 1;
-      } else if(uLen2 < uLen1){
+      } else if(uComparedLen1 > uComparedLen2) {
+         /* string 2 is a substring of string 1 */
          uComparison = -1;
-      } else  {
-         return 0;
+      } else {
+         /* do nothing, uComparison already is 0 */
       }
    }
 
diff --git a/src/qcbor_main_encode.c b/src/qcbor_main_encode.c
index f2f65f4..22d537d 100644
--- a/src/qcbor_main_encode.c
+++ b/src/qcbor_main_encode.c
@@ -839,10 +839,10 @@
  * change.
  */
 static QCBORError
-QCBOREncodePriv_DecodeHead(UsefulInputBuf *pUInBuf,
-                           int            *pnMajorType,
-                           uint64_t       *puArgument,
-                           int            *pnAdditionalInfo)
+QCBOREncode_Private_DecodeHead(UsefulInputBuf *pUInBuf,
+                               int            *pnMajorType,
+                               uint64_t       *puArgument,
+                               int            *pnAdditionalInfo)
 {
    QCBORError uReturn;
 
@@ -899,66 +899,94 @@
  *
  * @param[in] pInBuf  UsefulInputBuf from which to consume item.
  *
- * Recursive, but stack usage is light and encoding depth limit
+ * @retval QCBOR_SUCCESS  The next item has been consumed successfully.
+ *
+ * @retval QCBOR_ERR_HIT_END The next item is a break or has hit the end.
+ *
+ * @retval a QCOR error code indicating some decode failure
+ *
+ * Recursive, but stack usage is light and encoding depth limited.
  */
 static QCBORError
-QCBOR_Private_ConsumeNext(UsefulInputBuf *pInBuf)
+QCBOREncode_Private_ConsumeNext(UsefulInputBuf *pInBuf)
 {
-   int      nMajor;
-   uint64_t uArgument;
-   int      nAdditional;
-   uint16_t uItemCount;
-   uint16_t uMul;
-   uint16_t i;
+   int        nMajor;
+   uint64_t   uArgument;
+   int        nAdditional;
+   uint16_t   uItemCountTotal;
+   uint16_t   uMul;
+   uint16_t   uItemCounter;
    QCBORError uCBORError;
 
-   uCBORError = QCBOREncodePriv_DecodeHead(pInBuf, &nMajor, &uArgument, &nAdditional);
+   uCBORError = QCBOREncode_Private_DecodeHead(pInBuf, &nMajor, &uArgument, &nAdditional);
    if(uCBORError != QCBOR_SUCCESS) {
-      return uCBORError;
+      goto Done;
    }
 
    uMul = 1;
 
+   /* This intentionally doesn't check for a some not-well-formed
+    * conditions such as the wrong type in an indefinite length
+    * string chunk and the disallowed forms of the simple type.
+    * These conditions should never occur because this only decodes
+    * what was encoded by QCBOR. This saves object code.
+    */
+
    switch(nMajor) {
       case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
       case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
          break;
 
-      case CBOR_MAJOR_TYPE_SIMPLE:
-         return uArgument == CBOR_SIMPLE_BREAK ? 1 : 0;
-         break;
-
-      case CBOR_MAJOR_TYPE_BYTE_STRING:
-      case CBOR_MAJOR_TYPE_TEXT_STRING:
+      case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
+      case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
          if(nAdditional == LEN_IS_INDEFINITE) {
-            /* Segments of indefinite length */
-            while(QCBOR_Private_ConsumeNext(pInBuf) == 0);
+            /* Chunks of indefinite length string */
+            do {
+               uCBORError = QCBOREncode_Private_ConsumeNext(pInBuf);
+            } while(uCBORError == QCBOR_SUCCESS);
+            if(uCBORError != QCBOR_ERR_HIT_END) {
+               return uCBORError;
+            }
+            uCBORError = QCBOR_SUCCESS;
+         } else {
+            /* The bytes of a definite length string */
+            (void)UsefulInputBuf_GetBytes(pInBuf, uArgument);
          }
-         (void)UsefulInputBuf_GetBytes(pInBuf, uArgument);
          break;
 
-      case CBOR_MAJOR_TYPE_TAG:
-         QCBOR_Private_ConsumeNext(pInBuf);
-         break;
-
-      case CBOR_MAJOR_TYPE_MAP:
+      case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
          uMul = 2;
          /* Fallthrough */
-      case CBOR_MAJOR_TYPE_ARRAY:
-         uItemCount = (uint16_t)uArgument * uMul;
+      case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
+         /* Cast is safe because this is decoding CBOR that was created
+          * by QCBOR and because QCBOREncode_Private_ConsumeNext() can
+          * never read off the end. */
+         uItemCountTotal = (uint16_t)uArgument * uMul;
          if(nAdditional == LEN_IS_INDEFINITE) {
-            uItemCount = UINT16_MAX;
+            uItemCountTotal = UINT16_MAX;
          }
-         for(i = uItemCount; i > 0; i--) {
-            if(QCBOR_Private_ConsumeNext(pInBuf)) {
-               /* End of indefinite length */
+         for(uItemCounter = uItemCountTotal; uItemCounter > 0; uItemCounter--) {
+            uCBORError = QCBOREncode_Private_ConsumeNext(pInBuf);
+            if(uCBORError != QCBOR_SUCCESS) {
                break;
             }
          }
+         if(nAdditional == LEN_IS_INDEFINITE && uCBORError == QCBOR_ERR_HIT_END) {
+            uCBORError = QCBOR_SUCCESS;
+         }
+         break;
+
+      case CBOR_MAJOR_TYPE_TAG: /* Major type 6 */
+         uCBORError = QCBOREncode_Private_ConsumeNext(pInBuf);
+         break;
+
+      case CBOR_MAJOR_TYPE_SIMPLE: /* Major type 7 */
+         return uArgument == CBOR_SIMPLE_BREAK ? QCBOR_ERR_HIT_END : QCBOR_SUCCESS;
          break;
    }
 
-   return QCBOR_SUCCESS;
+Done:
+   return uCBORError;
 }
 
 
@@ -999,23 +1027,26 @@
    UsefulInputBuf_Init(&InBuf, EncodedMapBytes);
 
    /* This is always used on maps, so consume two, the label and the value */
-   uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
-   if(uCBORError) {
+   uCBORError = QCBOREncode_Private_ConsumeNext(&InBuf);
+   if(uCBORError != QCBOR_SUCCESS) {
+      pMe->uError = (uint8_t)uCBORError;
+      Result.uLabelLen = 0;
       return Result;
    }
 
    /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
    Result.uLabelLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
 
-   uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
-   if(uCBORError) {
+   uCBORError = QCBOREncode_Private_ConsumeNext(&InBuf);
+   if(uCBORError != QCBOR_SUCCESS) {
+      pMe->uError = (uint8_t)uCBORError;
       Result.uLabelLen = 0;
       return Result;
    }
 
+   /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
    Result.uItemLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
 
-   /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
    return Result;
 }
 
@@ -1093,7 +1124,7 @@
          }
          uStart2 = uStart2 + Lens2.uItemLen;
       }
-   } while(bSwapped);
+   } while(bSwapped && pMe->uError == QCBOR_SUCCESS);
 }
 
 
@@ -1331,5 +1362,5 @@
 
    const size_t uEnd = QCBOREncode_Tell(pMe);
 
-   return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart);
+   return UsefulOutBuf_OutSubString(&(pMe->OutBuf), uStart, uEnd - uStart);
 }
diff --git a/src/qcbor_number_encode.c b/src/qcbor_number_encode.c
index e23c2d3..269d323 100644
--- a/src/qcbor_number_encode.c
+++ b/src/qcbor_number_encode.c
@@ -1,6 +1,6 @@
 /* ===========================================================================
  * Copyright (c) 2016-2018, The Linux Foundation.
- * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2018-2025, Laurence Lundblade.
  * Copyright (c) 2021, Arm Limited.
  * All rights reserved.
  *
@@ -226,7 +226,7 @@
 
 
 /**
- * @brief Is there a carry when you subtract 1 from the BigNumber.
+ * @brief Is there a carry when you subtract 1 from the BigNumber?
  *
  * @param[in]  BigNumber  Big number to check for carry.
  *
@@ -331,9 +331,9 @@
  * @return Big number with no leading zeros.
  *
  * If the big number is all zeros, this returns a big number that is
- * one zero rather than the empty string.
+ * a single zero rather than the empty string.
  *
- * RFC 8949 3.4.3 does not explicitly decoders MUST handle the empty
+ * RFC 8949 3.4.3 does not explicitly say decoders MUST handle the empty
  * string, but does say decoders MUST handle leading zeros. So
  * Postel's Law is applied here and 0 is not encoded as an empty
  * string.
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index ae3862c..385551c 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -127,7 +127,7 @@
       goto Done;
    }
 
-   Out = UsefulOutBuf_SubString(&UOB, 10, 8);
+   Out = UsefulOutBuf_OutSubString(&UOB, 10, 8);
    if(UsefulBuf_IsNULLC(Out) ||
       UsefulBuf_Compare(UsefulBuf_FROM_SZ_LITERAL("unbounce"), Out) ||
       UsefulOutBuf_GetError(&UOB)) {
@@ -135,7 +135,7 @@
       goto Done;
    }
 
-   Out = UsefulOutBuf_SubString(&UOB, 0, Expected.len);
+   Out = UsefulOutBuf_OutSubString(&UOB, 0, Expected.len);
    if(UsefulBuf_IsNULLC(Out) ||
       UsefulBuf_Compare(Expected, Out) ||
       UsefulOutBuf_GetError(&UOB)) {
@@ -143,7 +143,7 @@
       goto Done;
    }
 
-   Out = UsefulOutBuf_SubString(&UOB, Expected.len, 0);
+   Out = UsefulOutBuf_OutSubString(&UOB, Expected.len, 0);
    if(UsefulBuf_IsNULLC(Out) ||
       UsefulBuf_Compare(UsefulBuf_FROM_SZ_LITERAL(""), Out) ||
       UsefulOutBuf_GetError(&UOB)) {
@@ -232,8 +232,11 @@
 const char *UOBTest_BoundaryConditionsTest(void)
 {
    UsefulBuf_MAKE_STACK_UB(outbuf, 2);
+   UsefulOutBuf            UOB_UnInitialized;
+   UsefulOutBuf            UOB;
 
-   UsefulOutBuf UOB;
+   /* For test detection of uninitlized UOB (wrong magic number) */
+   memset(&UOB_UnInitialized, 42, sizeof(UsefulInputBuf));
 
    UsefulOutBuf_Init(&UOB, outbuf);
 
@@ -284,26 +287,31 @@
       return "insert with data should have failed";
    }
 
+   UsefulOutBuf_InsertString(&UOB_UnInitialized, "abc123", 0);
+   if(!UsefulOutBuf_GetError(&UOB_UnInitialized)) {
+      return "InsertString failed uninit detect";
+   }
+
    UsefulOutBuf_Init(&UOB, outBuf2);
    UsefulOutBuf_AppendString(&UOB, "abc123");
 
-   UsefulBufC Out = UsefulOutBuf_SubString(&UOB, 7, 1);
+   UsefulBufC Out = UsefulOutBuf_OutSubString(&UOB, 7, 1);
    if(!UsefulBuf_IsNULLC(Out)) {
       return "SubString start should fail off end 1";
    }
-   Out = UsefulOutBuf_SubString(&UOB, 5, 3);
+   Out = UsefulOutBuf_OutSubString(&UOB, 5, 3);
    if(!UsefulBuf_IsNULLC(Out)) {
       return "SubString len should fail off end 2";
    }
-   Out = UsefulOutBuf_SubString(&UOB, 0, 7);
+   Out = UsefulOutBuf_OutSubString(&UOB, 0, 7);
    if(!UsefulBuf_IsNULLC(Out)) {
       return "SubString len should fail off end 3";
    }
-   Out = UsefulOutBuf_SubString(&UOB, 7, 0);
+   Out = UsefulOutBuf_OutSubString(&UOB, 7, 0);
    if(!UsefulBuf_IsNULLC(Out)) {
       return "SubString len should fail off end 4";
    }
-   Out = UsefulOutBuf_SubString(&UOB, 6, 1);
+   Out = UsefulOutBuf_OutSubString(&UOB, 6, 1);
    if(!UsefulBuf_IsNULLC(Out)) {
       return "SubString len should fail off end 5";
    }
@@ -313,6 +321,17 @@
    if(UsefulOutBuf_GetError(&UOB)) {
       return "insert in huge should have succeeded";
    }
+   UsefulOutBuf_Init(&UOB, outBuf2);
+   Out = UsefulOutBuf_OutSubString(&UOB, 0, 1);
+   if(!UsefulBuf_IsNULLC(Out)) {
+      return "SubString len should fail off end 5";
+   }
+   Out = UsefulOutBuf_OutSubString(&UOB_UnInitialized, 0, 1);
+   if(!UsefulBuf_IsNULLC(Out)) {
+      return "SubString failed uninit detect";
+   }
+
+
 
    UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
    UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -5);
@@ -1091,13 +1110,18 @@
 const char * UOBExtraTests(void)
 {
    #define COMPARE_TEST_SIZE 10
-   UsefulOutBuf_MakeOnStack( UOB, COMPARE_TEST_SIZE);
+   UsefulOutBuf_MakeOnStack( UOB, COMPARE_TEST_SIZE); /* includes initialization */
    int                       nCompare;
    UsefulBufC                Out;
+   UsefulOutBuf              UOB_UnInitialized;
 
-   /* Test UsefulOutBuf_Compare() */
+   /* For test detection of uninitlized UOB (wrong magic number) */
+   memset(&UOB_UnInitialized, 42, sizeof(UsefulInputBuf));
+
+   /* --- Test UsefulOutBuf_Compare() --- */
    UsefulOutBuf_AppendString(&UOB, "abcabdefab");
 
+   /* Tests of equal length, not off the end. */
    nCompare = UsefulOutBuf_Compare(&UOB, 0, 2, 8, 2);
    if(nCompare != 0) {
       return "ab should compare equal";
@@ -1108,6 +1132,11 @@
       return "abc should not equal abd";
    }
 
+   nCompare = UsefulOutBuf_Compare(&UOB, 3, 3, 0, 3);
+   if(nCompare !=  'c' - 'd') {
+      return "abd should not equal abc";
+   }
+
    nCompare = UsefulOutBuf_Compare(&UOB, 3, 2, 8, 2);
    if(nCompare != 0) {
        return "ab should compare equal";
@@ -1138,41 +1167,94 @@
       return "b should compare equal to b";
    }
 
+   /* Tests off end */
    nCompare = UsefulOutBuf_Compare(&UOB, 10, 1, 10, 1);
    if(nCompare != 0) {
-      return "Comparison off the end is equal";
+      return "Comparison off the end is not equal";
    }
 
    nCompare = UsefulOutBuf_Compare(&UOB, 0, 1, 100, 1);
-   if(nCompare != 0) {
-      return "Comparison off the end is equal";
+   if(nCompare != -1) {
+      return "Comparison off end fail 1";
    }
 
    nCompare = UsefulOutBuf_Compare(&UOB, 100, 1, 0, 1);
-   if(nCompare != 0) {
-      return "Comparison off the end is equal";
+   if(nCompare != 1) {
+      return "Comparison off end fail 2";
    }
 
+   nCompare = UsefulOutBuf_Compare(&UOB, 8, 3, 0, 3);
+   if(nCompare != 1) {
+      return "Comparison off end fail 3";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 3, 8, 3);
+   if(nCompare != -1) {
+      return "Comparison off end fail 4";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 10, 1, 5, 1);
+   if(nCompare != 1) {
+      return "Comparison off end fail 5";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 5, 1, 10, 1);
+   if(nCompare != -1) {
+      return "Comparison off end fail 6";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 8, 3, 0, 2);
+   if(nCompare != 0) {
+      return "Comparison off end fail 7";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 2, 8, 100);
+   if(nCompare != 0) {
+      return "Comparison off end fail 8";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 0, 0, 0);
+   if(nCompare != 0) {
+      return "Empty compare failed";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 1, 1, 9, 3);
+   if(nCompare != 0) {
+      return "Unequal lengths, off end";
+   }
+
+   /* Tests of unequal lengths */
    nCompare = UsefulOutBuf_Compare(&UOB, 0, 3, 3, 2);
-   if(nCompare > 0) {
+   if(nCompare >= 0) {
       return "Comparison of unequal lengths incorrect";
    }
 
    nCompare = UsefulOutBuf_Compare(&UOB, 8, 2, 0, 3);
-   if(nCompare < 0) {
+   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";
+      return "Unequal lengths, unequal strings";
    }
 
    nCompare = UsefulOutBuf_Compare(&UOB, 1, 3, 4, 2);
    if(nCompare != 'd' - 'c') {
-      return "Inequal lengths, but inequal strings";
+      return "Unequal lengths, unequal strings";
    }
 
+   nCompare = UsefulOutBuf_Compare(&UOB, 7, 0, 7, 1);
+   if(nCompare != 1) {
+      return "zero length unequal length compare";
+   }
+
+   nCompare = UsefulOutBuf_Compare(&UOB, 0, 8, 3, 5);
+   if(nCompare != 'd' - 'c') {
+      return "another unequal length compare";
+   }
+
+
    /* Test UsefulOutBuf_Swap() */
 
    UsefulOutBuf_Reset(&UOB);
@@ -1286,5 +1368,10 @@
       return "GetOutput fail 5";
    }
 
+   Out = UsefulOutBuf_OutUBufOffset(&UOB_UnInitialized, 1);
+   if(!UsefulBuf_IsNULLC(Out)) {
+      return "GetOutput fail 7";
+   }
+
    return NULL;
 }
diff --git a/test/float_tests.c b/test/float_tests.c
index f32d181..d36ef61 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -323,12 +323,17 @@
     {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
     {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
 
+   /* -18446744073709551616.0 -- largest that encodes into negative uint64 (65-bit neg) */
+   {-18446744073709551616.0,                     -18446744073709551616.0f,
+    {"\xFA\xDF\x80\x00\x00",                 5}, {"\xFB\xC3\xF0\x00\x00\x00\x00\x00\x00", 9},
+    {"\xFA\xDF\x80\x00\x00",                 5}, {"\x3B\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
+
    /* List terminator */
    {0.0, 0.0f, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
 };
 
 
-/* Can't use types double and float here because there's no way in C to
+/* Can't use the types double and float here because there's no way in C to
  * construct arbitrary payloads for those types.
  */
 struct NaNTestCase {
@@ -416,7 +421,7 @@
    for(uTestIndex = 0; FloatTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
       pTestCase = &FloatTestCases[uTestIndex];
 
-      if(uTestIndex == 2) {
+      if(uTestIndex == 48) {
          uDecoded = 1;
       }
 
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 8b77a11..af5b124 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -1080,6 +1080,27 @@
       }
    }
 
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   QCBORError uExpectedErr = QCBOR_ERR_NOT_PREFERRED;
+#else
+   QCBORError uExpectedErr = QCBOR_SUCCESS;
+#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+   /* Test failure for attempting non-prefered serialiation */
+   QCBOREncode_Init(&Enc, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_Config(&Enc, QCBOR_ENCODE_CONFIG_ONLY_PREFERRED_BIG_NUMBERS);
+   QCBOREncode_AddTBigNumberRaw(&Enc, QCBOR_ENCODE_AS_TAG, false, UsefulBuf_FROM_SZ_LITERAL("\x00"));
+   if(QCBOREncode_GetErrorState(&Enc) != uExpectedErr) {
+      return -1;
+   }
+
+   QCBOREncode_Init(&Enc, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+   QCBOREncode_Config(&Enc, QCBOR_ENCODE_CONFIG_ONLY_PREFERRED_BIG_NUMBERS);
+   QCBOREncode_AddTBigNumberNoPreferred(&Enc, QCBOR_ENCODE_AS_TAG, false, UsefulBuf_FROM_SZ_LITERAL("\x00"));
+   if(QCBOREncode_GetErrorState(&Enc) != uExpectedErr) {
+      return -2;
+   }
+
    return 0;
 }
 
@@ -3532,6 +3553,85 @@
 }
 
 
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+
+struct SortTest {
+   const char *szDescription;
+   UsefulBufC  ToBeSorted;
+   UsefulBufC  Sorted;
+   QCBORError  uError;
+};
+
+static const struct SortTest sSortTests[] =
+{
+   {
+      "Simple Sort Test",
+      {"\x03\x03\x01\x01\x04\x04\x02\x02", 8},
+      {"\xBF\x01\x01\x02\x02\x03\x03\x04\x04\xFF", 10},
+      QCBOR_SUCCESS
+   },
+
+   {
+      "Not well formed label",
+      {"\x1c\x03\x01\x01\x04\x04\x02\x02", 8},
+      NULLUsefulBufC,
+      QCBOR_ERR_UNSUPPORTED
+   },
+
+   {
+      "Not well formed value",
+      {"\x03\x1c\x01\x01\x04\x04\x02\x02", 8},
+      NULLUsefulBufC,
+      QCBOR_ERR_UNSUPPORTED
+   },
+
+   {
+      "Not well formed label at end",
+      {"\x03\x03\x01\x01\x04\x04\x1c\x02", 8},
+      NULLUsefulBufC,
+      QCBOR_ERR_UNSUPPORTED
+   },
+
+   {
+      "Extraneous break",
+      {"\x03\x03\x01\x01\x04\xff\x02\x02", 8},
+      NULLUsefulBufC,
+      QCBOR_ERR_HIT_END
+   },
+
+   {
+      "Off end",
+      {"\x03\x03\x01\x01\x04\x04\x02\x6f\x68\x69", 10},
+      NULLUsefulBufC,
+      QCBOR_ERR_HIT_END
+   },
+
+   {
+      "Indef string chunk in error",
+      {"\x03\x03\x5f\x61\x68\x1c\xff\x01\x04\x04\x02\x02", 12},
+      NULLUsefulBufC,
+      QCBOR_ERR_UNSUPPORTED
+   },
+
+   {
+      "All sorts of labels",
+      {"\x81\x00\x03\xFB\x40\x09\x1E\xB8\x51\xEB\x85\x1F\x01\xf4\x04\xa2"
+       "\x05\x05\x06\x06\x02\xc1\x38\xff\x05\x81\x01\x06\x81\x20\x07\x19"
+       "\x00\x01\x08", 35},
+      {"\xBF\x19\x00\x01\x08\x81\x00\x03\x81\x01\x06\x81\x20\x07\xA2\x05"
+       "\x05\x06\x06\x02\xC1\x38\xFF\x05\xF4\x04\xFB\x40\x09\x1E\xB8\x51"
+       "\xEB\x85\x1F\x01\xFF", 37},
+      QCBOR_SUCCESS
+   },
+
+   {
+      NULL,
+      NULLUsefulBufC,
+      NULLUsefulBufC,
+      QCBOR_SUCCESS
+   }
+};
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
 
 int32_t
 SortMapTest(void)
@@ -3542,6 +3642,44 @@
    QCBORError                 uErr;
    struct UBCompareDiagnostic CompareDiagnostics;
 
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+
+   for(int nIndex = 0; ; nIndex++) {
+      const struct SortTest *pTest = &sSortTests[nIndex];
+
+      if(pTest->szDescription == NULL) {
+         break;
+      }
+
+      if(nIndex == 7) {
+         uErr = 0; /* For break point */
+      }
+
+      QCBOREncode_Init(&EC, TestBuf);
+      /* Have to use indefinite length map to make test work */
+      QCBOREncode_OpenMapIndefiniteLength(&EC);
+      /* Violating layering here to be able to make test work.
+       * In particular to test error handling when the CBOR
+       * being sorted is not well formed. That should never happen
+       * but it needs to be tested for code safety.
+       */
+      UsefulOutBuf_AppendUsefulBuf(&(EC.OutBuf), pTest->ToBeSorted);
+      QCBOREncode_CloseAndSortMapIndef(&EC);
+      uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+      if(uErr != pTest->uError) {
+         return MakeTestResultCode((uint32_t)nIndex, 0, uErr);
+      }
+
+      if(uErr == QCBOR_SUCCESS && !UsefulBuf_IsNULLC(pTest->Sorted)) {
+         if(UsefulBuf_Compare(pTest->Sorted, EncodedAndSorted)) {
+            return MakeTestResultCode((uint32_t)nIndex, 1, uErr);
+
+         }
+      }
+   }
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+   // TODO: Move most of the tests below into sSortTests
+
 
    /* --- Basic sort test case --- */
    QCBOREncode_Init(&EC, TestBuf);
@@ -4086,12 +4224,10 @@
    QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
    QCBOREncode_Config(&EC, QCBOR_ENCODE_CONFIG_DCBOR);
    QCBOREncode_AddUndef(&EC);
-   QCBOREncode_CloseMap(&EC);
    if(QCBOREncode_GetErrorState(&EC) != uExpectedErr) {
       return 102;
    }
 
-
    /* Improvement: when indefinite length string encoding is supported
     * test it here too. */