Re: RFC: GLib testing framework



On 07/11/2007, Mikkel Kamstrup Erlandsen <mikkel kamstrup gmail com> wrote:
On 07/11/2007, Tim Janik <timj imendio com> wrote:
On Wed, 7 Nov 2007, Morten Welinder wrote:

>> nobody has to use this syntax. you can stick to the ever simple:
>>    g_assert (foo > bar);
>>
>> however if you want the value of 'foo' and 'bar' be printed out, instead
>> of just the value of (foo > bar) which would be 0 or 1, then there are
>> no other means than using something simialr to:
>>    g_assert_cmpfloat (foo, >, bar);
>
> No other way?  You just need to think outside the box^w^wcpp.  How
> about a pre-cpp filter that looks at the source code, finds the g_assert,
> and does a little creative rewriting?

how about that? bad.
we don't use a preprocessor like moc before cpp+cc. if we did,
GObject would look a million times different.
people are coding such a thing after the fact these days though,
look at vala to see how it looks like.

How about token concatenation[1]?

#define g_assert_cmp (arg1, cmp_op, arg2) \
    g_assert_cmp_##CMP_OP (arg1, arg2);

Then implement private methods:

g_assert_cmp_G_LESSTHAN
g_assert_cmp_G_EQUALS
...

Then call it like

g_assert_cmp (1, G_EQUALS, 2);


I just did a small implementation of the above suggestion to prove to myself that I was right :-). I think it works quite alright. See attachment.

If anybody agrees with me that we must have an IDE friendly syntax, or have other reasons to believe that

   g_assert_cmpint (1, G_EQUALS, 2);

is better than

  g_assert_cmpint (1, ==, 2);

I shall gladly make it into a real implementation. Tim?

Cheers,
Mikkel
/**
 * Compile with: gcc $(pkg-config --cflags --libs glib-2.0) g_test.c 
 *
 * This is a sample implementation of a set of test functions for glib.
 * 
 * It is a design goal to only expose one symbol per data type (int, float, etc).
 * This sample only implements a few comparisons for int and strings, but it is
 * designed to be straight forward to extend.
 *
 * LICENSE: Do what ever you like but don't blame me for anything. If you are nice
 *          you credit me, but if you don't that is fine too.
 *          You are also permitted to release the code under another license.
 */

#include <glib.h>

/* ** PUBLIC HEADER START  (this goes in the public .h files)** */
#define G_LESSTHAN G_LESSTHAN
#define G_EQUALS G_EQUALS

#define G_LESSTHAN_SYMBOL "<"
#define G_EQUALS_SYMBOL "=="

/* Indexes of comparison methods. Used for symbol lookups */
typedef enum {
	G_LESSTHAN_IDX,
	G_EQUALS_IDX,
} GCompOpIdx;


#define g_assert_cmpint(arg1, cmp_op, arg2) \
	g_assert_cmpint_full (arg1, cmp_op##_IDX, arg2, cmp_op##_SYMBOL, __FILE__, __PRETTY_FUNCTION__, __LINE__)
								 
#define g_assert_cmpstr(arg1, cmp_op, arg2) \
	g_assert_cmpstr_full (arg1, cmp_op##_IDX, arg2, cmp_op##_SYMBOL, __FILE__, __PRETTY_FUNCTION__, __LINE__)

/* Semi public. We expose these symbols but they are not meant for consumption. */
void	g_assert_cmpint_full 	(gint arg1,
								 GCompOpIdx cmp_op_idx,
								 gint arg2,
								 const gchar *cmp_symbol,
								 const gchar *file,
								 const gchar *method,
								 gint line);

void	g_assert_cmpstr_full 	(gchar *arg1, 
								 GCompOpIdx op,
								 gchar *arg2,
								 gchar *cmp_symbol,
								 const gchar *file,
								 const gchar *method,
								 gint line);

								 
/* ** PUBLIC HEADER END ** */

/* PRIVATE IMPLEMENTATION START (goes in .c file) */

/* Typed comparison functions */
typedef	gboolean (*GIntCompareFunc) (gint   a, gint   b);
typedef	gboolean (*GStrCompareFunc) (gchar *a, gchar *b);


/* Macro to create trivial comparison functions */
#define expand_compare(comp_op, short_type, ctype, bool_eval) \
static gboolean \
g_assert_cmp##short_type##_##comp_op (ctype arg1, ctype arg2)\
{\
	if (bool_eval) {\
		return TRUE;\
	} else {\
		return FALSE;\
	}\
}

expand_compare (G_LESSTHAN, 	int, gint, arg1 <  arg2);
expand_compare (G_EQUALS,		int, gint, arg1 == arg2);

expand_compare (G_EQUALS,		str, gchar*, g_str_equal(arg1,arg2));

/* Symbol tables for typed comparison functions. 
 * They might better be initialized in g_test_init */
GIntCompareFunc cmpint_funcs[] = {g_assert_cmpint_G_LESSTHAN, 
	                			  g_assert_cmpint_G_EQUALS};

GStrCompareFunc cmpstr_funcs[] = {NULL,
								  g_assert_cmpstr_G_EQUALS};



/* The implementations of the g_assert_cmp*_full methods can probably
 be autogenerated by the preprocessor as with expand_compare() */
void
g_assert_cmpint_full (gint arg1, GCompOpIdx cmp_op_idx, gint arg2, const gchar *cmp_symbol,
                      const gchar *file, const gchar *method, gint line)
{
	GIntCompareFunc cmp;	
	
	/*Lookup and run comparison func from symbol table */
	cmp = cmpint_funcs[cmp_op_idx];
	if (!cmp) {
		g_printf ("ERROR: In %s, %s, line %d: '%s' not applicable to integers\n", file, method, line, cmp_symbol);
		return;
	}
	
	if (cmp(arg1, arg2)) {
		g_printf ("GOOD: %d %s %d\n", arg1, cmp_symbol, arg2);
	} else {
		g_printf ("FAILED: In %s, %s, line %d: %d %s %d\n", file, method, line, arg1, cmp_symbol, arg2);
	}
}

void
g_assert_cmpstr_full (gchar *arg1, GCompOpIdx cmp_op_idx, gchar *arg2, gchar *cmp_symbol,
					  const gchar *file, const gchar *method, gint line)
{
	GStrCompareFunc cmp;

	/*Lookup and run comparison func from symbol table */
	cmp = cmpstr_funcs[cmp_op_idx];
	if (!cmp) {
		g_printf ("ERROR: In %s, %s, line %d: '%s' not applicable to strings\n", file, method, line, cmp_symbol);
		return;
	}
	
	/*Lookup and run comparison func from symbol table */
	if (cmpstr_funcs[cmp_op_idx](arg1, arg2)) {
		g_printf ("GOOD: '%s' %s '%s'\n", arg1, cmp_symbol, arg2);
	} else {
		g_printf ("FAILED: In %s, %s, line %d: %s %s %s\n", file, method, line, arg1, cmp_symbol, arg2);
	}
}


int
main (gint argc, gchar **argv)
{	
	g_assert_cmpint (1, G_LESSTHAN, 2);
	g_assert_cmpint (1, G_EQUALS, 2); //fail
	
	g_assert_cmpstr ("foo", G_EQUALS, "foo");
	g_assert_cmpstr ("foo", G_EQUALS, "bar"); //fail
	
	g_assert_cmpstr ("foo", G_LESSTHAN, "foo"); //error
	
	return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]