Max has submitted this change and it was merged. ( 
https://gerrit.osmocom.org/12017 )

Change subject: msgb: add test helpers
......................................................................

msgb: add test helpers

It's often handy to compare certain msgb layer to a given array and
print the position where they differ. Add simple pretty-printer and
corresponding L* wrappers.

Change-Id: I3bc95f2f5ab6e3f4b502647fb3e0aaaf1f7c4cf5
---
M include/osmocom/core/msgb.h
M src/msgb.c
2 files changed, 231 insertions(+), 0 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Pau Espin Pedrol: Looks good to me, but someone else must approve
  Stefan Sperling: Looks good to me, but someone else must approve
  Jenkins Builder: Verified



diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h
index 1bb5fe5..b7c8422 100644
--- a/include/osmocom/core/msgb.h
+++ b/include/osmocom/core/msgb.h
@@ -560,6 +560,145 @@
        return lbound <= msg->head +  msg->data_len;
 }

+
+/* msgb data comparison helpers */
+
+/*! Compare: check data in msgb against given data
+ *  \param[in] msg message buffer
+ *  \param[in] data expected data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb content is equal to the given data
+ */
+#define msgb_eq_data(msg, data, len)                           \
+       _msgb_eq(__FILE__, __LINE__, __func__, 0, msg, data, len, false)
+
+/*! Compare: check L1 data in msgb against given data
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L1 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L1 content is equal to the given 
data
+ */
+#define msgb_eq_l1_data(msg, data, len)                                \
+       _msgb_eq(__FILE__, __LINE__, __func__, 1, msg, data, len, false)
+
+/*! Compare: check L2 data in msgb against given data
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L2 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L2 content is equal to the given 
data
+ */
+#define msgb_eq_l2_data(msg, data, len)                                \
+       _msgb_eq(__FILE__, __LINE__, __func__, 2, msg, data, len, false)
+
+/*! Compare: check L3 data in msgb against given data
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L3 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L3 content is equal to the given 
data
+ */
+#define msgb_eq_l3_data(msg, data, len)                                \
+       _msgb_eq(__FILE__, __LINE__, __func__, 3, msg, data, len, false)
+
+/*! Compare: check L4 data in msgb against given data
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L4 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L4 content is equal to the given 
data
+ */
+#define msgb_eq_l4_data(msg, data, len)                                \
+       _msgb_eq(__FILE__, __LINE__, __func__, 4, msg, data, len, false)
+
+
+/* msgb test/debug helpers */
+
+/*! Compare and print: check data in msgb against given data and print errors 
if any
+ *  \param[in] msg message buffer
+ *  \param[in] data expected data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb content is equal to the given data
+ */
+#define msgb_eq_data_print(msg, data, len)                             \
+       _msgb_eq(__FILE__, __LINE__, __func__, 0, msg, data, len, true)
+
+/*! Compare and print: check L1 data in msgb against given data and print 
errors if any
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L1 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L1 content is equal to the given 
data
+ */
+#define msgb_eq_l1_data_print(msg, data, len)                          \
+       _msgb_eq(__FILE__, __LINE__, __func__, 1, msg, data, len, true)
+
+/*! Compare and print: check L2 data in msgb against given data and print 
errors if any
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L2 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L2 content is equal to the given 
data
+ */
+#define msgb_eq_l2_data_print(msg, data, len)                          \
+       _msgb_eq(__FILE__, __LINE__, __func__, 2, msg, data, len, true)
+
+/*! Compare and print: check L3 data in msgb against given data and print 
errors if any
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L3 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L3 content is equal to the given 
data
+ */
+#define msgb_eq_l3_data_print(msg, data, len)                          \
+       _msgb_eq(__FILE__, __LINE__, __func__, 3, msg, data, len, true)
+
+
+/*! Compare and print: check L4 data in msgb against given data and print 
errors if any
+ *  \param[in] msg message buffer
+ *  \param[in] data expected L4 data
+ *  \param[in] len length of data
+ *  \returns boolean indicating whether msgb L4 content is equal to the given 
data
+ */
+#define msgb_eq_l4_data_print(msg, data, len)                          \
+       _msgb_eq(__FILE__, __LINE__, __func__, 4, msg, data, len, true)
+
+bool _msgb_eq(const char *file, size_t line, const char *func, uint8_t level,
+             const struct msgb *msg, const uint8_t *data, size_t len, bool 
print);
+
+
+/* msgb data comparison */
+
+/*! Compare msgbs
+ *  \param[in] msg1 message buffer
+ *  \param[in] msg2 reference message buffer
+ *  \returns boolean indicating whether msgb content is equal
+ */
+#define msgb_eq(msg1, msgb2, len) msgb_eq_data(msg1, msgb_data(msg2), 
msgb_length(msg2))
+
+/*! Compare msgbs L1 content
+ *  \param[in] msg1 message buffer
+ *  \param[in] msg2 reference message buffer
+ *  \returns boolean indicating whether msgb L1 content is equal
+ */
+#define msgb_eq_l1(msg1, msgb2, len) msgb_eq_l1_data(msg1, msgb_l1(msg2), 
msgb_l1len(msg2))
+
+/*! Compare msgbs L2 content
+ *  \param[in] msg1 message buffer
+ *  \param[in] msg2 reference message buffer
+ *  \returns boolean indicating whether msgb L2 content is equal
+ */
+#define msgb_eq_l2(msg1, msgb2, len) msgb_eq_l2_data(msg1, msgb_l2(msg2), 
msgb_l2len(msg2))
+
+/*! Compare msgbs L3 content
+ *  \param[in] msg1 message buffer
+ *  \param[in] msg2 reference message buffer
+ *  \returns boolean indicating whether msgb L3 content is equal
+ */
+#define msgb_eq_l3(msg1, msgb2, len) msgb_eq_l3_data(msg1, msgb_l3(msg2), 
msgb_l3len(msg2))
+
+/*! Compare msgbs L4 content
+ *  \param[in] msg1 message buffer
+ *  \param[in] msg2 reference message buffer
+ *  \returns boolean indicating whether msgb L4 content is equal
+ */
+#define msgb_eq_l4(msg1, msgb2, len) msgb_eq_l4_data(msg1, msgb_l4(msg2), 
msgb_l4len(msg2))
+
+
 /* non inline functions to ease binding */

 uint8_t *msgb_data(const struct msgb *msg);
diff --git a/src/msgb.c b/src/msgb.c
index 844cfc6..9cd59c6 100644
--- a/src/msgb.c
+++ b/src/msgb.c
@@ -173,6 +173,98 @@
        return msg->data;
 }

+/*! Compare and print: check data in msgb against given data and print errors 
if any
+ *  \param[in] file text prefix, usually __FILE__, ignored if print == false
+ *  \param[in] line numeric prefix, usually __LINE__, ignored if print == false
+ *  \param[in] func text prefix, usually __func__, ignored if print == false
+ *  \param[in] level while layer (L1, L2 etc) data should be compared against
+ *  \param[in] msg message buffer
+ *  \param[in] data expected data
+ *  \param[in] len length of data
+ *  \param[in] print boolean indicating whether we should print anything to 
stdout
+ *  \returns boolean indicating whether msgb content is equal to a given data
+ *
+ * This function is not intended to be called directly but rather used through 
corresponding macro wrappers.
+ */
+bool _msgb_eq(const char *file, size_t line, const char *func, uint8_t level,
+             const struct msgb *msg, const uint8_t *data, size_t len, bool 
print)
+{
+       const char *m_dump;
+       unsigned int m_len, i;
+       uint8_t *m_data;
+
+       if (!msg) {
+               if (print)
+                       LOGPSRC(DLGLOBAL, LOGL_FATAL, file, line, "%s() NULL 
msg comparison\n", func);
+               return false;
+       }
+
+       if (!data) {
+               if (print)
+                       LOGPSRC(DLGLOBAL, LOGL_FATAL, file, line, "%s() NULL 
comparison data\n", func);
+               return false;
+       }
+
+       switch (level) {
+       case 0:
+               m_len = msgb_length(msg);
+               m_data = msgb_data(msg);
+               m_dump = print ? msgb_hexdump(msg) : NULL;
+               break;
+       case 1:
+               m_len = msgb_l1len(msg);
+               m_data = msgb_l1(msg);
+               m_dump = print ? msgb_hexdump_l1(msg) : NULL;
+               break;
+       case 2:
+               m_len = msgb_l2len(msg);
+               m_data = msgb_l2(msg);
+               m_dump = print ? msgb_hexdump_l2(msg) : NULL;
+               break;
+       case 3:
+               m_len = msgb_l3len(msg);
+               m_data = msgb_l3(msg);
+               m_dump = print ? msgb_hexdump_l3(msg) : NULL;
+               break;
+       case 4:
+               m_len = msgb_l4len(msg);
+               m_data = msgb_l4(msg);
+               m_dump = print ? msgb_hexdump_l4(msg) : NULL;
+               break;
+       default:
+               LOGPSRC(DLGLOBAL, LOGL_FATAL, file, line,
+                       "%s() FIXME: unexpected comparison level %u\n", func, 
level);
+               return false;
+       }
+
+       if (m_len != len) {
+               if (print)
+                       LOGPSRC(DLGLOBAL, LOGL_FATAL, file, line,
+                               "%s() Length mismatch: %d != %zu, %s\n", func, 
m_len, len, m_dump);
+               return false;
+       }
+
+       if (memcmp(m_data, data, len) == 0)
+               return true;
+
+       if (!print)
+               return false;
+
+       LOGPSRC(DLGLOBAL, LOGL_FATAL, file, line,
+               "%s() L%u data mismatch:\nexpected %s\n         ", func, level, 
osmo_hexdump(data, len));
+
+       for(i = 0; i < len; i++)
+               if (data[i] != m_data[i]) {
+                       LOGPC(DLGLOBAL, LOGL_FATAL, "!!\n");
+                       break;
+               } else
+                       LOGPC(DLGLOBAL, LOGL_FATAL, ".. ");
+
+       LOGPC(DLGLOBAL, LOGL_FATAL, "    msgb %s\n", m_dump);
+
+       return false;
+}
+
 /*! get length of message buffer
  *  \param[in] msg message buffer
  *  \returns length of data section in message buffer

--
To view, visit https://gerrit.osmocom.org/12017
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I3bc95f2f5ab6e3f4b502647fb3e0aaaf1f7c4cf5
Gerrit-Change-Number: 12017
Gerrit-PatchSet: 14
Gerrit-Owner: Max <msur...@sysmocom.de>
Gerrit-Reviewer: Harald Welte <lafo...@gnumonks.org>
Gerrit-Reviewer: Jenkins Builder (1000002)
Gerrit-Reviewer: Max <msur...@sysmocom.de>
Gerrit-Reviewer: Neels Hofmeyr <nhofm...@sysmocom.de>
Gerrit-Reviewer: Pau Espin Pedrol <pes...@sysmocom.de>
Gerrit-Reviewer: Stefan Sperling <s...@stsp.name>
Gerrit-Reviewer: Vadim Yanitskiy <axilira...@gmail.com>

Reply via email to