switched format of catches to pass in a variable to fill, more like C++.

git-svn-id: http://cexception.svn.sourceforge.net/svnroot/cexception/trunk@5 50f63946-2846-0410-8d77-f904c773002e
This commit is contained in:
mvandervoord
2008-12-19 17:17:53 +00:00
parent ecc3e29299
commit 959e43da62
6 changed files with 268 additions and 178 deletions
+78 -84
View File
@@ -12,6 +12,29 @@ this library should be useable with very little configuration. It
even supports environments where multiple program flows are in use,
such as real-time operating systems.
There are about a gabillion exception frameworks using a similar
setjmp/longjmp method out there... and there will probably be more
in the future. Unfortunately, when we started our last embedded
project, all those that existed either (a) did not support multiple
tasks (therefore multiple stacks) or (b) were way more complex than
we really wanted. CException was born.
Why use CException?
0. It's ANSI C, and it beats passing error codes around.
1. You want something simple... CException throws a single id. You can
define those ID's to be whatever you like. You might even choose which
type that number is for your project. But that's as far as it goes.
We weren't interested in passing objects or structs or strings...
just simple error codes.
2. Performance... CException can be configured for single tasking or
multitasking. In single tasking, there is very little overhead past
the setjmp/longjmp calls (which are already fast). In multitasking,
your only additional overhead is the time it takes you to determine
a unique task id 0 - num_tasks.
For the latest version, go to http://cexception.sourceforge.net
--------------------------------------------------------------------
@@ -35,22 +58,19 @@ if any Throws occur, program control is directly transferred to the
start of the Catch block.
A numerical exception ID is included with Throw, and is made accessible
from the Catch block. In addition, an optional details field can be
included, allowing a pointer or additional numerical information to be
added.
from the Catch block.
Throws can occur from within function calls or directly within the
function itself.
Throws can occur from within function calls (nested as deeply as you
like) or directly from within the function itself.
--------------------------------------------------------------------
Limitations
--------------------------------------------------------------------
This library was made to be as fast as possible, and provide *basic*
exception handling. It is not a full-blown exception library as
provided by many other operating systems. Because of this, there are
a number of limitations that should be observed in order to
successfully utilize this library:
This library was made to be as fast as possible, and provide basic
exception handling. It is not a full-blown exception library. Because
of this, there are a few limitations that should be observed in order
to successfully utilize this library:
1. Do not directly "return" from within a Try block, nor "goto"
into or out of a Try block.
@@ -62,11 +82,11 @@ successfully utilize this library:
Gotos and returns would bypass some of these steps, resulting in
memory leaks or unpredictable behavior.
2. If you change stack variables within your Try block (local variables
for example), and wish to make use of the updated values after an
exception is thrown, those variables should be made volatile. Note
that this is ONLY for locals and ONLY when you need access to them
after a throw.
2. If (a) you change local (stack) variables within your Try block,
AND (b) wish to make use of the updated values after an exception
is thrown, those variables should be made volatile. Note that this
is ONLY for locals and ONLY when you need access to them after a
throw.
Why?
@@ -74,17 +94,7 @@ successfully utilize this library:
memory location was updated and not just a register unless the
variable is marked volatile.
3. While EXCEPTION_ID and EXCEPTION_DETAIL are available outside a
Catch, it is good practice to ONLY access them from within the
Catch block.
Why?
EXCEPTION_ID is altered whenever a new Try block is encountered.
Both are obviously altered on Throws. It's best to isolate calls
to these to places where your state is well known.
4. Memory which is malloc'd or new'd is not automatically released
3. Memory which is malloc'd or new'd is not automatically released
when an error is thrown. This will sometimes be desirable, and
othertimes may not. It will be the responsibility of the Catch
block to perform this kind of cleanup.
@@ -95,74 +105,44 @@ successfully utilize this library:
replacing or wrapping malloc calls or something like that. This
is a light framework, so these options were not desirable.
5. If additional Try blocks are started from within a Catch (either
in the immediate function or from within a function called from
the Catch block), it will alter the EXCEPTION_ID. It is therefore
good practice to NOT call such functions from a Catch block.
Why?
See #3 above.
--------------------------------------------------------------------
API
--------------------------------------------------------------------
void Exception_Init(void);
Try
---
Try is a macro which starts a protected block. It MUST be followed by
a pair of braces, enclosing the data that is to be protected. It MUST
be followed by a Catch block.
a pair of braces or a single protected line (similar to an 'if'),
enclosing the data that is to be protected. It MUST be followed by a
Catch block (don't worry, you'll get compiler errors to let you know if
you mess any of that up).
Catch
-----
Catch(e)
--------
Catch is a macro which ends the Try block and starts the error handling
block. The catch block is called if and only if an exception was thrown
while within the Try block. This error could have been thrown by a
call to Throw or ThrowDetailed.
while within the Try block. This error was thrown by a Throw call
somewhere within Try (or within a function called within Try, or a function
called by a function called within Try, etc).
EXCEPTION_ID
------------
The single parameter 'e' is filled with the error code which was thrown.
This can be used for reporting, conditional cleanup, etc. (or you can just
ignore it if you really want... people ignore return codes all the time,
right?). 'e' should be of type EXCEPTION_T;
EXCEPTION_ID is a macro which returns the ID of the exception which was
passed to Throw or ThrowDetailed.
EXCEPTION_DETAILS
----------------
EXCEPTION_DETAILS is a macro which returns the detail int of the exception.
If Throw was called, it will contain the line number of the Throw. If
ThrowDetailed was called, it will contain whatever detail information was
provided.
Throw
-----
Throw(e)
--------
The method of throwing an error. Throws should only occur from within a
protected (Try...Catch) block, though it may easily be nested many function
calls deep without an impact on performance or functionality. Try takes
a single argument, which is an exception id to be used in Catch as the
reason for the error.
calls deep without an impact on performance or functionality. Throw takes
a single argument, which is an exception id which will be passed to Catch
as the reason for the error.
ThrowDetailed
-------------
Operates identically to Throw, with the added ability to send additional
details. This detail is a single int, which can represent whatever the
developer desires. This has been used as a pointer to an error message,
pointer to data which must be freed, an instance id of a problem, etc.
Rethrow
-------
Rethrow can be used in a Catch block and allows the current error to be
pushed back an additional level of protected blocks. Because protected
blocks can be nested, it is sometimes useful to handle some errors in
inner blocks while throwing the rest to outside blocks. This function
does that, allowing the error to be passed on unchanged.
If you wish to Rethrow an error, this can be done by calling Throw(e) with
the error code you just caught. It IS valid to throw from a catch block.
--------------------------------------------------------------------
CONFIGURATION
@@ -172,7 +152,8 @@ CException is a mostly portable library. It has one universal
dependency, and some macros which are required if working in a
multi-tasking environment.
1. The standard C library setjmp must be available
1. The standard C library setjmp must be available. Since this is part
of the standard library, chances are good that you'll be fine.
2. If working in a multitasking environment, methods for obtaining an
index into an array of frames and to get the overall number of
@@ -180,22 +161,31 @@ multi-tasking environment.
ID's, and those Tasks are number 0, 1, 2... you are in an ideal
situation. Otherwise, a more creative mapping function may be
required. Note that this function is likely to be called twice
for each protected block. This is the only overhead in the system.
for each protected block and once during a throw. This is the
only overhead in the system.
Exception.h
-----------------
By convention, most projects include Exception.h which defines any
further requirements, then calls CException.h to do the gruntwork.
further requirements, then calls CException.h to do the gruntwork. All
of these are optional. You could directly include CException.h if
you wanted and just use the defaults provided.
EXCEPTION_NONE - set to a number which will never be an exception id in
your system.
EXCEPTION_T - Set this to the type you want your exception id's
to be. Defaults to 'unsigned int'.
EXCEPTION_NONE - Set this to a number which will never be an
exception id in your system. Defaults to 0x5a5a5a5a.
EXCEPTION_GET_ID - If in a multi-tasking environment, this should be
set to be a call to the function described in #2 above.
Defaults to just return 0 all the time (good for
single tasking environments)
EXCEPTION_NUM_ID - If in a multi-tasking environment, this should be set
to the number of ID's required (usually the number of
tasks in the system)
tasks in the system). Defaults to 1 (for single
tasking environments).
You may also want to include any header files which will commonly be
needed by the rest of your application where it uses exception handling
@@ -205,9 +195,13 @@ here. For example, OS header files or exception codes would be useful.
TESTING
--------------------------------------------------------------------
If you want to validate that CException works with your tools or that
it works with your custom configuration, you may want to run the test
suite.
The test suite included makes use of the Unity Test Framework. It will
require a native C compiler, the example makefile using MinGW's gcc.
Modify the makefile to include the proper paths to tools, then run make
require a native C compiler. The example makefile uses MinGW's gcc.
Modify the makefile to include the proper paths to tools, then run 'make'
to compile and run the test application.
C_COMPILER - The C compiler to use to perform the tests
+28 -19
View File
@@ -3,36 +3,45 @@
volatile EXCEPTION_FRAME_T ExceptionFrames[EXCEPTION_NUM_ID];
//------------------------------------------------------------------------------------------
// ThrowDetailed
// Throw
//------------------------------------------------------------------------------------------
//
// PARAMETERS: None
//
// DESCRIPTION: throws a software exception with details
// DESCRIPTION: throws a software exception
//
// RETURNS: None
//
//------------------------------------------------------------------------------------------
void ThrowDetailed(unsigned int ExceptionID, unsigned int Details)
void Throw(EXCEPTION_T ExceptionID)
{
MY_FRAME.Exception = ExceptionID;
MY_FRAME.Details = Details;
longjmp(*MY_FRAME.pFrame, 1);
unsigned int MY_ID = EXCEPTION_GET_ID;
ExceptionFrames[MY_ID].Exception = ExceptionID;
longjmp(*ExceptionFrames[MY_ID].pFrame, 1);
}
//------------------------------------------------------------------------------------------
// Rethrow
// Explaination of what it's all for:
//------------------------------------------------------------------------------------------
//
// PARAMETERS: None
//
// DESCRIPTION: rethrows a software exception that has already been thrown
//
// RETURNS: None
//
//------------------------------------------------------------------------------------------
void Rethrow()
{
longjmp(*MY_FRAME.pFrame, 1);
}
/*
#define Try
{ <- give us some local scope. most compilers are happy with this
jmp_buf *PrevFrame, NewFrame; <- prev frame points to the last try block's frame. new frame gets created on stack for this Try block
unsigned int MY_ID = EXCEPTION_GET_ID; <- look up this task's id for use in frame array. always 0 if single-tasking
PrevFrame = ExceptionFrames[EXCEPTION_GET_ID].pFrame; <- set pointer to point at old frame (which array is currently pointing at)
ExceptionFrames[MY_ID].pFrame = &NewFrame; <- set array to point at my new frame instead, now
ExceptionFrames[MY_ID].Exception = EXCEPTION_NONE; <- initialize my exception id to be NONE
if (setjmp(NewFrame) == 0) { <- do setjmp. it returns 1 if longjump called, otherwise 0
if (&PrevFrame) <- this is here to force proper scoping. it requires braces or a single line to be but after Try, otherwise won't compile. This is always true at this point.
#define Catch(e)
else { } <- this also forces proper scoping. Without this they could stick their own 'else' in and it would get ugly
ExceptionFrames[MY_ID].Exception = EXCEPTION_NONE; <- no errors happened, so just set the exception id to NONE (in case it was corrupted)
}
else <- an exception occurred
{ e = ExceptionFrames[MY_ID].Exception; e=e;} <- assign the caught exception id to the variable passed in.
ExceptionFrames[MY_ID].pFrame = PrevFrame; <- make the pointer in the array point at the previous frame again, as if NewFrame never existed.
} <- finish off that local scope we created to have our own variables
if (ExceptionFrames[EXCEPTION_GET_ID].Exception != EXCEPTION_NONE) <- start the actual 'catch' processing if we have an exception id saved away
*/
+21 -19
View File
@@ -15,40 +15,42 @@
#define EXCEPTION_GET_ID (0) //use the first index always because there is only one anyway
#endif
#ifndef EXCEPTION_T
#define EXCEPTION_T unsigned int
#endif
//exception frame structures
typedef struct {
jmp_buf* pFrame;
volatile unsigned int Exception;
volatile unsigned int Details;
volatile EXCEPTION_T Exception;
} EXCEPTION_FRAME_T;
//actual root frame storage (only one if single-tasking)
extern volatile EXCEPTION_FRAME_T ExceptionFrames[];
#define MY_FRAME (ExceptionFrames[EXCEPTION_GET_ID])
#define MY_FRAME_FAST (ExceptionFrames[MY_ID])
#define EXCEPTION_ID (MY_FRAME.Exception)
#define EXCEPTION_DETAILS (MY_FRAME.Details)
//Try (see C file for explanation)
#define Try \
{ \
jmp_buf *PrevFrame, NewFrame; \
unsigned int MY_ID = EXCEPTION_GET_ID; \
PrevFrame = MY_FRAME.pFrame; \
MY_FRAME_FAST.pFrame = &NewFrame; \
MY_FRAME_FAST.Details = 0; \
MY_FRAME_FAST.Exception = EXCEPTION_NONE; \
PrevFrame = ExceptionFrames[EXCEPTION_GET_ID].pFrame; \
ExceptionFrames[MY_ID].pFrame = &NewFrame; \
ExceptionFrames[MY_ID].Exception = EXCEPTION_NONE; \
if (setjmp(NewFrame) == 0) { \
if (&PrevFrame)
if (&PrevFrame)
#define Catch \
//Catch (see C file for explanation)
#define Catch(e) \
else { } \
MY_FRAME_FAST.Exception = EXCEPTION_NONE; \
ExceptionFrames[MY_ID].Exception = EXCEPTION_NONE; \
} \
MY_FRAME_FAST.pFrame = PrevFrame; \
else \
{ e = ExceptionFrames[MY_ID].Exception; e=e; } \
ExceptionFrames[MY_ID].pFrame = PrevFrame; \
} \
if (MY_FRAME.Exception != EXCEPTION_NONE)
if (ExceptionFrames[EXCEPTION_GET_ID].Exception != EXCEPTION_NONE)
#define Throw(id) ThrowDetailed(id, __LINE__)
void ThrowDetailed(unsigned int ExceptionID, unsigned int Details);
void Rethrow(void);
//Throw an Error
void Throw(EXCEPTION_T ExceptionID);
#endif // _CEXCEPTION_H
+10 -3
View File
@@ -1,8 +1,11 @@
#ifndef _EXCEPTION_H
#define _EXCEPTION_H
// Define the reserved value representing NO EXCEPTION
#define EXCEPTION_NONE (0x5A5A5A5A)
//Optionally define the exception type (something like an int which can be directly assigned)
#define EXCEPTION_T int
// Optionally define the reserved value representing NO EXCEPTION
#define EXCEPTION_NONE (1234)
// Multi-Tasking environments will need a couple of macros defined to make this library
// properly handle multiple exception stacks. You will need to include and required
@@ -13,11 +16,15 @@
// For example, Quadros might include the following implementation:
#ifndef TEST
#include "OSAPI.h"
#define EXCEPTION_GET_ID() (KS_GetTaskID())
#define EXCEPTION_GET_ID (KS_GetTaskID())
#define EXCEPTION_NUM_ID (NTASKS + 1)
#endif
// INCLUDE THE ACTUAL CEXCEPTION LIBRARY
#include "CException.h"
//This could be a good place to define/include some error ID's:
#define ERROR_ID_EVERYTHING_IS_BROKEN (0x88)
#define ERROR_ID_ONLY_THIS_IS_BROKEN (0x77)
#endif // _EXCEPTION_H
+123 -50
View File
@@ -12,36 +12,64 @@ void tearDown(void)
void test_BasicTryDoesNothingIfNoThrow(void)
{
int i;
EXCEPTION_T e = 0x5a5a;
Try
{
i += 1;
}
Catch
Catch(e)
{
TEST_FAIL("Should Not Enter Catch If Not Thrown")
}
//verify that e was untouched
TEST_ASSERT_EQUAL(0x5a5a, e);
}
void test_BasicThrowAndCatch(void)
{
volatile unsigned int ID = 0;
EXCEPTION_T e;
Try
{
Throw(0xBEEFBEEF);
TEST_FAIL("Should Have Thrown An Error")
}
Catch
Catch(e)
{
ID = EXCEPTION_ID;
//verify that e has the right data
TEST_ASSERT_EQUAL(0xBEEFBEEF, e)
}
TEST_ASSERT_EQUAL(0xBEEFBEEF, ID);
//verify that e STILL has the right data
TEST_ASSERT_EQUAL(0xBEEFBEEF, e);
}
void test_BasicThrowAndCatch_WithMiniSyntax(void)
{
EXCEPTION_T e;
//Mini Throw and Catch
Try
Throw(0xBEEFBEEF);
Catch(e)
TEST_ASSERT_EQUAL(0xBEEFBEEF, e);
TEST_ASSERT_EQUAL(0xBEEFBEEF, e);
//Mini Passthrough
Try
e = 0;
Catch(e)
TEST_FAIL("I shouldn't be caught because there was no throw");
TEST_ASSERT_EQUAL(0, e);
}
void test_VerifyVolatilesSurviveThrowAndCatch(void)
{
volatile unsigned int VolVal = 0;
EXCEPTION_T e;
Try
{
@@ -49,24 +77,28 @@ void test_VerifyVolatilesSurviveThrowAndCatch(void)
Throw(0xBEEFBEEF);
TEST_FAIL("Should Have Thrown An Error")
}
Catch
Catch(e)
{
VolVal += 2;
TEST_ASSERT_EQUAL(0xBEEFBEEF, EXCEPTION_ID);
TEST_ASSERT_EQUAL(0xBEEFBEEF, e);
}
TEST_ASSERT_EQUAL(4, VolVal);
TEST_ASSERT_EQUAL(0xBEEFBEEF, e);
}
void HappyExceptionThrower(unsigned int ID)
{
if (ID != 0)
Throw(ID);
{
Throw(ID);
}
}
void test_ThrowFromASubFunctionAndCatchInRootFunc(void)
{
volatile unsigned int ID = 0;
EXCEPTION_T e;
Try
{
@@ -74,26 +106,29 @@ void test_ThrowFromASubFunctionAndCatchInRootFunc(void)
HappyExceptionThrower(0xBADDF00D);
TEST_FAIL("Should Have Thrown An Exception");
}
Catch
Catch(e)
{
ID = EXCEPTION_ID;
ID = e;
}
TEST_ASSERT_EQUAL(0xBADDF00D, ID);
//verify that I can pass that value to something else
TEST_ASSERT_EQUAL(0xBADDF00D, e);
}
void HappyExceptionRethrower(unsigned int ID)
{
EXCEPTION_T e;
Try
{
Throw(ID);
}
Catch
Catch(e)
{
switch (EXCEPTION_ID)
switch (e)
{
case 0xBADDF00D:
Rethrow();
Throw(0xBADDBEEF);
break;
default:
break;
@@ -104,41 +139,96 @@ void HappyExceptionRethrower(unsigned int ID)
void test_ThrowAndCatchFromASubFunctionAndRethrowToCatchInRootFunc(void)
{
volatile unsigned int ID = 0;
EXCEPTION_T e;
Try
{
HappyExceptionRethrower(0xBADDF00D);
TEST_FAIL("Should Have Rethrown Exception");
}
Catch
Catch(e)
{
ID = EXCEPTION_ID;
ID = 1;
}
TEST_ASSERT_EQUAL(0xBADDF00D, ID);
TEST_ASSERT_EQUAL(0xBADDBEEF, e);
TEST_ASSERT_EQUAL(1, ID);
}
void test_ThrowAndCatchFromASubFunctionAndNoRethrowToCatchInRootFunc(void)
{
EXCEPTION_T e = 3;
Try
{
HappyExceptionRethrower(0xBADDBEEF);
}
Catch
Catch(e)
{
TEST_FAIL("Should Not Have Thrown Error");
TEST_FAIL("Should Not Have Re-thrown Error (it should have already been caught)");
}
//verify that THIS e is still untouched, even though subfunction was touched
TEST_ASSERT_EQUAL(3, e);
}
void test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThisDoesntCorruptExceptionId(void)
{
EXCEPTION_T e;
Try
{
HappyExceptionThrower(0xBADDBEEF);
TEST_FAIL("Should Have Thrown Exception");
}
Catch(e)
{
TEST_ASSERT_EQUAL(0xBADDBEEF, e);
HappyExceptionRethrower(0x12345678);
TEST_ASSERT_EQUAL(0xBADDBEEF, e);
}
TEST_ASSERT_EQUAL(0xBADDBEEF, e);
}
void test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThatEachExceptionIdIndependent(void)
{
EXCEPTION_T e1, e2;
Try
{
HappyExceptionThrower(0xBADDBEEF);
TEST_FAIL("Should Have Thrown Exception");
}
Catch(e1)
{
TEST_ASSERT_EQUAL(0xBADDBEEF, e1);
Try
{
HappyExceptionThrower(0x12345678);
}
Catch(e2)
{
TEST_ASSERT_EQUAL(0x12345678, e2);
}
TEST_ASSERT_EQUAL(0x12345678, e2);
TEST_ASSERT_EQUAL(0xBADDBEEF, e1);
}
TEST_ASSERT_EQUAL(0x12345678, e2);
TEST_ASSERT_EQUAL(0xBADDBEEF, e1);
}
void test_CanHaveMultipleTryBlocksInASingleFunction(void)
{
EXCEPTION_T e;
Try
{
HappyExceptionThrower(0x01234567);
TEST_FAIL("Should Have Thrown Exception");
}
Catch
Catch(e)
{
TEST_ASSERT_EQUAL(0x01234567, EXCEPTION_ID);
TEST_ASSERT_EQUAL(0x01234567, e);
}
Try
@@ -146,15 +236,17 @@ void test_CanHaveMultipleTryBlocksInASingleFunction(void)
HappyExceptionThrower(0xF00D8888);
TEST_FAIL("Should Have Thrown Exception");
}
Catch
Catch(e)
{
TEST_ASSERT_EQUAL(0xF00D8888, EXCEPTION_ID);
TEST_ASSERT_EQUAL(0xF00D8888, e);
}
}
void test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside(void)
{
int i = 0;
EXCEPTION_T e;
Try
{
Try
@@ -163,12 +255,12 @@ void test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside(void)
i = 1;
TEST_FAIL("Should Have Rethrown Exception");
}
Catch
Catch(e)
{
TEST_ASSERT_EQUAL(0x01234567, EXCEPTION_ID);
TEST_ASSERT_EQUAL(0x01234567, e);
}
}
Catch
Catch(e)
{
TEST_FAIL("Should Have Been Caught By Inside Catch");
}
@@ -177,42 +269,23 @@ void test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside(void)
void test_CanHaveNestedTryBlocksInASingleFunction_ThrowOutside(void)
{
int i = 0;
EXCEPTION_T e;
Try
{
Try
{
i = 2;
}
Catch
Catch(e)
{
TEST_FAIL("Should NotBe Caught Here");
}
HappyExceptionThrower(0x01234567);
TEST_FAIL("Should Have Rethrown Exception");
}
Catch
Catch(e)
{
TEST_ASSERT_EQUAL(0x01234567, EXCEPTION_ID);
TEST_ASSERT_EQUAL(0x01234567, e);
}
}
void HappyDetailedExceptionThrower(unsigned int ID, unsigned int Details)
{
if (ID != 0)
ThrowDetailed(ID, Details);
}
void test_CanThrowADetailedExceptionAndCheckOutTheResults(void)
{
Try
{
HappyDetailedExceptionThrower(0x12345678, 0x90ABCDEF);
TEST_FAIL("Should Have Thrown An Exception");
}
Catch
{
TEST_ASSERT_EQUAL(0x12345678, EXCEPTION_ID);
TEST_ASSERT_EQUAL(0x90ABCDEF, EXCEPTION_DETAILS);
}
}
+8 -3
View File
@@ -7,6 +7,7 @@ extern void tearDown(void);
extern void test_BasicTryDoesNothingIfNoThrow(void);
extern void test_BasicThrowAndCatch(void);
extern void test_BasicThrowAndCatch_WithMiniSyntax(void);
extern void test_VerifyVolatilesSurviveThrowAndCatch(void);
extern void test_ThrowFromASubFunctionAndCatchInRootFunc(void);
extern void test_ThrowAndCatchFromASubFunctionAndRethrowToCatchInRootFunc(void);
@@ -14,10 +15,12 @@ extern void test_ThrowAndCatchFromASubFunctionAndNoRethrowToCatchInRootFunc(void
extern void test_CanHaveMultipleTryBlocksInASingleFunction(void);
extern void test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside(void);
extern void test_CanHaveNestedTryBlocksInASingleFunction_ThrowOutside(void);
extern void test_CanThrowADetailedExceptionAndCheckOutTheResults(void);
extern void test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThisDoesntCorruptExceptionId(void);
extern void test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThatEachExceptionIdIndependent(void);
static void runTest(UnityTestFunction test)
{
EXCEPTION_T e;
if (TEST_PROTECT())
{
setUp();
@@ -25,7 +28,7 @@ static void runTest(UnityTestFunction test)
{
test();
}
Catch
Catch(e)
{
TEST_FAIL("Unexpected exception!")
}
@@ -42,6 +45,7 @@ int main(void)
// RUN_TEST calls runTest
RUN_TEST(test_BasicTryDoesNothingIfNoThrow);
RUN_TEST(test_BasicThrowAndCatch);
RUN_TEST(test_BasicThrowAndCatch_WithMiniSyntax);
RUN_TEST(test_VerifyVolatilesSurviveThrowAndCatch);
RUN_TEST(test_ThrowFromASubFunctionAndCatchInRootFunc);
RUN_TEST(test_ThrowAndCatchFromASubFunctionAndRethrowToCatchInRootFunc);
@@ -49,7 +53,8 @@ int main(void)
RUN_TEST(test_CanHaveMultipleTryBlocksInASingleFunction);
RUN_TEST(test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside);
RUN_TEST(test_CanHaveNestedTryBlocksInASingleFunction_ThrowOutside);
RUN_TEST(test_CanThrowADetailedExceptionAndCheckOutTheResults);
RUN_TEST(test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThisDoesntCorruptExceptionId);
RUN_TEST(test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThatEachExceptionIdIndependent);
UnityEnd();