Re: RFC: GLib testing framework
- From: "Mikkel Kamstrup Erlandsen" <mikkel kamstrup gmail com>
- To: "Tim Janik" <timj imendio com>
- Cc: Gtk+ Developers <gtk-devel-list gnome org>
- Subject: Re: RFC: GLib testing framework
- Date: Thu, 8 Nov 2007 23:43:38 +0100
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]