Duplicate map label detection for encoding (#209)
This adds duplicate map label detection during encoding as part of sorting.
There was a lot of rework of map sorting.
UsefulOutBuf_Compare() was changed to behave differently and more universally.
* Duplicate detection for encoding
* rework UsefulOutBuf_Compare and test
* Dup detection seems to be working
* Final tidy-up
---------
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index e6be249..13e87e3 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2023, Laurence Lundblade.
+ Copyright (c) 2018-2024, Laurence Lundblade.
Copyright (c) 2021, Arm Limited.
All rights reserved.
@@ -885,61 +885,81 @@
/* Test UsefulOutBuf_Compare() */
UsefulOutBuf_AppendString(&UOB, "abcabdefab");
- nCompare = UsefulOutBuf_Compare(&UOB, 0, 8);
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 2, 8, 2);
if(nCompare != 0) {
return "ab should compare equal";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 0, 3);
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 3, 3, 3);
if(nCompare != 'd' - 'c') {
return "abc should not equal abd";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 3, 8);
+ nCompare = UsefulOutBuf_Compare(&UOB, 3, 2, 8, 2);
if(nCompare != 0) {
return "ab should compare equal";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 2, 5);
+ nCompare = UsefulOutBuf_Compare(&UOB, 2, 4, 5, 4);
if(nCompare != 'd' - 'c') {
return "ca should not equal de";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 5, 2);
+ nCompare = UsefulOutBuf_Compare(&UOB, 5, 1, 2, 1);
if(nCompare != 'c' - 'd') {
return "de should not equal ca";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 7, 8);
+ nCompare = UsefulOutBuf_Compare(&UOB, 7, 2, 8, 2);
if(nCompare != 'a' - 'f') {
return "fa should not equal ab";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 0, 0);
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 10, 0, 10);
if(nCompare != 0) {
return "comparison to self failed";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 9, 9);
+ nCompare = UsefulOutBuf_Compare(&UOB, 9, 1, 9, 1);
if(nCompare != 0) {
return "b should compare equal to b";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 10, 10);
+ nCompare = UsefulOutBuf_Compare(&UOB, 10, 1, 10, 1);
if(nCompare != 0) {
return "Comparison off the end is equal";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 0, 100);
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 1, 100, 1);
if(nCompare != 0) {
return "Comparison off the end is equal";
}
- nCompare = UsefulOutBuf_Compare(&UOB, 100, 0);
+ 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);
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 7594006..118b232 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -3196,7 +3196,24 @@
if(uErr) {
return 31;
}
- static const uint8_t spNested[] = {
+
+ /* Correctly sorted.
+ * {
+ * 88: 1(888888),
+ * 428: {
+ * "null": null,
+ * "array": [
+ * "hi",
+ * "there"
+ * ],
+ * "empty1": {},
+ * "empty2": {}
+ * },
+ * "boo": true,
+ * "three": 3
+ * }
+ */
+ static const uint8_t spSorted[] = {
0xA4, 0x18, 0x58, 0xC1, 0x1A, 0x00, 0x0D, 0x90,
0x38, 0x19, 0x01, 0xAC, 0xA4, 0x64, 0x6E, 0x75,
0x6C, 0x6C, 0xF6, 0x65, 0x61, 0x72, 0x72, 0x61,
@@ -3207,11 +3224,72 @@
0x65, 0x74, 0x68, 0x72, 0x65, 0x65, 0x03};
if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
- UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested),
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSorted),
&CompareDiagnostics)) {
return 32;
}
+
+ /* Same data items, but added in a different order */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMap(&EC, "three", 3);
+ QCBOREncode_OpenMapInMapN(&EC, 428);
+ QCBOREncode_OpenMapInMap(&EC, "empty1");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_OpenArrayInMap(&EC, "array");
+ QCBOREncode_AddSZString(&EC, "hi");
+ QCBOREncode_AddSZString(&EC, "there");
+ QCBOREncode_CloseArray(&EC);
+ QCBOREncode_OpenMapInMap(&EC, "empty2");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_AddNULLToMap(&EC, "null");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_AddDateEpochToMapN(&EC, 88, 888888);
+ QCBOREncode_AddBoolToMap(&EC, "boo", true);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 31;
+ }
+
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSorted),
+ &CompareDiagnostics)) {
+ return 32;
+ }
+
+ /* Same data items, but added in a different order */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddBoolToMap(&EC, "boo", true);
+ QCBOREncode_OpenMapInMapN(&EC, 428);
+ QCBOREncode_OpenMapInMap(&EC, "empty1");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_OpenArrayInMap(&EC, "array");
+ QCBOREncode_AddSZString(&EC, "hi");
+ QCBOREncode_AddSZString(&EC, "there");
+ QCBOREncode_CloseArray(&EC);
+ QCBOREncode_OpenMapInMap(&EC, "empty2");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_AddNULLToMap(&EC, "null");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_AddDateEpochToMapN(&EC, 88, 888888);
+ QCBOREncode_AddInt64ToMap(&EC, "three", 3);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 31;
+ }
+
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSorted),
+ &CompareDiagnostics)) {
+ return 32;
+ }
+
+
+
/* --- Degenerate case of everything in order --- */
QCBOREncode_Init(&EC, TestBuf);
QCBOREncode_OpenMap(&EC);
@@ -3429,6 +3507,44 @@
return 102;
}
+
+ /* --- Duplicate label test --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMapN(&EC, 3, 3);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr != QCBOR_ERR_DUPLICATE_LABEL) {
+ return 114;
+ }
+
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMapN(&EC, 3, 3);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 2);
+ QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr != QCBOR_ERR_DUPLICATE_LABEL) {
+ return 115;
+ }
+
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMap(&EC, "abc", 3);
+ QCBOREncode_AddInt64ToMap(&EC, "def", 1);
+ QCBOREncode_AddInt64ToMap(&EC, "def", 1);
+ QCBOREncode_AddInt64ToMap(&EC, "def", 2);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr != QCBOR_ERR_DUPLICATE_LABEL) {
+ return 116;
+ }
+
return 0;
}