mirror of https://github.com/yasm/yasm.git
parent
e649bada33
commit
cd3528249d
16 changed files with 1754 additions and 0 deletions
@ -0,0 +1,77 @@ |
||||
Thu Aug 23, 2001: |
||||
Released Check 0.7.3 |
||||
|
||||
Fixed the Autoconf Lyx check in acinclude.m4 so that configure works |
||||
on Solaris systems (and hopefully others), and cleaned up a minor |
||||
problem in Debian packaging. |
||||
|
||||
Fri Aug 17, 2001: |
||||
Released Check 0.7.2 |
||||
|
||||
Automated RPM packaging, and included debian packaging. The makefiles |
||||
now has an rpm target (the RPMFLAGS variable can be set to add |
||||
additional flags to RPM). Debian packages are built the ordinary way |
||||
(dpkg-buildpackage). |
||||
|
||||
Moved the example*.* files to tutorial*.*, since the docs really are |
||||
tutorials. Beefed up the tutorial docs to add clarity to the behavior |
||||
of fixture setup/teardown (based on a helpful critique by Fred Drake), |
||||
and to document the static nature of unit tests demanded by the bug |
||||
fix below. |
||||
|
||||
Many bugfixes: added -Wall to the CCFLAGS for gcc, and fixed a mess of |
||||
warnings that resulted. Changed a bizarre naming mismatch in |
||||
tcase_set_fixture (masked by the lack of compile warnings), and made |
||||
unit tests static (both bugfixes suggested by Fred Drake). Also added |
||||
a more sophisticated test of Lyx to (hopefully) ensure that Lyx |
||||
supports linuxdoc (but it's not clear to me how to test that for |
||||
sure). |
||||
|
||||
|
||||
Wed Jul 30, 2001: |
||||
Released Check 0.7.1 |
||||
|
||||
Reorganized printing and logging functions to allow for a less |
||||
primitive logging function. Logging is now documented in the tutorial |
||||
documentation. |
||||
|
||||
Wed Jul 11, 2001: |
||||
Released Check 0.7.0 |
||||
|
||||
Included a primitive logging function (at the moment, it only prints a |
||||
copy of the CRVERBOSE output to the log file), added the ability for |
||||
an SRunner to run multiple suites (and reorganized the Check tests to |
||||
take advantage of that), and added the magic to allow Check to be used |
||||
with C++. |
||||
|
||||
Also added Doxygen markup to the header file, but I'm not terribly |
||||
satisfied withe clarity of the output. I may switch to CWEB... Next |
||||
release should include API docs and improved logging, if nothing else |
||||
comes up... |
||||
|
||||
|
||||
Wed Jun 27, 2001: |
||||
|
||||
Released Check 0.6.1 |
||||
|
||||
Bug fix for srunner_failures (bad version actually returned all |
||||
results), added srunner_results to do what srunner_failures used to |
||||
do, and added corrected unit tests for both. |
||||
|
||||
Also changed the API for reporting the number of failed tests from |
||||
srunner_nfailed to srunner_ntests_failed, to harmonized better with |
||||
new function srunner_ntests_run. This unfortunately may break some |
||||
unit tests slightly -- that's why the major release number is 0 :-) |
||||
|
||||
Thu Jun 21, 2001: |
||||
Released Check 0.6.0 |
||||
|
||||
Features improved unit test reporting options, more complete unit |
||||
tests, and end-to-end test, and a full API into TestResults |
||||
|
||||
Check 0.5.2 |
||||
Minor edits |
||||
Check 0.5.1 |
||||
GPL compliance release |
||||
Check 0.5.0 |
||||
Initial public release |
@ -0,0 +1,9 @@ |
||||
Check is a unit test framework for C. It features a simple interface |
||||
for defining unit tests, putting little in the way of the |
||||
developer. Tests are run in a separate address space, so Check can |
||||
catch both assertion failures and code errors that cause segmentation |
||||
faults or other signals. The output from unit tests can be used within |
||||
source code editors and IDEs. |
||||
|
||||
See http://check.sourceforge.net for more information, including a |
||||
tutorial. |
@ -0,0 +1,123 @@ |
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include "error.h" |
||||
#include "list.h" |
||||
#include "check.h" |
||||
#include "check_impl.h" |
||||
#include "check_msg.h" |
||||
|
||||
|
||||
Suite *suite_create (char *name) |
||||
{ |
||||
Suite *s; |
||||
s = emalloc (sizeof(Suite)); /* freed in suite_free */ |
||||
if (name == NULL) |
||||
s->name = ""; |
||||
else |
||||
s->name = name; |
||||
s->tclst = list_create(); |
||||
return s; |
||||
} |
||||
|
||||
void suite_free (Suite *s) |
||||
{ |
||||
List *l; |
||||
if (s == NULL) |
||||
return; |
||||
for (l = s->tclst; !list_at_end(l); list_advance (l)) { |
||||
tcase_free (list_val(l)); |
||||
} |
||||
list_free (s->tclst); |
||||
free(s); |
||||
} |
||||
|
||||
TCase *tcase_create (char *name) |
||||
{ |
||||
TCase *tc = emalloc (sizeof(TCase)); /*freed in tcase_free */ |
||||
if (name == NULL) |
||||
tc->name = ""; |
||||
else |
||||
tc->name = name; |
||||
tc->tflst = list_create(); |
||||
tc->setup = tc->teardown = NULL; |
||||
|
||||
return tc; |
||||
} |
||||
|
||||
|
||||
void tcase_free (TCase *tc) |
||||
{ |
||||
List *l; |
||||
l = tc->tflst; |
||||
for (list_front(l); !list_at_end(l); list_advance(l)) { |
||||
free (list_val(l)); |
||||
} |
||||
list_free(tc->tflst); |
||||
free(tc); |
||||
} |
||||
|
||||
void suite_add_tcase (Suite *s, TCase *tc) |
||||
{ |
||||
if (s == NULL || tc == NULL) |
||||
return; |
||||
list_add_end (s->tclst, tc); |
||||
} |
||||
|
||||
void _tcase_add_test (TCase *tc, TFun fn, char *name) |
||||
{ |
||||
TF * tf; |
||||
if (tc == NULL || fn == NULL || name == NULL) |
||||
return; |
||||
tf = emalloc (sizeof(TF)); /* freed in tcase_free */ |
||||
tf->fn = fn; |
||||
tf->name = name; |
||||
list_add_end (tc->tflst, tf); |
||||
} |
||||
|
||||
void tcase_set_fixture (TCase *tc, SFun setup, SFun teardown) |
||||
{ |
||||
tc->setup = setup; |
||||
tc->teardown = teardown; |
||||
} |
||||
|
||||
|
||||
void tcase_fn_start (int msqid, char *fname, char *file, int line) |
||||
{ |
||||
send_last_loc_msg (msqid, file, line); |
||||
} |
||||
|
||||
void _mark_point (int msqid, char *file, int line) |
||||
{ |
||||
send_last_loc_msg (msqid, file, line); |
||||
} |
||||
|
||||
void _fail_unless (int msqid, int result, char *file, int line, char * msg) |
||||
{ |
||||
if (line > MAXLINE) |
||||
eprintf ("Line number %d too large to use", line); |
||||
|
||||
send_last_loc_msg (msqid, file, line); |
||||
if (!result) { |
||||
send_failure_msg (msqid, msg); |
||||
exit(1); |
||||
} |
||||
} |
@ -0,0 +1,295 @@ |
||||
#ifndef CHECK_H |
||||
#define CHECK_H |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
/* Comments are in Doxygen format: see http://www.stack.nl/~dimitri/doxygen/ */ |
||||
|
||||
/*! \mainpage Check: a unit test framework for C
|
||||
|
||||
\section overview |
||||
|
||||
Overview Check is a unit test framework for C. It features a simple |
||||
interface for defining unit tests, putting little in the way of the |
||||
developer. Tests are run in a separate address space, so Check can |
||||
catch both assertion failures and code errors that cause segmentation |
||||
faults or other signals. The output from unit tests can be used within |
||||
source code editors and IDEs. |
||||
|
||||
\section quickref Quick Reference |
||||
|
||||
\subsection creating Creating |
||||
|
||||
\par |
||||
|
||||
Unit tests are created with the #START_TEST/#END_TEST macro pair. The |
||||
#fail_unless and #fail macros are used for creating checks within unit |
||||
tests; the #mark_point macro is useful for trapping the location of |
||||
signals and/or early exits. |
||||
|
||||
\subsection managing Managing test cases and suites |
||||
|
||||
\par |
||||
|
||||
Test cases are created with #tcase_create, unit tests are added |
||||
with #tcase_add_test |
||||
|
||||
\par |
||||
|
||||
Suites are created with #suite_create, freed with #suite_free; test |
||||
cases are added with #suite_add_tcase |
||||
|
||||
\subsection running Running suites |
||||
|
||||
\par |
||||
|
||||
Suites are run through an SRunner, which is created with |
||||
#srunner_create, freed with #srunner_free. Additional suites can be |
||||
added to an SRunner with #srunner_add_suite. |
||||
|
||||
\par |
||||
|
||||
Use #srunner_run_all to run a suite and print results. |
||||
|
||||
*/ |
||||
|
||||
/*! \file check.h */ |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" {
|
||||
#endif |
||||
|
||||
/*! Magic values */ |
||||
enum { |
||||
CMAXMSG = 100 /*!< maximum length of a message, including terminating nul */ |
||||
}; |
||||
|
||||
/*! \defgroup check_core Check Core
|
||||
Core suite/test case types and functions |
||||
@{ |
||||
*/ |
||||
|
||||
/*! \brief opaque type for a test suite */ |
||||
typedef struct Suite Suite; |
||||
|
||||
/*! \brief opaque type for a test case
|
||||
|
||||
A TCase represents a test case. Create with #tcase_create, free with |
||||
#tcase_free. For the moment, test cases can only be run through a |
||||
suite |
||||
*/ |
||||
|
||||
typedef struct TCase TCase;
|
||||
|
||||
/*! type for a test function */ |
||||
typedef void (*TFun) (int); |
||||
|
||||
/*! type for a setup/teardown function */ |
||||
typedef void (*SFun) (void); |
||||
|
||||
/*! Create a test suite */ |
||||
Suite *suite_create (char *name); |
||||
|
||||
/*! Free a test suite
|
||||
(For the moment, this also frees all contained test cases) */ |
||||
void suite_free (Suite *s); |
||||
|
||||
/*! Create a test case */ |
||||
TCase *tcase_create (char *name); |
||||
|
||||
/*! Free a test case
|
||||
(Note that as it stands, one will normally free the contaning suite) */ |
||||
void tcase_free (TCase *tc); |
||||
|
||||
/*! Add a test case to a suite */ |
||||
void suite_add_tcase (Suite *s, TCase *tc); |
||||
|
||||
/*! Add a test function to a test case
|
||||
(macro version) */ |
||||
#define tcase_add_test(tc,tf) _tcase_add_test(tc,tf,"" # tf "") |
||||
/*! Add a test function to a test case
|
||||
(function version -- use this when the macro won't work */ |
||||
void _tcase_add_test (TCase *tc, TFun tf, char *fname); |
||||
|
||||
/*!
|
||||
|
||||
Add fixture setup/teardown functions to a test case Note that |
||||
setup/teardown functions are not run in a separate address space, like |
||||
test functions, and so must not exit or signal (e.g., segfault) |
||||
|
||||
*/ |
||||
void tcase_set_fixture(TCase *tc, SFun setup, SFun teardown); |
||||
|
||||
/*! Internal function to mark the start of a test function */ |
||||
void tcase_fn_start (int msqid, char *fname, char *file, int line); |
||||
|
||||
/*! Start a unit test with START_TEST(unit_name), end with END_TEST
|
||||
One must use braces within a START_/END_ pair to declare new variables */ |
||||
#define START_TEST(__testname)\ |
||||
static void __testname (int __msqid)\
|
||||
{\
|
||||
tcase_fn_start (__msqid,""# __testname, __FILE__, __LINE__); |
||||
|
||||
/*! End a unit test */ |
||||
#define END_TEST } |
||||
|
||||
|
||||
/*! Fail the test case unless result is true */ |
||||
#define fail_unless(result,msg) _fail_unless(__msqid,result,__FILE__,__LINE__,msg) |
||||
|
||||
/*! Non macro version of #fail_unless, with more complicated interface */ |
||||
void _fail_unless (int msqid, int result, char *file, int line, char *msg); |
||||
|
||||
/*! Always fail */ |
||||
#define fail(msg) _fail_unless(__msqid,0,__FILE__,__LINE__,msg) |
||||
|
||||
/*! Mark the last point reached in a unit test
|
||||
(useful for tracking down where a segfault, etc. occurs */ |
||||
#define mark_point() _mark_point(__msqid,__FILE__,__LINE__) |
||||
/*! Non macro version of #mark_point */ |
||||
void _mark_point (int msqid, char *file, int line); |
||||
|
||||
/*! @} */ |
||||
|
||||
/*! \defgroup check_run Suite running functions
|
||||
@{ |
||||
*/ |
||||
|
||||
|
||||
/*! Result of a test */ |
||||
enum test_result { |
||||
CRPASS, /*!< Test passed*/ |
||||
CRFAILURE, /*!< Test completed but failed */ |
||||
CRERROR /*!< Test failed to complete (signal or non-zero early exit) */ |
||||
}; |
||||
|
||||
/*! Specifies the verbosity of srunner printing */ |
||||
enum print_verbosity { |
||||
CRSILENT, /*!< No output */ |
||||
CRMINIMAL, /*!< Only summary output */ |
||||
CRNORMAL, /*!< All failed tests */ |
||||
CRVERBOSE, /*!< All tests */ |
||||
CRLAST |
||||
}; |
||||
|
||||
|
||||
/*! Holds state for a running of a test suite */ |
||||
typedef struct SRunner SRunner; |
||||
|
||||
/*! Opaque type for a test failure */ |
||||
typedef struct TestResult TestResult; |
||||
|
||||
/* accessors for tr fields */ |
||||
|
||||
/*! Type of result */ |
||||
int tr_rtype (TestResult *tr); |
||||
/*! Failure message */ |
||||
char *tr_msg (TestResult *tr); |
||||
/*! Line number at which failure occured */ |
||||
int tr_lno (TestResult *tr); |
||||
/*! File name at which failure occured */ |
||||
char *tr_lfile (TestResult *tr); |
||||
/*! Test case in which unit test was run */ |
||||
char *tr_tcname (TestResult *tr); |
||||
|
||||
/*! Creates an SRunner for the given suite */ |
||||
SRunner *srunner_create (Suite *s); |
||||
|
||||
/*! Adds a Suite to an SRunner */ |
||||
void srunner_add_suite (SRunner *sr, Suite *s); |
||||
|
||||
/*! Frees an SRunner */ |
||||
void srunner_free (SRunner *sr); |
||||
|
||||
/* Test running */ |
||||
|
||||
/*! Runs an SRunner, printing results as specified
|
||||
(see enum #print_verbosity)*/ |
||||
void srunner_run_all (SRunner *sr, int print_mode); |
||||
|
||||
/* Next functions are valid only after the suite has been
|
||||
completely run, of course */ |
||||
|
||||
/*! Number of failed tests in a run suite
|
||||
Includes failures + errors */ |
||||
int srunner_ntests_failed (SRunner *sr); |
||||
|
||||
/*! Total number of tests run in a run suite */ |
||||
int srunner_ntests_run (SRunner *sr); |
||||
|
||||
/*! \brief Return an array of results for all failures
|
||||
|
||||
Number of failures is equal to #srunner_nfailed_tests. Memory is |
||||
alloc'ed and must be freed, but individual TestResults must not */ |
||||
|
||||
TestResult **srunner_failures (SRunner *sr); |
||||
|
||||
/*! \brief Return an array of results for all run tests
|
||||
|
||||
Number of failrues is equal to #srunner_ntests_run Memory is alloc'ed |
||||
and must be freed, but individual TestResults must not */ |
||||
|
||||
TestResult **srunner_results (SRunner *sr); |
||||
/* Printing */ |
||||
|
||||
/*! Print the results contained in an SRunner
|
||||
|
||||
\param sr SRunner for which results are printed |
||||
|
||||
\param print_mode Specification of print verbosity, constrainted to |
||||
enum #print_verbosity |
||||
*/ |
||||
void srunner_print (SRunner *sr, int print_mode); |
||||
|
||||
/*! @} */ |
||||
|
||||
|
||||
/*! \defgroup check_log Logging functions
|
||||
@{ |
||||
*/ |
||||
|
||||
/*! Set a log file to which to write during test running.
|
||||
Log file setting is an initialize only operation -- it should be done |
||||
immediatly after SRunner creation, and the log file can't be changed |
||||
after being set. |
||||
\param sr The SRunner for which to enable logging |
||||
\param fname The file name to which to write the log |
||||
*/ |
||||
void srunner_set_log (SRunner *sr, char *fname); |
||||
|
||||
/*! Does the SRunner have a log file?
|
||||
\param sr The SRunner to test |
||||
\return True if logging, False otherwise |
||||
*/ |
||||
int srunner_has_log (SRunner *sr); |
||||
|
||||
/*! Return the name of the log file, or NULL if none
|
||||
\param sr The SRunner to query |
||||
\return The current log file, or NULL if not logging |
||||
*/ |
||||
char *srunner_log_fname (SRunner *sr); |
||||
|
||||
/*! @} */ |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* CHECK_H */ |
@ -0,0 +1,92 @@ |
||||
#ifndef CHECK_IMPL_H |
||||
#define CHECK_IMPL_H |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
/* This header should be included by any module that needs
|
||||
to know the implementation details of the check structures |
||||
Include stdio.h & list.h before this header |
||||
*/ |
||||
|
||||
/* magic values */ |
||||
|
||||
enum { |
||||
MAXLINE = 9999 /* maximum line no */ |
||||
}; |
||||
|
||||
typedef struct TF { |
||||
TFun fn; |
||||
char *name; |
||||
} TF; |
||||
|
||||
struct Suite { |
||||
char *name; |
||||
List *tclst; /* List of test cases */ |
||||
}; |
||||
|
||||
struct TCase { |
||||
char *name; |
||||
List *tflst; /* list of test functions */ |
||||
SFun setup; |
||||
SFun teardown; |
||||
}; |
||||
|
||||
typedef struct TestStats { |
||||
int n_checked; |
||||
int n_failed; |
||||
int n_errors; |
||||
} TestStats; |
||||
|
||||
struct TestResult { |
||||
int rtype; /* Type of result */ |
||||
char *file; /* File where the test occured */ |
||||
int line; /* Line number where the test occurred */ |
||||
char *tcname; /* Test case that generated the result */ |
||||
char *msg; /* Failure message */ |
||||
}; |
||||
|
||||
enum cl_event { |
||||
CLSTART_SR, |
||||
CLSTART_S, |
||||
CLEND_SR, |
||||
CLEND_S, |
||||
CLEND_T |
||||
}; |
||||
|
||||
typedef void (*LFun) (SRunner *, FILE*, enum print_verbosity, |
||||
void *, enum cl_event); |
||||
|
||||
typedef struct Log { |
||||
FILE *lfile; |
||||
LFun lfun; |
||||
int close; |
||||
enum print_verbosity mode; |
||||
} Log; |
||||
|
||||
struct SRunner { |
||||
List *slst; |
||||
TestStats *stats; |
||||
List *resultlst; |
||||
char *log_fname; |
||||
List *loglst; |
||||
}; |
||||
|
||||
|
||||
#endif /* CHECK_IMPL_H */ |
@ -0,0 +1,205 @@ |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <check.h> |
||||
#include "list.h" |
||||
#include "error.h" |
||||
#include "check_impl.h" |
||||
#include "check_log.h" |
||||
#include "check_print.h" |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
static void srunner_send_evt (SRunner *sr, void *obj, enum cl_event evt); |
||||
|
||||
void srunner_set_log (SRunner *sr, char *fname) |
||||
{ |
||||
if (sr->log_fname) |
||||
return; |
||||
sr->log_fname = fname; |
||||
} |
||||
|
||||
int srunner_has_log (SRunner *sr) |
||||
{ |
||||
return sr->log_fname != NULL; |
||||
} |
||||
|
||||
char *srunner_log_fname (SRunner *sr) |
||||
{ |
||||
return sr->log_fname; |
||||
} |
||||
|
||||
void srunner_register_lfun (SRunner *sr, FILE *lfile, int close, |
||||
LFun lfun, enum print_verbosity printmode) |
||||
{ |
||||
Log *l = emalloc (sizeof(Log)); |
||||
l->lfile = lfile; |
||||
l->lfun = lfun; |
||||
l->close = close; |
||||
l->mode = printmode; |
||||
list_add_end (sr->loglst, l); |
||||
return; |
||||
} |
||||
|
||||
void log_srunner_start (SRunner *sr) |
||||
{ |
||||
srunner_send_evt (sr, NULL, CLSTART_SR); |
||||
} |
||||
|
||||
void log_srunner_end (SRunner *sr) |
||||
{ |
||||
srunner_send_evt (sr, NULL, CLEND_SR); |
||||
} |
||||
|
||||
void log_suite_start (SRunner *sr, Suite *s) |
||||
{ |
||||
srunner_send_evt (sr, s, CLSTART_S); |
||||
} |
||||
|
||||
void log_suite_end (SRunner *sr, Suite *s) |
||||
{ |
||||
srunner_send_evt (sr, s, CLEND_S); |
||||
} |
||||
|
||||
void log_test_end (SRunner *sr, TestResult *tr) |
||||
{ |
||||
srunner_send_evt (sr, tr, CLEND_T); |
||||
} |
||||
|
||||
static void srunner_send_evt (SRunner *sr, void *obj, enum cl_event evt) |
||||
{ |
||||
List *l; |
||||
Log *lg; |
||||
l = sr->loglst; |
||||
for (list_front(l); !list_at_end(l); list_advance(l)) { |
||||
lg = list_val(l); |
||||
fflush(lg->lfile); |
||||
lg->lfun (sr, lg->lfile, lg->mode, obj, evt); |
||||
fflush(lg->lfile); |
||||
} |
||||
} |
||||
|
||||
void stdout_lfun (SRunner *sr, FILE *file, enum print_verbosity printmode, |
||||
void *obj, enum cl_event evt) |
||||
{ |
||||
TestResult *tr; |
||||
Suite *s; |
||||
|
||||
switch (evt) { |
||||
case CLSTART_SR: |
||||
if (printmode > CRSILENT) { |
||||
fprintf(file, "Running suite(s):"); |
||||
} |
||||
break; |
||||
case CLSTART_S: |
||||
s = obj; |
||||
if (printmode > CRSILENT) { |
||||
fprintf(file, " %s", s->name); |
||||
} |
||||
break; |
||||
case CLEND_SR: |
||||
if (printmode > CRSILENT) { |
||||
fprintf (file, "\n"); |
||||
srunner_fprint (file, sr, printmode); |
||||
} |
||||
break; |
||||
case CLEND_S: |
||||
s = obj; |
||||
break; |
||||
case CLEND_T: |
||||
tr = obj; |
||||
break; |
||||
default: |
||||
eprintf("Bad event type received in stdout_lfun"); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
void lfile_lfun (SRunner *sr, FILE *file, enum print_verbosity printmode, |
||||
void *obj, enum cl_event evt) |
||||
{ |
||||
TestResult *tr; |
||||
Suite *s; |
||||
|
||||
switch (evt) { |
||||
case CLSTART_SR: |
||||
break; |
||||
case CLSTART_S: |
||||
s = obj; |
||||
fprintf(file, "Running suite %s\n", s->name); |
||||
break; |
||||
case CLEND_SR: |
||||
fprintf (file, "Results for all suites run:\n"); |
||||
srunner_fprint (file, sr, CRMINIMAL); |
||||
break; |
||||
case CLEND_S: |
||||
s = obj; |
||||
break; |
||||
case CLEND_T: |
||||
tr = obj; |
||||
tr_fprint(file, tr, CRVERBOSE); |
||||
break; |
||||
default: |
||||
eprintf("Bad event type received in stdout_lfun"); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
FILE *srunner_open_lfile (SRunner *sr) |
||||
{ |
||||
FILE *f = NULL; |
||||
if (srunner_has_log (sr)) { |
||||
f = fopen(sr->log_fname, "w"); |
||||
if (f == NULL) |
||||
eprintf ("Could not open log file %s:", sr->log_fname); |
||||
} |
||||
return f; |
||||
} |
||||
|
||||
void srunner_init_logging (SRunner *sr, enum print_verbosity print_mode) |
||||
{ |
||||
FILE *f; |
||||
sr->loglst = list_create(); |
||||
srunner_register_lfun (sr, stdout, 0, stdout_lfun, print_mode); |
||||
f = srunner_open_lfile (sr); |
||||
if (f) { |
||||
srunner_register_lfun (sr, f, 1, lfile_lfun, print_mode); |
||||
} |
||||
} |
||||
|
||||
void srunner_end_logging (SRunner *sr) |
||||
{ |
||||
List *l; |
||||
int rval; |
||||
|
||||
l = sr->loglst; |
||||
for (list_front(l); !list_at_end(l); list_advance(l)) { |
||||
Log *lg = list_val(l); |
||||
if (lg->close) { |
||||
rval = fclose (lg->lfile); |
||||
if (rval != 0) |
||||
eprintf ("Error closing log file:"); |
||||
} |
||||
free (lg); |
||||
} |
||||
list_free(l); |
||||
sr->loglst = NULL; |
||||
} |
@ -0,0 +1,23 @@ |
||||
#ifndef CHECK_LOG_H |
||||
#define CHECK_LOG_H |
||||
|
||||
void log_srunner_start (SRunner *sr); |
||||
void log_srunner_end (SRunner *sr); |
||||
void log_suite_start (SRunner *sr, Suite *s); |
||||
void log_suite_end (SRunner *sr, Suite *s); |
||||
void log_test_end (SRunner *sr, TestResult *tr); |
||||
|
||||
void stdout_lfun (SRunner *sr, FILE *file, enum print_verbosity, |
||||
void *obj, enum cl_event evt); |
||||
|
||||
void lfile_lfun (SRunner *sr, FILE *file, enum print_verbosity, |
||||
void *obj, enum cl_event evt); |
||||
|
||||
void srunner_register_lfun (SRunner *sr, FILE *lfile, int close, |
||||
LFun lfun, enum print_verbosity); |
||||
|
||||
FILE *srunner_open_lfile (SRunner *sr); |
||||
void srunner_init_logging (SRunner *sr, enum print_verbosity print_mode); |
||||
void srunner_end_logging (SRunner *sr); |
||||
|
||||
#endif /* CHECK_LOG_H */ |
@ -0,0 +1,155 @@ |
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
#include <errno.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <sys/types.h> |
||||
#include <sys/ipc.h> |
||||
#include <sys/msg.h> |
||||
#include "list.h" |
||||
#include "error.h" |
||||
#include "check.h" |
||||
#include "check_impl.h" |
||||
#include "check_msg.h" |
||||
|
||||
enum { |
||||
LASTLOCMSG = 1, |
||||
FAILUREMSG = 2 |
||||
}; |
||||
static LastLocMsg *create_last_loc_msg (char *file, int line); |
||||
static FailureMsg *create_failure_msg (char *msg); |
||||
|
||||
static FailureMsg *create_failure_msg (char *msg) |
||||
{ |
||||
FailureMsg *m = emalloc (sizeof(FailureMsg)); |
||||
m->message_type = (long int) FAILUREMSG; |
||||
strncpy(m->msg, msg, CMAXMSG); |
||||
return m; |
||||
} |
||||
|
||||
|
||||
static LastLocMsg *create_last_loc_msg (char *file, int line) |
||||
{ |
||||
LastLocMsg *m = emalloc (sizeof(LastLocMsg)); |
||||
m->message_type = (long int) LASTLOCMSG; |
||||
snprintf(m->msg, CMAXMSG, "%s\n%d", file, line); |
||||
|
||||
return m; |
||||
} |
||||
|
||||
char *last_loc_file (LastLocMsg *msg) |
||||
{ |
||||
int i; |
||||
char *rmsg = emalloc (CMAXMSG); /* caller responsible for freeing */ |
||||
char *mmsg = msg->msg; |
||||
if (msg == NULL) |
||||
return NULL; |
||||
for (i = 0; mmsg[i] != '\n'; i++) { |
||||
if (mmsg[i] == '\0') |
||||
eprintf ("Badly formated last loc message"); |
||||
rmsg[i] = mmsg[i]; |
||||
} |
||||
rmsg[i] = '\0'; |
||||
return rmsg; |
||||
} |
||||
|
||||
int last_loc_line (LastLocMsg *msg) |
||||
{ |
||||
char *rmsg; |
||||
if (msg == NULL) |
||||
return -1; |
||||
rmsg = msg->msg; |
||||
while (*rmsg != '\n') { |
||||
if (*rmsg == '\0') |
||||
eprintf ("Badly formated last loc message"); |
||||
rmsg++; |
||||
} |
||||
rmsg++; /*advance past \n */ |
||||
return atoi (rmsg); |
||||
} |
||||
|
||||
|
||||
void send_last_loc_msg (int msqid, char * file, int line) |
||||
{ |
||||
int rval; |
||||
LastLocMsg *rmsg = create_last_loc_msg(file, line); |
||||
rval = msgsnd(msqid, (void *) rmsg, CMAXMSG, IPC_NOWAIT); |
||||
if (rval == -1) { |
||||
eprintf ("send_last_loc_msg:Failed to send message, msqid = %d:",msqid); |
||||
} |
||||
free(rmsg); |
||||
} |
||||
|
||||
int create_msq (void) { |
||||
int msqid; |
||||
msqid = msgget((key_t) 1, 0666 | IPC_CREAT); |
||||
if (msqid == -1) |
||||
eprintf ("Unable to create message queue:"); |
||||
return msqid; |
||||
} |
||||
|
||||
void delete_msq (int msqid) |
||||
{ |
||||
if (msgctl (msqid, IPC_RMID, NULL) == -1) |
||||
eprintf ("Failed to free message queue:"); |
||||
} |
||||
|
||||
|
||||
void send_failure_msg (int msqid, char *msg) |
||||
{ |
||||
int rval; |
||||
|
||||
FailureMsg *rmsg = create_failure_msg(msg); |
||||
|
||||
rval = msgsnd(msqid, (void *) rmsg, CMAXMSG, IPC_NOWAIT); |
||||
if (rval == -1) |
||||
eprintf ("send_failure_msg:Failed to send message:"); |
||||
free(rmsg); |
||||
} |
||||
|
||||
LastLocMsg *receive_last_loc_msg (int msqid) |
||||
{ |
||||
LastLocMsg *rmsg = emalloc(sizeof(LastLocMsg)); /* caller responsible for freeing */ |
||||
while (1) { |
||||
int rval; |
||||
rval = msgrcv(msqid, (void *) rmsg, CMAXMSG, LASTLOCMSG, IPC_NOWAIT); |
||||
if (rval == -1) { |
||||
if (errno == ENOMSG) |
||||
break; |
||||
eprintf ("receive_last_loc_msg:Failed to receive message:"); |
||||
} |
||||
} |
||||
return rmsg; |
||||
} |
||||
|
||||
FailureMsg *receive_failure_msg (int msqid) |
||||
{
|
||||
FailureMsg *rmsg = emalloc(sizeof(FailureMsg)); |
||||
int rval; |
||||
rval = msgrcv(msqid, (void *) rmsg, CMAXMSG, FAILUREMSG, IPC_NOWAIT); |
||||
if (rval == -1) { |
||||
if (errno == ENOMSG) |
||||
return NULL; |
||||
eprintf ("receive_failure_msg:Failed to receive message:"); |
||||
} |
||||
return rmsg; |
||||
} |
||||
|
@ -0,0 +1,53 @@ |
||||
#ifndef CHECK_MSG_H |
||||
#define CHECK_MSG_H |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
/* Functions implementing messaging during test runs */ |
||||
/* check.h must be included before this header */ |
||||
|
||||
|
||||
typedef struct LastLocMsg { |
||||
long int message_type; |
||||
char msg[CMAXMSG]; /* Format: filename\nlineno\0 */ |
||||
} LastLocMsg; |
||||
|
||||
typedef struct FailureMsg { |
||||
long int message_type; |
||||
char msg[CMAXMSG]; |
||||
} FailureMsg; |
||||
|
||||
int create_msq (void); |
||||
void delete_msq (int msqid); |
||||
|
||||
void send_failure_msg (int msqid, char *msg); |
||||
void send_last_loc_msg (int msqid, char * file, int line); |
||||
|
||||
/* malloc'd return value which caller is responsible for
|
||||
freeing in each of the next two functions */ |
||||
FailureMsg *receive_failure_msg (int msqid); |
||||
LastLocMsg *receive_last_loc_msg (int msqid); |
||||
|
||||
/* file name contained in the LastLocMsg */ |
||||
/* return value is malloc'd, caller responsible for freeing */ |
||||
char *last_loc_file(LastLocMsg *msg); |
||||
int last_loc_line(LastLocMsg *msg); |
||||
|
||||
#endif /*CHECK_MSG_H */ |
@ -0,0 +1,106 @@ |
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <check.h> |
||||
#include "list.h" |
||||
#include "check_impl.h" |
||||
#include "check_print.h" |
||||
#include "error.h" |
||||
|
||||
static void srunner_fprint_summary (FILE *file, SRunner *sr, int print_mode); |
||||
static void srunner_fprint_results (FILE *file, SRunner *sr, int print_mode); |
||||
|
||||
static int percent_passed (TestStats *t); |
||||
static char *rtype_to_string (int rtype); |
||||
|
||||
void srunner_print (SRunner *sr, int print_mode) |
||||
{ |
||||
srunner_fprint (stdout, sr, print_mode); |
||||
} |
||||
|
||||
void srunner_fprint (FILE *file, SRunner *sr, int print_mode) |
||||
{ |
||||
srunner_fprint_summary (file, sr, print_mode); |
||||
srunner_fprint_results (file, sr, print_mode); |
||||
} |
||||
|
||||
static void srunner_fprint_summary (FILE *file, SRunner *sr, int print_mode) |
||||
{ |
||||
TestStats *ts = sr->stats; |
||||
if (print_mode >= CRMINIMAL) { |
||||
fprintf (file, "%d%%: Checks: %d, Failures: %d, Errors: %d\n", |
||||
percent_passed (ts), ts->n_checked, ts->n_failed, |
||||
ts->n_errors); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
static void srunner_fprint_results (FILE *file, SRunner *sr, int print_mode) |
||||
{ |
||||
List *resultlst; |
||||
|
||||
resultlst = sr->resultlst; |
||||
|
||||
for (list_front(resultlst); !list_at_end(resultlst); list_advance(resultlst)) { |
||||
TestResult *tr = list_val(resultlst); |
||||
tr_fprint (file, tr, print_mode); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
void tr_fprint (FILE *file, TestResult *tr, int print_mode) |
||||
{ |
||||
char *exact_msg; |
||||
exact_msg = (tr->rtype == CRERROR) ? "(after this point) ": ""; |
||||
if ((print_mode >= CRVERBOSE && tr->rtype == CRPASS) || |
||||
(tr->rtype != CRPASS && print_mode >= CRNORMAL)) { |
||||
fprintf (file, "%s:%d:%s:%s: %s%s\n", |
||||
tr->file, tr->line, |
||||
rtype_to_string(tr->rtype), tr->tcname, |
||||
exact_msg, tr->msg); |
||||
} |
||||
} |
||||
|
||||
static int percent_passed (TestStats *t) |
||||
{ |
||||
if (t->n_failed == 0 && t->n_errors == 0) |
||||
return 100; |
||||
else |
||||
return (int) ( (float) (t->n_checked - (t->n_failed + t->n_errors)) / |
||||
(float) t->n_checked * 100); |
||||
} |
||||
|
||||
static char *rtype_to_string (int rtype) |
||||
{ |
||||
switch (rtype) { |
||||
case CRPASS: |
||||
return "P"; |
||||
break; |
||||
case CRFAILURE: |
||||
return "F"; |
||||
break; |
||||
case CRERROR: |
||||
return "E"; |
||||
break; |
||||
default: |
||||
eprintf("Bad argument %d to rtype_to_string", rtype); |
||||
return NULL; |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
#ifndef CHECK_PRINT_H |
||||
#define CHECK_PRINT_H |
||||
|
||||
void tr_fprint (FILE *file, TestResult *tr, int print_mode); |
||||
void srunner_fprint (FILE *file, SRunner *sr, int print_mode); |
||||
|
||||
|
||||
#endif /* CHECK_PRINT_H */ |
@ -0,0 +1,333 @@ |
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/wait.h> |
||||
#include <unistd.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <stdarg.h> |
||||
#include "error.h" |
||||
#include "list.h" |
||||
#include "check.h" |
||||
#include "check_impl.h" |
||||
#include "check_msg.h" |
||||
#include "check_log.h" |
||||
|
||||
|
||||
static void srunner_run_tcase (SRunner *sr, TCase *tc); |
||||
static void srunner_add_failure (SRunner *sr, TestResult *tf); |
||||
static TestResult *tfun_run (int msqid, char *tcname, TF *tf); |
||||
static TestResult *receive_result_info (int msqid, int status, char *tcname); |
||||
static void receive_last_loc_info (int msqid, TestResult *tr); |
||||
static void receive_failure_info (int msqid, int status, TestResult *tr); |
||||
static List *srunner_resultlst (SRunner *sr); |
||||
|
||||
|
||||
static char *signal_msg (int sig); |
||||
static char *exit_msg (int exitstatus); |
||||
static int non_pass (int val); |
||||
|
||||
|
||||
SRunner *srunner_create (Suite *s) |
||||
{ |
||||
SRunner *sr = emalloc (sizeof(SRunner)); /* freed in srunner_free */ |
||||
sr->slst = list_create(); |
||||
list_add_end(sr->slst, s); |
||||
sr->stats = emalloc (sizeof(TestStats)); /* freed in srunner_free */ |
||||
sr->stats->n_checked = sr->stats->n_failed = sr->stats->n_errors = 0; |
||||
sr->resultlst = list_create(); |
||||
sr->log_fname = NULL; |
||||
sr->loglst = NULL; |
||||
return sr; |
||||
} |
||||
|
||||
void srunner_add_suite (SRunner *sr, Suite *s) |
||||
{ |
||||
list_add_end(sr->slst, s); |
||||
} |
||||
|
||||
void srunner_free (SRunner *sr) |
||||
{ |
||||
List *l; |
||||
TestResult *tr; |
||||
if (sr == NULL) |
||||
return; |
||||
|
||||
free (sr->stats); |
||||
list_free(sr->slst); |
||||
|
||||
l = sr->resultlst; |
||||
for (list_front(l); !list_at_end(l); list_advance(l)) { |
||||
tr = list_val(l); |
||||
free(tr->file); |
||||
if (tr->rtype == CRFAILURE || tr->rtype == CRERROR) |
||||
free(tr->msg); |
||||
free(tr); |
||||
} |
||||
list_free (sr->resultlst); |
||||
|
||||
free (sr); |
||||
}
|
||||
|
||||
|
||||
|
||||
void srunner_run_all (SRunner *sr, int print_mode) |
||||
{ |
||||
List *slst; |
||||
List *tcl; |
||||
TCase *tc; |
||||
if (sr == NULL) |
||||
return; |
||||
if (print_mode < 0 || print_mode >= CRLAST) |
||||
eprintf("Bad print_mode argument to srunner_run_all: %d", print_mode); |
||||
|
||||
srunner_init_logging (sr, print_mode); |
||||
|
||||
log_srunner_start (sr); |
||||
|
||||
slst = sr->slst; |
||||
|
||||
for (list_front(slst); !list_at_end(slst); list_advance(slst)) { |
||||
Suite *s = list_val(slst); |
||||
|
||||
log_suite_start (sr, s); |
||||
|
||||
tcl = s->tclst; |
||||
|
||||
for (list_front(tcl);!list_at_end (tcl); list_advance (tcl)) { |
||||
tc = list_val (tcl); |
||||
srunner_run_tcase (sr, tc); |
||||
} |
||||
} |
||||
|
||||
log_srunner_end (sr); |
||||
|
||||
srunner_end_logging (sr); |
||||
} |
||||
|
||||
static void srunner_add_failure (SRunner *sr, TestResult *tr) |
||||
{ |
||||
sr->stats->n_checked++; |
||||
list_add_end (sr->resultlst, tr); |
||||
switch (tr->rtype) { |
||||
|
||||
case CRPASS: |
||||
return; |
||||
case CRFAILURE: |
||||
sr->stats->n_failed++; |
||||
return; |
||||
case CRERROR: |
||||
sr->stats->n_errors++; |
||||
return; |
||||
} |
||||
} |
||||
|
||||
|
||||
static void srunner_run_tcase (SRunner *sr, TCase *tc) |
||||
{ |
||||
List *tfl; |
||||
TF *tfun; |
||||
TestResult *tr; |
||||
int msqid; |
||||
|
||||
if (tc->setup) |
||||
tc->setup(); |
||||
msqid = create_msq(); |
||||
tfl = tc->tflst; |
||||
|
||||
for (list_front(tfl); !list_at_end (tfl); list_advance (tfl)) { |
||||
tfun = list_val (tfl); |
||||
tr = tfun_run (msqid, tc->name, tfun); |
||||
srunner_add_failure (sr, tr); |
||||
log_test_end(sr, tr); |
||||
} |
||||
delete_msq(msqid); |
||||
if (tc->teardown) |
||||
tc->teardown(); |
||||
} |
||||
|
||||
static void receive_last_loc_info (int msqid, TestResult *tr) |
||||
{ |
||||
LastLocMsg *lmsg; |
||||
lmsg = receive_last_loc_msg (msqid); |
||||
tr->file = last_loc_file (lmsg); |
||||
tr->line = last_loc_line (lmsg); |
||||
free (lmsg); |
||||
}
|
||||
|
||||
static void receive_failure_info (int msqid, int status, TestResult *tr) |
||||
{ |
||||
FailureMsg *fmsg; |
||||
|
||||
if (WIFSIGNALED(status)) { |
||||
tr->rtype = CRERROR; |
||||
tr->msg = signal_msg (WTERMSIG(status)); |
||||
return; |
||||
} |
||||
|
||||
if (WIFEXITED(status)) { |
||||
|
||||
if (WEXITSTATUS(status) == 0) { |
||||
tr->rtype = CRPASS; |
||||
/* TODO: It would be cleaner to strdup this &
|
||||
not special case the free...*/ |
||||
tr->msg = "Test passed"; |
||||
} |
||||
else { |
||||
|
||||
fmsg = receive_failure_msg (msqid); |
||||
if (fmsg == NULL) { /* implies early exit */ |
||||
tr->rtype = CRERROR; |
||||
tr->msg = exit_msg (WEXITSTATUS(status)); |
||||
} |
||||
else { |
||||
tr->rtype = CRFAILURE; |
||||
tr->msg = emalloc(strlen(fmsg->msg) + 1); |
||||
strcpy (tr->msg, fmsg->msg); |
||||
free (fmsg); |
||||
} |
||||
} |
||||
} else { |
||||
eprintf ("Bad status from wait() call\n"); |
||||
} |
||||
} |
||||
|
||||
static TestResult *receive_result_info (int msqid, int status, char *tcname) |
||||
{ |
||||
TestResult *tr = emalloc (sizeof(TestResult)); |
||||
|
||||
tr->tcname = tcname; |
||||
receive_last_loc_info (msqid, tr); |
||||
receive_failure_info (msqid, status, tr); |
||||
return tr; |
||||
} |
||||
|
||||
static TestResult *tfun_run (int msqid, char *tcname, TF *tfun) |
||||
{ |
||||
pid_t pid; |
||||
int status = 0; |
||||
|
||||
pid = fork(); |
||||
if (pid == -1) |
||||
eprintf ("Unable to fork:"); |
||||
if (pid == 0) { |
||||
tfun->fn(msqid); |
||||
_exit(EXIT_SUCCESS); |
||||
} |
||||
(void) wait(&status); |
||||
return receive_result_info(msqid, status, tcname); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
int srunner_ntests_failed (SRunner *sr) |
||||
{ |
||||
return sr->stats->n_failed + sr->stats->n_errors; |
||||
} |
||||
|
||||
int srunner_ntests_run (SRunner *sr) |
||||
{ |
||||
return sr->stats->n_checked; |
||||
} |
||||
|
||||
TestResult **srunner_failures (SRunner *sr) |
||||
{ |
||||
int i = 0; |
||||
TestResult **trarray; |
||||
List *rlst; |
||||
trarray = malloc (sizeof(trarray[0]) * srunner_ntests_failed (sr)); |
||||
|
||||
rlst = srunner_resultlst (sr); |
||||
for (list_front(rlst); !list_at_end(rlst); list_advance(rlst)) { |
||||
TestResult *tr = list_val(rlst); |
||||
if (non_pass(tr->rtype)) |
||||
trarray[i++] = tr; |
||||
|
||||
} |
||||
return trarray; |
||||
} |
||||
|
||||
TestResult **srunner_results (SRunner *sr) |
||||
{ |
||||
int i = 0; |
||||
TestResult **trarray; |
||||
List *rlst; |
||||
|
||||
trarray = malloc (sizeof(trarray[0]) * srunner_ntests_run (sr)); |
||||
|
||||
rlst = srunner_resultlst (sr); |
||||
for (list_front(rlst); !list_at_end(rlst); list_advance(rlst)) { |
||||
trarray[i++] = list_val(rlst); |
||||
} |
||||
return trarray; |
||||
} |
||||
|
||||
static List *srunner_resultlst (SRunner *sr) |
||||
{ |
||||
return sr->resultlst; |
||||
} |
||||
|
||||
char *tr_msg (TestResult *tr) |
||||
{ |
||||
return tr->msg; |
||||
} |
||||
|
||||
int tr_lno (TestResult *tr) |
||||
{ |
||||
return tr->line; |
||||
} |
||||
|
||||
char *tr_lfile (TestResult *tr) |
||||
{ |
||||
return tr->file; |
||||
} |
||||
|
||||
int tr_rtype (TestResult *tr) |
||||
{ |
||||
return tr->rtype; |
||||
} |
||||
|
||||
char *tr_tcname (TestResult *tr) |
||||
{ |
||||
return tr->tcname; |
||||
} |
||||
|
||||
|
||||
static char *signal_msg (int signal) |
||||
{ |
||||
char *msg = emalloc (CMAXMSG); /* free'd by caller */ |
||||
snprintf(msg, CMAXMSG, "Received signal %d", signal); |
||||
return msg; |
||||
} |
||||
|
||||
static char *exit_msg (int exitval) |
||||
{ |
||||
char *msg = emalloc(CMAXMSG); /* free'd by caller */ |
||||
snprintf(msg, CMAXMSG, |
||||
"Early exit with return value %d", exitval); |
||||
return msg; |
||||
} |
||||
|
||||
static int non_pass (int val) |
||||
{ |
||||
return val == CRFAILURE || val == CRERROR; |
||||
} |
||||
|
@ -0,0 +1,60 @@ |
||||
#include <stdarg.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include "error.h" |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
void eprintf (char *fmt, ...) |
||||
{ |
||||
va_list args; |
||||
fflush(stdout); |
||||
|
||||
va_start(args, fmt); |
||||
vfprintf(stderr, fmt, args); |
||||
va_end(args); |
||||
|
||||
/*include system error information if format ends in colon */ |
||||
if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') |
||||
fprintf(stderr, " %s", strerror(errno)); |
||||
fprintf(stderr, "\n"); |
||||
|
||||
exit(2); |
||||
} |
||||
|
||||
void *emalloc (size_t n) |
||||
{ |
||||
void *p; |
||||
p = malloc(n); |
||||
if (p == NULL) |
||||
eprintf("malloc of %u bytes failed:", n); |
||||
return p; |
||||
} |
||||
|
||||
void *erealloc (void * ptr, size_t n) |
||||
{ |
||||
void *p; |
||||
p = realloc (ptr, n); |
||||
if (p == NULL) |
||||
eprintf("realloc of %u bytes failed:", n); |
||||
return p; |
||||
} |
@ -0,0 +1,32 @@ |
||||
#ifndef ERROR_H |
||||
#define ERROR_H |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
/* Include stdlib.h beforehand */ |
||||
|
||||
/* Print error message and die
|
||||
If fmt ends in colon, include system error information */ |
||||
void eprintf (char *fmt, ...); |
||||
/* malloc or die */ |
||||
void *emalloc(size_t n); |
||||
void *erealloc(void *, size_t n); |
||||
|
||||
#endif /*ERROR_H*/ |
@ -0,0 +1,113 @@ |
||||
#include <stdlib.h> |
||||
#include "list.h" |
||||
#include "error.h" |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
enum { |
||||
LINIT = 1, |
||||
LGROW = 2 |
||||
}; |
||||
|
||||
struct List { |
||||
int n_elts; |
||||
int max_elts; |
||||
int current; /* pointer to the current node */ |
||||
int last; /* pointer to the node before END */ |
||||
void **data; |
||||
}; |
||||
|
||||
static void maybe_grow (List *lp) |
||||
{ |
||||
if (lp->n_elts >= lp->max_elts) { |
||||
lp->max_elts *= LGROW; |
||||
lp->data = erealloc (lp->data, lp->max_elts * sizeof(lp->data[0])); |
||||
} |
||||
} |
||||
|
||||
List *list_create (void) |
||||
{ |
||||
List *lp; |
||||
lp = emalloc (sizeof(List)); |
||||
lp->n_elts = 0; |
||||
lp->max_elts = LINIT; |
||||
lp->data = emalloc(sizeof(lp->data[0]) * LINIT); |
||||
lp->current = lp->last = -1; |
||||
return lp; |
||||
} |
||||
|
||||
void list_add_end (List *lp, void *val) |
||||
{ |
||||
if (lp == NULL) |
||||
return; |
||||
maybe_grow(lp); |
||||
lp->last++; |
||||
lp->n_elts++; |
||||
lp->current = lp->last; |
||||
lp->data[lp->current] = val; |
||||
} |
||||
|
||||
int list_at_end (List *lp) |
||||
{ |
||||
if (lp->current == -1) |
||||
return 1; |
||||
else |
||||
return (lp->current > lp->last); |
||||
} |
||||
|
||||
void list_front (List *lp) |
||||
{ |
||||
if (lp->current == -1) |
||||
return; |
||||
lp->current = 0; |
||||
} |
||||
|
||||
|
||||
void list_free (List *lp) |
||||
{ |
||||
if (lp == NULL) |
||||
return; |
||||
|
||||
free(lp->data); |
||||
free (lp); |
||||
} |
||||
|
||||
void *list_val (List *lp) |
||||
{ |
||||
if (lp == NULL) |
||||
return NULL; |
||||
if (lp->current == -1 || lp->current > lp->last) |
||||
return NULL; |
||||
|
||||
return lp->data[lp->current]; |
||||
} |
||||
|
||||
void list_advance (List *lp) |
||||
{ |
||||
if (lp == NULL) |
||||
return; |
||||
if (list_at_end(lp)) |
||||
return; |
||||
lp->current++; |
||||
} |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,51 @@ |
||||
#ifndef LIST_H |
||||
#define LIST_H |
||||
|
||||
/*
|
||||
Check: a unit test framework for C |
||||
Copyright (C) 2001, Arien Malec |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
typedef struct List List; |
||||
|
||||
/* Create an empty list */ |
||||
List * list_create (void); |
||||
|
||||
/* Is list at end? */ |
||||
int list_at_end (List * lp); |
||||
|
||||
/* Position list at front */ |
||||
void list_front(List *lp); |
||||
|
||||
|
||||
/* Add a value to the end of the list,
|
||||
positioning newly added value as current value */ |
||||
void list_add_end (List *lp, void *val); |
||||
|
||||
/* Give the value of the current node */ |
||||
void *list_val (List * lp); |
||||
|
||||
/* Position the list at the next node */ |
||||
void list_advance (List * lp); |
||||
|
||||
/* Free a list, but don't free values */ |
||||
void list_free (List * lp); |
||||
|
||||
/* Free a list, freeing values using a freeing function */ |
||||
/* void list_vfree (List * lp, void (*fp) (void *)); */ |
||||
|
||||
#endif /*LIST_H*/ |
Loading…
Reference in new issue