1#!/usr/bin/perl -w
2# exotic 0.4
3# Copyright (c) 2007-2012, Jan Vidar Krey
4
5use strict;
6
7my $program = $0;
8my $file;
9my $line;
10my @tests;
11my $found;
12my $test;
13my @files;
14
15if ($#ARGV == -1)
16{
17	die "Usage: $program files\n";
18}
19
20my $version = "0.4";
21
22foreach my $arg (@ARGV)
23{
24	push(@files, $arg);
25}
26
27
28print "/* THIS FILE IS AUTOMATICALLY GENERATED BY EXOTIC - DO NOT EDIT THIS FILE! */\n";
29print "/* exotic/$version (Mon Nov  7 11:15:31 CET 2011) */\n\n";
30
31print "#define __EXOTIC__STANDALONE__\n";
32standalone_include_exotic_h();
33
34if ($#ARGV >= 0)
35{
36	foreach $file (@ARGV)
37	{
38		$found = 0;
39		open( FILE, "$file") || next;
40		my @data = <FILE>;
41		my $comment = 0;
42
43		foreach $line (@data) {
44			chomp($line);
45
46			if ($comment == 1)
47			{
48				if ($line =~ /^(.*\*\/)(.*)/)
49				{
50					$line = $2;
51					$comment = 0;
52				}
53				else
54				{
55					next; # ignore comment data
56				}
57			}
58
59			if ($line =~ /^(.*)\/\*(.*)\*\/(.*)$/)
60			{
61				$line = $1 . " " . $3; # exclude comment stuff in between "/*" and "*/".
62			}
63
64			if ($line =~ /^(.*)(\/\/.*)$/) {
65				$line = $1; # exclude stuff after "//" (FIXME: does not work if they are inside a string)
66			}
67
68			if ($line =~ /\/\*/) {
69				$comment = 1;
70				next;
71			}
72
73			if ($line =~ /^\s*EXO_TEST\(\s*(\w+)\s*,/)
74			{
75				$found++;
76				push(@tests, $1);
77			}
78		}
79
80		if ($found > 0) {
81			print "#include \"" . $file . "\"\n";
82		}
83
84		close(FILE);
85	}
86	print "\n";
87}
88
89# Write a main() that will start the test run
90print "int main(int argc, char** argv)\n{\n";
91print "\tstruct exotic_handle handle;\n\n";
92print "\tif (exotic_initialize(&handle, argc, argv) == -1)\n\t\treturn -1;\n\n";
93
94if ($#tests > 0)
95{
96	print "\t/* Register the tests to be run */\n";
97	foreach $test (@tests)
98	{
99		print "\texotic_add_test(&handle, &exotic_test_" . $test . ", \"" . $test . "\");\n";
100	}
101}
102else
103{
104	print "\t/* No tests are found! */\n";
105}
106
107print "\n";
108print "\treturn exotic_run(&handle);\n";
109print "}\n\n";
110
111
112standalone_include_exotic_c();
113
114sub standalone_include_exotic_h {
115print '
116/*
117 * Exotic (EXtatic.Org Test InfrastuCture)
118 * Copyright (c) 2007, Jan Vidar Krey
119 */
120
121#ifndef EXO_TEST
122#define EXO_TEST(NAME, block) int exotic_test_ ## NAME (void) block
123#endif
124
125#ifndef HAVE_EXOTIC_AUTOTEST_H
126#define HAVE_EXOTIC_AUTOTEST_H
127
128#ifdef __cplusplus
129extern "C" {
130#endif
131
132typedef int(*exo_test_t)();
133
134enum exo_toggle { cfg_default, cfg_off, cfg_on };
135
136struct exotic_handle
137{
138	enum exo_toggle config_show_summary;
139	enum exo_toggle config_show_pass;
140	enum exo_toggle config_show_fail;
141	unsigned int fail;
142	unsigned int pass;
143	struct exo_test_data* first;
144	struct exo_test_data* current;
145};
146
147extern int  exotic_initialize(struct exotic_handle* handle, int argc, char** argv);
148extern void exotic_add_test(struct exotic_handle* handle, exo_test_t, const char* name);
149extern int  exotic_run(struct exotic_handle* handle);
150
151#ifdef __cplusplus
152}
153#endif
154
155#endif /* HAVE_EXOTIC_AUTOTEST_H */
156
157'; }
158sub standalone_include_exotic_c {
159print '
160/*
161 * Exotic - C/C++ source code testing
162 * Copyright (c) 2007, Jan Vidar Krey
163 */
164
165#include <sys/types.h>
166#include <stdio.h>
167#include <stdlib.h>
168#include <string.h>
169
170static void exotic_version();
171
172#ifndef __EXOTIC__STANDALONE__
173#include "autotest.h"
174static void exotic_version()
175{
176	printf("Extatic.org Test Infrastructure: exotic " "${version}" "\n\n");
177	printf("Copyright (C) 2007 Jan Vidar Krey, janvidar@extatic.org\n");
178	printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n");
179}
180#endif
181
182struct exo_test_data
183{
184	exo_test_t test;
185	char* name;
186	struct exo_test_data* next;
187};
188
189
190static void exotic_summary(struct exotic_handle* handle)
191{
192	int total     = handle->pass + handle->fail;
193	int pass_rate = total ? (100*handle->pass / total) : 0;
194	int fail_rate = total ? (100*handle->fail / total) : 0;
195
196	printf("\n");
197	printf("--------------------------------------------\n");
198	printf("Results:\n");
199	printf(" * Total tests run:  %8d\n", total);
200	printf(" * Tests passed:     %8d (~%d%%)\n", (int) handle->pass, pass_rate);
201	printf(" * Tests failed:     %8d (~%d%%)\n", (int) handle->fail, fail_rate);
202	printf("--------------------------------------------\n");
203}
204
205
206static void exotic_help(const char* program)
207{
208	printf("Usage: %s [OPTIONS]\n\n", program);
209	printf("Options:\n");
210	printf("  --help      -h    Show this message\n");
211	printf("  --version   -v    Show version\n");
212	printf("  --summary   -s    show only summary)\n");
213	printf("  --fail      -f    show only test failures\n");
214	printf("  --pass      -p    show only test passes\n");
215	printf("\nExamples:\n");
216	printf("  %s -s -f\n\n", program);
217}
218
219
220int exotic_initialize(struct exotic_handle* handle, int argc, char** argv)
221{
222	int n;
223	if (!handle || !argv) return -1;
224
225	memset(handle, 0, sizeof(struct exotic_handle));
226
227	for (n = 1; n < argc; n++)
228	{
229		if (!strcmp(argv[n], "-h") || !strcmp(argv[n], "--help"))
230		{
231			exotic_help(argv[0]);
232			exit(0);
233		}
234
235		if (!strcmp(argv[n], "-v") || !strcmp(argv[n], "--version"))
236		{
237			exotic_version();
238			exit(0);
239		}
240
241		if (!strcmp(argv[n], "-s") || !strcmp(argv[n], "--summary"))
242		{
243			handle->config_show_summary = cfg_on;
244			continue;
245		}
246
247		if (!strcmp(argv[n], "-f") || !strcmp(argv[n], "--fail"))
248		{
249			handle->config_show_fail = cfg_on;
250			continue;
251		}
252
253		if (!strcmp(argv[n], "-p") || !strcmp(argv[n], "--pass"))
254		{
255			handle->config_show_pass = cfg_on;
256			continue;
257		}
258
259		fprintf(stderr, "Unknown argument: %s\n\n", argv[n]);
260		exotic_help(argv[0]);
261		exit(0);
262	}
263
264	if (handle->config_show_summary == cfg_on)
265	{
266		if (handle->config_show_pass == cfg_default) handle->config_show_pass = cfg_off;
267		if (handle->config_show_fail == cfg_default) handle->config_show_fail = cfg_off;
268
269	}
270	else if (handle->config_show_pass == cfg_on)
271	{
272		if (handle->config_show_summary == cfg_default) handle->config_show_summary = cfg_off;
273		if (handle->config_show_fail    == cfg_default) handle->config_show_fail = cfg_off;
274	}
275	else if (handle->config_show_fail == cfg_on)
276	{
277		if (handle->config_show_summary == cfg_default) handle->config_show_summary = cfg_off;
278		if (handle->config_show_fail    == cfg_default) handle->config_show_fail = cfg_off;
279	}
280	else
281	{
282		if (handle->config_show_summary == cfg_default) handle->config_show_summary = cfg_on;
283		if (handle->config_show_fail    == cfg_default) handle->config_show_fail = cfg_on;
284		if (handle->config_show_pass    == cfg_default) handle->config_show_pass = cfg_on;
285	}
286	return 0;
287}
288
289
290void exotic_add_test(struct exotic_handle* handle, exo_test_t func, const char* name)
291{
292	struct exo_test_data* test;
293	if (!handle)
294	{
295		fprintf(stderr, "exotic_add_test: failed, no handle!\n");
296		exit(-1);
297	}
298
299	test = (struct exo_test_data*) malloc(sizeof(struct exo_test_data));
300	if (!test)
301	{
302		fprintf(stderr, "exotic_add_test: out of memory!\n");
303		exit(-1);
304	}
305
306	/* Create the test */
307	memset(test, 0, sizeof(struct exo_test_data));
308	test->test = func;
309	test->name = strdup(name);
310
311	/* Register the test in the handle */
312	if (!handle->first)
313	{
314		handle->first = test;
315		handle->current = test;
316	}
317	else
318	{
319		handle->current->next = test;
320		handle->current = test;
321	}
322}
323
324
325int exotic_run(struct exotic_handle* handle)
326{
327	struct exo_test_data* tmp = NULL;
328
329	if (!handle)
330	{
331		fprintf(stderr, "Error: exotic is not initialized\n");
332		return -1;
333	}
334
335	handle->current = handle->first;
336	while (handle->current)
337	{
338		tmp = handle->current;
339
340		if (handle->current->test()) {
341			if (handle->config_show_pass == cfg_on) printf("* PASS test \'%s\'\n", tmp->name);
342			handle->pass++;
343		} else {
344			if (handle->config_show_fail == cfg_on) printf("* FAIL test \'%s\'\n", tmp->name);
345			handle->fail++;
346		}
347
348		handle->current = handle->current->next;
349
350		free(tmp->name);
351		free(tmp);
352	}
353
354	if (!handle->first)
355	{
356		printf("(No tests added)\n");
357	}
358
359	if (handle->config_show_summary == cfg_on)
360		exotic_summary(handle);
361
362	return (handle->fail) ? handle->fail : 0;
363}
364
365
366static void exotic_version() {
367	printf("exotic 0.4-standalone\n\n");
368	printf("Copyright (C) 2007 Jan Vidar Krey, janvidar@extatic.org\n");
369	printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n");
370}
371'; }
372
373