Commit e5e1dac9 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

test/mock: introduce MOCK_ENQUEUE() macro



This macro allows users to specify multiple values to be returned by
consecutive calls to a mocked function.  This can be especially useful
while testing a function that calls the same mocked function multiple
times, because it makes it possible to check how it behaves when each
of those calls return a different value.

The usage is very similar to MOCK_SET() - each call to MOCK_ENQUEUE()
specifies a value that will be returned by a consecutive call to the
mocked function (in a FIFO fashion).  Once all such values are exhausted
(or none have been specified), the mocked function will return the value
assigned by MOCK_SET().  For instance, the following code:

int foo(void);

MOCK_SET(foo, 1);
MOCK_ENQUEUE(foo, 2);
MOCK_ENQUEUE(foo, 3);

would cause foo() to return 2, 3, 1, 1, ...

Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I67c4ccde17948a65ba48aa7dc988de680c881cb7
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/22811


Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Community-CI: Mellanox Build Bot
parent d16018c1
Loading
Loading
Loading
Loading
+69 −13
Original line number Diff line number Diff line
@@ -6,15 +6,40 @@
#ifndef SPDK_INTERNAL_MOCK_H
#define SPDK_INTERNAL_MOCK_H

#include "spdk/queue.h"
#include "spdk/stdinc.h"

#define MOCK_STRUCT_INIT(...) \
	{ __VA_ARGS__ }

#define DEFINE_RETURN_MOCK(fn, ret) \
	DECLARE_MOCK_QUEUE(fn, ret);		\
	DEFINE_MOCK_QUEUE(fn, ret);		\
	bool ut_ ## fn ## _mocked = false;	\
	ret ut_ ## fn

#define DECLARE_MOCK_QUEUE(fn, ret) \
	struct ut_mqe_ ## fn {						\
		ret				val;			\
		TAILQ_ENTRY(ut_mqe_ ## fn)	link;			\
	};								\
	extern TAILQ_HEAD(ut_mqh_ ## fn, ut_mqe_ ## fn) ut_mqh_ ## fn;	\
	ret ut_mq_dequeue_ ## fn (void);					\

#define DEFINE_MOCK_QUEUE(fn, ret) \
	struct ut_mqh_ ## fn ut_mqh_ ## fn =				\
		TAILQ_HEAD_INITIALIZER(ut_mqh_ ## fn);			\
									\
	ret ut_mq_dequeue_ ## fn (void)					\
	{								\
		struct ut_mqe_ ## fn *mqe;				\
		ret val;						\
		mqe = TAILQ_FIRST(&ut_mqh_ ## fn);			\
		TAILQ_REMOVE(&ut_mqh_ ## fn, mqe, link);		\
		val = mqe->val;						\
		free(mqe);						\
		return val;						\
	}
/*
 * For controlling mocked function behavior, setting
 * and getting values from the stub, the _P macros are
@@ -24,15 +49,39 @@
	ut_ ## fn ## _mocked = true; \
	ut_ ## fn = val

/*
 * MOCK_ENQUEUE() can be used to specify multiple different return values for the same function.
 * Each consecutive call to a function will return a value specified by this macro (in a FIFO
 * fashion).  Once all such values are exhausted (or none has been specified), the value assgined by
 * MOCK_SET() will be returned.
 */
#define MOCK_ENQUEUE(fn, _val) do { \
		struct ut_mqe_ ## fn *mqe = calloc(1, sizeof(*mqe));	\
		mqe->val = _val;					\
		TAILQ_INSERT_TAIL(&ut_mqh_ ## fn, mqe, link);		\
	} while (0)

#define MOCK_GET(fn) \
	ut_ ## fn
	!TAILQ_EMPTY(&ut_mqh_ ## fn) ? ut_mq_dequeue_ ## fn () : ut_ ## fn

#define MOCK_CLEAR(fn) \
	ut_ ## fn ## _mocked = false
#define MOCK_CLEAR_QUEUE(fn) do { \
		struct ut_mqe_ ## fn *mqe;				\
		while ((mqe = TAILQ_FIRST(&ut_mqh_ ## fn))) {		\
			TAILQ_REMOVE(&ut_mqh_ ## fn, mqe, link);	\
			free(mqe);					\
		}							\
	} while (0)

#define MOCK_CLEAR_P(fn) \
#define MOCK_CLEAR(fn) do { \
		ut_ ## fn ## _mocked = false;	\
	ut_ ## fn = NULL
		MOCK_CLEAR_QUEUE(fn);		\
	} while (0)

#define MOCK_CLEAR_P(fn) do { \
		ut_ ## fn ## _mocked = false;	\
		ut_ ## fn = NULL;		\
		MOCK_CLEAR_QUEUE(fn);		\
	} while (0)

/* for proving to *certain* static analysis tools that we didn't reset the mock function. */
#define MOCK_CLEARED_ASSERT(fn) \
@@ -40,6 +89,7 @@

/* for declaring function protoypes for wrappers */
#define DECLARE_WRAPPER(fn, ret, args) \
	DECLARE_MOCK_QUEUE(fn, ret); \
	extern bool ut_ ## fn ## _mocked; \
	extern ret ut_ ## fn; \
	ret __wrap_ ## fn args; ret __real_ ## fn args
@@ -60,11 +110,14 @@
	}

#define DEFINE_WRAPPER_MOCK(fn, ret) \
	DEFINE_MOCK_QUEUE(fn, ret);		\
	bool ut_ ## fn ## _mocked = false;	\
	ret ut_ ## fn

/* DEFINE_STUB is for defining the implementation of stubs for SPDK funcs. */
#define DEFINE_STUB(fn, ret, dargs, val) \
	DECLARE_MOCK_QUEUE(fn, ret); \
	DEFINE_MOCK_QUEUE(fn, ret); \
	bool ut_ ## fn ## _mocked = true; \
	ret ut_ ## fn = val; \
	ret fn dargs; \
@@ -81,9 +134,12 @@
	}

#define HANDLE_RETURN_MOCK(fn)  \
	if (!TAILQ_EMPTY(&ut_mqh_ ## fn)) {	\
		return ut_mq_dequeue_ ## fn ();	\
	}					\
	if (ut_ ## fn ## _mocked) {		\
		return ut_ ## fn;		\
	}
	}					\


/* declare wrapper protos (alphabetically please) here */