Skip to content

Instantly share code, notes, and snippets.

@dmatveev
Created September 11, 2011 11:53
Show Gist options
  • Save dmatveev/1209489 to your computer and use it in GitHub Desktop.
Save dmatveev/1209489 to your computer and use it in GitHub Desktop.
GFileMonitor test for gio/kqueue GSoC project
#include <glib.h>
#include <glib/gprintf.h>
#include <gio/gio.h>
#include <string.h> /* memset, strlen */
#include <stdlib.h> /* system */
#define MAX_EXPECTED_EVENTS 10
#ifndef EVENT_EXPECT_TIME
# define EVENT_EXPECT_TIME 5
#endif
/* #define MORE_LOGS */
#ifdef MORE_LOGS
# define gft_log g_printf
#else
# define gft_log
#endif
typedef struct {
GFileMonitorEvent flags;
gchar *file1;
gchar *file2;
} registered_event;
typedef struct {
int caret;
registered_event events[MAX_EXPECTED_EVENTS];
} registered_events;
typedef struct {
GFileMonitorEvent event;
const gchar *humanr;
gchar *file1;
gchar *file2;
} humanr_event;
typedef struct {
const gchar *action;
humanr_event events[MAX_EXPECTED_EVENTS];
} test_case;
#define EV_(sym, f1, f2) {G_FILE_MONITOR_EVENT_##sym, #sym, f1, f2}
#define END {-1, ""}
#define NOT_END(x) ((x.event) != -1)
#define SELF "%s"
typedef struct {
const char *name;
const char *filename;
GFileMonitorFlags flags;
test_case *cases;
int count;
} test;
void register_activity (GFileMonitor *mon,
GFile *first,
GFile *second,
GFileMonitorEvent event,
gpointer udata);
gpointer run_test (gpointer ptr);
int run_test_case (test *t,
test_case *tc,
registered_events *regd);
void run_suite (test *tests, int count);
void test_complete ();
void
decode (GFileMonitorEvent event, gchar *events)
{
#define CHECK(x, def) \
if (((x) & (def)) == def) { \
g_sprintf (events, "%s ", #def); \
events += (strlen (#def) + 1); \
}
CHECK(event, G_FILE_MONITOR_EVENT_CHANGED);
CHECK(event, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT);
CHECK(event, G_FILE_MONITOR_EVENT_DELETED);
CHECK(event, G_FILE_MONITOR_EVENT_CREATED);
CHECK(event, G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED);
CHECK(event, G_FILE_MONITOR_EVENT_PRE_UNMOUNT);
CHECK(event, G_FILE_MONITOR_EVENT_UNMOUNTED);
CHECK(event, G_FILE_MONITOR_EVENT_MOVED);
#undef CHECK
}
void
register_activity (GFileMonitor *mon,
GFile *first,
GFile *second,
GFileMonitorEvent event,
gpointer udata)
{
registered_event *ev;
(void) mon;
(void) first;
(void) second;
g_assert (udata != NULL);
registered_events *registered = (registered_events *) udata;
ev = &registered->events[registered->caret++];
ev->flags = event;
ev->file1 = first ? g_file_get_basename (first) : NULL;
ev->file2 = second ? g_file_get_basename (second) : NULL;
}
int
matched_fname (const gchar *test_file, /* associated with the entire test case */
const gchar *expected_file, /* (mask) associated an expected event */
const gchar *registered_name) /* what have have got in the "changed" */
{
if (expected_file) {
gchar final_filename[1024];
g_sprintf (final_filename, expected_file, test_file);
gft_log (" -- Comparing %s and %s\n", final_filename, registered_name);
if (strcmp (final_filename, registered_name) != 0) {
gft_log (" -- NOT EQUAL\n");
return 1; /* should continue */
}
}
return 0; /* normal */
}
#define file_or(a, b) ((a) > 0 ? (a) : (b))
int
run_test_case (test *t, test_case *tc, registered_events *regd)
{
g_assert (t != NULL);
g_assert (tc != NULL);
g_assert (regd != NULL);
int j, k, registered_count;
gchar action[1024];
g_sprintf (action, tc->action, t->filename, t->filename);
system (action);
g_usleep (G_USEC_PER_SEC * EVENT_EXPECT_TIME);
registered_count = regd->caret;
for (j = 0; j < MAX_EXPECTED_EVENTS; j++) {
humanr_event he = tc->events[j];
if (NOT_END(he)) {
gft_log ("-- Looking for %s (%d) [%s; %s]\n",
he.humanr,
he.event,
file_or (he.file1, "--"),
file_or (he.file2, "--"));
for (k = 0; k < regd->caret; k++) {
gft_log (" -- Probing an registered one #%d (code %d) [%s; %s]\n",
k,
regd->events[k].flags,
file_or (regd->events[k].file1, "--"),
file_or (regd->events[k].file2, "--"));
if ((regd->events[k].flags & he.event) == he.event) {
gft_log (" -- Event code matched!\n");
if (matched_fname (t->filename, he.file1, regd->events[k].file1)
|| matched_fname (t->filename, he.file2, regd->events[k].file2)) {
gft_log (" -- One of file names NOT matched too, continuing...\n");
continue;
}
gft_log (" -- Looks like we\'ve found it!\n");
break;
}
}
if (k != regd->caret) {
--registered_count;
}
g_printf ("%s (%s): %s on \"%s\"\n",
(k == regd->caret) ? "FAIL" : "PASS",
t->name,
he.humanr,
action);
} else {
break;
}
}
if (registered_count) {
g_printf ("*** (%s) Warning! There are %d unexpected event(s) registered on \"%s\"\n",
t->name,
registered_count,
action);
gft_log ("*** The full event list is:\n");
for (k = 0; k < regd->caret; k++) {
g_printf (" %02d: Event code %d, file 1: \"%s\", file 2: \"%s\"\n",
k,
regd->events[k].flags,
file_or(regd->events[k].file1, "--"),
file_or(regd->events[k].file2, "--"));
}
}
}
gpointer
run_test (gpointer ptr)
{
test *t = (test *) ptr;
g_assert (t != NULL);
g_assert (t->name != NULL);
g_assert (t->filename != NULL);
g_assert (t->cases != NULL);
GFileMonitor *mon;
GFile *file;
int i;
registered_events regd;
file = g_file_new_for_path (t->filename);
g_assert (file != NULL);
mon = g_file_monitor (file, t->flags, NULL, NULL);
g_assert (mon != NULL);
g_signal_connect (mon, "changed", G_CALLBACK (register_activity), &regd);
for (i = 0; i < t->count; i++) {
memset (&regd, 0, sizeof (registered_events));
run_test_case (t, &t->cases[i], &regd);
}
g_file_monitor_cancel (mon);
g_object_unref (G_OBJECT(mon));
g_object_unref (G_OBJECT(file));
test_complete ();
return NULL;
}
GMainLoop *loop;
int num_tests;
GStaticMutex mutex = G_STATIC_MUTEX_INIT;
void
run_suite (test *tests, int count)
{
int i;
g_static_mutex_lock (&mutex);
num_tests = count;
for (i = 0; i < count; i++) {
g_thread_create (run_test, &tests[i], FALSE, NULL);
}
g_static_mutex_unlock (&mutex);
}
void
test_complete ()
{
g_assert (loop != NULL);
g_static_mutex_lock (&mutex);
if (--num_tests == 0) {
g_main_loop_quit (loop);
}
g_static_mutex_unlock (&mutex);
}
test_case file_test_cases[] = {
{"touch %s", {EV_(CREATED, SELF, NULL), END}},
{"touch %s", {EV_(ATTRIBUTE_CHANGED, SELF, NULL), END}},
{"echo 1 >> %s", {EV_(CHANGED, SELF, NULL), EV_(CHANGES_DONE_HINT, NULL, NULL), END}},
{"rm %s", {EV_(DELETED, SELF, NULL), END}},
{"touch %s", {EV_(CREATED, SELF, NULL), END}},
{"mv %s gfmt-ft-moved", {EV_(MOVED, SELF, NULL), END}},
{"rm gfmt-ft-moved", {EV_(DELETED, SELF, NULL), END}},
};
test_case dir_test_cases[] = {
{"mkdir %s", {EV_(CREATED, SELF, NULL), END}},
{"touch %s", {EV_(ATTRIBUTE_CHANGED, SELF, NULL), END}},
{"touch %s/foo", {EV_(CREATED, "foo", NULL), END}},
{"rm %s/foo", {EV_(DELETED, "foo", NULL), END}},
{"touch %s/foo", {EV_(CREATED, "foo", NULL), END}},
{"touch %s/bar", {EV_(CREATED, "bar", NULL), END}},
{"mv %s/foo %s/bar", {EV_(MOVED, "foo", "bar"), END}},
{"rm %s/bar", {EV_(DELETED, "bar", NULL), END}},
{"touch %s/baz", {EV_(CREATED, "baz", NULL), END}},
{"mv %s/baz %s/bazz", {EV_(MOVED, "baz", "bazz"), END}},
{"rm %s/bazz", {EV_(DELETED, "bazz", NULL), END}},
{"mkdir %s/dir", {EV_(CREATED, "dir", NULL), END}},
{"rmdir %s/dir", {EV_(DELETED, "dir", NULL), END}},
{"mv %s gfmt-dt-moved", {EV_(MOVED, SELF, NULL), END}},
{"rm -rf gfmt-dt-moved", {EV_(DELETED, SELF, NULL), END}},
};
test_case move_test_cases[] = {
{"mkdir %s", {EV_(CREATED, SELF, NULL), END}},
{"touch %s/foo", {EV_(CREATED, "foo", NULL), END}},
{"mv %s/foo %s/bar", {EV_(DELETED, "foo", NULL), EV_(CREATED, "bar", NULL), END}},
{"rm %s/bar", {EV_(DELETED, "bar", NULL), END}},
{"rm -rf %s", {EV_(DELETED, SELF, NULL), END}},
};
test test_suite[] = {
{ "File test",
"gfmt-test",
G_FILE_MONITOR_SEND_MOVED,
file_test_cases,
G_N_ELEMENTS (file_test_cases)
},
{"Directory test",
"gfmt-testdir",
G_FILE_MONITOR_SEND_MOVED,
dir_test_cases,
G_N_ELEMENTS (dir_test_cases)
},
{"Movements test",
"gfmt-movedir",
G_FILE_MONITOR_NONE,
move_test_cases,
G_N_ELEMENTS (move_test_cases)
},
};
int
main (int argc, char *argv[])
{
g_type_init ();
g_thread_init (NULL);
g_printf ("Starting tests for Glib %d.%d.%d...\n",
GLIB_MAJOR_VERSION,
GLIB_MINOR_VERSION,
GLIB_MICRO_VERSION);
run_suite (test_suite, G_N_ELEMENTS(test_suite));
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment