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") {