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;
*/
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,
void tr_reset(TestResult *tr);
enum cl_event {
+ CLINITLOG_SR,
+ CLENDLOG_SR,
CLSTART_SR,
CLSTART_S,
CLEND_SR,
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,
#include <stdlib.h>
#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
#include <check.h>
#include "check_error.h"
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)
{
}
switch (evt) {
+ case CLINITLOG_SR:
+ break;
+ case CLENDLOG_SR:
+ break;
case CLSTART_SR:
if (printmode > CK_SILENT) {
fprintf(file, "Running suite(s):");
Suite *s;
switch (evt) {
+ case CLINITLOG_SR:
+ break;
+ case CLENDLOG_SR:
+ break;
case CLSTART_SR:
break;
case CLSTART_S:
}
+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;
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;
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)
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);
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);
}
}
+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");
#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);
tc = list_val (tcl);
srunner_run_tcase (sr, tc);
}
+
+ log_suite_end (sr, s);
}
}
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
ex_log_output_SOURCES = ex_log_output.c
+ex_xml_output_SOURCES = ex_xml_output.c
+
INCLUDES = -I$(srcdir)/../src
LDADD = ../src/libcheck.a
}
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;
}
-
-
-
--- /dev/null
+#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;
+}
+
--- /dev/null
+#!/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