root/test/test-common.c

Revision 7934c2ea8d4eb000fe5a1fe69a3b5bcaba5dace6, 6.0 kB (checked in by hansp <hansp>, 3 years ago)

Add option to suspend the process on error instead of exiting/aborting.
Store result code in global variable before exiting/aborting/suspending.

  • Property mode set to 100644
Line 
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
3 /* test-common.c - Common code for tests.
4  *
5  * Copyright (C) 2006 Hans Petter Jansson
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * Authors: Hans Petter Jansson <hpj@copyleft.no>
23  */
24
25 /* This file should be included directly in each test program */
26
27 #define __USE_GNU 1
28
29 #include "config.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <signal.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <fcntl.h>
39 #include <glib/gprintf.h>
40
41 #include <flow/flow-gobject-util.h>
42 #include <flow/flow.h>
43
44 typedef enum
45 {
46   TEST_RESULT_OK,
47   TEST_RESULT_SYSTEM_ERROR,
48   TEST_RESULT_FAILED,
49   TEST_RESULT_CRASH,
50   TEST_RESULT_TIMEOUT
51 }
52 TestResult;
53
54 struct timeval begin_tv;
55
56 static void test_run (void);
57
58 static const gchar *result_text [] =
59 {
60   "passed",
61   "not run - system error",
62   "FAILED",
63   "FAILED - crash",
64   "FAILED - timeout"
65 };
66
67 static TestResult global_result_code  = TEST_RESULT_OK;
68
69 static gboolean   test_is_verbose       = FALSE;
70 static gboolean   test_trap             = TRUE;
71 static gboolean   test_abort_on_error   = FALSE;
72 static gboolean   test_suspend_on_error = FALSE;
73 static GMainLoop *main_loop;
74
75 static gchar *
76 test_print_timestamp (void)
77 {
78   struct timeval  now_tv;
79   struct timeval  diff_tv;
80
81   gettimeofday (&now_tv, NULL);
82
83   diff_tv.tv_sec = now_tv.tv_sec - begin_tv.tv_sec;
84   if (now_tv.tv_usec < begin_tv.tv_usec)
85   {
86     diff_tv.tv_sec -= 1;
87     now_tv.tv_usec += 1000000;
88   }
89
90   diff_tv.tv_usec = now_tv.tv_usec - begin_tv.tv_usec;
91
92   return g_strdup_printf ("%02lu:%02lu.%02lu", diff_tv.tv_sec / 60, diff_tv.tv_sec % 60,
93                           diff_tv.tv_usec / 10000);
94 }
95
96 G_GNUC_UNUSED static void
97 test_print (const gchar *format, ...)
98 {
99   va_list  args;
100   gchar   *retval;
101   gchar   *joined;
102   gchar   *ts;
103
104   if (!test_is_verbose)
105     return;
106
107   ts = test_print_timestamp ();
108
109   va_start (args, format);
110   retval = g_strdup_vprintf (format, args);
111   va_end (args);
112
113   joined = g_strjoin (" ", ts, retval, NULL);
114
115   fwrite (joined, 1, strlen (joined), stdout);
116   fflush (stdout);
117
118   g_free (joined);
119   g_free (retval);
120   g_free (ts);
121 }
122
123 static void
124 test_end (TestResult result_code, const gchar *result_description)
125 {
126   gchar *ts;
127
128   ts = test_print_timestamp ();
129
130   g_print ("%s%s%s%s%s%s\n",
131            test_is_verbose ? "\n" : "",
132            test_is_verbose ? ts : "",
133            test_is_verbose ? " Result: " : "",
134            result_text [result_code],
135            result_description ? " - " : "",
136            result_description ? result_description : "");
137
138   g_free (ts);
139   g_main_loop_unref (main_loop);
140
141   global_result_code = result_code;
142
143   if (result_code == TEST_RESULT_OK)
144     exit (0);
145
146   if (test_abort_on_error)
147     G_BREAKPOINT ();
148
149   if (test_suspend_on_error)
150   {
151     g_print ("Going to sleep - you can attach a debugger now.\n");
152     sleep (30 * 24 * 60 * 60);  /* 1 month should do it */
153   }
154
155   exit (1);
156 }
157
158 static void
159 test_crash (void)
160 {
161   test_end (TEST_RESULT_CRASH, NULL);
162 }
163
164 static void
165 test_timeout (void)
166 {
167   test_end (TEST_RESULT_TIMEOUT, NULL);
168 }
169
170 static void
171 test_begin (const gchar *name)
172 {
173   g_print ("Testing %s%s", name, test_is_verbose ? "...\n\n" : ": ");
174   fflush (stdout);
175
176   g_type_init ();
177   g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR);
178
179   main_loop = g_main_loop_new (NULL, FALSE);
180
181   if (test_trap)
182   {
183     /* In case the test crashes, bail out and notify */
184     signal (SIGSEGV, (sig_t) test_crash);
185
186     /* In case the test hangs, bail out and notify */
187     signal (SIGALRM, (sig_t) test_timeout);
188     alarm (TEST_TIMEOUT_S);
189   }
190
191   gettimeofday (&begin_tv, NULL);
192 }
193
194 G_GNUC_UNUSED static void
195 test_run_main_loop (void)
196 {
197   g_main_loop_run (main_loop);
198 }
199
200 G_GNUC_UNUSED static void
201 test_quit_main_loop (void)
202 {
203   g_main_loop_quit (main_loop);
204 }
205
206 static void
207 print_help (const gchar *prog_name)
208 {
209   g_printerr ("%s tests %s. It takes the following arguments:\n\n"
210               "-h --help      Print this help and exit.\n"
211               "-v --verbose   Show test debug information.\n"
212               "-n --no-trap   Don't trap timeout or segv.\n"
213               "-a --abort     Abort on error, don't exit.\n"
214               "-s --suspend   Emit a message and go to sleep on error.\n\n",
215               prog_name, TEST_UNIT_NAME);
216 }
217
218 gint
219 main (gint argc, gchar *argv [])
220 {
221   gint i;
222
223   for (i = 1; i < argc; i++)
224   {
225     gchar *arg = argv [i];
226
227     if (!strcmp (arg, "-h") || !strcmp (arg, "--help"))
228     {
229       print_help (argv [0]);
230       exit (0);
231     }
232     else if (!strcmp (arg, "-v") || !strcmp (arg, "--verbose"))
233     {
234       test_is_verbose = TRUE;
235     }
236     else if (!strcmp (arg, "-n") || !strcmp (arg, "--no-trap"))
237     {
238       test_trap = FALSE;
239     }
240     else if (!strcmp (arg, "-a") || !strcmp (arg, "--abort"))
241     {
242       test_abort_on_error = TRUE;
243     }
244     else if (!strcmp (arg, "-s") || !strcmp (arg, "--suspend"))
245     {
246       test_suspend_on_error = TRUE;
247     }
248     else
249     {
250       g_printerr ("%s: Unknown argument '%s'.\n", argv [0], arg);
251       print_help (argv [0]);
252       exit (1);
253     }
254   }
255
256   if (test_abort_on_error && test_suspend_on_error)
257   {
258     g_printerr ("%s: Options --abort and --suspend conflict.\n", argv [0]);
259     print_help (argv [0]);
260     exit (1);
261   }
262
263   test_begin (TEST_UNIT_NAME);
264   test_run ();
265   test_end (TEST_RESULT_OK, NULL);
266
267   return 0;
268 }
Note: See TracBrowser for help on using the browser.