diff options
| author | Max <msuraev@sysmocom.de> | 2018-12-03 14:14:44 +0100 | 
|---|---|---|
| committer | Max <msuraev@sysmocom.de> | 2018-12-12 09:34:12 +0000 | 
| commit | db038255eb1a2ff1a026b6c1ecd7328c22242985 (patch) | |
| tree | a3c77ec1b6142959fe2526057964ad308695e718 | |
| parent | 48b2de097216d5fb86d3e03fbccc39a7a83e8228 (diff) | |
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
| -rw-r--r-- | include/osmocom/core/msgb.h | 139 | ||||
| -rw-r--r-- | src/msgb.c | 92 | 
2 files changed, 231 insertions, 0 deletions
diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index 1bb5fe59..b7c84221 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -560,6 +560,145 @@ static inline int msgb_test_invariant(const struct msgb *msg)  	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); @@ -173,6 +173,98 @@ uint8_t *msgb_data(const struct msgb *msg)  	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  | 
