iPXE
setjmp_test.c
Go to the documentation of this file.
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 */
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 __attribute__ (( noreturn ))
116  const char *file, unsigned int line ) {
117 
118  /* Record expected value. A zero passed to longjmp() should
119  * result in setjmp() returning a value of one.
120  */
121  test->expected = ( value ? value : 1 );
122 
123  /* Record test code file and line */
124  test->file = file;
125  test->line = line;
126 
127  /* Record expected jump */
128  jumped = test;
129 
130  /* Perform longjmp(). Should return via setjmp_okx() */
131  longjmp ( test->env, value );
132 
133  /* longjmp() should never return */
134  assert ( 0 );
135 }
136 #define longjmp_ok( test, value ) \
137  longjmp_okx ( test, value, __FILE__, __LINE__ )
138 
139 /**
140  * Perform setjmp()/longjmp() self-tests
141  *
142  */
143 static void setjmp_test_exec ( void ) {
144  static struct setjmp_test alpha;
145  static struct setjmp_test beta;
146  static int iteration;
147 
148  /* This is one of the very few situations in which the
149  * "for-case" pattern is justified.
150  */
151  for ( iteration = 0 ; iteration < 10 ; iteration++ ) {
152  DBGC ( jumped, "SETJMP test iteration %d\n", iteration );
153  switch ( iteration ) {
154  case 0: setjmp_ok ( &alpha ); break;
155  case 1: setjmp_ok ( &beta ); break;
156  case 2: longjmp_ok ( &alpha, 0 );
157  case 3: longjmp_ok ( &alpha, 1 );
158  case 4: longjmp_ok ( &alpha, 2 );
159  case 5: longjmp_ok ( &beta, 17 );
160  case 6: longjmp_ok ( &beta, 29 );
161  case 7: longjmp_ok ( &alpha, -1 );
162  case 8: longjmp_ok ( &beta, 0 );
163  case 9: longjmp_ok ( &beta, 42 );
164  }
165  }
166 }
167 
168 /** setjmp()/longjmp() self-test */
170  .name = "setjmp",
171  .exec = setjmp_test_exec,
172 };
int expected
Expected value.
Definition: setjmp_test.c:45
#define __attribute__(x)
Definition: compiler.h:10
#define longjmp_ok(test, value)
Definition: setjmp_test.c:136
static void setjmp_return_ok(struct setjmp_test *test, int value)
Report a setjmp()/longjmp() test result.
Definition: setjmp_test.c:90
static void longjmp_okx(struct setjmp_test *test, int value, const char *file, unsigned int line)
Report a longjmp() test result.
Definition: setjmp_test.c:115
#define DBGC(...)
Definition: compiler.h:505
Self-test infrastructure.
const char * name
Test set name.
Definition: test.h:17
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define setjmp_ok(test)
Report a setjmp() test result.
Definition: setjmp_test.c:64
A jump buffer.
Definition: setjmp.h:9
A self-test set.
Definition: test.h:15
static struct setjmp_test * jumped
Expected jump.
Definition: setjmp_test.c:53
A setjmp()/longjmp() test.
Definition: setjmp_test.c:41
#define okx(success, file, line)
Report test result.
Definition: test.h:44
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
struct self_test setjmp_test __self_test
setjmp()/longjmp() self-test
Definition: setjmp_test.c:169
unsigned int line
Test code line.
Definition: setjmp_test.c:49
static void setjmp_test_exec(void)
Perform setjmp()/longjmp() self-tests.
Definition: setjmp_test.c:143
const char * file
Test code file.
Definition: setjmp_test.c:47
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
jmp_buf env
Jump buffer.
Definition: setjmp_test.c:43
static int test
Definition: epic100.c:73