Browse Source

[test] Add setjmp()/longjmp() self-tests

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
dc795b9fef
2 changed files with 172 additions and 0 deletions
  1. 171
    0
      src/tests/setjmp_test.c
  2. 1
    0
      src/tests/tests.c

+ 171
- 0
src/tests/setjmp_test.c View File

@@ -0,0 +1,171 @@
1
+/*
2
+ * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/** @file
27
+ *
28
+ * setjmp()/longjmp() tests
29
+ *
30
+ */
31
+
32
+/* Forcibly enable assertions */
33
+#undef NDEBUG
34
+
35
+#include <stddef.h>
36
+#include <assert.h>
37
+#include <setjmp.h>
38
+#include <ipxe/test.h>
39
+
40
+/** A setjmp()/longjmp() test */
41
+struct setjmp_test {
42
+	/** Jump buffer */
43
+	jmp_buf env;
44
+	/** Expected value */
45
+	int expected;
46
+	/** Test code file */
47
+	const char *file;
48
+	/** Test code line */
49
+	unsigned int line;
50
+};
51
+
52
+/** Expected jump */
53
+static struct setjmp_test *jumped;
54
+
55
+/**
56
+ * Report a setjmp() test result
57
+ *
58
+ * @v test		setjmp()/longjmp() test
59
+ *
60
+ * This has to be implemented as a macro since if it were a function
61
+ * then the context saved by setjmp() would be invalidated when the
62
+ * function returned.
63
+ */
64
+#define setjmp_ok( test ) do {						\
65
+	int value;							\
66
+	/* Sanity check */						\
67
+	assert ( jumped == NULL );					\
68
+	/* Initialise test */						\
69
+	(test)->expected = 0;						\
70
+	(test)->file = __FILE__;					\
71
+	(test)->line = __LINE__;					\
72
+	/* Perform setjmp() */						\
73
+	value = setjmp ( (test)->env );					\
74
+	/* Report setjmp()/longjmp() result */				\
75
+	setjmp_return_ok ( (test), value );				\
76
+	} while ( 0 )
77
+
78
+/**
79
+ * Report a setjmp()/longjmp() test result
80
+ *
81
+ * @v test		setjmp()/longjmp() test
82
+ * @v value		Value returned from setjmp()
83
+ *
84
+ * This function ends up reporting results from either setjmp() or
85
+ * longjmp() tests (since calls to longjmp() will return via the
86
+ * corresponding setjmp()).  It therefore uses the test code file and
87
+ * line stored in the test structure, which will represent the line
88
+ * from which either setjmp() or longjmp() was called.
89
+ */
90
+static void setjmp_return_ok ( struct setjmp_test *test, int value ) {
91
+
92
+	/* Determine whether this was reached via setjmp() or longjmp() */
93
+	if ( value == 0 ) {
94
+		/* This is the initial call to setjmp() */
95
+		okx ( test->expected == 0, test->file, test->line );
96
+		okx ( jumped == NULL, test->file, test->line );
97
+	} else {
98
+		/* This is reached via a call to longjmp() */
99
+		okx ( value == test->expected, test->file, test->line );
100
+		okx ( jumped == test, test->file, test->line );
101
+	}
102
+
103
+	/* Clear expected jump */
104
+	jumped = NULL;
105
+}
106
+
107
+/**
108
+ * Report a longjmp() test result
109
+ *
110
+ * @v test		setjmp()/longjmp() test
111
+ * @v file		Test code file
112
+ * @v line		Test code line
113
+ */
114
+static void longjmp_okx ( struct setjmp_test *test, int value,
115
+			  const char *file, unsigned int line ) {
116
+
117
+	/* Record expected value.  A zero passed to longjmp() should
118
+	 * result in setjmp() returning a value of one.
119
+	 */
120
+	test->expected = ( value ? value : 1 );
121
+
122
+	/* Record test code file and line */
123
+	test->file = file;
124
+	test->line = line;
125
+
126
+	/* Record expected jump */
127
+	jumped = test;
128
+
129
+	/* Perform longjmp().  Should return via setjmp_okx() */
130
+	longjmp ( test->env, value );
131
+
132
+	/* longjmp() should never return */
133
+	assert ( 0 );
134
+}
135
+#define longjmp_ok( test, value ) \
136
+	longjmp_okx ( test, value, __FILE__, __LINE__ )
137
+
138
+/**
139
+ * Perform setjmp()/longjmp() self-tests
140
+ *
141
+ */
142
+static void setjmp_test_exec ( void ) {
143
+	static struct setjmp_test alpha;
144
+	static struct setjmp_test beta;
145
+	static int iteration;
146
+
147
+	/* This is one of the very few situations in which the
148
+	 * "for-case" pattern is justified.
149
+	 */
150
+	for ( iteration = 0 ; iteration < 10 ; iteration++ ) {
151
+		DBGC ( jumped, "SETJMP test iteration %d\n", iteration );
152
+		switch ( iteration ) {
153
+		case 0: setjmp_ok ( &alpha ); break;
154
+		case 1: setjmp_ok ( &beta ); break;
155
+		case 2:	longjmp_ok ( &alpha, 0 );
156
+		case 3: longjmp_ok ( &alpha, 1 );
157
+		case 4: longjmp_ok ( &alpha, 2 );
158
+		case 5: longjmp_ok ( &beta, 17 );
159
+		case 6: longjmp_ok ( &beta, 29 );
160
+		case 7: longjmp_ok ( &alpha, -1 );
161
+		case 8: longjmp_ok ( &beta, 0 );
162
+		case 9: longjmp_ok ( &beta, 42 );
163
+		}
164
+	}
165
+}
166
+
167
+/** setjmp()/longjmp() self-test */
168
+struct self_test setjmp_test __self_test = {
169
+	.name = "setjmp",
170
+	.exec = setjmp_test_exec,
171
+};

+ 1
- 0
src/tests/tests.c View File

@@ -63,3 +63,4 @@ REQUIRE_OBJECT ( png_test );
63 63
 REQUIRE_OBJECT ( dns_test );
64 64
 REQUIRE_OBJECT ( uri_test );
65 65
 REQUIRE_OBJECT ( profile_test );
66
+REQUIRE_OBJECT ( setjmp_test );

Loading…
Cancel
Save