]> granicus.if.org Git - yasm/commitdiff
Initial revision
authorPeter Johnson <peter@tortall.net>
Tue, 18 Sep 2001 17:31:02 +0000 (17:31 -0000)
committerPeter Johnson <peter@tortall.net>
Tue, 18 Sep 2001 17:31:02 +0000 (17:31 -0000)
svn path=/trunk/yasm/; revision=186

16 files changed:
check/NEWS [new file with mode: 0644]
check/README [new file with mode: 0644]
check/check.c [new file with mode: 0644]
check/check.h [new file with mode: 0644]
check/check_impl.h [new file with mode: 0644]
check/check_log.c [new file with mode: 0644]
check/check_log.h [new file with mode: 0644]
check/check_msg.c [new file with mode: 0644]
check/check_msg.h [new file with mode: 0644]
check/check_print.c [new file with mode: 0644]
check/check_print.h [new file with mode: 0644]
check/check_run.c [new file with mode: 0644]
check/error.c [new file with mode: 0644]
check/error.h [new file with mode: 0644]
check/list.c [new file with mode: 0644]
check/list.h [new file with mode: 0644]

diff --git a/check/NEWS b/check/NEWS
new file mode 100644 (file)
index 0000000..bb1f1b2
--- /dev/null
@@ -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
diff --git a/check/README b/check/README
new file mode 100644 (file)
index 0000000..aaf8e69
--- /dev/null
@@ -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.
diff --git a/check/check.c b/check/check.c
new file mode 100644 (file)
index 0000000..79607d2
--- /dev/null
@@ -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);
+  }
+}
diff --git a/check/check.h b/check/check.h
new file mode 100644 (file)
index 0000000..208c8ab
--- /dev/null
@@ -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 */
diff --git a/check/check_impl.h b/check/check_impl.h
new file mode 100644 (file)
index 0000000..bca52c6
--- /dev/null
@@ -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 */
diff --git a/check/check_log.c b/check/check_log.c
new file mode 100644 (file)
index 0000000..501c68c
--- /dev/null
@@ -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;
+}
diff --git a/check/check_log.h b/check/check_log.h
new file mode 100644 (file)
index 0000000..a7205d7
--- /dev/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 */
diff --git a/check/check_msg.c b/check/check_msg.c
new file mode 100644 (file)
index 0000000..b87d187
--- /dev/null
@@ -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;
+}
+
diff --git a/check/check_msg.h b/check/check_msg.h
new file mode 100644 (file)
index 0000000..76ab94a
--- /dev/null
@@ -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 */
diff --git a/check/check_print.c b/check/check_print.c
new file mode 100644 (file)
index 0000000..31de5b9
--- /dev/null
@@ -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;
+  }
+}
diff --git a/check/check_print.h b/check/check_print.h
new file mode 100644 (file)
index 0000000..ee90905
--- /dev/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 */
diff --git a/check/check_run.c b/check/check_run.c
new file mode 100644 (file)
index 0000000..6a2462f
--- /dev/null
@@ -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;
+}
+
diff --git a/check/error.c b/check/error.c
new file mode 100644 (file)
index 0000000..f2227a2
--- /dev/null
@@ -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;
+}
diff --git a/check/error.h b/check/error.h
new file mode 100644 (file)
index 0000000..01c2e13
--- /dev/null
@@ -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*/
diff --git a/check/list.c b/check/list.c
new file mode 100644 (file)
index 0000000..5e2d04a
--- /dev/null
@@ -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++;
+}
+
+
+
+  
diff --git a/check/list.h b/check/list.h
new file mode 100644 (file)
index 0000000..17215a2
--- /dev/null
@@ -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*/