]> granicus.if.org Git - check/commitdiff
Added support for XML output of the test results.
authorhugo303 <hugo303@64e312b2-a51f-0410-8e61-82d0ca0eb02a>
Wed, 18 Aug 2004 12:02:02 +0000 (12:02 +0000)
committerhugo303 <hugo303@64e312b2-a51f-0410-8e61-82d0ca0eb02a>
Wed, 18 Aug 2004 12:02:02 +0000 (12:02 +0000)
git-svn-id: svn+ssh://svn.code.sf.net/p/check/code/trunk@184 64e312b2-a51f-0410-8e61-82d0ca0eb02a

12 files changed:
check/src/check.c
check/src/check.h.in
check/src/check_impl.h
check/src/check_log.c
check/src/check_log.h
check/src/check_print.c
check/src/check_print.h
check/src/check_run.c
check/tests/Makefile.am
check/tests/check_check_log.c
check/tests/ex_xml_output.c [new file with mode: 0644]
check/tests/test_xml_output.sh [new file with mode: 0755]

index 2a3cf5d0c3742e5843a6f31043fdf3efd7a9a83c..78e29eb0314de53522cc7f580909716d410338f2 100644 (file)
@@ -199,6 +199,7 @@ SRunner *srunner_create (Suite *s)
   sr->stats->n_checked = sr->stats->n_failed = sr->stats->n_errors = 0;
   sr->resultlst = list_create();
   sr->log_fname = NULL;
+  sr->xml_fname = NULL;
   sr->loglst = NULL;
   sr->fstat = CK_FORK_UNSPECIFIED;
   return sr;
index 746fee59aad156691712d38d9c28752bc22106f6..78ad17abaaeb22152885e5046fa1a83e8624fee9 100644 (file)
@@ -291,6 +291,24 @@ int srunner_has_log (SRunner *sr);
 */
 const char *srunner_log_fname (SRunner *sr);
 
+/* Set a xml file to which to write during test running.
+
+  XML file setting is an initialize only operation -- it should be
+  done immediatly after SRunner creation, and the XML file can't be
+  changed after being set.
+ */
+void srunner_set_xml (SRunner *sr, const char *fname);
+
+/* Does the SRunner have a log file?
+*/
+int srunner_has_xml (SRunner *sr);
+
+/* Return the name of the XML file, or NULL if none
+*/
+const char *srunner_xml_fname (SRunner *sr);
+
+
+
 /* Control forking */
 enum fork_status {
   CK_FORK,
index a50e286f8cc4e8c0ca4e709daf6901da6b847d9e..9f19c093a75799f287dd94605f5ce235af888b13 100644 (file)
@@ -78,6 +78,8 @@ TestResult *tr_create(void);
 void tr_reset(TestResult *tr);
 
 enum cl_event {
+  CLINITLOG_SR,
+  CLENDLOG_SR,
   CLSTART_SR,
   CLSTART_S,
   CLEND_SR,
@@ -100,6 +102,7 @@ struct SRunner {
   TestStats *stats; /* Run statistics */
   List *resultlst; /* List of unit test results */
   const char *log_fname; /* name of log file */
+  const char *xml_fname; /* name of xml output file */
   List *loglst; /* list of Log objects */
   enum fork_status fstat; /* controls if suites are forked or not
                             NOTE: Don't use this value directly,
index 9aab990996d69a5faafb2c5d4937828319d77063..7b1457bbd16cdee8610df569fd906d99ebd6636b 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
 #include <check.h>
 
 #include "check_error.h"
@@ -50,6 +52,24 @@ const char *srunner_log_fname (SRunner *sr)
   return sr->log_fname;
 }
 
+
+void srunner_set_xml (SRunner *sr, const char *fname)
+{
+  if (sr->xml_fname)
+    return;
+  sr->xml_fname = fname;
+}
+
+int srunner_has_xml (SRunner *sr)
+{
+  return sr->xml_fname != NULL;
+}
+
+const char *srunner_xml_fname (SRunner *sr)
+{
+  return sr->xml_fname;
+}
+
 void srunner_register_lfun (SRunner *sr, FILE *lfile, int close,
                            LFun lfun, enum print_output printmode)
 {
@@ -116,6 +136,10 @@ void stdout_lfun (SRunner *sr, FILE *file, enum print_output printmode,
   }
 
   switch (evt) {
+  case CLINITLOG_SR:
+    break;
+  case CLENDLOG_SR:
+    break;
   case CLSTART_SR:
     if (printmode > CK_SILENT) {
       fprintf(file, "Running suite(s):");
@@ -153,6 +177,10 @@ void lfile_lfun (SRunner *sr, FILE *file, enum print_output printmode,
   Suite *s;
   
   switch (evt) {
+  case CLINITLOG_SR:
+    break;
+  case CLENDLOG_SR:
+    break;
   case CLSTART_SR:
     break;
   case CLSTART_S:
@@ -177,6 +205,61 @@ void lfile_lfun (SRunner *sr, FILE *file, enum print_output printmode,
   
 }
 
+void xml_lfun (SRunner *sr, FILE *file, enum print_output printmode,
+                 void *obj, enum cl_event evt)
+{
+  TestResult *tr;
+  Suite *s;
+  static struct tm *now = NULL;
+  static struct timeval inittv, endtv;
+  char *t;
+
+  if (now == NULL)
+  {
+    now = emalloc(sizeof(struct tm));
+    gettimeofday(&inittv, NULL);
+    localtime_r(&(inittv.tv_sec), now);
+  }
+
+  switch (evt) {
+  case CLINITLOG_SR:
+    fprintf(file, "<?xml version=\"1.0\"?>\n");
+    fprintf(file, "<testsuites xmlns=\"http://check.sourceforge.net/ns\">\n");
+    t = emalloc(sizeof("yyyy-mm-dd hh:mm:ss"));
+    strftime(t, sizeof("yyyy-mm-dd hh:mm:ss"), "%Y-%m-%d %H:%M:%S", now);
+    fprintf(file, "  <datetime>%s</datetime>\n", t);
+    break;
+  case CLENDLOG_SR:
+    gettimeofday(&endtv, NULL);
+    fprintf(file, "  <duration>%f</duration>\n",
+        (endtv.tv_sec + (float)(endtv.tv_usec)/1000000) - \
+        (inittv.tv_sec + (float)(inittv.tv_usec/1000000)));
+    fprintf(file, "</testsuites>\n");
+    break;
+  case CLSTART_SR:
+    break;
+  case CLSTART_S:
+    s = obj;
+    fprintf(file, "  <suite>\n");
+    fprintf(file, "    <title>%s</title>\n", s->name);
+    break;
+  case CLEND_SR:
+    break;
+  case CLEND_S:
+    fprintf(file, "  </suite>\n");
+    s = obj;
+    break;
+  case CLEND_T:
+    tr = obj;
+    tr_xmlprint(file, tr, CK_VERBOSE);
+    break;
+  default:
+    eprintf("Bad event type received in xml_lfun", __FILE__, __LINE__);
+  }
+
+}
+
+
 FILE *srunner_open_lfile (SRunner *sr)
 {
   FILE *f = NULL;
@@ -189,6 +272,18 @@ FILE *srunner_open_lfile (SRunner *sr)
   return f;
 }
 
+FILE *srunner_open_xmlfile (SRunner *sr)
+{
+  FILE *f = NULL;
+  if (srunner_has_xml (sr)) {
+    f = fopen(sr->xml_fname, "w");
+    if (f == NULL)
+      eprintf ("Could not open xml file %s:", __FILE__, __LINE__,
+              sr->xml_fname);
+  }
+  return f;
+}
+
 void srunner_init_logging (SRunner *sr, enum print_output print_mode)
 {
   FILE *f;
@@ -198,6 +293,11 @@ void srunner_init_logging (SRunner *sr, enum print_output print_mode)
   if (f) {
     srunner_register_lfun (sr, f, 1, lfile_lfun, print_mode);
   }
+  f = srunner_open_xmlfile (sr);
+  if (f) {
+    srunner_register_lfun (sr, f, 2, xml_lfun, print_mode);
+  }
+  srunner_send_evt (sr, NULL, CLINITLOG_SR);
 }
 
 void srunner_end_logging (SRunner *sr)
@@ -205,6 +305,8 @@ void srunner_end_logging (SRunner *sr)
   List *l;
   int rval;
 
+  srunner_send_evt (sr, NULL, CLENDLOG_SR);
+
   l = sr->loglst;
   for (list_front(l); !list_at_end(l); list_advance(l)) {
     Log *lg = list_val(l);
index 77f4512269a54e954aebeacf57f79932072c0d3d..e0a4b29ee1e84df0c6581e2c76075cea4a275bc0 100644 (file)
@@ -33,10 +33,14 @@ void stdout_lfun (SRunner *sr, FILE *file, enum print_output,
 void lfile_lfun (SRunner *sr, FILE *file, enum print_output,
                  void *obj, enum cl_event evt);
 
+void xml_lfun (SRunner *sr, FILE *file, enum print_output,
+                 void *obj, enum cl_event evt);
+
 void srunner_register_lfun (SRunner *sr, FILE *lfile, int close,
                            LFun lfun, enum print_output);
 
 FILE *srunner_open_lfile (SRunner *sr);
+FILE *srunner_open_xmlfile (SRunner *sr);
 void srunner_init_logging (SRunner *sr, enum print_output print_mode);
 void srunner_end_logging (SRunner *sr);
 
index d763b52549a0ff15363a185bc3d17bb590554599..c0f0db183a82791c9eee1b7281831ec5ff80831d 100644 (file)
@@ -92,6 +92,29 @@ void tr_fprint (FILE *file, TestResult *tr, enum print_output print_mode)
   }
 }
 
+void tr_xmlprint (FILE *file, TestResult *tr, enum print_output print_mode)
+{
+  char result[10];
+
+  switch (tr->rtype) {
+  case CK_PASS:
+    strcpy(result, "success");
+    break;
+  case CK_FAILURE:
+    strcpy(result, "failure");
+    break;
+  case CK_ERROR:
+    strcpy(result, "error");
+    break;
+  }
+  fprintf(file, "    <test result=\"%s\">\n", result);
+  fprintf(file, "      <fn>%s:%d</fn>\n", tr->file, tr->line);
+  fprintf(file, "      <id>%s</id>\n", tr->tname);
+  fprintf(file, "      <description>%s</description>\n", tr->tcname);
+  fprintf(file, "      <message>%s</message>\n", tr->msg);
+  fprintf(file, "    </test>\n");
+}
+
 enum print_output get_env_printmode (void)
 {
   char *env = getenv ("CK_VERBOSITY");
index 206c0f20176fcce11984c77633e213d6a65fb0dd..f4b02da32a9edec6aab3df7e8358a9285a587e09 100644 (file)
@@ -22,6 +22,7 @@
 #define CHECK_PRINT_H
 
 void tr_fprint (FILE *file, TestResult *tr, enum print_output print_mode);
+void tr_xmlprint (FILE *file, TestResult *tr, enum print_output print_mode);
 void srunner_fprint (FILE *file, SRunner *sr, enum print_output print_mode);
 enum print_output get_env_printmode (void);
 
index 980d7eb231e3b13adabf9c8eb92041f37650438b..31ca4ee510b78c8873ce31e107636f3c4a78228b 100644 (file)
@@ -113,6 +113,8 @@ static void srunner_iterate_suites (SRunner *sr,
       tc = list_val (tcl);
       srunner_run_tcase (sr, tc);
     }
+    
+    log_suite_end (sr, s);
   }
 }
 
index 443700b5732944ca3e433fee464514960738fb3e..b8a1e23a7be7dee55bf073246ec58d9403314b13 100644 (file)
@@ -1,12 +1,14 @@
 TESTS = \
        check_check             \
        test_output.sh          \
+       test_xml_output.sh      \
        test_log_output.sh
 
 noinst_PROGRAMS = \
        check_check     \
        check_stress    \
        ex_output       \
+       ex_xml_output   \
        ex_log_output
 
 EXTRA_DIST = test_output.sh test_log_output.sh
@@ -30,6 +32,8 @@ ex_output_SOURCES = ex_output.c
 
 ex_log_output_SOURCES = ex_log_output.c
 
+ex_xml_output_SOURCES = ex_xml_output.c
+
 
 INCLUDES = -I$(srcdir)/../src
 LDADD = ../src/libcheck.a
index 457fc7a9d50bb2b5f447a451956dbfaef4091d97..0cc002f22b8dba4cd5e56a9c93a429211cb39943 100644 (file)
@@ -41,23 +41,63 @@ START_TEST(test_double_set_log)
 }
 END_TEST
 
+
+START_TEST(test_set_xml)
+{
+  Suite *s = suite_create("Suite");
+  SRunner *sr = srunner_create(s);
+
+  srunner_set_xml (sr, "test_log.xml");
+
+  fail_unless (srunner_has_xml (sr), "SRunner not logging XML");
+  fail_unless (strcmp(srunner_xml_fname(sr), "test_log.xml") == 0,
+              "Bad file name returned");
+}
+END_TEST
+
+START_TEST(test_no_set_xml)
+{
+  Suite *s = suite_create("Suite");
+  SRunner *sr = srunner_create(s);
+
+  fail_unless (!srunner_has_xml (sr), "SRunner not logging XML");
+  fail_unless (srunner_xml_fname(sr) == NULL, "Bad file name returned");
+}
+END_TEST
+
+START_TEST(test_double_set_xml)
+{
+  Suite *s = suite_create("Suite");
+  SRunner *sr = srunner_create(s);
+
+  srunner_set_xml (sr, "test_log.xml");
+  srunner_set_xml (sr, "test2_log.xml");
+
+  fail_unless(strcmp(srunner_xml_fname(sr), "test_log.xml") == 0,
+             "XML Log file is initialize only and shouldn't be changeable once set");
+}
+END_TEST
+
 Suite *make_log_suite(void)
 {
 
   Suite *s;
-  TCase *tc_core;
+  TCase *tc_core, *tc_core_xml;
 
   s = suite_create("Log");
   tc_core = tcase_create("Core");
+  tc_core_xml = tcase_create("Core XML");
 
   suite_add_tcase(s, tc_core);
   tcase_add_test(tc_core, test_set_log);
   tcase_add_test(tc_core, test_no_set_log);
   tcase_add_test(tc_core, test_double_set_log);
 
+  suite_add_tcase(s, tc_core_xml);
+  tcase_add_test(tc_core_xml, test_set_xml);
+  tcase_add_test(tc_core_xml, test_no_set_xml);
+  tcase_add_test(tc_core_xml, test_double_set_xml);
+
   return s;
 }
 
-
-  
-  
diff --git a/check/tests/ex_xml_output.c b/check/tests/ex_xml_output.c
new file mode 100644 (file)
index 0000000..19ffb06
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <check.h>
+
+START_TEST(test_pass)
+{
+  fail_unless (1==1, "Shouldn't see this");
+}
+END_TEST
+
+START_TEST(test_fail)
+{
+  fail("Failure");
+}
+END_TEST
+
+START_TEST(test_exit)
+{
+  exit(1);
+}
+END_TEST
+
+START_TEST(test_pass2)
+{
+  fail_unless (1==1, "Shouldn't see this");
+}
+END_TEST
+
+static Suite *make_s1_suite (void)
+{
+  Suite *s;
+  TCase *tc;
+
+  s = suite_create("S1");
+  tc = tcase_create ("Core");
+  suite_add_tcase(s, tc);
+  tcase_add_test (tc, test_pass);
+  tcase_add_test (tc, test_fail);
+  tcase_add_test (tc, test_exit);
+
+  return s;
+}
+
+static Suite *make_s2_suite (void)
+{
+  Suite *s;
+  TCase *tc;
+
+  s = suite_create("S2");
+  tc = tcase_create ("Core");
+  suite_add_tcase(s, tc);
+  tcase_add_test (tc, test_pass2);
+
+  return s;
+}
+
+static void run_tests (int printmode)
+{
+  SRunner *sr;
+
+  sr = srunner_create(make_s1_suite());
+  srunner_add_suite(sr, make_s2_suite());
+  srunner_set_xml(sr, "test.log.xml");
+  srunner_run_all(sr, printmode);
+}
+
+
+int main (int argc, char **argv)
+{
+  run_tests(CK_SILENT);                /* not considered in XML output */
+
+  return EXIT_SUCCESS;
+}
+  
diff --git a/check/tests/test_xml_output.sh b/check/tests/test_xml_output.sh
new file mode 100755 (executable)
index 0000000..104475d
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+if [ "${srcdir}" = "." ]; then
+    lsrc=""
+else
+    lsrc="${srcdir}/"
+fi
+
+expected="<?xml version=\"1.0\"?>
+<testsuites xmlns=\"http://check.sourceforge.net/ns\">
+  <suite>
+    <title>S1</title>
+    <test result=\"success\">
+      <fn>ex_xml_output.c:8</fn>
+      <id>test_pass</id>
+      <description>Core</description>
+      <message>Passed</message>
+    </test>
+    <test result=\"failure\">
+      <fn>ex_xml_output.c:14</fn>
+      <id>test_fail</id>
+      <description>Core</description>
+      <message>Failure</message>
+    </test>
+    <test result=\"error\">
+      <fn>ex_xml_output.c:18</fn>
+      <id>test_exit</id>
+      <description>Core</description>
+      <message>Early exit with return value 1</message>
+    </test>
+  </suite>
+  <suite>
+    <title>S2</title>
+    <test result=\"success\">
+      <fn>ex_xml_output.c:26</fn>
+      <id>test_pass2</id>
+      <description>Core</description>
+      <message>Passed</message>
+    </test>
+  </suite>
+</testsuites>"
+
+./ex_xml_output > /dev/null
+actual=`cat test.log.xml | grep -v duration | grep -v datetime`
+if [ x"${expected}" != x"${actual}" ]; then
+    echo "Problem with ex_log_output ${3}";
+    echo "Expected:";
+    echo "${expected}";
+    echo "Got:";
+    echo "${actual}";
+    exit 1;
+fi
+    
+exit 0