From a64be28f757d96cc9e90689275c012f7d2f12839 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 03:40:19 +0000 Subject: [PATCH 01/24] chore: eliminate [in/out] parameters --- CMakeLists.txt | 2 + n_helpers.c | 186 +++++++++++++------- note.h | 12 +- test/CMakeLists.txt | 5 + test/src/NoteBinaryDecode_test.cpp | 22 +-- test/src/NoteBinaryEncode_test.cpp | 22 +-- test/src/NoteBinaryReceiveRange_test.cpp | 202 +++++++++++++++++++++ test/src/NoteBinaryReceive_test.cpp | 212 +++++++---------------- test/src/NoteBinaryTransmit_test.cpp | 4 +- 9 files changed, 434 insertions(+), 233 deletions(-) create mode 100644 test/src/NoteBinaryReceiveRange_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c1dba13..36fb4659 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,8 @@ target_compile_options( -Wextra -Wpedantic -Werror + -Og + -ggdb ) target_include_directories( note_c diff --git a/n_helpers.c b/n_helpers.c index 28ef2178..777739c7 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -91,7 +91,7 @@ static const char BINARY_EOP = '\n'; @brief Get the length of the data stored on the Notecard. If there's no data stored on the Notecard, then `*len` will return 0. - @param len [out] the length of the decoded contents of the Notecard's binary + @param len [out] The length of the decoded contents of the Notecard's binary data store. @returns An error string on error and NULL on success. @@ -135,9 +135,9 @@ const char * NoteBinaryDataDecodedLength(uint32_t *len) @brief Get the required buffer length to receive the entire binary object stored on the Notecard. - @param len [out] the length required to hold the entire contents of the + @param len [out] The length required to hold the entire contents of the Notecard's binary data store. If there's no data stored on the - Notecard, then `*len` will return 0. + Notecard, then `len` will return 0. @returns An error string on error and NULL on success. */ @@ -226,26 +226,30 @@ const char * NoteBinaryDataReset(void) @param inLen The length of the binary payload. @param outBuf The buffer to write the decoded payload to. This can be the same address as inBuf, allowing for in-place decoding. - @param outLen On input, holds the length of outBuf. On output, holds the - length of the decoded data. + @param outLen The length of outBuf. + @param decLen [out] The length of the decoded data. @returns NULL on success, else an error string pointer. + + @note When in-place decoding, the overall length shrinks and the + decoded data will be left-justified in the buffer. */ /**************************************************************************/ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen) + uint8_t *outBuf, uint32_t outLen, + uint32_t *decLen) { - if (inBuf == NULL || outBuf == NULL || outLen == NULL) { + if (inBuf == NULL || outBuf == NULL || decLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); return ERRSTR("NULL parameter", c_err); } - if (*outLen < cobsGuaranteedFit(inLen)) { + if (outLen < cobsGuaranteedFit(inLen)) { NOTE_C_LOG_ERROR("output buffer too small"); return ERRSTR("output buffer too small", c_err); } - *outLen = cobsDecode((uint8_t *)inBuf, inLen, BINARY_EOP, outBuf); + *decLen = cobsDecode((uint8_t *)inBuf, inLen, BINARY_EOP, outBuf); return NULL; } @@ -259,28 +263,33 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, @param inLen The length of the data to encode. @param outBuf The buffer to write the encoded data to. This can be the same address as inBuf, allowing for in-place encoding. - @param outLen On input, holds the length of outBuf. On output, holds the - length of the encoded data. + @param outLen The length of outBuf. + @param encLen [out] The length of the encoded data. @returns NULL on success, else an error string pointer. + + @note When in-place encoding, the overall length expands. Therefore, the + unencoded data should first be right-justified in the buffer, then the + value of `outBuf` should be set to the beginning of the buffer. */ /**************************************************************************/ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen) + uint8_t *outBuf, uint32_t outLen, + uint32_t *encLen) { - if (inBuf == NULL || outBuf == NULL || outLen == NULL) { + if (inBuf == NULL || outBuf == NULL || encLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); return ERRSTR("NULL parameter", c_err); } - if (*outLen < cobsEncodedMaxLength(inLen)) { - if (*outLen < cobsEncodedLength(inBuf, inLen)) { + if (outLen < cobsEncodedMaxLength(inLen)) { + if (outLen < cobsEncodedLength(inBuf, inLen)) { NOTE_C_LOG_ERROR("output buffer too small"); return ERRSTR("output buffer too small", c_err); } } - *outLen = cobsEncode((uint8_t *)inBuf, inLen, BINARY_EOP, outBuf); + *encLen = cobsEncode((uint8_t *)inBuf, inLen, BINARY_EOP, outBuf); return NULL; } @@ -335,15 +344,61 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) /*! @brief Receive a large binary object from the Notecard's binary buffer - @param buffer A buffer to hold the binary object - @param bufLen The total length of the provided buffer + @param buffer A buffer to hold the binary object + @param bufLen The total length of the provided buffer + @param dataLen [out] The length of the decoded data received from the + Notecard. + + @returns NULL on success, else an error string pointer. + + @note The buffer must be large enough to hold the encoded value of the + data store contents from the requested offset for the specified length. + To determine the necessary buffer size the Notecard's binary data, use + `NoteBinaryDataEncodedLength()`. + */ +/**************************************************************************/ +const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, + uint32_t *dataLen) +{ + const char *err = NULL; + uint32_t decodedLen = 0; + + // Validate parameter(s) + if (!buffer) { + err = ERRSTR("NULL buffer", c_bad); + NOTE_C_LOG_ERROR(err); + } + else if (!dataLen) { + err = ERRSTR("NULL dataLen not allowed", c_bad); + NOTE_C_LOG_ERROR(err); + } + else { + // Calculate the data length available on the Notecard + if ((err = NoteBinaryDataDecodedLength(&decodedLen))) { + decodedLen = 0; + } + // Request entire binary data store from Notecard + else if ((err = NoteBinaryReceiveRange(buffer, bufLen, 0, decodedLen))) { + decodedLen = 0; + } + + // Populate `dataLen` if available + *dataLen = decodedLen; + } + + return err; +} + +//**************************************************************************/ +/*! + @brief Receive a large binary range from the Notecard's binary buffer + + @param buffer A buffer to hold the binary range + @param bufLen The total length of the provided buffer @param decodedOffset The offset to the decoded binary data already residing on the Notecard - @param decodedLen [in/out] The length of the decoded data to fetch from the - Notecard. If you wish to fetch the entire buffer from the - given offset, set this value to `NOTE_C_BINARY_RX_ALL`. - This parameter will return the bytes actually received from - the Notecard. + @param decodedLen The length of the decoded data to fetch from the + Notecard. @returns NULL on success, else an error string pointer. @@ -354,21 +409,25 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) entire buffer use `NoteBinaryDataEncodedLength()` instead. */ /**************************************************************************/ -const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, - uint32_t decodedOffset, uint32_t * decodedLen) +const char * NoteBinaryReceiveRange(uint8_t *buffer, uint32_t bufLen, + uint32_t decodedOffset, + uint32_t decodedLen) { // Validate parameter(s) if (!buffer) { - NOTE_C_LOG_ERROR("NULL buffer"); - return ERRSTR("NULL buffer", c_err); + const char *err = ERRSTR("NULL buffer", c_bad); + NOTE_C_LOG_ERROR(err); + return err; } - if (!decodedLen) { - NOTE_C_LOG_ERROR("decodedLen cannot be NULL"); - return ERRSTR("decodedLen cannot be NULL", c_err); + if (bufLen < (cobsEncodedMaxLength(decodedLen) + 1)) { + const char *err = ERRSTR("insufficient buffer size", c_bad); + NOTE_C_LOG_ERROR(err); + return err; } - if (bufLen < (cobsEncodedMaxLength(*decodedLen) + 1)) { - NOTE_C_LOG_ERROR("insufficient buffer size"); - return ERRSTR("insufficient buffer size", c_err); + if (decodedLen == 0) { + const char *err = ERRSTR("decodedLen cannot be zero (0)", c_bad); + NOTE_C_LOG_ERROR(err); + return err; } // Claim Notecard Mutex @@ -379,25 +438,27 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, J *req = NoteNewRequest("card.binary.get"); if (req) { JAddIntToObject(req, "offset", decodedOffset); - JAddIntToObject(req, "length", *decodedLen); + JAddIntToObject(req, "length", decodedLen); // Ensure the transaction doesn't return an error. J *rsp = NoteRequestResponse(req); if (NoteResponseError(rsp)) { NOTE_C_LOG_ERROR(JGetString(rsp,"err")); JDelete(rsp); - NOTE_C_LOG_ERROR("failed to initialize binary transaction"); + const char *err = ERRSTR("failed to initialize binary transaction", c_err); + NOTE_C_LOG_ERROR(err); _UnlockNote(); - return ERRSTR("failed to initialize binary transaction", c_err); + return err; } // Examine "status" from the response to evaluate the MD5 checksum. strlcpy(status, JGetString(rsp,"status"), NOTE_MD5_HASH_STRING_SIZE); JDelete(rsp); } else { - NOTE_C_LOG_ERROR("unable to allocate request"); + const char *err = ERRSTR("unable to allocate request", c_mem); + NOTE_C_LOG_ERROR(err); _UnlockNote(); - return ERRSTR("unable to allocate request", c_mem); + return err; } // Read raw bytes from the active interface into a predefined buffer @@ -414,8 +475,9 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, // Check buffer overflow condition if (available) { - NOTE_C_LOG_ERROR("unexpected data available"); - return ERRSTR("unexpected data available", c_err); + const char *err = ERRSTR("unexpected data available", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // _ChunkedReceive returns the raw bytes that came off the wire, which @@ -423,14 +485,18 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, // part of the binary payload, so we decrement the length by 1 to remove it. --bufLen; - uint32_t decLen = bufLen; + uint32_t decLen = 0; // Decode it in place, which is safe because decoding shrinks - err = NoteBinaryDecode(buffer, bufLen, buffer, &decLen); + err = NoteBinaryDecode(buffer, bufLen, buffer, bufLen, &decLen); if (err) { return err; } - // Return the decoded length in the decodedLen out parameter. - *decodedLen = decLen; + // Ensure the decoded length matches the caller's expectations. + if (decodedLen != decLen) { + const char *err = ERRSTR("length mismatch after decoding", c_err); + NOTE_C_LOG_ERROR(err); + return err; + } // Put a hard marker at the end of the decoded portion of the buffer. This // enables easier human reasoning when interrogating the buffer, if the @@ -441,8 +507,9 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, char hashString[NOTE_MD5_HASH_STRING_SIZE] = {0}; NoteMD5HashString(buffer, decLen, hashString, NOTE_MD5_HASH_STRING_SIZE); if (strncmp(hashString, status, NOTE_MD5_HASH_STRING_SIZE)) { - NOTE_C_LOG_ERROR("computed MD5 does not match received MD5"); - return ERRSTR("computed MD5 does not match received MD5", c_err); + const char *err = ERRSTR("computed MD5 does not match received MD5", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Return `NULL` if success, else error string pointer @@ -534,13 +601,16 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, const uint32_t dataShift = (bufLen - unencodedLen); memmove(unencodedData + dataShift, unencodedData, unencodedLen); - // `encLen` holds the buffer size available for encoding. The `- 1` accounts - // for one byte of space we need to save for a newline to mark the end of - // the packet. When `NoteBinaryEncode()` returns, `encLen` will hold the - // encoded length. - uint32_t encLen = (bufLen - 1); + // Create an alias to help reason about the buffer after in-place encoding. uint8_t * const encodedData = unencodedData; - err = NoteBinaryEncode(unencodedData + dataShift, unencodedLen, encodedData, &encLen); + + // Update unencoded data pointer + unencodedData += dataShift; + uint32_t encLen = 0; + + // `(bufLen - 1)` accounts for one byte of space we need to save for a + // newline to mark the end of the packet. + err = NoteBinaryEncode(unencodedData, unencodedLen, encodedData, (bufLen - 1), &encLen); if (err) { return err; } @@ -569,13 +639,13 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // On errors, we restore the caller's input buffer by COBS // decoding it. The caller is then able to retry transmission // with their original pointer to this buffer. - NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); + NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); return ERRSTR("failed to initialize binary transaction", c_err); } } else { NOTE_C_LOG_ERROR("unable to allocate request"); _UnlockNote(); - NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); + NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); return ERRSTR("unable to allocate request", c_mem); } @@ -587,7 +657,7 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // Ensure transaction was successful if (err) { - NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); + NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); return ERRSTR(err, c_err); } @@ -595,7 +665,7 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { NOTE_C_LOG_ERROR("unable to validate request"); - NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); + NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); return ERRSTR("unable to validate request", c_err); } @@ -611,13 +681,13 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, continue; } NOTE_C_LOG_ERROR("binary data invalid"); - NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); + NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); return ERRSTR("binary data invalid", c_bad); } else { JDelete(rsp); NOTE_C_LOG_ERROR("unexpected error received during " "confirmation"); - NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); + NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); return ERRSTR("unexpected error received during confirmation", c_bad); } diff --git a/note.h b/note.h index e78757c9..0e1c9192 100644 --- a/note.h +++ b/note.h @@ -317,18 +317,22 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen // High-level helper functions that are both useful and serve to show developers // how to call the API -#define NOTE_C_BINARY_RX_ALL 0 const char * NoteBinaryDataDecodedLength(uint32_t *len); const char * NoteBinaryDataEncodedLength(uint32_t *len); const char * NoteBinaryDataReset(void); const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); + uint8_t *outBuf, uint32_t outLen, + uint32_t *decLen); const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); + uint8_t *outBuf, uint32_t outLen, + uint32_t *encLen); uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, - uint32_t decodedOffset, uint32_t *decodedLen); + uint32_t *dataLen); +const char * NoteBinaryReceiveRange(uint8_t *buffer, uint32_t bufLen, + uint32_t decodedOffset, + uint32_t decodedLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, uint32_t bufLen, uint32_t notecardOffset); uint32_t NoteSetSTSecs(uint32_t secs); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3b621ef1..f3e6023b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,6 +46,10 @@ macro(add_test TEST_NAME) PRIVATE note_c PRIVATE Catch2::Catch2WithMain ) + target_compile_options(${TEST_NAME} + PRIVATE -Og + PRIVATE -ggdb + ) list(APPEND TEST_TARGETS ${TEST_NAME}) @@ -152,6 +156,7 @@ add_test(NoteBinaryEncode_test) add_test(NoteBinaryMaxEncodedLength_test) add_test(NoteBinaryMaxDecodedLength_test) add_test(NoteBinaryReceive_test) +add_test(NoteBinaryReceiveRange_test) add_test(NoteBinaryTransmit_test) if(NOTE_C_COVERAGE) diff --git a/test/src/NoteBinaryDecode_test.cpp b/test/src/NoteBinaryDecode_test.cpp index 0dee3060..0453a6d5 100644 --- a/test/src/NoteBinaryDecode_test.cpp +++ b/test/src/NoteBinaryDecode_test.cpp @@ -22,9 +22,10 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(uint32_t, cobsDecode, uint8_t *, uint32_t, uint8_t, uint8_t *) uint8_t inBuf[12]; -uint32_t inLen; +const uint32_t inLen = sizeof(inBuf); uint8_t outBuf[10]; -uint32_t outLen; +const uint32_t outLen = sizeof(outBuf); +uint32_t decLen; namespace { @@ -32,26 +33,25 @@ namespace SCENARIO("NoteBinaryDecode") { RESET_FAKE(cobsDecode); - uint32_t inLen = sizeof(inBuf); - uint32_t outLen = sizeof(outBuf); + decLen = 0; GIVEN("Bad parameters are supplied") { WHEN("inBuf is NULL") { - const char *err = NoteBinaryDecode(NULL, inLen, outBuf, &outLen); + const char *err = NoteBinaryDecode(NULL, inLen, outBuf, outLen, &decLen); THEN("An error is returned") { CHECK(err != NULL); } } WHEN("outBuf is NULL") { - const char *err = NoteBinaryDecode(inBuf, inLen, NULL, &outLen); + const char *err = NoteBinaryDecode(inBuf, inLen, NULL, outLen, &decLen); THEN("An error is returned") { CHECK(err != NULL); } } - WHEN("outLen is NULL") { - const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, NULL); + WHEN("decLen is NULL") { + const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, outLen, NULL); THEN("An error is returned") { CHECK(err != NULL); @@ -59,7 +59,7 @@ SCENARIO("NoteBinaryDecode") } WHEN("outLen is less than the size required for the worst-case decoding") { uint32_t badOutLen = (cobsGuaranteedFit(inLen) - 1); - const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, &badOutLen); + const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, badOutLen, &decLen); THEN("An error is returned") { CHECK(err != NULL); @@ -70,7 +70,7 @@ SCENARIO("NoteBinaryDecode") GIVEN("Parameters are in order") { const uint32_t EXPECTED_RESULT = 79; cobsDecode_fake.return_val = EXPECTED_RESULT; - const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, &outLen); + const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, outLen, &decLen); THEN("cobsDecode is invoked") { CHECK(cobsDecode_fake.call_count > 0); @@ -84,7 +84,7 @@ SCENARIO("NoteBinaryDecode") } THEN("The result is returned without modification") { - CHECK(EXPECTED_RESULT == outLen); + CHECK(EXPECTED_RESULT == decLen); } } } diff --git a/test/src/NoteBinaryEncode_test.cpp b/test/src/NoteBinaryEncode_test.cpp index cc29822f..f400952b 100644 --- a/test/src/NoteBinaryEncode_test.cpp +++ b/test/src/NoteBinaryEncode_test.cpp @@ -24,9 +24,10 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(uint32_t, cobsEncode, uint8_t *, uint32_t, uint8_t, uint8_t *) uint8_t inBuf[10] = "Hi there!"; -uint32_t inLen; +uint32_t inLen = strlen((const char *)inBuf); uint8_t outBuf[12]; -uint32_t outLen; +uint32_t outLen = sizeof(outBuf); +uint32_t encLen; namespace { @@ -34,26 +35,25 @@ namespace SCENARIO("NoteBinaryEncode") { RESET_FAKE(cobsEncode); - uint32_t inLen = strlen((const char *)inBuf); - uint32_t outLen = sizeof(outBuf); + encLen = 0; GIVEN("Bad parameters are supplied") { WHEN("inBuf is NULL") { - const char *err = NoteBinaryEncode(NULL, inLen, outBuf, &outLen); + const char *err = NoteBinaryEncode(NULL, inLen, outBuf, outLen, &encLen); THEN("An error is returned") { CHECK(err != NULL); } } WHEN("outBuf is NULL") { - const char *err = NoteBinaryEncode(inBuf, inLen, NULL, &outLen); + const char *err = NoteBinaryEncode(inBuf, inLen, NULL, outLen, &encLen); THEN("An error is returned") { CHECK(err != NULL); } } - WHEN("outLen is NULL") { - const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, NULL); + WHEN("encLen is NULL") { + const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, outLen, NULL); THEN("An error is returned") { CHECK(err != NULL); @@ -61,7 +61,7 @@ SCENARIO("NoteBinaryEncode") } WHEN("outLen is less than the size required for in place encoding") { uint32_t badOutLen = (cobsEncodedLength(inBuf, inLen) - 1); - const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, &badOutLen); + const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, badOutLen, &encLen); THEN("An error is returned") { CHECK(err != NULL); @@ -72,7 +72,7 @@ SCENARIO("NoteBinaryEncode") GIVEN("Parameters are in order") { const uint32_t EXPECTED_RESULT = 79; cobsEncode_fake.return_val = EXPECTED_RESULT; - const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, &outLen); + const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, outLen, &encLen); THEN("cobsEncode is invoked") { CHECK(cobsEncode_fake.call_count > 0); @@ -86,7 +86,7 @@ SCENARIO("NoteBinaryEncode") } THEN("The result is returned without modification") { - CHECK(EXPECTED_RESULT == outLen); + CHECK(EXPECTED_RESULT == encLen); } } } diff --git a/test/src/NoteBinaryReceiveRange_test.cpp b/test/src/NoteBinaryReceiveRange_test.cpp new file mode 100644 index 00000000..501e4aae --- /dev/null +++ b/test/src/NoteBinaryReceiveRange_test.cpp @@ -0,0 +1,202 @@ +/*! + * @file NoteBinaryReceiveRange_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) +FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, uint32_t *) +FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) +FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, uint32_t *, bool, + size_t, uint32_t *) +FAKE_VOID_FUNC(NoteLockNote) +FAKE_VOID_FUNC(NoteUnlockNote) + +// Most of these variables have to be global because they're accessed in +// lambda functions used as fakes for various note-c functions. They can't be +// captured by the lambdas because the lambdas need to be convertible to plain +// old function pointers in order to be used by the fff mocking/fake framework. +// If a lambda captures anything, it can't be converted in this way, and you get +// a compiler error. +uint8_t buf[32]; +uint32_t bufLen = sizeof(buf); +uint32_t dataLen = 17; + +char rawMsg[] = "Hello Blues!"; +uint32_t rawMsgLen = strlen(rawMsg); + +namespace +{ + +SCENARIO("NoteBinaryReceiveRange") +{ + RESET_FAKE(NoteNewRequest); + RESET_FAKE(NoteBinaryDataEncodedLength); + RESET_FAKE(NoteRequestResponse); + RESET_FAKE(NoteChunkedReceive); + RESET_FAKE(NoteLockNote); + RESET_FAKE(NoteUnlockNote); + + const uint32_t OFFSET_ZERO = 0; + + NoteSetFnDefault(malloc, free, NULL, NULL); + + // These fakes are the default. Tests below may override them to exercise + // different scenarios. + NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { + return JCreateObject(); + }; + NoteBinaryDataEncodedLength_fake.custom_fake = [](uint32_t *size) + -> const char * { + *size = bufLen; + + return NULL; + }; + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + char hash[NOTE_MD5_HASH_STRING_SIZE] = {0}; + NoteMD5HashString((unsigned char *)rawMsg, rawMsgLen, hash, + NOTE_MD5_HASH_STRING_SIZE); + JAddStringToObject(rsp, "status", hash); + + return rsp; + }; + + GIVEN("Allocating the card.binary.get request fails") { + NoteNewRequest_fake.custom_fake = NULL; + NoteNewRequest_fake.return_val = NULL; + + WHEN("NoteBinaryReceiveRange is called") { + const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + + REQUIRE(NoteNewRequest_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("The response to the card.binary.get request has an error") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + JAddStringToObject(rsp, "err", "some error"); + + return rsp; + }; + + WHEN("NoteBinaryReceiveRange is called") { + const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("NoteChunkedReceive returns an error") { + NoteChunkedReceive_fake.return_val = "some error"; + + WHEN("NoteBinaryReceiveRange is called") { + const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("NoteChunkedReceive indicates there's unexpectedly more data " + "available") { + NoteChunkedReceive_fake.custom_fake = [](uint8_t *, uint32_t *, bool, + size_t, uint32_t *available) -> const char* { + *available = 1; + + return NULL; + }; + + WHEN("NoteBinaryReceiveRange is called") { + const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("The binary payload is received") { + NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, uint32_t *size, + bool, size_t, uint32_t *available) -> const char* { + uint32_t outLen = 0; + NoteBinaryEncode((uint8_t *)rawMsg, rawMsgLen, buffer, *size, &outLen); + + buffer[outLen] = '\n'; + *size = outLen + 1; + *available = 0; + + return NULL; + }; + + AND_GIVEN("The computed MD5 hash doesn't match the status field") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + JAddStringToObject(rsp, "status", "garbage"); + + return rsp; + }; + + WHEN("NoteBinaryReceiveRange is called") { + const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + AND_GIVEN("The computed MD5 matches the status field") { + WHEN("NoteBinaryReceiveRange is called") { + uint32_t dataLen = rawMsgLen; + const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + THEN("No error is returned") { + CHECK(err == NULL); + } + + THEN("The decoded payload is as expected, with no trailing " + "newline") { + CHECK(memcmp(buf, rawMsg, dataLen) == 0); + } + } + } + } + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index e85edf72..6714fd88 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -19,186 +19,104 @@ #include "n_lib.h" DEFINE_FFF_GLOBALS -FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) -FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, uint32_t *) -FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) -FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, uint32_t *, bool, - size_t, uint32_t *) -FAKE_VOID_FUNC(NoteLockNote) -FAKE_VOID_FUNC(NoteUnlockNote) - -// Most of these variables have to be global because they're accessed in -// lambda functions used as fakes for various note-c functions. They can't be -// captured by the lambdas because the lambdas need to be convertible to plain -// old function pointers in order to be used by the fff mocking/fake framework. -// If a lambda captures anything, it can't be converted in this way, and you get -// a compiler error. -uint8_t buf[32]; -uint32_t bufLen = sizeof(buf); -uint32_t dataLen = 0; +FAKE_VALUE_FUNC(const char *, NoteBinaryDataDecodedLength, uint32_t *) +FAKE_VALUE_FUNC(const char *, NoteBinaryReceiveRange, uint8_t *, uint32_t, uint32_t, uint32_t) -char rawMsg[] = "Hello Blues!"; -uint32_t rawMsgLen = strlen(rawMsg); +uint8_t buffer[12]; +const uint32_t bufLen = sizeof(buffer); +uint32_t dataLen = 0; namespace { SCENARIO("NoteBinaryReceive") { - RESET_FAKE(NoteNewRequest); - RESET_FAKE(NoteBinaryDataEncodedLength); - RESET_FAKE(NoteRequestResponse); - RESET_FAKE(NoteChunkedReceive); - RESET_FAKE(NoteLockNote); - RESET_FAKE(NoteUnlockNote); - - const uint32_t OFFSET_ZERO = 0; - - NoteSetFnDefault(malloc, free, NULL, NULL); - - // These fakes are the default. Tests below may override them to exercise - // different scenarios. - NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { - return JCreateObject(); - }; - NoteBinaryDataEncodedLength_fake.custom_fake = [](uint32_t *size) - -> const char * { - *size = bufLen; - - return NULL; - }; - NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { - JDelete(req); - J *rsp = JCreateObject(); - char hash[NOTE_MD5_HASH_STRING_SIZE] = {0}; - NoteMD5HashString((unsigned char *)rawMsg, rawMsgLen, hash, - NOTE_MD5_HASH_STRING_SIZE); - JAddStringToObject(rsp, "status", hash); - - return rsp; - }; - - GIVEN("Allocating the card.binary.get request fails") { - NoteNewRequest_fake.custom_fake = NULL; - NoteNewRequest_fake.return_val = NULL; - - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); - - REQUIRE(NoteNewRequest_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("The response to the card.binary.get request has an error") { - NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { - JDelete(req); - J *rsp = JCreateObject(); - JAddStringToObject(rsp, "err", "some error"); - - return rsp; - }; + RESET_FAKE(NoteBinaryDataDecodedLength); + RESET_FAKE(NoteBinaryReceiveRange); + dataLen = 17; - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + GIVEN("Bad parameters are supplied") { + WHEN("buffer is NULL") { + const char *err = NoteBinaryReceive(NULL, bufLen, &dataLen); - REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { CHECK(err != NULL); } } - } - - GIVEN("NoteChunkedReceive returns an error") { - NoteChunkedReceive_fake.return_val = "some error"; - - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + WHEN("dataLen is NULL") { + const char *err = NoteBinaryReceive(buffer, bufLen, NULL); - REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("An error is returned") { CHECK(err != NULL); } } } - GIVEN("NoteChunkedReceive indicates there's unexpectedly more data " - "available") { - NoteChunkedReceive_fake.custom_fake = [](uint8_t *, uint32_t *, bool, - size_t, uint32_t *available) -> const char* { - *available = 1; + GIVEN("NoteBinaryDataDecodedLength() is invoked") { + WHEN("An error is encountered") { + const char *errMsg = "ERROR! Hacking too much time!"; + NoteBinaryDataDecodedLength_fake.return_val = errMsg; + const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); - return NULL; - }; - - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); + THEN("NoteBinaryReceiveRange() is not invoked") { + CHECK(NoteBinaryReceiveRange_fake.call_count == 0); + } + THEN("The dataLen is set to zero") { + CHECK(dataLen == 0); + } + THEN("The error is returned") { + CHECK(!strcmp(err,errMsg)); + } + } + WHEN("No error is encountered") { + const uint32_t DECODED_LEN = 79; + NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { + *len = DECODED_LEN; + return NULL; + }; + const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); - REQUIRE(NoteChunkedReceive_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); + REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); + THEN("NoteBinaryReceiveRange() is invoked") { + CHECK(NoteBinaryReceiveRange_fake.call_count > 0); + } + THEN("The decoded length is passed to NoteBinaryReceiveRange()") { + CHECK(NoteBinaryReceiveRange_fake.arg3_history[0] == DECODED_LEN); } } } - - GIVEN("The binary payload is received") { - NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, uint32_t *size, - bool, size_t, uint32_t *available) -> const char* { - uint32_t outLen = *size; - NoteBinaryEncode((uint8_t *)rawMsg, rawMsgLen, buffer, &outLen); - - buffer[outLen] = '\n'; - *size = outLen + 1; - *available = 0; - + GIVEN("NoteBinaryReceiveRange() is invoked") { + const uint32_t DECODED_LEN = 79; + NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { + *len = DECODED_LEN; return NULL; }; - - AND_GIVEN("The computed MD5 hash doesn't match the status field") { - NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { - JDelete(req); - J *rsp = JCreateObject(); - JAddStringToObject(rsp, "status", "garbage"); - - return rsp; - }; - - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); - - REQUIRE(NoteChunkedReceive_fake.call_count > 0); - REQUIRE(NoteRequestResponse_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); - } + WHEN("An error is encountered") { + const char *errMsg = "ERROR! Hacking too much time!"; + NoteBinaryReceiveRange_fake.return_val = errMsg; + const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); + + REQUIRE(NoteBinaryReceiveRange_fake.call_count > 0); + THEN("The dataLen is set to zero") { + CHECK(dataLen == 0); + } + THEN("The error is returned") { + CHECK(!strcmp(err,errMsg)); } } + WHEN("No error is encountered") { + const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); - AND_GIVEN("The computed MD5 matches the status field") { - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); - - REQUIRE(NoteChunkedReceive_fake.call_count > 0); - THEN("No error is returned") { - CHECK(err == NULL); - } - - THEN("The length of the payload is returned in the dataLen out" - " parameter") { - CHECK(dataLen == rawMsgLen); - } - - THEN("The decoded payload is as expected, with no trailing " - "newline") { - CHECK(memcmp(buf, rawMsg, dataLen) == 0); - } + REQUIRE(NoteBinaryReceiveRange_fake.call_count > 0); + THEN("The decoded length is returned") { + CHECK(dataLen == DECODED_LEN); + } + THEN("The return value is NULL") { + CHECK(err == NULL); } } } - CHECK(NoteLockNote_fake.call_count > 0); - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); } } diff --git a/test/src/NoteBinaryTransmit_test.cpp b/test/src/NoteBinaryTransmit_test.cpp index 701e0929..df6eb129 100644 --- a/test/src/NoteBinaryTransmit_test.cpp +++ b/test/src/NoteBinaryTransmit_test.cpp @@ -184,8 +184,8 @@ SCENARIO("NoteBinaryTransmit") // Discover the actual encoded length of the data const uint32_t tempBufLen = cobsEncodedMaxLength(dataLen); uint8_t *tempBuf = (uint8_t *)malloc(tempBufLen); - uint32_t newBufLen = tempBufLen; - REQUIRE(!NoteBinaryEncode(buf, dataLen, tempBuf, &newBufLen)); + uint32_t newBufLen = 0; + REQUIRE(!NoteBinaryEncode(buf, dataLen, tempBuf, tempBufLen, &newBufLen)); free(tempBuf); WHEN("NoteBinaryTransmit is called") { From d48d585ed93aaeac7a660fe3ae018d5c07d8f112 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 03:41:48 +0000 Subject: [PATCH 02/24] fix: astyle --- n_helpers.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 777739c7..65f6d788 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -367,12 +367,10 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, if (!buffer) { err = ERRSTR("NULL buffer", c_bad); NOTE_C_LOG_ERROR(err); - } - else if (!dataLen) { + } else if (!dataLen) { err = ERRSTR("NULL dataLen not allowed", c_bad); NOTE_C_LOG_ERROR(err); - } - else { + } else { // Calculate the data length available on the Notecard if ((err = NoteBinaryDataDecodedLength(&decodedLen))) { decodedLen = 0; From 97ee79871c0c3a1948b30cca547d090cb78d620f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 04:14:02 +0000 Subject: [PATCH 03/24] test: improve coverage --- test/src/NoteBinaryReceiveRange_test.cpp | 46 +++++++++++++++++------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/test/src/NoteBinaryReceiveRange_test.cpp b/test/src/NoteBinaryReceiveRange_test.cpp index 501e4aae..77d309be 100644 --- a/test/src/NoteBinaryReceiveRange_test.cpp +++ b/test/src/NoteBinaryReceiveRange_test.cpp @@ -35,7 +35,8 @@ FAKE_VOID_FUNC(NoteUnlockNote) // a compiler error. uint8_t buf[32]; uint32_t bufLen = sizeof(buf); -uint32_t dataLen = 17; +uint32_t decodedOffset = 0; +uint32_t decodedLen = 17; char rawMsg[] = "Hello Blues!"; uint32_t rawMsgLen = strlen(rawMsg); @@ -52,8 +53,6 @@ SCENARIO("NoteBinaryReceiveRange") RESET_FAKE(NoteLockNote); RESET_FAKE(NoteUnlockNote); - const uint32_t OFFSET_ZERO = 0; - NoteSetFnDefault(malloc, free, NULL, NULL); // These fakes are the default. Tests below may override them to exercise @@ -78,12 +77,36 @@ SCENARIO("NoteBinaryReceiveRange") return rsp; }; + GIVEN("Bad parameters are supplied") { + WHEN("buffer is NULL") { + const char *err = NoteBinaryReceiveRange(NULL, bufLen, decodedOffset, decodedLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("bufLen is too small") { + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, bufLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("decodedLen is zero") { + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, 0); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + GIVEN("Allocating the card.binary.get request fails") { NoteNewRequest_fake.custom_fake = NULL; NoteNewRequest_fake.return_val = NULL; WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteNewRequest_fake.call_count > 0); THEN("An error is returned") { @@ -102,7 +125,7 @@ SCENARIO("NoteBinaryReceiveRange") }; WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { @@ -115,7 +138,7 @@ SCENARIO("NoteBinaryReceiveRange") NoteChunkedReceive_fake.return_val = "some error"; WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("An error is returned") { @@ -134,7 +157,7 @@ SCENARIO("NoteBinaryReceiveRange") }; WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("An error is returned") { @@ -166,7 +189,7 @@ SCENARIO("NoteBinaryReceiveRange") }; WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); REQUIRE(NoteRequestResponse_fake.call_count > 0); @@ -178,8 +201,8 @@ SCENARIO("NoteBinaryReceiveRange") AND_GIVEN("The computed MD5 matches the status field") { WHEN("NoteBinaryReceiveRange is called") { - uint32_t dataLen = rawMsgLen; - const char *err = NoteBinaryReceiveRange(buf, bufLen, OFFSET_ZERO, dataLen); + uint32_t decodedLen = rawMsgLen; + const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("No error is returned") { @@ -188,12 +211,11 @@ SCENARIO("NoteBinaryReceiveRange") THEN("The decoded payload is as expected, with no trailing " "newline") { - CHECK(memcmp(buf, rawMsg, dataLen) == 0); + CHECK(memcmp(buf, rawMsg, decodedLen) == 0); } } } } - CHECK(NoteLockNote_fake.call_count > 0); CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); } From cc3071a28fb76f5e0a171c39b6b68b5426c41210 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 05:12:00 +0000 Subject: [PATCH 04/24] chore: rename binary RX API --- n_helpers.c | 15 +- note.h | 5 +- test/CMakeLists.txt | 2 +- test/src/NoteBinaryReceiveAll_test.cpp | 124 +++++++++++++ test/src/NoteBinaryReceiveRange_test.cpp | 224 ----------------------- test/src/NoteBinaryReceive_test.cpp | 220 ++++++++++++++++------ 6 files changed, 294 insertions(+), 296 deletions(-) create mode 100644 test/src/NoteBinaryReceiveAll_test.cpp delete mode 100644 test/src/NoteBinaryReceiveRange_test.cpp diff --git a/n_helpers.c b/n_helpers.c index 65f6d788..07d14bd5 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -342,7 +342,7 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) //**************************************************************************/ /*! - @brief Receive a large binary object from the Notecard's binary buffer + @brief Receive the Notecard's entire binary buffer @param buffer A buffer to hold the binary object @param bufLen The total length of the provided buffer @@ -357,8 +357,8 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) `NoteBinaryDataEncodedLength()`. */ /**************************************************************************/ -const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, - uint32_t *dataLen) +const char * NoteBinaryReceiveAll(uint8_t *buffer, uint32_t bufLen, + uint32_t *dataLen) { const char *err = NULL; uint32_t decodedLen = 0; @@ -376,7 +376,7 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, decodedLen = 0; } // Request entire binary data store from Notecard - else if ((err = NoteBinaryReceiveRange(buffer, bufLen, 0, decodedLen))) { + else if ((err = NoteBinaryReceive(buffer, bufLen, 0, decodedLen))) { decodedLen = 0; } @@ -389,7 +389,7 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, //**************************************************************************/ /*! - @brief Receive a large binary range from the Notecard's binary buffer + @brief Receive a large binary object from the Notecard's binary buffer @param buffer A buffer to hold the binary range @param bufLen The total length of the provided buffer @@ -407,9 +407,8 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, entire buffer use `NoteBinaryDataEncodedLength()` instead. */ /**************************************************************************/ -const char * NoteBinaryReceiveRange(uint8_t *buffer, uint32_t bufLen, - uint32_t decodedOffset, - uint32_t decodedLen) +const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, + uint32_t decodedOffset, uint32_t decodedLen) { // Validate parameter(s) if (!buffer) { diff --git a/note.h b/note.h index 0e1c9192..30be9abf 100644 --- a/note.h +++ b/note.h @@ -329,10 +329,9 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, + uint32_t decodedOffset, uint32_t decodedLen); +const char * NoteBinaryReceiveAll(uint8_t *buffer, uint32_t bufLen, uint32_t *dataLen); -const char * NoteBinaryReceiveRange(uint8_t *buffer, uint32_t bufLen, - uint32_t decodedOffset, - uint32_t decodedLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, uint32_t bufLen, uint32_t notecardOffset); uint32_t NoteSetSTSecs(uint32_t secs); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f3e6023b..9856a120 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -156,7 +156,7 @@ add_test(NoteBinaryEncode_test) add_test(NoteBinaryMaxEncodedLength_test) add_test(NoteBinaryMaxDecodedLength_test) add_test(NoteBinaryReceive_test) -add_test(NoteBinaryReceiveRange_test) +add_test(NoteBinaryReceiveAll_test) add_test(NoteBinaryTransmit_test) if(NOTE_C_COVERAGE) diff --git a/test/src/NoteBinaryReceiveAll_test.cpp b/test/src/NoteBinaryReceiveAll_test.cpp new file mode 100644 index 00000000..c0778299 --- /dev/null +++ b/test/src/NoteBinaryReceiveAll_test.cpp @@ -0,0 +1,124 @@ +/*! + * @file NoteBinaryReceiveAll_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(const char *, NoteBinaryDataDecodedLength, uint32_t *) +FAKE_VALUE_FUNC(const char *, NoteBinaryReceive, uint8_t *, uint32_t, uint32_t, uint32_t) + +uint8_t buffer[12]; +const uint32_t bufLen = sizeof(buffer); +uint32_t dataLen = 0; + +namespace +{ + +SCENARIO("NoteBinaryReceiveAll") +{ + RESET_FAKE(NoteBinaryDataDecodedLength); + RESET_FAKE(NoteBinaryReceive); + dataLen = 17; + + GIVEN("Bad parameters are supplied") { + WHEN("buffer is NULL") { + const char *err = NoteBinaryReceiveAll(NULL, bufLen, &dataLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("dataLen is NULL") { + const char *err = NoteBinaryReceiveAll(buffer, bufLen, NULL); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("NoteBinaryDataDecodedLength() is invoked") { + WHEN("An error is encountered") { + const char *errMsg = "ERROR! Hacking too much time!"; + NoteBinaryDataDecodedLength_fake.return_val = errMsg; + const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); + + REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); + THEN("NoteBinaryReceive() is not invoked") { + CHECK(NoteBinaryReceive_fake.call_count == 0); + } + THEN("The dataLen is set to zero") { + CHECK(dataLen == 0); + } + THEN("The error is returned") { + CHECK(!strcmp(err,errMsg)); + } + } + WHEN("No error is encountered") { + const uint32_t DECODED_LEN = 79; + NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { + *len = DECODED_LEN; + return NULL; + }; + const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); + + REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); + THEN("NoteBinaryReceive() is invoked") { + CHECK(NoteBinaryReceive_fake.call_count > 0); + } + THEN("The decoded length is passed to NoteBinaryReceive()") { + CHECK(NoteBinaryReceive_fake.arg3_history[0] == DECODED_LEN); + } + } + } + GIVEN("NoteBinaryReceive() is invoked") { + const uint32_t DECODED_LEN = 79; + NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { + *len = DECODED_LEN; + return NULL; + }; + WHEN("An error is encountered") { + const char *errMsg = "ERROR! Hacking too much time!"; + NoteBinaryReceive_fake.return_val = errMsg; + const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); + + REQUIRE(NoteBinaryReceive_fake.call_count > 0); + THEN("The dataLen is set to zero") { + CHECK(dataLen == 0); + } + THEN("The error is returned") { + CHECK(!strcmp(err,errMsg)); + } + } + WHEN("No error is encountered") { + const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); + + REQUIRE(NoteBinaryReceive_fake.call_count > 0); + THEN("The decoded length is returned") { + CHECK(dataLen == DECODED_LEN); + } + THEN("The return value is NULL") { + CHECK(err == NULL); + } + } + } +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryReceiveRange_test.cpp b/test/src/NoteBinaryReceiveRange_test.cpp deleted file mode 100644 index 77d309be..00000000 --- a/test/src/NoteBinaryReceiveRange_test.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/*! - * @file NoteBinaryReceiveRange_test.cpp - * - * Written by the Blues Inc. team. - * - * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is - * governed by licenses granted by the copyright holder including that found in - * the - * LICENSE - * file. - * - */ - -#ifdef NOTE_C_TEST - -#include -#include "fff.h" - -#include "n_lib.h" - -DEFINE_FFF_GLOBALS -FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) -FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, uint32_t *) -FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) -FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, uint32_t *, bool, - size_t, uint32_t *) -FAKE_VOID_FUNC(NoteLockNote) -FAKE_VOID_FUNC(NoteUnlockNote) - -// Most of these variables have to be global because they're accessed in -// lambda functions used as fakes for various note-c functions. They can't be -// captured by the lambdas because the lambdas need to be convertible to plain -// old function pointers in order to be used by the fff mocking/fake framework. -// If a lambda captures anything, it can't be converted in this way, and you get -// a compiler error. -uint8_t buf[32]; -uint32_t bufLen = sizeof(buf); -uint32_t decodedOffset = 0; -uint32_t decodedLen = 17; - -char rawMsg[] = "Hello Blues!"; -uint32_t rawMsgLen = strlen(rawMsg); - -namespace -{ - -SCENARIO("NoteBinaryReceiveRange") -{ - RESET_FAKE(NoteNewRequest); - RESET_FAKE(NoteBinaryDataEncodedLength); - RESET_FAKE(NoteRequestResponse); - RESET_FAKE(NoteChunkedReceive); - RESET_FAKE(NoteLockNote); - RESET_FAKE(NoteUnlockNote); - - NoteSetFnDefault(malloc, free, NULL, NULL); - - // These fakes are the default. Tests below may override them to exercise - // different scenarios. - NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { - return JCreateObject(); - }; - NoteBinaryDataEncodedLength_fake.custom_fake = [](uint32_t *size) - -> const char * { - *size = bufLen; - - return NULL; - }; - NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { - JDelete(req); - J *rsp = JCreateObject(); - char hash[NOTE_MD5_HASH_STRING_SIZE] = {0}; - NoteMD5HashString((unsigned char *)rawMsg, rawMsgLen, hash, - NOTE_MD5_HASH_STRING_SIZE); - JAddStringToObject(rsp, "status", hash); - - return rsp; - }; - - GIVEN("Bad parameters are supplied") { - WHEN("buffer is NULL") { - const char *err = NoteBinaryReceiveRange(NULL, bufLen, decodedOffset, decodedLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("bufLen is too small") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, bufLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("decodedLen is zero") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, 0); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("Allocating the card.binary.get request fails") { - NoteNewRequest_fake.custom_fake = NULL; - NoteNewRequest_fake.return_val = NULL; - - WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); - - REQUIRE(NoteNewRequest_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("The response to the card.binary.get request has an error") { - NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { - JDelete(req); - J *rsp = JCreateObject(); - JAddStringToObject(rsp, "err", "some error"); - - return rsp; - }; - - WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); - - REQUIRE(NoteRequestResponse_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("NoteChunkedReceive returns an error") { - NoteChunkedReceive_fake.return_val = "some error"; - - WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); - - REQUIRE(NoteChunkedReceive_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("NoteChunkedReceive indicates there's unexpectedly more data " - "available") { - NoteChunkedReceive_fake.custom_fake = [](uint8_t *, uint32_t *, bool, - size_t, uint32_t *available) -> const char* { - *available = 1; - - return NULL; - }; - - WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); - - REQUIRE(NoteChunkedReceive_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("The binary payload is received") { - NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, uint32_t *size, - bool, size_t, uint32_t *available) -> const char* { - uint32_t outLen = 0; - NoteBinaryEncode((uint8_t *)rawMsg, rawMsgLen, buffer, *size, &outLen); - - buffer[outLen] = '\n'; - *size = outLen + 1; - *available = 0; - - return NULL; - }; - - AND_GIVEN("The computed MD5 hash doesn't match the status field") { - NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { - JDelete(req); - J *rsp = JCreateObject(); - JAddStringToObject(rsp, "status", "garbage"); - - return rsp; - }; - - WHEN("NoteBinaryReceiveRange is called") { - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); - - REQUIRE(NoteChunkedReceive_fake.call_count > 0); - REQUIRE(NoteRequestResponse_fake.call_count > 0); - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - AND_GIVEN("The computed MD5 matches the status field") { - WHEN("NoteBinaryReceiveRange is called") { - uint32_t decodedLen = rawMsgLen; - const char *err = NoteBinaryReceiveRange(buf, bufLen, decodedOffset, decodedLen); - - REQUIRE(NoteChunkedReceive_fake.call_count > 0); - THEN("No error is returned") { - CHECK(err == NULL); - } - - THEN("The decoded payload is as expected, with no trailing " - "newline") { - CHECK(memcmp(buf, rawMsg, decodedLen) == 0); - } - } - } - } - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); -} - -} - -#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index 6714fd88..22d2e4db 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -19,32 +19,81 @@ #include "n_lib.h" DEFINE_FFF_GLOBALS -FAKE_VALUE_FUNC(const char *, NoteBinaryDataDecodedLength, uint32_t *) -FAKE_VALUE_FUNC(const char *, NoteBinaryReceiveRange, uint8_t *, uint32_t, uint32_t, uint32_t) - -uint8_t buffer[12]; -const uint32_t bufLen = sizeof(buffer); -uint32_t dataLen = 0; +FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) +FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, uint32_t *) +FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) +FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, uint32_t *, bool, + size_t, uint32_t *) +FAKE_VOID_FUNC(NoteLockNote) +FAKE_VOID_FUNC(NoteUnlockNote) + +// Most of these variables have to be global because they're accessed in +// lambda functions used as fakes for various note-c functions. They can't be +// captured by the lambdas because the lambdas need to be convertible to plain +// old function pointers in order to be used by the fff mocking/fake framework. +// If a lambda captures anything, it can't be converted in this way, and you get +// a compiler error. +uint8_t buf[32]; +uint32_t bufLen = sizeof(buf); +uint32_t decodedOffset = 0; +uint32_t decodedLen = 17; + +char rawMsg[] = "Hello Blues!"; +uint32_t rawMsgLen = strlen(rawMsg); namespace { SCENARIO("NoteBinaryReceive") { - RESET_FAKE(NoteBinaryDataDecodedLength); - RESET_FAKE(NoteBinaryReceiveRange); - dataLen = 17; + RESET_FAKE(NoteNewRequest); + RESET_FAKE(NoteBinaryDataEncodedLength); + RESET_FAKE(NoteRequestResponse); + RESET_FAKE(NoteChunkedReceive); + RESET_FAKE(NoteLockNote); + RESET_FAKE(NoteUnlockNote); + + NoteSetFnDefault(malloc, free, NULL, NULL); + + // These fakes are the default. Tests below may override them to exercise + // different scenarios. + NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { + return JCreateObject(); + }; + NoteBinaryDataEncodedLength_fake.custom_fake = [](uint32_t *size) + -> const char * { + *size = bufLen; + + return NULL; + }; + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + char hash[NOTE_MD5_HASH_STRING_SIZE] = {0}; + NoteMD5HashString((unsigned char *)rawMsg, rawMsgLen, hash, + NOTE_MD5_HASH_STRING_SIZE); + JAddStringToObject(rsp, "status", hash); + + return rsp; + }; GIVEN("Bad parameters are supplied") { WHEN("buffer is NULL") { - const char *err = NoteBinaryReceive(NULL, bufLen, &dataLen); + const char *err = NoteBinaryReceive(NULL, bufLen, decodedOffset, decodedLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("bufLen is too small") { + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, bufLen); THEN("An error is returned") { CHECK(err != NULL); } } - WHEN("dataLen is NULL") { - const char *err = NoteBinaryReceive(buffer, bufLen, NULL); + WHEN("decodedLen is zero") { + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -52,71 +101,122 @@ SCENARIO("NoteBinaryReceive") } } - GIVEN("NoteBinaryDataDecodedLength() is invoked") { - WHEN("An error is encountered") { - const char *errMsg = "ERROR! Hacking too much time!"; - NoteBinaryDataDecodedLength_fake.return_val = errMsg; - const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); + GIVEN("Allocating the card.binary.get request fails") { + NoteNewRequest_fake.custom_fake = NULL; + NoteNewRequest_fake.return_val = NULL; - REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); - THEN("NoteBinaryReceiveRange() is not invoked") { - CHECK(NoteBinaryReceiveRange_fake.call_count == 0); - } - THEN("The dataLen is set to zero") { - CHECK(dataLen == 0); - } - THEN("The error is returned") { - CHECK(!strcmp(err,errMsg)); + WHEN("NoteBinaryReceive is called") { + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + + REQUIRE(NoteNewRequest_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); } } - WHEN("No error is encountered") { - const uint32_t DECODED_LEN = 79; - NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { - *len = DECODED_LEN; - return NULL; - }; - const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); + } + + GIVEN("The response to the card.binary.get request has an error") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + JAddStringToObject(rsp, "err", "some error"); + + return rsp; + }; + + WHEN("NoteBinaryReceive is called") { + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); - REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); - THEN("NoteBinaryReceiveRange() is invoked") { - CHECK(NoteBinaryReceiveRange_fake.call_count > 0); + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); } - THEN("The decoded length is passed to NoteBinaryReceiveRange()") { - CHECK(NoteBinaryReceiveRange_fake.arg3_history[0] == DECODED_LEN); + } + } + + GIVEN("NoteChunkedReceive returns an error") { + NoteChunkedReceive_fake.return_val = "some error"; + + WHEN("NoteBinaryReceive is called") { + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); } } } - GIVEN("NoteBinaryReceiveRange() is invoked") { - const uint32_t DECODED_LEN = 79; - NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { - *len = DECODED_LEN; + + GIVEN("NoteChunkedReceive indicates there's unexpectedly more data " + "available") { + NoteChunkedReceive_fake.custom_fake = [](uint8_t *, uint32_t *, bool, + size_t, uint32_t *available) -> const char* { + *available = 1; + return NULL; }; - WHEN("An error is encountered") { - const char *errMsg = "ERROR! Hacking too much time!"; - NoteBinaryReceiveRange_fake.return_val = errMsg; - const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); - - REQUIRE(NoteBinaryReceiveRange_fake.call_count > 0); - THEN("The dataLen is set to zero") { - CHECK(dataLen == 0); - } - THEN("The error is returned") { - CHECK(!strcmp(err,errMsg)); + + WHEN("NoteBinaryReceive is called") { + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); } } - WHEN("No error is encountered") { - const char *err = NoteBinaryReceive(buffer, bufLen, &dataLen); + } + + GIVEN("The binary payload is received") { + NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, uint32_t *size, + bool, size_t, uint32_t *available) -> const char* { + uint32_t outLen = 0; + NoteBinaryEncode((uint8_t *)rawMsg, rawMsgLen, buffer, *size, &outLen); + + buffer[outLen] = '\n'; + *size = outLen + 1; + *available = 0; - REQUIRE(NoteBinaryReceiveRange_fake.call_count > 0); - THEN("The decoded length is returned") { - CHECK(dataLen == DECODED_LEN); + return NULL; + }; + + AND_GIVEN("The computed MD5 hash doesn't match the status field") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + JAddStringToObject(rsp, "status", "garbage"); + + return rsp; + }; + + WHEN("NoteBinaryReceive is called") { + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } } - THEN("The return value is NULL") { - CHECK(err == NULL); + } + + AND_GIVEN("The computed MD5 matches the status field") { + WHEN("NoteBinaryReceive is called") { + uint32_t decodedLen = rawMsgLen; + const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + THEN("No error is returned") { + CHECK(err == NULL); + } + + THEN("The decoded payload is as expected, with no trailing " + "newline") { + CHECK(memcmp(buf, rawMsg, decodedLen) == 0); + } } } } + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); } } From 46a7b94b36b021a7dfaa68644e7d6bf936c1b696 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 05:16:24 +0000 Subject: [PATCH 05/24] fix: astyle --- note.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/note.h b/note.h index 30be9abf..4a1d1e47 100644 --- a/note.h +++ b/note.h @@ -331,7 +331,7 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); const char * NoteBinaryReceiveAll(uint8_t *buffer, uint32_t bufLen, - uint32_t *dataLen); + uint32_t *dataLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, uint32_t bufLen, uint32_t notecardOffset); uint32_t NoteSetSTSecs(uint32_t secs); From 766fa8c1bb48b1768c7efdf226b6e15ae840067f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 13:09:37 +0000 Subject: [PATCH 06/24] chore: align cobsEncodedMaxLength with cobsGuaranteedFit --- n_cobs.c | 14 ++++++++++---- n_helpers.c | 12 ++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/n_cobs.c b/n_cobs.c index 1013a4eb..426a5a1a 100644 --- a/n_cobs.c +++ b/n_cobs.c @@ -4,6 +4,8 @@ #include +#define COBS_EOP_OVERHEAD 1 + //**************************************************************************/ /*! @brief Decode a string encoded with COBS encoding @@ -94,6 +96,7 @@ uint32_t cobsEncode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst) @param length Length of the data to encode @return the length required for encoded data + @note The computed length does not include the EOP (end-of-packet) marker */ /**************************************************************************/ @@ -123,17 +126,19 @@ uint32_t cobsEncodedLength(const uint8_t *ptr, uint32_t length) @param length Length of the data to encode @return The max length required to encode the data + @note Since the contents of the buffer are unknown, then we must assume that the entire buffer has no end-of-packet markers. This would require the injection of overhead bytes (as opposed to the replacement of end-of-packet markers with overhead bytes) at intervals of 255, thus producing the worst case scenario. + @note An additional byte is added for the EOP (end-of-packet) marker. */ /**************************************************************************/ uint32_t cobsEncodedMaxLength(uint32_t length) { const uint32_t overheadBytes = ((length / 254) + ((length % 254) > 0)); - return (length + overheadBytes); + return (length + overheadBytes + COBS_EOP_OVERHEAD); } //**************************************************************************/ @@ -144,12 +149,13 @@ uint32_t cobsEncodedMaxLength(uint32_t length) @param bufLen Length of the buffer in bytes @return the length of unencoded data - @note The computation may leave additional space at the end, including one - byte for the EOP (end-of-packet) marker. + + @note The computation may leave additional space at the end. + @note An additional byte is added for the EOP (end-of-packet) marker. */ /**************************************************************************/ uint32_t cobsGuaranteedFit(uint32_t bufLen) { - uint32_t cobsOverhead = 1 + (bufLen / 254) + 1; + uint32_t cobsOverhead = 1 + (bufLen / 254) + COBS_EOP_OVERHEAD; return (cobsOverhead > bufLen ? 0 : (bufLen - cobsOverhead)); } diff --git a/n_helpers.c b/n_helpers.c index 07d14bd5..298e719c 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -403,8 +403,8 @@ const char * NoteBinaryReceiveAll(uint8_t *buffer, uint32_t bufLen, @note The buffer must be large enough to hold the encoded value of the data store contents from the requested offset for the specified length. To determine the necessary buffer size for a given data length, use - `(NoteBinaryMaxEncodedLength() + 1)`, or if you wish to consume the - entire buffer use `NoteBinaryDataEncodedLength()` instead. + `NoteBinaryMaxEncodedLength()`, or if you wish to consume the entire + buffer use `NoteBinaryDataEncodedLength()` instead. */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, @@ -416,7 +416,7 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, NOTE_C_LOG_ERROR(err); return err; } - if (bufLen < (cobsEncodedMaxLength(decodedLen) + 1)) { + if (bufLen < cobsEncodedMaxLength(decodedLen)) { const char *err = ERRSTR("insufficient buffer size", c_bad); NOTE_C_LOG_ERROR(err); return err; @@ -529,9 +529,9 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. - Use `(NoteBinaryMaxEncodedLength() + 1)` to calculate the required size - for the buffer pointed to by the `bufLen` parameter, which MUST - accommodate the encoded data and newline terminator. + Use `NoteBinaryMaxEncodedLength()` to calculate the required size for + the buffer pointed to by the `bufLen` parameter, which MUST accommodate + both the encoded data and newline terminator. */ /**************************************************************************/ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, From 1f450a7ebf61739c50d0cfd3f1fb7394bb757337 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 14:16:14 +0000 Subject: [PATCH 07/24] chore: Remove NoteBinaryReceiveAll() --- n_helpers.c | 47 ---------- note.h | 2 - test/CMakeLists.txt | 1 - test/src/NoteBinaryReceiveAll_test.cpp | 124 ------------------------- 4 files changed, 174 deletions(-) delete mode 100644 test/src/NoteBinaryReceiveAll_test.cpp diff --git a/n_helpers.c b/n_helpers.c index 298e719c..b37633d9 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -340,53 +340,6 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) return cobsEncodedMaxLength(unencodedLength); } -//**************************************************************************/ -/*! - @brief Receive the Notecard's entire binary buffer - - @param buffer A buffer to hold the binary object - @param bufLen The total length of the provided buffer - @param dataLen [out] The length of the decoded data received from the - Notecard. - - @returns NULL on success, else an error string pointer. - - @note The buffer must be large enough to hold the encoded value of the - data store contents from the requested offset for the specified length. - To determine the necessary buffer size the Notecard's binary data, use - `NoteBinaryDataEncodedLength()`. - */ -/**************************************************************************/ -const char * NoteBinaryReceiveAll(uint8_t *buffer, uint32_t bufLen, - uint32_t *dataLen) -{ - const char *err = NULL; - uint32_t decodedLen = 0; - - // Validate parameter(s) - if (!buffer) { - err = ERRSTR("NULL buffer", c_bad); - NOTE_C_LOG_ERROR(err); - } else if (!dataLen) { - err = ERRSTR("NULL dataLen not allowed", c_bad); - NOTE_C_LOG_ERROR(err); - } else { - // Calculate the data length available on the Notecard - if ((err = NoteBinaryDataDecodedLength(&decodedLen))) { - decodedLen = 0; - } - // Request entire binary data store from Notecard - else if ((err = NoteBinaryReceive(buffer, bufLen, 0, decodedLen))) { - decodedLen = 0; - } - - // Populate `dataLen` if available - *dataLen = decodedLen; - } - - return err; -} - //**************************************************************************/ /*! @brief Receive a large binary object from the Notecard's binary buffer diff --git a/note.h b/note.h index 4a1d1e47..2e4416ed 100644 --- a/note.h +++ b/note.h @@ -330,8 +330,6 @@ uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); -const char * NoteBinaryReceiveAll(uint8_t *buffer, uint32_t bufLen, - uint32_t *dataLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, uint32_t bufLen, uint32_t notecardOffset); uint32_t NoteSetSTSecs(uint32_t secs); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9856a120..b3e73837 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -156,7 +156,6 @@ add_test(NoteBinaryEncode_test) add_test(NoteBinaryMaxEncodedLength_test) add_test(NoteBinaryMaxDecodedLength_test) add_test(NoteBinaryReceive_test) -add_test(NoteBinaryReceiveAll_test) add_test(NoteBinaryTransmit_test) if(NOTE_C_COVERAGE) diff --git a/test/src/NoteBinaryReceiveAll_test.cpp b/test/src/NoteBinaryReceiveAll_test.cpp deleted file mode 100644 index c0778299..00000000 --- a/test/src/NoteBinaryReceiveAll_test.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/*! - * @file NoteBinaryReceiveAll_test.cpp - * - * Written by the Blues Inc. team. - * - * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is - * governed by licenses granted by the copyright holder including that found in - * the - * LICENSE - * file. - * - */ - -#ifdef NOTE_C_TEST - -#include -#include "fff.h" - -#include "n_lib.h" - -DEFINE_FFF_GLOBALS -FAKE_VALUE_FUNC(const char *, NoteBinaryDataDecodedLength, uint32_t *) -FAKE_VALUE_FUNC(const char *, NoteBinaryReceive, uint8_t *, uint32_t, uint32_t, uint32_t) - -uint8_t buffer[12]; -const uint32_t bufLen = sizeof(buffer); -uint32_t dataLen = 0; - -namespace -{ - -SCENARIO("NoteBinaryReceiveAll") -{ - RESET_FAKE(NoteBinaryDataDecodedLength); - RESET_FAKE(NoteBinaryReceive); - dataLen = 17; - - GIVEN("Bad parameters are supplied") { - WHEN("buffer is NULL") { - const char *err = NoteBinaryReceiveAll(NULL, bufLen, &dataLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("dataLen is NULL") { - const char *err = NoteBinaryReceiveAll(buffer, bufLen, NULL); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("NoteBinaryDataDecodedLength() is invoked") { - WHEN("An error is encountered") { - const char *errMsg = "ERROR! Hacking too much time!"; - NoteBinaryDataDecodedLength_fake.return_val = errMsg; - const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); - - REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); - THEN("NoteBinaryReceive() is not invoked") { - CHECK(NoteBinaryReceive_fake.call_count == 0); - } - THEN("The dataLen is set to zero") { - CHECK(dataLen == 0); - } - THEN("The error is returned") { - CHECK(!strcmp(err,errMsg)); - } - } - WHEN("No error is encountered") { - const uint32_t DECODED_LEN = 79; - NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { - *len = DECODED_LEN; - return NULL; - }; - const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); - - REQUIRE(NoteBinaryDataDecodedLength_fake.call_count > 0); - THEN("NoteBinaryReceive() is invoked") { - CHECK(NoteBinaryReceive_fake.call_count > 0); - } - THEN("The decoded length is passed to NoteBinaryReceive()") { - CHECK(NoteBinaryReceive_fake.arg3_history[0] == DECODED_LEN); - } - } - } - GIVEN("NoteBinaryReceive() is invoked") { - const uint32_t DECODED_LEN = 79; - NoteBinaryDataDecodedLength_fake.custom_fake = [](uint32_t *len) -> const char * { - *len = DECODED_LEN; - return NULL; - }; - WHEN("An error is encountered") { - const char *errMsg = "ERROR! Hacking too much time!"; - NoteBinaryReceive_fake.return_val = errMsg; - const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); - - REQUIRE(NoteBinaryReceive_fake.call_count > 0); - THEN("The dataLen is set to zero") { - CHECK(dataLen == 0); - } - THEN("The error is returned") { - CHECK(!strcmp(err,errMsg)); - } - } - WHEN("No error is encountered") { - const char *err = NoteBinaryReceiveAll(buffer, bufLen, &dataLen); - - REQUIRE(NoteBinaryReceive_fake.call_count > 0); - THEN("The decoded length is returned") { - CHECK(dataLen == DECODED_LEN); - } - THEN("The return value is NULL") { - CHECK(err == NULL); - } - } - } -} - -} - -#endif // NOTE_C_TEST From db4176e403a5ad3f4513e330f7f2c35725345140 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 16:43:21 +0000 Subject: [PATCH 08/24] chore: refactor NoteBinaryCodecDecode() --- n_helpers.c | 74 +++++++++---------- note.h | 5 +- test/CMakeLists.txt | 2 +- test/src/NoteBinaryCodecDecode_test.cpp | 89 +++++++++++++++++++++++ test/src/NoteBinaryDecode_test.cpp | 95 ------------------------- 5 files changed, 130 insertions(+), 135 deletions(-) create mode 100644 test/src/NoteBinaryCodecDecode_test.cpp delete mode 100644 test/src/NoteBinaryDecode_test.cpp diff --git a/n_helpers.c b/n_helpers.c index b37633d9..5ae9e21b 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -84,7 +84,7 @@ NOTE_C_STATIC void setTime(JTIME seconds); NOTE_C_STATIC bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs); NOTE_C_STATIC int ytodays(int year); -static const char BINARY_EOP = '\n'; +static const char NOTE_C_BINARY_EOP = '\n'; //**************************************************************************/ /*! @@ -220,38 +220,40 @@ const char * NoteBinaryDataReset(void) //**************************************************************************/ /*! - @brief Decode a binary payload received from the Notecard. + @brief Decode binary data received from the Notecard. - @param inBuf The binary payload. - @param inLen The length of the binary payload. - @param outBuf The buffer to write the decoded payload to. This can be the - same address as inBuf, allowing for in-place decoding. - @param outLen The length of outBuf. - @param decLen [out] The length of the decoded data. + @param encData The encoded binary data. + @param encLen The length of the encoded binary data. + @param decBuf The target buffer for the decoded data. This can be the + same address as `encData`, allowing for in-place decoding. + @param decBufLen The length of decBuf. - @returns NULL on success, else an error string pointer. + @returns The length of the decoded data, or zero on error. - @note When in-place decoding, the overall length shrinks and the - decoded data will be left-justified in the buffer. + @note This API supports in-place decoding. If you wish to utilize in-place + decoding, then set `decBuf` to `encData` and `decBufLen` to `encLen`. + @note Use `NoteBinaryMaxDecodedLength()` to calculate the required size for + the buffer pointed to by the `decBuf` parameter, which MUST accommodate + both the encoded data and newline terminator. */ /**************************************************************************/ -const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t outLen, - uint32_t *decLen) +uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, + uint8_t *decBuf, uint32_t decBufLen) { - if (inBuf == NULL || outBuf == NULL || decLen == NULL) { - NOTE_C_LOG_ERROR("NULL parameter"); - return ERRSTR("NULL parameter", c_err); - } + uint32_t result; - if (outLen < cobsGuaranteedFit(inLen)) { - NOTE_C_LOG_ERROR("output buffer too small"); - return ERRSTR("output buffer too small", c_err); + // Validate parameter(s) + if (encData == NULL || decBuf == NULL) { + NOTE_C_LOG_ERROR(ERRSTR("NULL parameter", c_err)); + result = 0; + } else if (decBufLen < cobsGuaranteedFit(encDataLen)) { + NOTE_C_LOG_ERROR(ERRSTR("output buffer too small", c_err)); + result = 0; + } else { + result = cobsDecode((uint8_t *)encData, encDataLen, NOTE_C_BINARY_EOP, decBuf); } - *decLen = cobsDecode((uint8_t *)inBuf, inLen, BINARY_EOP, outBuf); - - return NULL; + return result; } //**************************************************************************/ @@ -271,6 +273,9 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, @note When in-place encoding, the overall length expands. Therefore, the unencoded data should first be right-justified in the buffer, then the value of `outBuf` should be set to the beginning of the buffer. + @note Use `NoteBinaryMaxEncodedLength()` to calculate the required size for + the buffer pointed to by the `outBuf` parameter, which MUST accommodate + both the encoded data and newline terminator. */ /**************************************************************************/ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, @@ -289,7 +294,7 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, } } - *encLen = cobsEncode((uint8_t *)inBuf, inLen, BINARY_EOP, outBuf); + *encLen = cobsEncode((uint8_t *)inBuf, inLen, NOTE_C_BINARY_EOP, outBuf); return NULL; } @@ -435,12 +440,9 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, // part of the binary payload, so we decrement the length by 1 to remove it. --bufLen; - uint32_t decLen = 0; // Decode it in place, which is safe because decoding shrinks - err = NoteBinaryDecode(buffer, bufLen, buffer, bufLen, &decLen); - if (err) { - return err; - } + const uint32_t decLen = NoteBinaryCodecDecode(buffer, bufLen, buffer, bufLen); + // Ensure the decoded length matches the caller's expectations. if (decodedLen != decLen) { const char *err = ERRSTR("length mismatch after decoding", c_err); @@ -589,13 +591,13 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // On errors, we restore the caller's input buffer by COBS // decoding it. The caller is then able to retry transmission // with their original pointer to this buffer. - NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); + NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); return ERRSTR("failed to initialize binary transaction", c_err); } } else { NOTE_C_LOG_ERROR("unable to allocate request"); _UnlockNote(); - NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); + NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); return ERRSTR("unable to allocate request", c_mem); } @@ -607,7 +609,7 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // Ensure transaction was successful if (err) { - NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); + NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); return ERRSTR(err, c_err); } @@ -615,7 +617,7 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { NOTE_C_LOG_ERROR("unable to validate request"); - NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); + NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); return ERRSTR("unable to validate request", c_err); } @@ -631,13 +633,13 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, continue; } NOTE_C_LOG_ERROR("binary data invalid"); - NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); + NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); return ERRSTR("binary data invalid", c_bad); } else { JDelete(rsp); NOTE_C_LOG_ERROR("unexpected error received during " "confirmation"); - NoteBinaryDecode(encodedData, encLen, encodedData, bufLen, &encLen); + NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); return ERRSTR("unexpected error received during confirmation", c_bad); } diff --git a/note.h b/note.h index 2e4416ed..f8499841 100644 --- a/note.h +++ b/note.h @@ -320,9 +320,8 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen const char * NoteBinaryDataDecodedLength(uint32_t *len); const char * NoteBinaryDataEncodedLength(uint32_t *len); const char * NoteBinaryDataReset(void); -const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t outLen, - uint32_t *decLen); +uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, + uint8_t *decBuf, uint32_t decBufLen); const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t outLen, uint32_t *encLen); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b3e73837..77553ef3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -151,7 +151,7 @@ add_test(i2cChunkedTransmit_test) add_test(NoteBinaryDataDecodedLength_test) add_test(NoteBinaryDataEncodedLength_test) add_test(NoteBinaryDataReset_test) -add_test(NoteBinaryDecode_test) +add_test(NoteBinaryCodecDecode_test) add_test(NoteBinaryEncode_test) add_test(NoteBinaryMaxEncodedLength_test) add_test(NoteBinaryMaxDecodedLength_test) diff --git a/test/src/NoteBinaryCodecDecode_test.cpp b/test/src/NoteBinaryCodecDecode_test.cpp new file mode 100644 index 00000000..6deb56c1 --- /dev/null +++ b/test/src/NoteBinaryCodecDecode_test.cpp @@ -0,0 +1,89 @@ +/*! + * @file NoteBinaryCodecDecode_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(uint32_t, cobsDecode, uint8_t *, uint32_t, uint8_t, uint8_t *) + +uint8_t encData[12]; +const uint32_t encDataLen = sizeof(encData); +uint8_t decBuf[10]; +const uint32_t decBufLen = sizeof(decBuf); +uint32_t decLen; + +namespace +{ + +SCENARIO("NoteBinaryCodecDecode") +{ + RESET_FAKE(cobsDecode); + decLen = 0; + + GIVEN("Bad parameters are supplied") { + decLen = 79; + WHEN("encData is NULL") { + decLen = NoteBinaryCodecDecode(NULL, encDataLen, decBuf, decBufLen); + + THEN("The decoded length is zero") { + CHECK(decLen == 0); + } + } + WHEN("decBuf is NULL") { + decLen = NoteBinaryCodecDecode(encData, encDataLen, NULL, decBufLen); + + THEN("The decoded length is zero") { + CHECK(decLen == 0); + } + } + WHEN("decBufLen is less than the size required for the worst-case decoding") { + uint32_t badDecLen = (cobsGuaranteedFit(encDataLen) - 1); + decLen = NoteBinaryCodecDecode(encData, encDataLen, decBuf, badDecLen); + + THEN("The decoded length is zero") { + CHECK(decLen == 0); + } + } + } + + GIVEN("Parameters are in order") { + const uint32_t EXPECTED_RESULT = 79; + cobsDecode_fake.return_val = EXPECTED_RESULT; + decLen = NoteBinaryCodecDecode(encData, encDataLen, decBuf, decBufLen); + + THEN("cobsDecode is invoked") { + CHECK(cobsDecode_fake.call_count > 0); + } + + WHEN("cobsDecode is invoked") { + THEN("The parameters are passed without modification") { + CHECK(cobsDecode_fake.arg0_history[0] == encData); + CHECK(cobsDecode_fake.arg1_history[0] == encDataLen); + CHECK(cobsDecode_fake.arg3_history[0] == decBuf); + } + + THEN("The result is returned without modification") { + CHECK(EXPECTED_RESULT == decLen); + } + } + } +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryDecode_test.cpp b/test/src/NoteBinaryDecode_test.cpp deleted file mode 100644 index 0453a6d5..00000000 --- a/test/src/NoteBinaryDecode_test.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/*! - * @file NoteBinaryDecode_test.cpp - * - * Written by the Blues Inc. team. - * - * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is - * governed by licenses granted by the copyright holder including that found in - * the - * LICENSE - * file. - * - */ - -#ifdef NOTE_C_TEST - -#include -#include "fff.h" - -#include "n_lib.h" - -DEFINE_FFF_GLOBALS -FAKE_VALUE_FUNC(uint32_t, cobsDecode, uint8_t *, uint32_t, uint8_t, uint8_t *) - -uint8_t inBuf[12]; -const uint32_t inLen = sizeof(inBuf); -uint8_t outBuf[10]; -const uint32_t outLen = sizeof(outBuf); -uint32_t decLen; - -namespace -{ - -SCENARIO("NoteBinaryDecode") -{ - RESET_FAKE(cobsDecode); - decLen = 0; - - GIVEN("Bad parameters are supplied") { - WHEN("inBuf is NULL") { - const char *err = NoteBinaryDecode(NULL, inLen, outBuf, outLen, &decLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("outBuf is NULL") { - const char *err = NoteBinaryDecode(inBuf, inLen, NULL, outLen, &decLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("decLen is NULL") { - const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, outLen, NULL); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("outLen is less than the size required for the worst-case decoding") { - uint32_t badOutLen = (cobsGuaranteedFit(inLen) - 1); - const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, badOutLen, &decLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("Parameters are in order") { - const uint32_t EXPECTED_RESULT = 79; - cobsDecode_fake.return_val = EXPECTED_RESULT; - const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, outLen, &decLen); - - THEN("cobsDecode is invoked") { - CHECK(cobsDecode_fake.call_count > 0); - } - - WHEN("cobsDecode is invoked") { - THEN("The parameters are passed without modification") { - CHECK(cobsDecode_fake.arg0_history[0] == inBuf); - CHECK(cobsDecode_fake.arg1_history[0] == inLen); - CHECK(cobsDecode_fake.arg3_history[0] == outBuf); - } - - THEN("The result is returned without modification") { - CHECK(EXPECTED_RESULT == decLen); - } - } - } -} - -} - -#endif // NOTE_C_TEST From 3a6549193252154d73a74f45de816837e858e9c0 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 17:57:55 +0000 Subject: [PATCH 09/24] chore: refactor NoteBinaryCodecEncode() --- n_helpers.c | 76 ++++++++++--------- note.h | 7 +- test/CMakeLists.txt | 4 +- test/src/NoteBinaryCodecEncode_test.cpp | 90 +++++++++++++++++++++++ test/src/NoteBinaryEncode_test.cpp | 97 ------------------------- test/src/NoteBinaryReceive_test.cpp | 3 +- test/src/NoteBinaryTransmit_test.cpp | 4 +- 7 files changed, 135 insertions(+), 146 deletions(-) create mode 100644 test/src/NoteBinaryCodecEncode_test.cpp delete mode 100644 test/src/NoteBinaryEncode_test.cpp diff --git a/n_helpers.c b/n_helpers.c index 5ae9e21b..143046be 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -222,23 +222,23 @@ const char * NoteBinaryDataReset(void) /*! @brief Decode binary data received from the Notecard. - @param encData The encoded binary data. + @param encData The encoded binary data to decode. @param encLen The length of the encoded binary data. @param decBuf The target buffer for the decoded data. This can be the same address as `encData`, allowing for in-place decoding. - @param decBufLen The length of decBuf. + @param decBufSize The size of `decBuf`. @returns The length of the decoded data, or zero on error. - @note This API supports in-place decoding. If you wish to utilize in-place - decoding, then set `decBuf` to `encData` and `decBufLen` to `encLen`. @note Use `NoteBinaryMaxDecodedLength()` to calculate the required size for the buffer pointed to by the `decBuf` parameter, which MUST accommodate both the encoded data and newline terminator. + @note This API supports in-place decoding. If you wish to utilize in-place + decoding, then set `decBuf` to `encData` and `decBufSize` to `encLen`. */ /**************************************************************************/ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, - uint8_t *decBuf, uint32_t decBufLen) + uint8_t *decBuf, uint32_t decBufSize) { uint32_t result; @@ -246,7 +246,7 @@ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, if (encData == NULL || decBuf == NULL) { NOTE_C_LOG_ERROR(ERRSTR("NULL parameter", c_err)); result = 0; - } else if (decBufLen < cobsGuaranteedFit(encDataLen)) { + } else if (decBufSize < cobsGuaranteedFit(encDataLen)) { NOTE_C_LOG_ERROR(ERRSTR("output buffer too small", c_err)); result = 0; } else { @@ -259,44 +259,45 @@ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, //**************************************************************************/ /*! - @brief Binary encode a buffer to prepare it for transmission to the Notecard. + @brief Encode binary data to transmit to the Notecard. - @param inBuf The data to encode. - @param inLen The length of the data to encode. - @param outBuf The buffer to write the encoded data to. This can be the - same address as inBuf, allowing for in-place encoding. - @param outLen The length of outBuf. - @param encLen [out] The length of the encoded data. + @param decData The decoded binary data to encode. + @param decDataLen The length of the decoded binary data. + @param encBuf The target buffer for the encoded data. This can be in the same + buffer as `decData`, allowing for in-place encoding (see note). + @param encBufSize The size of `encBuf`. @returns NULL on success, else an error string pointer. - @note When in-place encoding, the overall length expands. Therefore, the - unencoded data should first be right-justified in the buffer, then the - value of `outBuf` should be set to the beginning of the buffer. @note Use `NoteBinaryMaxEncodedLength()` to calculate the required size for - the buffer pointed to by the `outBuf` parameter, which MUST accommodate + the buffer pointed to by the `encBuf` parameter, which MUST accommodate both the encoded data and newline terminator. + @note This API supports in-place encoding. If you wish to utilize in-place + encoding, then right-justify the decoded data in the buffer (updating + `decBuf` accordingly) and set the value of `encBuf` to the beginning + of the buffer. */ /**************************************************************************/ -const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t outLen, - uint32_t *encLen) +uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, + uint8_t *encBuf, uint32_t encBufSize) { - if (inBuf == NULL || outBuf == NULL || encLen == NULL) { - NOTE_C_LOG_ERROR("NULL parameter"); - return ERRSTR("NULL parameter", c_err); - } + uint32_t result; - if (outLen < cobsEncodedMaxLength(inLen)) { - if (outLen < cobsEncodedLength(inBuf, inLen)) { - NOTE_C_LOG_ERROR("output buffer too small"); - return ERRSTR("output buffer too small", c_err); - } + // Validate parameter(s) + if (decData == NULL || encBuf == NULL) { + NOTE_C_LOG_ERROR(ERRSTR("NULL parameter", c_err)); + result = 0; + } else if ((encBufSize < cobsEncodedMaxLength(decDataLen)) && (encBufSize < cobsEncodedLength(decData, decDataLen))) { + // NOTE: `cobsEncodedMaxLength()` provides a constant time [O(1)] means + // of checking the buffer size. Only when it fails will the linear + // time [O(n)] check, `cobsEncodedLength()`, be invoked. + NOTE_C_LOG_ERROR(ERRSTR("output buffer too small", c_err)); + result = 0; + } else { + result = cobsEncode((uint8_t *)decData, decDataLen, NOTE_C_BINARY_EOP, encBuf); } - *encLen = cobsEncode((uint8_t *)inBuf, inLen, NOTE_C_BINARY_EOP, outBuf); - - return NULL; + return result; } //**************************************************************************/ @@ -558,14 +559,11 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // Update unencoded data pointer unencodedData += dataShift; - uint32_t encLen = 0; - // `(bufLen - 1)` accounts for one byte of space we need to save for a - // newline to mark the end of the packet. - err = NoteBinaryEncode(unencodedData, unencodedLen, encodedData, (bufLen - 1), &encLen); - if (err) { - return err; - } + // Capture encoded length + // NOTE: `(bufLen - 1)` accounts for one byte of space we need to save for a + // newline to mark the end of the packet. + const uint32_t encLen = NoteBinaryCodecEncode(unencodedData, unencodedLen, encodedData, (bufLen - 1)); // Append the \n, which marks the end of a packet. encodedData[encLen] = '\n'; diff --git a/note.h b/note.h index f8499841..e47ac87f 100644 --- a/note.h +++ b/note.h @@ -321,10 +321,9 @@ const char * NoteBinaryDataDecodedLength(uint32_t *len); const char * NoteBinaryDataEncodedLength(uint32_t *len); const char * NoteBinaryDataReset(void); uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, - uint8_t *decBuf, uint32_t decBufLen); -const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t outLen, - uint32_t *encLen); + uint8_t *decBuf, uint32_t decBufSize); +uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, + uint8_t *encBuf, uint32_t encBufSize); uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 77553ef3..04531a83 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -148,11 +148,11 @@ add_test(serialChunkedTransmit_test) add_test(i2cNoteQueryLength_test) add_test(i2cChunkedReceive_test) add_test(i2cChunkedTransmit_test) +add_test(NoteBinaryCodecDecode_test) +add_test(NoteBinaryCodecEncode_test) add_test(NoteBinaryDataDecodedLength_test) add_test(NoteBinaryDataEncodedLength_test) add_test(NoteBinaryDataReset_test) -add_test(NoteBinaryCodecDecode_test) -add_test(NoteBinaryEncode_test) add_test(NoteBinaryMaxEncodedLength_test) add_test(NoteBinaryMaxDecodedLength_test) add_test(NoteBinaryReceive_test) diff --git a/test/src/NoteBinaryCodecEncode_test.cpp b/test/src/NoteBinaryCodecEncode_test.cpp new file mode 100644 index 00000000..a6ee2298 --- /dev/null +++ b/test/src/NoteBinaryCodecEncode_test.cpp @@ -0,0 +1,90 @@ +/*! + * @file NoteBinaryCodecEncode_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(uint32_t, cobsEncode, uint8_t *, uint32_t, uint8_t, uint8_t *) + +uint8_t decData[10] = "Hi Blues!"; +uint32_t decDataLen = strlen((const char *)decData); +uint8_t encBuf[12]; +uint32_t encBufLen = sizeof(encBuf); +uint32_t encLen; + +namespace +{ + +SCENARIO("NoteBinaryCodecEncode") +{ + RESET_FAKE(cobsEncode); + encLen = 0; + + GIVEN("Bad parameters are supplied") { + WHEN("decData is NULL") { + encLen = NoteBinaryCodecEncode(NULL, decDataLen, encBuf, encBufLen); + + THEN("The encoded length is zero") { + CHECK(encLen == 0); + } + } + WHEN("encBuf is NULL") { + encLen = NoteBinaryCodecEncode(decData, decDataLen, NULL, encBufLen); + + THEN("The encoded length is zero") { + CHECK(encLen == 0); + } + } + WHEN("encBufLen is less than the size required for in place encoding") { + uint32_t badOutLen = (cobsEncodedLength(decData, decDataLen) - 1); + encLen = NoteBinaryCodecEncode(decData, decDataLen, encBuf, badOutLen); + + THEN("The encoded length is zero") { + CHECK(encLen == 0); + } + } + } + + GIVEN("Parameters are in order") { + const uint32_t EXPECTED_RESULT = 79; + cobsEncode_fake.return_val = EXPECTED_RESULT; + encLen = NoteBinaryCodecEncode(decData, decDataLen, encBuf, encBufLen); + + THEN("cobsEncode is invoked") { + CHECK(cobsEncode_fake.call_count > 0); + } + + WHEN("cobsEncode is invoked") { + THEN("The parameters are passed without modification") { + CHECK(cobsEncode_fake.arg0_history[0] == decData); + CHECK(cobsEncode_fake.arg1_history[0] == decDataLen); + CHECK(cobsEncode_fake.arg3_history[0] == encBuf); + } + + THEN("The result is returned without modification") { + CHECK(EXPECTED_RESULT == encLen); + } + } + } +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryEncode_test.cpp b/test/src/NoteBinaryEncode_test.cpp deleted file mode 100644 index f400952b..00000000 --- a/test/src/NoteBinaryEncode_test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/*! - * @file NoteBinaryEncode_test.cpp - * - * Written by the Blues Inc. team. - * - * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is - * governed by licenses granted by the copyright holder including that found in - * the - * LICENSE - * file. - * - */ - -#ifdef NOTE_C_TEST - -#include - -#include -#include "fff.h" - -#include "n_lib.h" - -DEFINE_FFF_GLOBALS -FAKE_VALUE_FUNC(uint32_t, cobsEncode, uint8_t *, uint32_t, uint8_t, uint8_t *) - -uint8_t inBuf[10] = "Hi there!"; -uint32_t inLen = strlen((const char *)inBuf); -uint8_t outBuf[12]; -uint32_t outLen = sizeof(outBuf); -uint32_t encLen; - -namespace -{ - -SCENARIO("NoteBinaryEncode") -{ - RESET_FAKE(cobsEncode); - encLen = 0; - - GIVEN("Bad parameters are supplied") { - WHEN("inBuf is NULL") { - const char *err = NoteBinaryEncode(NULL, inLen, outBuf, outLen, &encLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("outBuf is NULL") { - const char *err = NoteBinaryEncode(inBuf, inLen, NULL, outLen, &encLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("encLen is NULL") { - const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, outLen, NULL); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - WHEN("outLen is less than the size required for in place encoding") { - uint32_t badOutLen = (cobsEncodedLength(inBuf, inLen) - 1); - const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, badOutLen, &encLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("Parameters are in order") { - const uint32_t EXPECTED_RESULT = 79; - cobsEncode_fake.return_val = EXPECTED_RESULT; - const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, outLen, &encLen); - - THEN("cobsEncode is invoked") { - CHECK(cobsEncode_fake.call_count > 0); - } - - WHEN("cobsEncode is invoked") { - THEN("The parameters are passed without modification") { - CHECK(cobsEncode_fake.arg0_history[0] == inBuf); - CHECK(cobsEncode_fake.arg1_history[0] == inLen); - CHECK(cobsEncode_fake.arg3_history[0] == outBuf); - } - - THEN("The result is returned without modification") { - CHECK(EXPECTED_RESULT == encLen); - } - } - } -} - -} - -#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index 22d2e4db..ac1c87f8 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -169,8 +169,7 @@ SCENARIO("NoteBinaryReceive") GIVEN("The binary payload is received") { NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, uint32_t *size, bool, size_t, uint32_t *available) -> const char* { - uint32_t outLen = 0; - NoteBinaryEncode((uint8_t *)rawMsg, rawMsgLen, buffer, *size, &outLen); + uint32_t outLen = NoteBinaryCodecEncode((uint8_t *)rawMsg, rawMsgLen, buffer, *size); buffer[outLen] = '\n'; *size = outLen + 1; diff --git a/test/src/NoteBinaryTransmit_test.cpp b/test/src/NoteBinaryTransmit_test.cpp index df6eb129..0ac03182 100644 --- a/test/src/NoteBinaryTransmit_test.cpp +++ b/test/src/NoteBinaryTransmit_test.cpp @@ -184,8 +184,8 @@ SCENARIO("NoteBinaryTransmit") // Discover the actual encoded length of the data const uint32_t tempBufLen = cobsEncodedMaxLength(dataLen); uint8_t *tempBuf = (uint8_t *)malloc(tempBufLen); - uint32_t newBufLen = 0; - REQUIRE(!NoteBinaryEncode(buf, dataLen, tempBuf, tempBufLen, &newBufLen)); + uint32_t newBufLen = NoteBinaryCodecEncode(buf, dataLen, tempBuf, tempBufLen); + REQUIRE(newBufLen > 0); free(tempBuf); WHEN("NoteBinaryTransmit is called") { From 0941431e574b8b4eb85cf183ea11b5f9a9794887 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 18:03:10 +0000 Subject: [PATCH 10/24] chore: refactor NoteBinaryCodecMaxDecodedLength() --- n_helpers.c | 8 ++++---- note.h | 2 +- test/CMakeLists.txt | 2 +- ..._test.cpp => NoteBinaryCodecMaxDecodedLength_test.cpp} | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) rename test/src/{NoteBinaryMaxDecodedLength_test.cpp => NoteBinaryCodecMaxDecodedLength_test.cpp} (87%) diff --git a/n_helpers.c b/n_helpers.c index 143046be..5521f0ad 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -230,9 +230,9 @@ const char * NoteBinaryDataReset(void) @returns The length of the decoded data, or zero on error. - @note Use `NoteBinaryMaxDecodedLength()` to calculate the required size for - the buffer pointed to by the `decBuf` parameter, which MUST accommodate - both the encoded data and newline terminator. + @note Use `NoteBinaryCodecMaxDecodedLength()` to calculate the required + size for the buffer pointed to by the `decBuf` parameter, which MUST + accommodate both the encoded data and newline terminator. @note This API supports in-place decoding. If you wish to utilize in-place decoding, then set `decBuf` to `encData` and `decBufSize` to `encLen`. */ @@ -326,7 +326,7 @@ uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, buffer, after being encoded. */ /**************************************************************************/ -uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize) +uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize) { return cobsGuaranteedFit(bufferSize); } diff --git a/note.h b/note.h index e47ac87f..f55dbc9a 100644 --- a/note.h +++ b/note.h @@ -324,7 +324,7 @@ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, uint8_t *decBuf, uint32_t decBufSize); uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, uint8_t *encBuf, uint32_t encBufSize); -uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize); +uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 04531a83..e77a006b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -150,11 +150,11 @@ add_test(i2cChunkedReceive_test) add_test(i2cChunkedTransmit_test) add_test(NoteBinaryCodecDecode_test) add_test(NoteBinaryCodecEncode_test) +add_test(NoteBinaryCodecMaxDecodedLength_test) add_test(NoteBinaryDataDecodedLength_test) add_test(NoteBinaryDataEncodedLength_test) add_test(NoteBinaryDataReset_test) add_test(NoteBinaryMaxEncodedLength_test) -add_test(NoteBinaryMaxDecodedLength_test) add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) diff --git a/test/src/NoteBinaryMaxDecodedLength_test.cpp b/test/src/NoteBinaryCodecMaxDecodedLength_test.cpp similarity index 87% rename from test/src/NoteBinaryMaxDecodedLength_test.cpp rename to test/src/NoteBinaryCodecMaxDecodedLength_test.cpp index 81894220..129aaa5c 100644 --- a/test/src/NoteBinaryMaxDecodedLength_test.cpp +++ b/test/src/NoteBinaryCodecMaxDecodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryMaxDecodedLength_test.cpp + * @file NoteBinaryCodecMaxDecodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -26,14 +26,14 @@ const uint32_t bufferSize = 10; namespace { -SCENARIO("NoteBinaryMaxDecodedLength") +SCENARIO("NoteBinaryCodecMaxDecodedLength") { RESET_FAKE(cobsGuaranteedFit); GIVEN("Parameters are in order") { const uint32_t EXPECTED_RESULT = 79; cobsGuaranteedFit_fake.return_val = EXPECTED_RESULT; - const uint32_t result = NoteBinaryMaxDecodedLength(bufferSize); + const uint32_t result = NoteBinaryCodecMaxDecodedLength(bufferSize); THEN("cobsGuaranteedFit is invoked") { CHECK(cobsGuaranteedFit_fake.call_count > 0); From 1cf2669d47fb0a15e5b2815c33b0bc253fa5853f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 18:11:28 +0000 Subject: [PATCH 11/24] chore: refactor NoteBinaryCodecMaxEncodedLength() --- n_helpers.c | 18 +++++++++--------- note.h | 2 +- test/CMakeLists.txt | 2 +- ...> NoteBinaryCodecMaxEncodedLength_test.cpp} | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) rename test/src/{NoteBinaryMaxEncodedLength_test.cpp => NoteBinaryCodecMaxEncodedLength_test.cpp} (87%) diff --git a/n_helpers.c b/n_helpers.c index 5521f0ad..9c75c1c1 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -269,9 +269,9 @@ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, @returns NULL on success, else an error string pointer. - @note Use `NoteBinaryMaxEncodedLength()` to calculate the required size for - the buffer pointed to by the `encBuf` parameter, which MUST accommodate - both the encoded data and newline terminator. + @note Use `NoteBinaryCodecMaxEncodedLength()` to calculate the required + size for the buffer pointed to by the `encBuf` parameter, which MUST + accommodate both the encoded data and newline terminator. @note This API supports in-place encoding. If you wish to utilize in-place encoding, then right-justify the decoded data in the buffer (updating `decBuf` accordingly) and set the value of `encBuf` to the beginning @@ -341,7 +341,7 @@ uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize) @returns The max required buffer size to hold the encoded data. */ /**************************************************************************/ -uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) +uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength) { return cobsEncodedMaxLength(unencodedLength); } @@ -362,8 +362,8 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) @note The buffer must be large enough to hold the encoded value of the data store contents from the requested offset for the specified length. To determine the necessary buffer size for a given data length, use - `NoteBinaryMaxEncodedLength()`, or if you wish to consume the entire - buffer use `NoteBinaryDataEncodedLength()` instead. + `NoteBinaryCodecMaxEncodedLength()`, or if you wish to consume the + entire buffer use `NoteBinaryDataEncodedLength()` instead. */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, @@ -485,9 +485,9 @@ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. - Use `NoteBinaryMaxEncodedLength()` to calculate the required size for - the buffer pointed to by the `bufLen` parameter, which MUST accommodate - both the encoded data and newline terminator. + Use `NoteBinaryCodecMaxEncodedLength()` to calculate the required size + for the buffer pointed to by the `unencodedData` parameter, which MUST + accommodate both the encoded data and newline terminator. */ /**************************************************************************/ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, diff --git a/note.h b/note.h index f55dbc9a..abb432ea 100644 --- a/note.h +++ b/note.h @@ -325,7 +325,7 @@ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, uint8_t *encBuf, uint32_t encBufSize); uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize); -uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); +uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e77a006b..b4841dc8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -151,10 +151,10 @@ add_test(i2cChunkedTransmit_test) add_test(NoteBinaryCodecDecode_test) add_test(NoteBinaryCodecEncode_test) add_test(NoteBinaryCodecMaxDecodedLength_test) +add_test(NoteBinaryCodecMaxEncodedLength_test) add_test(NoteBinaryDataDecodedLength_test) add_test(NoteBinaryDataEncodedLength_test) add_test(NoteBinaryDataReset_test) -add_test(NoteBinaryMaxEncodedLength_test) add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) diff --git a/test/src/NoteBinaryMaxEncodedLength_test.cpp b/test/src/NoteBinaryCodecMaxEncodedLength_test.cpp similarity index 87% rename from test/src/NoteBinaryMaxEncodedLength_test.cpp rename to test/src/NoteBinaryCodecMaxEncodedLength_test.cpp index fb3227dc..012f1ade 100644 --- a/test/src/NoteBinaryMaxEncodedLength_test.cpp +++ b/test/src/NoteBinaryCodecMaxEncodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryMaxEncodedLength_test.cpp + * @file NoteBinaryCodecMaxEncodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -26,14 +26,14 @@ const uint32_t unencodedLen = 10; namespace { -SCENARIO("NoteBinaryMaxEncodedLength") +SCENARIO("NoteBinaryCodecMaxEncodedLength") { RESET_FAKE(cobsEncodedMaxLength); GIVEN("Parameters are in order") { const uint32_t EXPECTED_RESULT = 79; cobsEncodedMaxLength_fake.return_val = EXPECTED_RESULT; - const uint32_t result = NoteBinaryMaxEncodedLength(unencodedLen); + const uint32_t result = NoteBinaryCodecMaxEncodedLength(unencodedLen); THEN("cobsEncodedMaxLength is invoked") { CHECK(cobsEncodedMaxLength_fake.call_count > 0); From 91d90cc47a320abe144299773c9aed5af72c33d0 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 18:14:50 +0000 Subject: [PATCH 12/24] chore: refactor NoteBinaryStoreDecodedLength() --- n_helpers.c | 17 ++++++++------ note.h | 6 ++--- test/CMakeLists.txt | 2 +- ... => NoteBinaryStoreDecodedLength_test.cpp} | 22 +++++++++---------- 4 files changed, 25 insertions(+), 22 deletions(-) rename test/src/{NoteBinaryDataDecodedLength_test.cpp => NoteBinaryStoreDecodedLength_test.cpp} (81%) diff --git a/n_helpers.c b/n_helpers.c index 9c75c1c1..eaadd615 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -97,19 +97,21 @@ static const char NOTE_C_BINARY_EOP = '\n'; @returns An error string on error and NULL on success. */ /**************************************************************************/ -const char * NoteBinaryDataDecodedLength(uint32_t *len) +const char * NoteBinaryStoreDecodedLength(uint32_t *len) { // Validate parameter(s) if (!len) { - NOTE_C_LOG_ERROR("len cannot be NULL"); - return ERRSTR("len cannot be NULL", c_err); + const char *err = ERRSTR("len cannot be NULL", c_bad); + NOTE_C_LOG_ERROR(err); + return err; } // Issue a "card.binary" request. J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { - NOTE_C_LOG_ERROR("unable to issue binary request"); - return ERRSTR("unable to issue binary request", c_err); + const char *err = ERRSTR("unable to issue binary request", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Ensure the transaction doesn't return an error and confirm the binary @@ -118,8 +120,9 @@ const char * NoteBinaryDataDecodedLength(uint32_t *len) const char *err = JGetString(rsp, "err"); NOTE_C_LOG_ERROR(err); JDelete(rsp); - NOTE_C_LOG_ERROR("unexpected error received during handshake"); - return ERRSTR("unexpected error received during handshake", c_bad); + err = ERRSTR("unexpected error received during handshake", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Examine "length" from the response to evaluate the length of the decoded diff --git a/note.h b/note.h index abb432ea..afcdd3fb 100644 --- a/note.h +++ b/note.h @@ -317,15 +317,15 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen // High-level helper functions that are both useful and serve to show developers // how to call the API -const char * NoteBinaryDataDecodedLength(uint32_t *len); -const char * NoteBinaryDataEncodedLength(uint32_t *len); -const char * NoteBinaryDataReset(void); uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, uint8_t *decBuf, uint32_t decBufSize); uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, uint8_t *encBuf, uint32_t encBufSize); uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength); +const char * NoteBinaryStoreDecodedLength(uint32_t *len); +const char * NoteBinaryDataEncodedLength(uint32_t *len); +const char * NoteBinaryDataReset(void); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b4841dc8..c52828f1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -152,7 +152,7 @@ add_test(NoteBinaryCodecDecode_test) add_test(NoteBinaryCodecEncode_test) add_test(NoteBinaryCodecMaxDecodedLength_test) add_test(NoteBinaryCodecMaxEncodedLength_test) -add_test(NoteBinaryDataDecodedLength_test) +add_test(NoteBinaryStoreDecodedLength_test) add_test(NoteBinaryDataEncodedLength_test) add_test(NoteBinaryDataReset_test) add_test(NoteBinaryReceive_test) diff --git a/test/src/NoteBinaryDataDecodedLength_test.cpp b/test/src/NoteBinaryStoreDecodedLength_test.cpp similarity index 81% rename from test/src/NoteBinaryDataDecodedLength_test.cpp rename to test/src/NoteBinaryStoreDecodedLength_test.cpp index 3a0dccb8..a892b86c 100644 --- a/test/src/NoteBinaryDataDecodedLength_test.cpp +++ b/test/src/NoteBinaryStoreDecodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryDataDecodedLength_test.cpp + * @file NoteBinaryStoreDecodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -26,7 +26,7 @@ const size_t len = 10; namespace { -SCENARIO("NoteBinaryDataDecodedLength") +SCENARIO("NoteBinaryStoreDecodedLength") { RESET_FAKE(NoteRequestResponse); @@ -36,7 +36,7 @@ SCENARIO("NoteBinaryDataDecodedLength") GIVEN("Bad parameters are supplied") { WHEN("Length is NULL") { - const char *err = NoteBinaryDataDecodedLength(NULL); + const char *err = NoteBinaryStoreDecodedLength(NULL); THEN("An error is returned") { CHECK(err != NULL); @@ -51,8 +51,8 @@ SCENARIO("NoteBinaryDataDecodedLength") return NULL; }; - WHEN("NoteBinaryDataDecodedLength is called") { - const char *err = NoteBinaryDataDecodedLength(&size); + WHEN("NoteBinaryStoreDecodedLength is called") { + const char *err = NoteBinaryStoreDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { @@ -70,8 +70,8 @@ SCENARIO("NoteBinaryDataDecodedLength") return rsp; }; - WHEN("NoteBinaryDataDecodedLength is called") { - const char *err = NoteBinaryDataDecodedLength(&size); + WHEN("NoteBinaryStoreDecodedLength is called") { + const char *err = NoteBinaryStoreDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { @@ -90,8 +90,8 @@ SCENARIO("NoteBinaryDataDecodedLength") return rsp; }; - WHEN("NoteBinaryDataDecodedLength is called") { - const char *err = NoteBinaryDataDecodedLength(&size); + WHEN("NoteBinaryStoreDecodedLength is called") { + const char *err = NoteBinaryStoreDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is not returned") { @@ -114,8 +114,8 @@ SCENARIO("NoteBinaryDataDecodedLength") return rsp; }; - WHEN("NoteBinaryDataDecodedLength is called") { - const char *err = NoteBinaryDataDecodedLength(&size); + WHEN("NoteBinaryStoreDecodedLength is called") { + const char *err = NoteBinaryStoreDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is not returned") { From 70867b9c11532c15895a8d64f10bc3e94faceb93 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 18:50:00 +0000 Subject: [PATCH 13/24] chore: refactor NoteBinaryStoreEncodedLength() --- n_helpers.c | 29 ++++++++----------- note.h | 2 +- test/CMakeLists.txt | 2 +- test/src/NoteBinaryReceive_test.cpp | 6 ++-- ... => NoteBinaryStoreEncodedLength_test.cpp} | 28 +++++++++--------- 5 files changed, 32 insertions(+), 35 deletions(-) rename test/src/{NoteBinaryDataEncodedLength_test.cpp => NoteBinaryStoreEncodedLength_test.cpp} (76%) diff --git a/n_helpers.c b/n_helpers.c index eaadd615..ba4a1ee9 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -145,19 +145,21 @@ const char * NoteBinaryStoreDecodedLength(uint32_t *len) @returns An error string on error and NULL on success. */ /**************************************************************************/ -const char * NoteBinaryDataEncodedLength(uint32_t *len) +const char * NoteBinaryStoreEncodedLength(uint32_t *len) { // Validate parameter(s) if (!len) { - NOTE_C_LOG_ERROR("size cannot be NULL"); - return ERRSTR("size cannot be NULL", c_err); + const char *err = ERRSTR("size cannot be NULL", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Issue a "card.binary" request. J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { - NOTE_C_LOG_ERROR("unable to issue binary request"); - return ERRSTR("unable to issue binary request", c_err); + const char *err = ERRSTR("unable to issue binary request", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Ensure the transaction doesn't return an error and confirm the binary @@ -166,23 +168,16 @@ const char * NoteBinaryDataEncodedLength(uint32_t *len) const char *err = JGetString(rsp, "err"); NOTE_C_LOG_ERROR(err); JDelete(rsp); - NOTE_C_LOG_ERROR("unexpected error received during handshake"); - return ERRSTR("unexpected error received during handshake", c_bad); + err = ERRSTR("unexpected error received during handshake", c_bad); + NOTE_C_LOG_ERROR(err); + return err; } // Examine "cobs" from the response to evaluate the space required to hold // the COBS-encoded data to be received from the Notecard. long int cobs = JGetInt(rsp, "cobs"); JDelete(rsp); - if (!cobs) { - // If cobs is 0, the required buffer length is 0 because there's nothing - // to receive. - *len = 0; - } else { - // Otherwise, the required length is cobs + 1: the binary data plus - // 1 byte for the terminating newline. - *len = cobs + 1; - } + *len = cobs; return NULL; } @@ -366,7 +361,7 @@ uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength) data store contents from the requested offset for the specified length. To determine the necessary buffer size for a given data length, use `NoteBinaryCodecMaxEncodedLength()`, or if you wish to consume the - entire buffer use `NoteBinaryDataEncodedLength()` instead. + entire buffer use `(NoteBinaryStoreEncodedLength() + 1)` instead. */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, diff --git a/note.h b/note.h index afcdd3fb..79ebc8a3 100644 --- a/note.h +++ b/note.h @@ -324,7 +324,7 @@ uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryStoreDecodedLength(uint32_t *len); -const char * NoteBinaryDataEncodedLength(uint32_t *len); +const char * NoteBinaryStoreEncodedLength(uint32_t *len); const char * NoteBinaryDataReset(void); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c52828f1..f37ead06 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -153,7 +153,7 @@ add_test(NoteBinaryCodecEncode_test) add_test(NoteBinaryCodecMaxDecodedLength_test) add_test(NoteBinaryCodecMaxEncodedLength_test) add_test(NoteBinaryStoreDecodedLength_test) -add_test(NoteBinaryDataEncodedLength_test) +add_test(NoteBinaryStoreEncodedLength_test) add_test(NoteBinaryDataReset_test) add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index ac1c87f8..a2cd3cb4 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -20,7 +20,7 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) -FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, uint32_t *) +FAKE_VALUE_FUNC(const char *, NoteBinaryStoreEncodedLength, uint32_t *) FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, uint32_t *, bool, size_t, uint32_t *) @@ -47,7 +47,7 @@ namespace SCENARIO("NoteBinaryReceive") { RESET_FAKE(NoteNewRequest); - RESET_FAKE(NoteBinaryDataEncodedLength); + RESET_FAKE(NoteBinaryStoreEncodedLength); RESET_FAKE(NoteRequestResponse); RESET_FAKE(NoteChunkedReceive); RESET_FAKE(NoteLockNote); @@ -60,7 +60,7 @@ SCENARIO("NoteBinaryReceive") NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { return JCreateObject(); }; - NoteBinaryDataEncodedLength_fake.custom_fake = [](uint32_t *size) + NoteBinaryStoreEncodedLength_fake.custom_fake = [](uint32_t *size) -> const char * { *size = bufLen; diff --git a/test/src/NoteBinaryDataEncodedLength_test.cpp b/test/src/NoteBinaryStoreEncodedLength_test.cpp similarity index 76% rename from test/src/NoteBinaryDataEncodedLength_test.cpp rename to test/src/NoteBinaryStoreEncodedLength_test.cpp index 605e6cf4..d9e5cefb 100644 --- a/test/src/NoteBinaryDataEncodedLength_test.cpp +++ b/test/src/NoteBinaryStoreEncodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryDataEncodedLength_test.cpp + * @file NoteBinaryStoreEncodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -18,6 +18,8 @@ #include "n_lib.h" +const char * NoteBinaryStoreEncodedLength(uint32_t *); + DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) @@ -26,7 +28,7 @@ const uint32_t cobsLen = 10; namespace { -SCENARIO("NoteBinaryDataEncodedLength") +SCENARIO("NoteBinaryStoreEncodedLength") { RESET_FAKE(NoteRequestResponse); @@ -36,7 +38,7 @@ SCENARIO("NoteBinaryDataEncodedLength") GIVEN("Bad parameters are supplied") { WHEN("Length is NULL") { - const char *err = NoteBinaryDataEncodedLength(NULL); + const char *err = NoteBinaryStoreEncodedLength(NULL); THEN("An error is returned") { CHECK(err != NULL); @@ -51,8 +53,8 @@ SCENARIO("NoteBinaryDataEncodedLength") return NULL; }; - WHEN("NoteBinaryDataEncodedLength is called") { - const char *err = NoteBinaryDataEncodedLength(&size); + WHEN("NoteBinaryStoreEncodedLength is called") { + const char *err = NoteBinaryStoreEncodedLength(&size); THEN("An error is returned") { CHECK(err != NULL); @@ -69,8 +71,8 @@ SCENARIO("NoteBinaryDataEncodedLength") return rsp; }; - WHEN("NoteBinaryDataEncodedLength is called") { - const char *err = NoteBinaryDataEncodedLength(&size); + WHEN("NoteBinaryStoreEncodedLength is called") { + const char *err = NoteBinaryStoreEncodedLength(&size); THEN("An error is returned") { CHECK(err != NULL); @@ -88,8 +90,8 @@ SCENARIO("NoteBinaryDataEncodedLength") return rsp; }; - WHEN("NoteBinaryDataEncodedLength is called") { - const char *err = NoteBinaryDataEncodedLength(&size); + WHEN("NoteBinaryStoreEncodedLength is called") { + const char *err = NoteBinaryStoreEncodedLength(&size); THEN("An error is not returned") { CHECK(err == NULL); @@ -111,16 +113,16 @@ SCENARIO("NoteBinaryDataEncodedLength") return rsp; }; - WHEN("NoteBinaryDataEncodedLength is called") { - const char *err = NoteBinaryDataEncodedLength(&size); + WHEN("NoteBinaryStoreEncodedLength is called") { + const char *err = NoteBinaryStoreEncodedLength(&size); THEN("An error is not returned") { CHECK(err == NULL); } THEN("The size out parameter is the cobs value in the card.binary " - "response, plus 1 for the trailing newline") { - CHECK(size == cobsLen + 1); + "response") { + CHECK(size == cobsLen); } } } From 62a79437d18d6e4dc66d377a50223e7a02dda12e Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 18:57:59 +0000 Subject: [PATCH 14/24] chore: refactor NoteBinaryStoreReset() --- n_helpers.c | 260 +++++++++--------- note.h | 2 +- test/CMakeLists.txt | 2 +- ...test.cpp => NoteBinaryStoreReset_test.cpp} | 16 +- 4 files changed, 140 insertions(+), 140 deletions(-) rename test/src/{NoteBinaryDataReset_test.cpp => NoteBinaryStoreReset_test.cpp} (82%) diff --git a/n_helpers.c b/n_helpers.c index ba4a1ee9..f3b125fe 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -86,136 +86,6 @@ NOTE_C_STATIC int ytodays(int year); static const char NOTE_C_BINARY_EOP = '\n'; -//**************************************************************************/ -/*! - @brief Get the length of the data stored on the Notecard. If there's no data - stored on the Notecard, then `*len` will return 0. - - @param len [out] The length of the decoded contents of the Notecard's binary - data store. - - @returns An error string on error and NULL on success. - */ -/**************************************************************************/ -const char * NoteBinaryStoreDecodedLength(uint32_t *len) -{ - // Validate parameter(s) - if (!len) { - const char *err = ERRSTR("len cannot be NULL", c_bad); - NOTE_C_LOG_ERROR(err); - return err; - } - - // Issue a "card.binary" request. - J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); - if (!rsp) { - const char *err = ERRSTR("unable to issue binary request", c_err); - NOTE_C_LOG_ERROR(err); - return err; - } - - // Ensure the transaction doesn't return an error and confirm the binary - // feature is available. - if (NoteResponseError(rsp)) { - const char *err = JGetString(rsp, "err"); - NOTE_C_LOG_ERROR(err); - JDelete(rsp); - err = ERRSTR("unexpected error received during handshake", c_err); - NOTE_C_LOG_ERROR(err); - return err; - } - - // Examine "length" from the response to evaluate the length of the decoded - // data residing on the Notecard. - *len = JGetInt(rsp, "length"); - JDelete(rsp); - - return NULL; -} - -//**************************************************************************/ -/*! - @brief Get the required buffer length to receive the entire binary object - stored on the Notecard. - - @param len [out] The length required to hold the entire contents of the - Notecard's binary data store. If there's no data stored on the - Notecard, then `len` will return 0. - - @returns An error string on error and NULL on success. - */ -/**************************************************************************/ -const char * NoteBinaryStoreEncodedLength(uint32_t *len) -{ - // Validate parameter(s) - if (!len) { - const char *err = ERRSTR("size cannot be NULL", c_err); - NOTE_C_LOG_ERROR(err); - return err; - } - - // Issue a "card.binary" request. - J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); - if (!rsp) { - const char *err = ERRSTR("unable to issue binary request", c_err); - NOTE_C_LOG_ERROR(err); - return err; - } - - // Ensure the transaction doesn't return an error and confirm the binary - // feature is available. - if (NoteResponseError(rsp)) { - const char *err = JGetString(rsp, "err"); - NOTE_C_LOG_ERROR(err); - JDelete(rsp); - err = ERRSTR("unexpected error received during handshake", c_bad); - NOTE_C_LOG_ERROR(err); - return err; - } - - // Examine "cobs" from the response to evaluate the space required to hold - // the COBS-encoded data to be received from the Notecard. - long int cobs = JGetInt(rsp, "cobs"); - JDelete(rsp); - *len = cobs; - - return NULL; -} - -//**************************************************************************/ -/*! - @brief Reset the Notecard's binary buffer. - - @returns NULL on success, else an error string pointer. - - @note This operation is necessary to clear the Notecard's binary buffer after - a binary object is received from the Notecard, or if the Notecard's - binary buffer has been left in an unknown state due to an error arising - from a binary transfer to the Notecard. - */ -/**************************************************************************/ -const char * NoteBinaryDataReset(void) -{ - J *req = NoteNewRequest("card.binary"); - if (req) { - JAddBoolToObject(req, "delete", true); - - // Ensure the transaction doesn't return an error. - J *rsp = NoteRequestResponse(req); - if (NoteResponseError(rsp)) { - NOTE_C_LOG_ERROR(JGetString(rsp,"err")); - JDelete(rsp); - NOTE_C_LOG_ERROR("failed to reset binary buffer"); - return ERRSTR("failed to reset binary buffer", c_err); - } - } else { - NOTE_C_LOG_ERROR("unable to allocate request"); - return ERRSTR("unable to allocate request", c_mem); - } - - return NULL; -} - //**************************************************************************/ /*! @brief Decode binary data received from the Notecard. @@ -344,6 +214,136 @@ uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength) return cobsEncodedMaxLength(unencodedLength); } +//**************************************************************************/ +/*! + @brief Get the length of the data stored on the Notecard. If there's no data + stored on the Notecard, then `*len` will return 0. + + @param len [out] The length of the decoded contents of the Notecard's binary + data store. + + @returns An error string on error and NULL on success. + */ +/**************************************************************************/ +const char * NoteBinaryStoreDecodedLength(uint32_t *len) +{ + // Validate parameter(s) + if (!len) { + const char *err = ERRSTR("len cannot be NULL", c_bad); + NOTE_C_LOG_ERROR(err); + return err; + } + + // Issue a "card.binary" request. + J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); + if (!rsp) { + const char *err = ERRSTR("unable to issue binary request", c_err); + NOTE_C_LOG_ERROR(err); + return err; + } + + // Ensure the transaction doesn't return an error and confirm the binary + // feature is available. + if (NoteResponseError(rsp)) { + NOTE_C_LOG_ERROR(JGetString(rsp, "err")); + JDelete(rsp); + const char *err = ERRSTR("unexpected error received during handshake", c_err); + NOTE_C_LOG_ERROR(err); + return err; + } + + // Examine "length" from the response to evaluate the length of the decoded + // data residing on the Notecard. + *len = JGetInt(rsp, "length"); + JDelete(rsp); + + return NULL; +} + +//**************************************************************************/ +/*! + @brief Get the required buffer length to receive the entire binary object + stored on the Notecard. + + @param len [out] The length required to hold the entire contents of the + Notecard's binary data store. If there's no data stored on the + Notecard, then `len` will return 0. + + @returns An error string on error and NULL on success. + */ +/**************************************************************************/ +const char * NoteBinaryStoreEncodedLength(uint32_t *len) +{ + // Validate parameter(s) + if (!len) { + const char *err = ERRSTR("size cannot be NULL", c_err); + NOTE_C_LOG_ERROR(err); + return err; + } + + // Issue a "card.binary" request. + J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); + if (!rsp) { + const char *err = ERRSTR("unable to issue binary request", c_err); + NOTE_C_LOG_ERROR(err); + return err; + } + + // Ensure the transaction doesn't return an error and confirm the binary + // feature is available. + if (NoteResponseError(rsp)) { + NOTE_C_LOG_ERROR(JGetString(rsp, "err")); + JDelete(rsp); + const char *err = ERRSTR("unexpected error received during handshake", c_bad); + NOTE_C_LOG_ERROR(err); + return err; + } + + // Examine "cobs" from the response to evaluate the space required to hold + // the COBS-encoded data to be received from the Notecard. + long int cobs = JGetInt(rsp, "cobs"); + JDelete(rsp); + *len = cobs; + + return NULL; +} + +//**************************************************************************/ +/*! + @brief Reset the Notecard's binary buffer. + + @returns NULL on success, else an error string pointer. + + @note This operation is necessary to clear the Notecard's binary buffer after + a binary object is received from the Notecard, or if the Notecard's + binary buffer has been left in an unknown state due to an error arising + from a binary transfer to the Notecard. + */ +/**************************************************************************/ +const char * NoteBinaryStoreReset(void) +{ + J *req = NoteNewRequest("card.binary"); + if (req) { + JAddBoolToObject(req, "delete", true); + + // Ensure the transaction doesn't return an error. + J *rsp = NoteRequestResponse(req); + if (NoteResponseError(rsp)) { + NOTE_C_LOG_ERROR(JGetString(rsp,"err")); + JDelete(rsp); + const char *err = ERRSTR("failed to reset binary buffer", c_err); + NOTE_C_LOG_ERROR(err); + return err; + } + } else { + const char *err = ERRSTR("unable to allocate request", c_mem); + NOTE_C_LOG_ERROR(err); + return err; + } + + return NULL; +} + //**************************************************************************/ /*! @brief Receive a large binary object from the Notecard's binary buffer diff --git a/note.h b/note.h index 79ebc8a3..067fbffa 100644 --- a/note.h +++ b/note.h @@ -325,7 +325,7 @@ uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryStoreDecodedLength(uint32_t *len); const char * NoteBinaryStoreEncodedLength(uint32_t *len); -const char * NoteBinaryDataReset(void); +const char * NoteBinaryStoreReset(void); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f37ead06..70aae270 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -154,7 +154,7 @@ add_test(NoteBinaryCodecMaxDecodedLength_test) add_test(NoteBinaryCodecMaxEncodedLength_test) add_test(NoteBinaryStoreDecodedLength_test) add_test(NoteBinaryStoreEncodedLength_test) -add_test(NoteBinaryDataReset_test) +add_test(NoteBinaryStoreReset_test) add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) diff --git a/test/src/NoteBinaryDataReset_test.cpp b/test/src/NoteBinaryStoreReset_test.cpp similarity index 82% rename from test/src/NoteBinaryDataReset_test.cpp rename to test/src/NoteBinaryStoreReset_test.cpp index 2ea6f5fe..e28cb9e1 100644 --- a/test/src/NoteBinaryDataReset_test.cpp +++ b/test/src/NoteBinaryStoreReset_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryDataReset_test.cpp + * @file NoteBinaryStoreReset_test.cpp * * Written by the Blues Inc. team. * @@ -25,7 +25,7 @@ FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) namespace { -SCENARIO("NoteBinaryDataReset") +SCENARIO("NoteBinaryStoreReset") { RESET_FAKE(NoteNewRequest); RESET_FAKE(NoteRequestResponse); @@ -43,8 +43,8 @@ SCENARIO("NoteBinaryDataReset") NoteNewRequest_fake.custom_fake = NULL; NoteNewRequest_fake.return_val = NULL; - WHEN("NoteBinaryDataReset is called") { - const char *err = NoteBinaryDataReset(); + WHEN("NoteBinaryStoreReset is called") { + const char *err = NoteBinaryStoreReset(); THEN("An error is returned") { CHECK(err != NULL); @@ -61,8 +61,8 @@ SCENARIO("NoteBinaryDataReset") return rsp; }; - WHEN("NoteBinaryDataReset is called") { - const char *err = NoteBinaryDataReset(); + WHEN("NoteBinaryStoreReset is called") { + const char *err = NoteBinaryStoreReset(); THEN("An error is returned") { CHECK(err != NULL); @@ -71,8 +71,8 @@ SCENARIO("NoteBinaryDataReset") } GIVEN("The response to the card.binary indicates success") { - WHEN("NoteBinaryDataReset is called") { - const char *err = NoteBinaryDataReset(); + WHEN("NoteBinaryStoreReset is called") { + const char *err = NoteBinaryStoreReset(); THEN("An error is not returned") { CHECK(err == NULL); From 5e7d0337ffe4b238ba9e0341844f4676a8f1a574 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 19:03:23 +0000 Subject: [PATCH 15/24] chore: refactor NoteBinaryStoreReceive() --- n_helpers.c | 4 +-- note.h | 4 +-- test/CMakeLists.txt | 2 +- ...st.cpp => NoteBinaryStoreReceive_test.cpp} | 34 +++++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) rename test/src/{NoteBinaryReceive_test.cpp => NoteBinaryStoreReceive_test.cpp} (82%) diff --git a/n_helpers.c b/n_helpers.c index f3b125fe..ace4778f 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -364,8 +364,8 @@ const char * NoteBinaryStoreReset(void) entire buffer use `(NoteBinaryStoreEncodedLength() + 1)` instead. */ /**************************************************************************/ -const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, - uint32_t decodedOffset, uint32_t decodedLen) +const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, + uint32_t decodedOffset, uint32_t decodedLen) { // Validate parameter(s) if (!buffer) { diff --git a/note.h b/note.h index 067fbffa..14410c17 100644 --- a/note.h +++ b/note.h @@ -325,9 +325,9 @@ uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryStoreDecodedLength(uint32_t *len); const char * NoteBinaryStoreEncodedLength(uint32_t *len); +const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, + uint32_t decodedOffset, uint32_t decodedLen); const char * NoteBinaryStoreReset(void); -const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, - uint32_t decodedOffset, uint32_t decodedLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, uint32_t bufLen, uint32_t notecardOffset); uint32_t NoteSetSTSecs(uint32_t secs); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 70aae270..0d5666cc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -154,8 +154,8 @@ add_test(NoteBinaryCodecMaxDecodedLength_test) add_test(NoteBinaryCodecMaxEncodedLength_test) add_test(NoteBinaryStoreDecodedLength_test) add_test(NoteBinaryStoreEncodedLength_test) +add_test(NoteBinaryStoreReceive_test) add_test(NoteBinaryStoreReset_test) -add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) if(NOTE_C_COVERAGE) diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryStoreReceive_test.cpp similarity index 82% rename from test/src/NoteBinaryReceive_test.cpp rename to test/src/NoteBinaryStoreReceive_test.cpp index a2cd3cb4..deee29fa 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryStoreReceive_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryReceive_test.cpp + * @file NoteBinaryStoreReceive_test.cpp * * Written by the Blues Inc. team. * @@ -44,7 +44,7 @@ uint32_t rawMsgLen = strlen(rawMsg); namespace { -SCENARIO("NoteBinaryReceive") +SCENARIO("NoteBinaryStoreReceive") { RESET_FAKE(NoteNewRequest); RESET_FAKE(NoteBinaryStoreEncodedLength); @@ -79,21 +79,21 @@ SCENARIO("NoteBinaryReceive") GIVEN("Bad parameters are supplied") { WHEN("buffer is NULL") { - const char *err = NoteBinaryReceive(NULL, bufLen, decodedOffset, decodedLen); + const char *err = NoteBinaryStoreReceive(NULL, bufLen, decodedOffset, decodedLen); THEN("An error is returned") { CHECK(err != NULL); } } WHEN("bufLen is too small") { - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, bufLen); + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, bufLen); THEN("An error is returned") { CHECK(err != NULL); } } WHEN("decodedLen is zero") { - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, 0); + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -105,8 +105,8 @@ SCENARIO("NoteBinaryReceive") NoteNewRequest_fake.custom_fake = NULL; NoteNewRequest_fake.return_val = NULL; - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + WHEN("NoteBinaryStoreReceive is called") { + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteNewRequest_fake.call_count > 0); THEN("An error is returned") { @@ -124,8 +124,8 @@ SCENARIO("NoteBinaryReceive") return rsp; }; - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + WHEN("NoteBinaryStoreReceive is called") { + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { @@ -137,8 +137,8 @@ SCENARIO("NoteBinaryReceive") GIVEN("NoteChunkedReceive returns an error") { NoteChunkedReceive_fake.return_val = "some error"; - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + WHEN("NoteBinaryStoreReceive is called") { + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("An error is returned") { @@ -156,8 +156,8 @@ SCENARIO("NoteBinaryReceive") return NULL; }; - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + WHEN("NoteBinaryStoreReceive is called") { + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("An error is returned") { @@ -187,8 +187,8 @@ SCENARIO("NoteBinaryReceive") return rsp; }; - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + WHEN("NoteBinaryStoreReceive is called") { + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); REQUIRE(NoteRequestResponse_fake.call_count > 0); @@ -199,9 +199,9 @@ SCENARIO("NoteBinaryReceive") } AND_GIVEN("The computed MD5 matches the status field") { - WHEN("NoteBinaryReceive is called") { + WHEN("NoteBinaryStoreReceive is called") { uint32_t decodedLen = rawMsgLen; - const char *err = NoteBinaryReceive(buf, bufLen, decodedOffset, decodedLen); + const char *err = NoteBinaryStoreReceive(buf, bufLen, decodedOffset, decodedLen); REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("No error is returned") { From 8538dde7e27b3779d9538b8be2d54b14871d12fb Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 19:21:58 +0000 Subject: [PATCH 16/24] chore: refactor NoteBinaryStoreTransmit() --- n_helpers.c | 75 +++++++++++-------- note.h | 4 +- test/CMakeLists.txt | 2 +- ...t.cpp => NoteBinaryStoreTransmit_test.cpp} | 60 +++++++-------- 4 files changed, 75 insertions(+), 66 deletions(-) rename test/src/{NoteBinaryTransmit_test.cpp => NoteBinaryStoreTransmit_test.cpp} (85%) diff --git a/n_helpers.c b/n_helpers.c index ace4778f..4d6978a7 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -488,33 +488,35 @@ const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, accommodate both the encoded data and newline terminator. */ /**************************************************************************/ -const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, - uint32_t bufLen, uint32_t notecardOffset) +const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedLen, + uint32_t bufLen, uint32_t notecardOffset) { // Validate parameter(s) if (!unencodedData) { - NOTE_C_LOG_ERROR("unencodedData cannot be NULL"); - return ERRSTR("unencodedData cannot be NULL", c_err); + const char *err = ERRSTR("unencodedData cannot be NULL", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Issue a "card.binary" request. J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { - NOTE_C_LOG_ERROR("unable to issue binary request"); - return ERRSTR("unable to issue binary request", c_err); + const char *err = ERRSTR("unable to issue binary request", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Ensure the transaction doesn't return an error // and confirm the binary feature is available - const char *err = NULL; if (NoteResponseError(rsp)) { - err = JGetString(rsp, "err"); + const char *jErr = JGetString(rsp, "err"); // Swallow `{bad-bin}` errors, because we intend to overwrite the data. - if (!NoteErrorContains(err, c_badbinerr)) { - NOTE_C_LOG_ERROR(err); + if (!NoteErrorContains(jErr, c_badbinerr)) { + NOTE_C_LOG_ERROR(jErr); JDelete(rsp); - NOTE_C_LOG_ERROR("unexpected error received during handshake"); - return ERRSTR("unexpected error received during handshake", c_bad); + const char *err = ERRSTR("unexpected error received during handshake", c_bad); + NOTE_C_LOG_ERROR(err); + return err; } } @@ -524,23 +526,26 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, const long max = JGetInt(rsp,"max"); JDelete(rsp); if (!max) { - NOTE_C_LOG_ERROR("unexpected response: max is zero or not present"); - return ERRSTR("unexpected response: max is zero or not present", c_err); + const char *err = ERRSTR("unexpected response: max is zero or not present", c_err); + NOTE_C_LOG_ERROR(err); + return err; } // Validate the index provided by the caller, against the `length` value // returned from the Notecard to ensure the caller and Notecard agree on // how much data is residing on the Notecard. if ((long)notecardOffset != len) { - NOTE_C_LOG_ERROR("notecard data length is misaligned with offset"); - return ERRSTR("notecard data length is misaligned with offset", c_mem); + const char *err = ERRSTR("notecard data length is misaligned with offset", c_mem); + NOTE_C_LOG_ERROR(err); + return err; } // When offset is zero, the Notecard's entire binary buffer is available const uint32_t remaining = (notecardOffset ? (max - len) : max); if (unencodedLen > remaining) { - NOTE_C_LOG_ERROR("buffer size exceeds available memory"); - return ERRSTR("buffer size exceeds available memory", c_mem); + const char *err = ERRSTR("buffer size exceeds available memory", c_mem); + NOTE_C_LOG_ERROR(err); + return err; } // Calculate MD5 @@ -582,19 +587,21 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // Ensure the transaction doesn't return an error. if (!NoteRequest(req)) { - NOTE_C_LOG_ERROR("failed to initialize binary transaction"); + const char *err = ERRSTR("failed to initialize binary transaction", c_err); + NOTE_C_LOG_ERROR(err); _UnlockNote(); // On errors, we restore the caller's input buffer by COBS // decoding it. The caller is then able to retry transmission // with their original pointer to this buffer. NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); - return ERRSTR("failed to initialize binary transaction", c_err); + return err; } } else { - NOTE_C_LOG_ERROR("unable to allocate request"); + const char *err = ERRSTR("unable to allocate request", c_mem); + NOTE_C_LOG_ERROR(err); _UnlockNote(); NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); - return ERRSTR("unable to allocate request", c_mem); + return err; } // Immediately send the COBS binary. @@ -612,32 +619,34 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // Issue a `"card.binary"` request. rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { - NOTE_C_LOG_ERROR("unable to validate request"); + const char *err = ERRSTR("unable to validate request", c_err); + NOTE_C_LOG_ERROR(err); NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); - return ERRSTR("unable to validate request", c_err); + return err; } // Ensure the transaction doesn't return an error // to confirm the binary was received if (NoteResponseError(rsp)) { - const char *err = JGetString(rsp, "err"); - NOTE_C_LOG_ERROR(err); - if (NoteErrorContains(err, c_badbinerr)) { + const char *jErr = JGetString(rsp, "err"); + if (NoteErrorContains(jErr, c_badbinerr)) { + NOTE_C_LOG_WARN(jErr); JDelete(rsp); if ( i < (NOTE_C_BINARY_RETRIES - 1) ) { NOTE_C_LOG_WARN("retrying binary transmission..."); continue; } - NOTE_C_LOG_ERROR("binary data invalid"); + const char *err = ERRSTR("binary data invalid", c_bad); + NOTE_C_LOG_ERROR(err); NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); - return ERRSTR("binary data invalid", c_bad); + return err; } else { + NOTE_C_LOG_ERROR(jErr); JDelete(rsp); - NOTE_C_LOG_ERROR("unexpected error received during " - "confirmation"); + const char *err = ERRSTR("unexpected error received during confirmation", c_bad); + NOTE_C_LOG_ERROR(err); NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); - return ERRSTR("unexpected error received during confirmation", - c_bad); + return err; } } JDelete(rsp); diff --git a/note.h b/note.h index 14410c17..c1f7aca1 100644 --- a/note.h +++ b/note.h @@ -328,8 +328,8 @@ const char * NoteBinaryStoreEncodedLength(uint32_t *len); const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t decodedLen); const char * NoteBinaryStoreReset(void); -const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, - uint32_t bufLen, uint32_t notecardOffset); +const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedLen, + uint32_t bufLen, uint32_t notecardOffset); uint32_t NoteSetSTSecs(uint32_t secs); bool NoteTimeValid(void); bool NoteTimeValidST(void); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0d5666cc..df562ea7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -156,7 +156,7 @@ add_test(NoteBinaryStoreDecodedLength_test) add_test(NoteBinaryStoreEncodedLength_test) add_test(NoteBinaryStoreReceive_test) add_test(NoteBinaryStoreReset_test) -add_test(NoteBinaryTransmit_test) +add_test(NoteBinaryStoreTransmit_test) if(NOTE_C_COVERAGE) find_program(LCOV lcov REQUIRED) diff --git a/test/src/NoteBinaryTransmit_test.cpp b/test/src/NoteBinaryStoreTransmit_test.cpp similarity index 85% rename from test/src/NoteBinaryTransmit_test.cpp rename to test/src/NoteBinaryStoreTransmit_test.cpp index 0ac03182..0be84121 100644 --- a/test/src/NoteBinaryTransmit_test.cpp +++ b/test/src/NoteBinaryStoreTransmit_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryTransmit_test.cpp + * @file NoteBinaryStoreTransmit_test.cpp * * Written by the Blues Inc. team. * @@ -33,7 +33,7 @@ uint32_t bufLen = sizeof(buf); namespace { -SCENARIO("NoteBinaryTransmit") +SCENARIO("NoteBinaryStoreTransmit") { RESET_FAKE(NoteNewRequest); RESET_FAKE(NoteRequestResponse); @@ -58,8 +58,8 @@ SCENARIO("NoteBinaryTransmit") return NULL; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -76,8 +76,8 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -94,8 +94,8 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -114,8 +114,8 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -136,8 +136,8 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { @@ -158,8 +158,8 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, dataLen); THEN("An error is returned") { @@ -188,8 +188,8 @@ SCENARIO("NoteBinaryTransmit") REQUIRE(newBufLen > 0); free(tempBuf); - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, newBufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, newBufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -215,8 +215,8 @@ SCENARIO("NoteBinaryTransmit") J *noteNewReqRetSequence[] = {JCreateObject(), NULL}; SET_RETURN_SEQ(NoteNewRequest, noteNewReqRetSequence, 2); - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -235,8 +235,8 @@ SCENARIO("NoteBinaryTransmit") return false; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -256,8 +256,8 @@ SCENARIO("NoteBinaryTransmit") }; NoteChunkedTransmit_fake.return_val = "some error"; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, 0); + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -299,8 +299,8 @@ SCENARIO("NoteBinaryTransmit") return NULL; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { @@ -323,8 +323,8 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { @@ -348,8 +348,8 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { @@ -385,8 +385,8 @@ SCENARIO("NoteBinaryTransmit") SET_CUSTOM_FAKE_SEQ(NoteRequestResponse, reqRespFakeSequenceSuccess, 3); - WHEN("NoteBinaryTransmit is called") { - const char *err = NoteBinaryTransmit(buf, dataLen, bufLen, + WHEN("NoteBinaryStoreTransmit is called") { + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("No error is returned") { From 007ea1745cc16f761d1e8515a678f755e99f5e0a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 19:27:13 +0000 Subject: [PATCH 17/24] fix: astyle --- n_helpers.c | 2 +- note.h | 2 +- test/src/NoteBinaryStoreTransmit_test.cpp | 18 ++++++------------ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 4d6978a7..63b905d2 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -106,7 +106,7 @@ static const char NOTE_C_BINARY_EOP = '\n'; */ /**************************************************************************/ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, - uint8_t *decBuf, uint32_t decBufSize) + uint8_t *decBuf, uint32_t decBufSize) { uint32_t result; diff --git a/note.h b/note.h index c1f7aca1..1d7317f0 100644 --- a/note.h +++ b/note.h @@ -318,7 +318,7 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen // High-level helper functions that are both useful and serve to show developers // how to call the API uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, - uint8_t *decBuf, uint32_t decBufSize); + uint8_t *decBuf, uint32_t decBufSize); uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, uint8_t *encBuf, uint32_t encBufSize); uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize); diff --git a/test/src/NoteBinaryStoreTransmit_test.cpp b/test/src/NoteBinaryStoreTransmit_test.cpp index 0be84121..eab59afd 100644 --- a/test/src/NoteBinaryStoreTransmit_test.cpp +++ b/test/src/NoteBinaryStoreTransmit_test.cpp @@ -137,8 +137,7 @@ SCENARIO("NoteBinaryStoreTransmit") }; WHEN("NoteBinaryStoreTransmit is called") { - const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, - 0); + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -159,8 +158,7 @@ SCENARIO("NoteBinaryStoreTransmit") }; WHEN("NoteBinaryStoreTransmit is called") { - const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, - dataLen); + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -300,8 +298,7 @@ SCENARIO("NoteBinaryStoreTransmit") }; WHEN("NoteBinaryStoreTransmit is called") { - const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, - 0); + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -324,8 +321,7 @@ SCENARIO("NoteBinaryStoreTransmit") }; WHEN("NoteBinaryStoreTransmit is called") { - const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, - 0); + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -349,8 +345,7 @@ SCENARIO("NoteBinaryStoreTransmit") }; WHEN("NoteBinaryStoreTransmit is called") { - const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, - 0); + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("An error is returned") { CHECK(err != NULL); @@ -386,8 +381,7 @@ SCENARIO("NoteBinaryStoreTransmit") reqRespFakeSequenceSuccess, 3); WHEN("NoteBinaryStoreTransmit is called") { - const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, - 0); + const char *err = NoteBinaryStoreTransmit(buf, dataLen, bufLen, 0); THEN("No error is returned") { CHECK(err == NULL); From a2d98840916c8df29327779a18cbc5d79af799ff Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 19:54:28 +0000 Subject: [PATCH 18/24] fix: memory leak --- n_helpers.c | 5 +++++ test/src/NoteBinaryStoreTransmit_test.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 63b905d2..8ead1d1d 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -497,6 +497,11 @@ const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedL NOTE_C_LOG_ERROR(err); return err; } + if (bufLen < (cobsEncodedLength(unencodedData, unencodedLen) + 1)) { + const char *err = ERRSTR("insufficient buffer size", c_bad); + NOTE_C_LOG_ERROR(err); + return err; + } // Issue a "card.binary" request. J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); diff --git a/test/src/NoteBinaryStoreTransmit_test.cpp b/test/src/NoteBinaryStoreTransmit_test.cpp index eab59afd..a4ad0e76 100644 --- a/test/src/NoteBinaryStoreTransmit_test.cpp +++ b/test/src/NoteBinaryStoreTransmit_test.cpp @@ -182,12 +182,12 @@ SCENARIO("NoteBinaryStoreTransmit") // Discover the actual encoded length of the data const uint32_t tempBufLen = cobsEncodedMaxLength(dataLen); uint8_t *tempBuf = (uint8_t *)malloc(tempBufLen); - uint32_t newBufLen = NoteBinaryCodecEncode(buf, dataLen, tempBuf, tempBufLen); - REQUIRE(newBufLen > 0); + uint32_t encLen = NoteBinaryCodecEncode(buf, dataLen, tempBuf, tempBufLen); + REQUIRE(encLen > 0); free(tempBuf); WHEN("NoteBinaryStoreTransmit is called") { - const char *err = NoteBinaryStoreTransmit(buf, dataLen, newBufLen, 0); + const char *err = NoteBinaryStoreTransmit(buf, dataLen, encLen, 0); THEN("An error is returned") { CHECK(err != NULL); From fa5be7f86309d2ad196c0493665beff58b87c029 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 19:55:57 +0000 Subject: [PATCH 19/24] reorder --- n_helpers.c | 72 ++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 8ead1d1d..db09a837 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -308,42 +308,6 @@ const char * NoteBinaryStoreEncodedLength(uint32_t *len) return NULL; } -//**************************************************************************/ -/*! - @brief Reset the Notecard's binary buffer. - - @returns NULL on success, else an error string pointer. - - @note This operation is necessary to clear the Notecard's binary buffer after - a binary object is received from the Notecard, or if the Notecard's - binary buffer has been left in an unknown state due to an error arising - from a binary transfer to the Notecard. - */ -/**************************************************************************/ -const char * NoteBinaryStoreReset(void) -{ - J *req = NoteNewRequest("card.binary"); - if (req) { - JAddBoolToObject(req, "delete", true); - - // Ensure the transaction doesn't return an error. - J *rsp = NoteRequestResponse(req); - if (NoteResponseError(rsp)) { - NOTE_C_LOG_ERROR(JGetString(rsp,"err")); - JDelete(rsp); - const char *err = ERRSTR("failed to reset binary buffer", c_err); - NOTE_C_LOG_ERROR(err); - return err; - } - } else { - const char *err = ERRSTR("unable to allocate request", c_mem); - NOTE_C_LOG_ERROR(err); - return err; - } - - return NULL; -} - //**************************************************************************/ /*! @brief Receive a large binary object from the Notecard's binary buffer @@ -467,6 +431,42 @@ const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, return NULL; } +//**************************************************************************/ +/*! + @brief Reset the Notecard's binary buffer. + + @returns NULL on success, else an error string pointer. + + @note This operation is necessary to clear the Notecard's binary buffer after + a binary object is received from the Notecard, or if the Notecard's + binary buffer has been left in an unknown state due to an error arising + from a binary transfer to the Notecard. + */ +/**************************************************************************/ +const char * NoteBinaryStoreReset(void) +{ + J *req = NoteNewRequest("card.binary"); + if (req) { + JAddBoolToObject(req, "delete", true); + + // Ensure the transaction doesn't return an error. + J *rsp = NoteRequestResponse(req); + if (NoteResponseError(rsp)) { + NOTE_C_LOG_ERROR(JGetString(rsp,"err")); + JDelete(rsp); + const char *err = ERRSTR("failed to reset binary buffer", c_err); + NOTE_C_LOG_ERROR(err); + return err; + } + } else { + const char *err = ERRSTR("unable to allocate request", c_mem); + NOTE_C_LOG_ERROR(err); + return err; + } + + return NULL; +} + //**************************************************************************/ /*! @brief Transmit a large binary object to the Notecard's binary buffer From f71e62e130004b7b3dfe64ba99722958a03b603f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 20:08:18 +0000 Subject: [PATCH 20/24] code formatting --- n_helpers.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/n_helpers.c b/n_helpers.c index db09a837..046991f0 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -155,7 +155,8 @@ uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, if (decData == NULL || encBuf == NULL) { NOTE_C_LOG_ERROR(ERRSTR("NULL parameter", c_err)); result = 0; - } else if ((encBufSize < cobsEncodedMaxLength(decDataLen)) && (encBufSize < cobsEncodedLength(decData, decDataLen))) { + } else if ((encBufSize < cobsEncodedMaxLength(decDataLen)) + && (encBufSize < cobsEncodedLength(decData, decDataLen))) { // NOTE: `cobsEncodedMaxLength()` provides a constant time [O(1)] means // of checking the buffer size. Only when it fails will the linear // time [O(n)] check, `cobsEncodedLength()`, be invoked. From 993c1f85a5efa8912c7e3e894d1a039246f42617 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 20:43:32 +0000 Subject: [PATCH 21/24] fix: astyle --- n_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n_helpers.c b/n_helpers.c index 046991f0..637c98d2 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -156,7 +156,7 @@ uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, NOTE_C_LOG_ERROR(ERRSTR("NULL parameter", c_err)); result = 0; } else if ((encBufSize < cobsEncodedMaxLength(decDataLen)) - && (encBufSize < cobsEncodedLength(decData, decDataLen))) { + && (encBufSize < cobsEncodedLength(decData, decDataLen))) { // NOTE: `cobsEncodedMaxLength()` provides a constant time [O(1)] means // of checking the buffer size. Only when it fails will the linear // time [O(n)] check, `cobsEncodedLength()`, be invoked. From 7df7deb667b84dbc54721723ec9344b46ca6d53a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 20:49:28 +0000 Subject: [PATCH 22/24] chore: enhance buffer check --- n_helpers.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 637c98d2..2ae5ffe7 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -497,8 +497,11 @@ const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedL const char *err = ERRSTR("unencodedData cannot be NULL", c_err); NOTE_C_LOG_ERROR(err); return err; - } - if (bufLen < (cobsEncodedLength(unencodedData, unencodedLen) + 1)) { + } else if ((bufLen < cobsEncodedMaxLength(unencodedLen)) + && (bufLen < (cobsEncodedLength(unencodedData, unencodedLen) + 1))) { + // NOTE: `cobsEncodedMaxLength()` provides a constant time [O(1)] means + // of checking the buffer size. Only when it fails will the linear + // time [O(n)] check, `cobsEncodedLength()`, be invoked. const char *err = ERRSTR("insufficient buffer size", c_bad); NOTE_C_LOG_ERROR(err); return err; From ddd9d51277854f197c7ba5dd2c5fa288a193eb41 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 8 Sep 2023 23:37:05 +0000 Subject: [PATCH 23/24] chore: address PR feedback --- n_helpers.c | 69 +++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 2ae5ffe7..f11d1475 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -91,9 +91,9 @@ static const char NOTE_C_BINARY_EOP = '\n'; @brief Decode binary data received from the Notecard. @param encData The encoded binary data to decode. - @param encLen The length of the encoded binary data. - @param decBuf The target buffer for the decoded data. This can be the - same address as `encData`, allowing for in-place decoding. + @param encDataLen The length of the encoded binary data. + @param decBuf The target buffer for the decoded data. For in-place decoding, + `decBuf` can use the same address as `encData` (see note). @param decBufSize The size of `decBuf`. @returns The length of the decoded data, or zero on error. @@ -131,18 +131,19 @@ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, @param decData The decoded binary data to encode. @param decDataLen The length of the decoded binary data. - @param encBuf The target buffer for the encoded data. This can be in the same - buffer as `decData`, allowing for in-place encoding (see note). + @param encBuf The target buffer for the encoded data. For in-place encoding, + `encBuf` can use the same buffer as `decData`, but cannot + share the same address (see note). @param encBufSize The size of `encBuf`. - @returns NULL on success, else an error string pointer. + @returns The length of the encoded data, or zero on error. @note Use `NoteBinaryCodecMaxEncodedLength()` to calculate the required size for the buffer pointed to by the `encBuf` parameter, which MUST accommodate both the encoded data and newline terminator. @note This API supports in-place encoding. If you wish to utilize in-place - encoding, then right-justify the decoded data in the buffer (updating - `decBuf` accordingly) and set the value of `encBuf` to the beginning + encoding, shift the decoded data to the end of the buffer, update + `decBuf` accordingly, and set the value of `encBuf` to the beginning of the buffer. */ /**************************************************************************/ @@ -217,11 +218,11 @@ uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength) //**************************************************************************/ /*! - @brief Get the length of the data stored on the Notecard. If there's no data - stored on the Notecard, then `*len` will return 0. + @brief Get the length of the data in the Notecard's binary store. If there's + no data on the Notecard, then `*len` will return 0. @param len [out] The length of the decoded contents of the Notecard's binary - data store. + store. @returns An error string on error and NULL on success. */ @@ -264,11 +265,11 @@ const char * NoteBinaryStoreDecodedLength(uint32_t *len) //**************************************************************************/ /*! @brief Get the required buffer length to receive the entire binary object - stored on the Notecard. + stored in the Notecard's binary store. @param len [out] The length required to hold the entire contents of the - Notecard's binary data store. If there's no data stored on the - Notecard, then `len` will return 0. + Notecard's binary store. If there's no data on the Notecard, then + `len` will return 0. @returns An error string on error and NULL on success. */ @@ -301,7 +302,7 @@ const char * NoteBinaryStoreEncodedLength(uint32_t *len) } // Examine "cobs" from the response to evaluate the space required to hold - // the COBS-encoded data to be received from the Notecard. + // the encoded data to be received from the Notecard. long int cobs = JGetInt(rsp, "cobs"); JDelete(rsp); *len = cobs; @@ -311,14 +312,13 @@ const char * NoteBinaryStoreEncodedLength(uint32_t *len) //**************************************************************************/ /*! - @brief Receive a large binary object from the Notecard's binary buffer + @brief Receive a large binary object from the Notecard's binary store. - @param buffer A buffer to hold the binary range - @param bufLen The total length of the provided buffer - @param decodedOffset The offset to the decoded binary data already residing - on the Notecard - @param decodedLen The length of the decoded data to fetch from the - Notecard. + @param buffer A buffer to hold the binary range. + @param bufLen The total length of the provided buffer. + @param decodedOffset The offset to the decoded binary data residing + in the Notecard's binary store. + @param decodedLen The length of the decoded data to fetch from the Notecard. @returns NULL on success, else an error string pointer. @@ -434,13 +434,13 @@ const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, //**************************************************************************/ /*! - @brief Reset the Notecard's binary buffer. + @brief Reset the Notecard's binary store. @returns NULL on success, else an error string pointer. @note This operation is necessary to clear the Notecard's binary buffer after a binary object is received from the Notecard, or if the Notecard's - binary buffer has been left in an unknown state due to an error arising + binary store has been left in an unknown state due to an error arising from a binary transfer to the Notecard. */ /**************************************************************************/ @@ -459,6 +459,7 @@ const char * NoteBinaryStoreReset(void) NOTE_C_LOG_ERROR(err); return err; } + JDelete(rsp); } else { const char *err = ERRSTR("unable to allocate request", c_mem); NOTE_C_LOG_ERROR(err); @@ -470,14 +471,14 @@ const char * NoteBinaryStoreReset(void) //**************************************************************************/ /*! - @brief Transmit a large binary object to the Notecard's binary buffer + @brief Transmit a large binary object to the Notecard's binary store. - @param unencodedData A buffer with data to encode in place - @param unencodedLen The length of the data in the buffer - @param bufLen The total length of the buffer (see notes) + @param unencodedData A buffer with data to encode in place. + @param unencodedLen The length of the data in the buffer. + @param bufLen The total length of the buffer (see notes). @param notecardOffset The offset where the data buffer should be appended - to the decoded binary data already residing on the - Notecard. This does not provide random access, but + to the decoded binary data residing in the Notecard's + binary store. This does not provide random access, but rather ensures alignment across sequential writes. @returns NULL on success, else an error string pointer. @@ -599,9 +600,9 @@ const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedL const char *err = ERRSTR("failed to initialize binary transaction", c_err); NOTE_C_LOG_ERROR(err); _UnlockNote(); - // On errors, we restore the caller's input buffer by COBS - // decoding it. The caller is then able to retry transmission - // with their original pointer to this buffer. + // On errors, we restore the caller's input buffer by decoding + // it. The caller is then able to retry transmission with their + // original pointer to this buffer. NoteBinaryCodecDecode(encodedData, encLen, encodedData, bufLen); return err; } @@ -613,7 +614,7 @@ const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedL return err; } - // Immediately send the COBS binary. + // Immediately send the encoded binary. const char *err = _ChunkedTransmit(encodedData, (encLen + 1), false); // Release Notecard Mutex From 209b099382a71625f76994b41e6d5faa294f45c9 Mon Sep 17 00:00:00 2001 From: Hayden Roche Date: Fri, 8 Sep 2023 17:50:35 -0700 Subject: [PATCH 24/24] fix: Fix memory leak in NoteBinaryStoreReset. --- n_helpers.c | 1 + test/src/NoteBinaryStoreReset_test.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index f11d1475..290aa106 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -459,6 +459,7 @@ const char * NoteBinaryStoreReset(void) NOTE_C_LOG_ERROR(err); return err; } + JDelete(rsp); } else { const char *err = ERRSTR("unable to allocate request", c_mem); diff --git a/test/src/NoteBinaryStoreReset_test.cpp b/test/src/NoteBinaryStoreReset_test.cpp index e28cb9e1..3f8a3617 100644 --- a/test/src/NoteBinaryStoreReset_test.cpp +++ b/test/src/NoteBinaryStoreReset_test.cpp @@ -27,15 +27,13 @@ namespace SCENARIO("NoteBinaryStoreReset") { - RESET_FAKE(NoteNewRequest); - RESET_FAKE(NoteRequestResponse); - NoteSetFnDefault(malloc, free, NULL, NULL); NoteNewRequest_fake.custom_fake = [](const char *req) -> J * { return JCreateObject(); }; NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); return JCreateObject(); }; @@ -79,6 +77,9 @@ SCENARIO("NoteBinaryStoreReset") } } } + + RESET_FAKE(NoteNewRequest); + RESET_FAKE(NoteRequestResponse); } }