commit - 68c450f8c58e81bc478c2ed12bc6b5b4170af4cd
commit + d6e96558852535185d7b78a859b770a7a4fe8823
blob - a2e34dfcea0eddc4ca1a490c5cbf4a533c44b487
blob + b3369c380f2cb9d8f913c3d7ccb099fc2ca362d6
--- CMakeLists.txt
+++ CMakeLists.txt
cmake_minimum_required (VERSION 3.9.2)
project(testres)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wextra -Wfloat-equal")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wundef -Wpointer-arith -Wcast-align -Wshadow")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-enum -Wunreachable-code -Winit-self")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter -Werror -pedantic")
+
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O3 -fsanitize=address")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O0 -g")
+
+include(CTest)
+
+if(BUILD_TESTING)
+ enable_testing()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function -Wno-unused-variable")
+ set(TESTING_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Testing")
+endif()
+
+add_subdirectory(libtestoutput)
add_subdirectory(src)
-add_subdirectory(tests)
-enable_testing()
-add_test(NAME unit COMMAND runtest)
blob - /dev/null
blob + fbf66df99ecb39aceaeff386c1862daefee6e535 (mode 644)
--- /dev/null
+++ libtestoutput/CMakeLists.txt
+cmake_minimum_required(VERSION 3.9.2)
+
+set(SOURCE_FILES
+parse_common.h
+parse_common.c
+parse_subunit_v1.h
+parse_subunit_v1.c
+parse_subunit_v2.h
+parse_subunit_v2.c
+parse_junit.h
+parse_junit.c
+parse_subunit_v2.c
+parse_testanything.h
+parse_testanything.c
+sha1.h
+sha1.c
+)
+
+include(FindEXPAT)
+find_package(EXPAT REQUIRED)
+
+include_directories(${EXPAT_INCLUDE_DIRS})
+add_library(testoutput ${SOURCE_FILES})
+
+if(BUILD_TESTING)
+ add_subdirectory(tests)
+endif()
blob - /dev/null
blob + 173ffe007ce19f3787b19b22e14b092a67ca7295 (mode 644)
--- /dev/null
+++ libtestoutput/parse_common.c
+/*
+ * Copyright © 2018-2019 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <dirent.h>
+#include <stdlib.h>
+
+#include "parse_common.h"
+#include "parse_junit.h"
+#include "parse_subunit_v1.h"
+#include "parse_subunit_v2.h"
+#include "parse_testanything.h"
+#include "sha1.h"
+
+void
+free_reports(struct reportq * reports)
+{
+ tailq_report *report_item = NULL;
+ while ((report_item = TAILQ_FIRST(reports))) {
+ if (report_item->suites != NULL) {
+ free_suites(report_item->suites);
+ }
+ TAILQ_REMOVE(reports, report_item, entries);
+ free_report(report_item);
+ }
+}
+
+void
+free_report(tailq_report *report)
+{
+ if (report->suites != NULL) {
+ free_suites(report->suites);
+ }
+ free(report->path);
+ free(report->id);
+ free(report);
+}
+
+void
+free_suites(struct suiteq * suites)
+{
+ tailq_suite *suite_item = NULL;
+ while ((suite_item = TAILQ_FIRST(suites))) {
+ TAILQ_REMOVE(suites, suite_item, entries);
+ free_suite(suite_item);
+ }
+}
+
+void
+free_suite(tailq_suite * suite)
+{
+ if (suite->name) {
+ free((char*)suite->name);
+ }
+ if (suite->hostname) {
+ free((char*)suite->hostname);
+ }
+ if (suite->timestamp) {
+ free((char*)suite->timestamp);
+ }
+ if (!TAILQ_EMPTY(suite->tests)) {
+ free_tests(suite->tests);
+ }
+
+ free(suite);
+}
+
+void
+free_tests(struct testq * tests)
+{
+ tailq_test *test_item;
+ while ((test_item = TAILQ_FIRST(tests))) {
+ TAILQ_REMOVE(tests, test_item, entries);
+ free_test(test_item);
+ }
+}
+
+void
+free_test(tailq_test * test)
+{
+ if (test->name) {
+ free((char*)test->name);
+ }
+ if (test->time) {
+ free((char*)test->time);
+ }
+ if (test->comment) {
+ free((char*)test->comment);
+ }
+ if (test->error) {
+ free((char*)test->error);
+ }
+ if (test->system_out) {
+ free((char*)test->system_out);
+ }
+ if (test->system_err) {
+ free((char*)test->system_err);
+ }
+ free(test);
+}
+
+char *
+get_filename_ext(const char *filename)
+{
+ char *dot = strrchr(filename, '.');
+ if (!dot || dot == filename)
+ return (char *) NULL;
+
+ return dot + 1;
+}
+
+enum test_format
+detect_format(char *path)
+{
+ char *file_ext;
+ file_ext = get_filename_ext(basename(path));
+ if (file_ext == NULL) {
+ return FORMAT_UNKNOWN;
+ }
+
+ if (strcasecmp("xml", file_ext) == 0) {
+ return FORMAT_JUNIT;
+ } else if (strcasecmp("tap", file_ext) == 0) {
+ return FORMAT_TAP13;
+ } else if (strcasecmp("subunit", file_ext) == 0) {
+ if (is_subunit_v2(path) == 0) {
+ return FORMAT_SUBUNIT_V2;
+ } else {
+ return FORMAT_SUBUNIT_V1;
+ }
+ } else {
+ return FORMAT_UNKNOWN;
+ }
+}
+
+unsigned char *digest_to_str(unsigned char *str, unsigned char digest[], unsigned int n) {
+ int r;
+ if (n == 0) return 0;
+ if (n == 1) r = sprintf((char*)str, "%x", digest[0]);
+ else r = sprintf((char*)str, "%x", digest[0]);
+ digest_to_str(str + r, digest + 1, n - 1);
+
+ return str;
+}
+
+tailq_report *
+process_file(char *path)
+{
+ FILE *file;
+ file = fopen(path, "r");
+ if (file == NULL) {
+ printf("failed to open file %s\n", path);
+ return NULL;
+ }
+ tailq_report *report = NULL;
+ report = calloc(1, sizeof(tailq_report));
+ if (report == NULL) {
+ perror("malloc failed");
+ fclose(file);
+ return NULL;
+ }
+ enum test_format format;
+ format = detect_format(path);
+ switch (format) {
+ case FORMAT_JUNIT:
+ report->format = FORMAT_JUNIT;
+ report->suites = parse_junit(file);
+ break;
+ case FORMAT_TAP13:
+ report->format = FORMAT_TAP13;
+ report->suites = parse_testanything(file);
+ break;
+ case FORMAT_SUBUNIT_V1:
+ report->format = FORMAT_SUBUNIT_V1;
+ report->suites = parse_subunit_v1(file);
+ break;
+ case FORMAT_SUBUNIT_V2:
+ report->format = FORMAT_SUBUNIT_V2;
+ report->suites = parse_subunit_v2(file);
+ break;
+ case FORMAT_UNKNOWN:
+ report->format = FORMAT_UNKNOWN;
+ return report;
+ }
+ fclose(file);
+
+ report->path = (unsigned char*)strdup(path);
+
+ int length = 20;
+ unsigned char digest[length];
+ SHA1_CTX ctx;
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, report->path, strlen(path));
+ SHA1Final(digest, &ctx);
+
+ report->id = calloc(length, sizeof(unsigned char*));
+ digest_to_str(report->id, digest, length);
+
+ struct stat sb;
+ if (stat(path, &sb) == -1) {
+ perror("cannot open specified path");
+ return NULL;
+ }
+ report->time = sb.st_mtime;
+
+ return report;
+}
+
+struct tailq_report *is_report_exists(struct reportq *reports, const char* report_id) {
+
+ tailq_report *report_item = NULL;
+ TAILQ_FOREACH(report_item, reports, entries) {
+ if (strcmp(report_id, (char*)report_item->id) == 0) {
+ break;
+ }
+ }
+
+ return report_item;
+}
+
+/*
+static int cmp_date(const void *p1, const void *p2) {
+ return strcmp(* (char * const *) p1, * (char * const *) p2);
+}
+
+struct reportq *sort_reports(struct reportq *reports) {
+ return reports;
+}
+*/
+
+int num_by_status_class(struct tailq_report *report, enum test_status_class c) {
+
+ int number = 0;
+ if (report->suites != NULL) {
+ tailq_suite *suite_item = NULL;
+ TAILQ_FOREACH(suite_item, report->suites, entries) {
+ if (!TAILQ_EMPTY(suite_item->tests)) {
+ tailq_test *test_item = NULL;
+ TAILQ_FOREACH(test_item, suite_item->tests, entries) {
+ if (class_by_status(test_item->status) == c) number++;
+ }
+ }
+ }
+ }
+
+ return number;
+}
+
+enum test_status_class class_by_status(enum test_status status) {
+
+ switch (status) {
+ case STATUS_OK:
+ return STATUS_CLASS_PASS;
+ case STATUS_PASS:
+ return STATUS_CLASS_PASS;
+ case STATUS_SUCCESS:
+ return STATUS_CLASS_PASS;
+ case STATUS_NOTOK:
+ return STATUS_CLASS_FAIL;
+ case STATUS_ERROR:
+ return STATUS_CLASS_FAIL;
+ case STATUS_FAILURE:
+ return STATUS_CLASS_FAIL;
+ case STATUS_FAILED:
+ return STATUS_CLASS_FAIL;
+ case STATUS_XFAILURE:
+ return STATUS_CLASS_FAIL;
+ case STATUS_UXSUCCESS:
+ return STATUS_CLASS_FAIL;
+ case STATUS_MISSING:
+ return STATUS_CLASS_SKIP;
+ case STATUS_TODO:
+ return STATUS_CLASS_SKIP;
+ case STATUS_SKIP:
+ return STATUS_CLASS_SKIP;
+ case STATUS_SKIPPED:
+ return STATUS_CLASS_SKIP;
+ case STATUS_UNDEFINED:
+ return STATUS_CLASS_SKIP;
+ case STATUS_ENUMERATION:
+ return STATUS_CLASS_SKIP;
+ case STATUS_INPROGRESS:
+ return STATUS_CLASS_SKIP;
+ default:
+ return STATUS_CLASS_SKIP;
+ }
+}
+
+struct reportq*
+process_dir(char *path) {
+
+ DIR *d;
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if ((d = fdopendir(fd)) == NULL) {
+ printf("failed to open dir %s\n", path);
+ close(fd);
+ return NULL;
+ }
+
+ struct reportq *reports;
+ reports = calloc(1, sizeof(struct reportq));
+ if (reports == NULL) {
+ return NULL;
+ }
+ TAILQ_INIT(reports);
+
+ struct dirent *dir;
+ char *path_file = (char *) NULL;
+ tailq_report *report_item;
+ while ((dir = readdir(d)) != NULL) {
+ char *basename;
+ basename = dir->d_name;
+ if ((strcmp("..", basename) == 0) || (strcmp(".", basename) == 0)) {
+ continue;
+ }
+ /* TODO: recursive search in directories */
+ int path_len = strlen(path) + strlen(basename) + 2;
+ path_file = calloc(path_len, sizeof(char));
+ if (path_file == NULL) {
+ return NULL;
+ }
+ snprintf(path_file, path_len, "%s/%s", path, basename);
+
+ struct stat path_st;
+ if (stat(path, &path_st) == -1) {
+ perror("cannot open specified path");
+ return NULL;
+ }
+ if (S_ISREG(path_st.st_mode)) {
+ continue;
+ }
+ report_item = process_file(path_file);
+ if (report_item->format != FORMAT_UNKNOWN) {
+ TAILQ_INSERT_TAIL(reports, report_item, entries);
+ }
+ free(path_file);
+ }
+ close(fd);
+ closedir(d);
+
+ return reports;
+}
+
+struct reportq*
+process_db(char *path)
+{
+ /* not implemented */
+ return NULL;
+}
+
+int
+check_sqlite(char *path)
+{
+ /* not implemented */
+ /* see https://www.sqlite.org/fileformat.html */
+ return 1;
+}
+
+struct reportq *filter_reports(struct reportq *reports, const char *qsearch) {
+
+ if (qsearch == NULL || reports == NULL) {
+ return NULL;
+ }
+
+ struct reportq *filtered;
+ filtered = calloc(1, sizeof(struct reportq));
+ if (filtered == NULL) {
+ return NULL;
+ }
+ TAILQ_INIT(filtered);
+
+ tailq_report *report_item = NULL;
+ TAILQ_FOREACH(report_item, reports, entries) {
+ if (report_item->suites != NULL) {
+ tailq_suite *suite_item = NULL;
+ int matched = 0;
+ TAILQ_FOREACH(suite_item, report_item->suites, entries) {
+ if (matched == 1) {
+ break;
+ }
+ if (!TAILQ_EMPTY(suite_item->tests)) {
+ tailq_test *test_item = NULL;
+ TAILQ_FOREACH(test_item, suite_item->tests, entries) {
+ if (strstr(test_item->name, qsearch) != NULL) {
+ TAILQ_INSERT_TAIL(filtered, report_item, entries);
+ matched = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return reports;
+}
blob - /dev/null
blob + 869dde5a9a1065c5df51305ce12b4fd0ca0d612b (mode 644)
--- /dev/null
+++ libtestoutput/parse_common.h
+/*
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PARSE_COMMON_H
+#define PARSE_COMMON_H
+
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+enum test_format {
+ FORMAT_UNKNOWN,
+ FORMAT_TAP13,
+ FORMAT_JUNIT,
+ FORMAT_SUBUNIT_V1,
+ FORMAT_SUBUNIT_V2
+};
+
+enum test_status {
+ STATUS_OK, /* TestAnythingProtocol */
+ STATUS_NOTOK, /* TestAnythingProtocol */
+ STATUS_MISSING, /* TestAnythingProtocol */
+ STATUS_TODO, /* TestAnythingProtocol */
+ STATUS_SKIP, /* TestAnythingProtocol */
+
+ STATUS_UNDEFINED, /* Subunit */
+ STATUS_ENUMERATION, /* Subunit */
+ STATUS_INPROGRESS, /* Subunit */
+ STATUS_SUCCESS, /* Subunit */
+ STATUS_UXSUCCESS, /* Subunit */
+ STATUS_SKIPPED, /* Subunit */
+ STATUS_FAILED, /* Subunit */
+ STATUS_XFAILURE, /* Subunit */
+
+ STATUS_ERROR, /* JUnit */
+ STATUS_FAILURE, /* JUnit */
+ STATUS_PASS /* JUnit */
+};
+
+enum test_status_class {
+ STATUS_CLASS_PASS,
+ STATUS_CLASS_FAIL,
+ STATUS_CLASS_SKIP
+};
+
+struct tailq_test {
+ const char *name;
+ const char *time;
+ const char *comment;
+ const char *error;
+ const char *system_out;
+ const char *system_err;
+ enum test_status status;
+ TAILQ_ENTRY(tailq_test) entries;
+};
+
+TAILQ_HEAD(testq, tailq_test);
+
+struct tailq_suite {
+ const char *name;
+ const char *hostname;
+ const char *timestamp;
+ int n_failures;
+ int n_errors;
+ double time;
+ struct testq *tests;
+ TAILQ_ENTRY(tailq_suite) entries;
+};
+
+TAILQ_HEAD(suiteq, tailq_suite);
+
+struct tailq_report {
+ enum test_format format;
+ struct suiteq *suites;
+ time_t time;
+ unsigned char *id;
+ unsigned char *path;
+ TAILQ_ENTRY(tailq_report) entries;
+};
+
+TAILQ_HEAD(reportq, tailq_report);
+
+typedef struct tailq_test tailq_test;
+typedef struct tailq_suite tailq_suite;
+typedef struct tailq_report tailq_report;
+
+/* cleanup */
+void free_reports(struct reportq *reports);
+void free_suites(struct suiteq *suites);
+void free_tests(struct testq *tests);
+
+void free_report(tailq_report * report);
+void free_suite(tailq_suite * suite);
+void free_test(tailq_test * test);
+
+
+char *get_filename_ext(const char *filename);
+enum test_format detect_format(char *path);
+int check_sqlite(char *path);
+struct reportq *process_db(char *path);
+struct reportq *process_dir(char *path);
+tailq_report *process_file(char *path);
+tailq_test *make_test(char *name, char *time, char *comment);
+unsigned char *digest_to_str(unsigned char *str, unsigned char digest[], unsigned int n);
+struct tailq_report *is_report_exists(struct reportq *reports, const char* report_id);
+
+/*
+static int cmp_date(const void *p1, const void *p2);
+struct reportq *sort_reports(struct reportq *reports);
+*/
+
+int num_by_status_class(struct tailq_report *report, enum test_status_class c);
+enum test_status_class class_by_status(enum test_status status);
+struct reportq *filter_reports(struct reportq *reports, const char *qsearch);
+
+#endif /* PARSE_COMMON_H */
blob - /dev/null
blob + 42eb77426f9c77c82a6a034f977e2c22673f7782 (mode 644)
--- /dev/null
+++ libtestoutput/parse_junit.c
+/*
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include "parse_junit.h"
+
+#ifdef XML_LARGE_SIZE
+#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
+#define XML_FMT_INT_MOD "I64"
+#else
+#define XML_FMT_INT_MOD "ll"
+#endif
+#else
+#define XML_FMT_INT_MOD "l"
+#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_FMT_STR "ls"
+#else
+#define XML_FMT_STR "s"
+#endif
+
+#define BUFFSIZE 8192
+
+/* https://github.com/kristapsdz/divecmd/blob/master/parser.c */
+
+char buf[BUFFSIZE];
+
+tailq_test *test_item;
+tailq_suite *suite_item;
+struct suiteq *suites;
+
+int system_out_flag = 0;
+int system_err_flag = 0;
+int error_flag = 0;
+
+const XML_Char *
+name_to_value(const XML_Char ** attr, const char attr_name[])
+{
+ XML_Char *attr_value = NULL;
+ int i;
+ for (i = 0; attr[i]; i += 2) {
+ if (strcmp(attr[i], attr_name) == 0) {
+ attr_value = calloc(strlen(attr[i + 1]) + 1, sizeof(XML_Char));
+ if (attr_value == NULL) {
+ perror("malloc failed");
+ return (char *) NULL;
+ }
+ strcpy(attr_value, attr[i + 1]);
+ break;
+ }
+ }
+ return attr_value;
+}
+
+static void XMLCALL
+start_handler(void *data, const XML_Char * elem, const XML_Char ** attr)
+{
+ (void) data;
+ if (strcmp(elem, "testsuite") == 0) {
+ suite_item = calloc(1, sizeof(tailq_suite));
+ if (suite_item == NULL) {
+ perror("malloc failed");
+ }
+ suite_item->name = name_to_value(attr, "name");
+ suite_item->hostname = name_to_value(attr, "hostname");
+ suite_item->n_errors = atoi(name_to_value(attr, "errors"));
+ suite_item->n_failures = atoi(name_to_value(attr, "failures"));
+ suite_item->time = atof(name_to_value(attr, "time"));
+ suite_item->timestamp = name_to_value(attr, "timestamp");
+ suite_item->tests = calloc(1, sizeof(struct testq));
+ if (suite_item->tests == NULL) {
+ perror("malloc failed");
+ }
+ TAILQ_INIT(suite_item->tests);
+ } else if (strcmp(elem, "testcase") == 0) {
+ test_item = calloc(1, sizeof(tailq_test));
+ if (test_item == NULL) {
+ perror("malloc failed");
+ };
+ test_item->name = name_to_value(attr, "name");
+ test_item->time = name_to_value(attr, "time");
+ test_item->status = STATUS_PASS;
+ } else if (strcmp(elem, "error") == 0) {
+ error_flag = 1;
+ test_item->status = STATUS_ERROR;
+ test_item->comment = name_to_value(attr, "comment");
+ } else if (strcmp(elem, "failure") == 0) {
+ test_item->status = STATUS_FAILURE;
+ test_item->comment = name_to_value(attr, "comment");
+ } else if (strcmp(elem, "skipped") == 0) {
+ test_item->status = STATUS_SKIPPED;
+ test_item->comment = name_to_value(attr, "comment");
+ } else if (strcmp(elem, "system-out") == 0) {
+ system_out_flag = 1;
+ } else if (strcmp(elem, "system-err") == 0) {
+ system_err_flag = 1;
+ }
+}
+
+static void XMLCALL
+end_handler(void *data, const XML_Char * elem)
+{
+ (void) data;
+ (void) elem;
+
+ if (strcmp(elem, "testsuite") == 0) {
+ /* TODO: check a number of failures and errors */
+ TAILQ_INSERT_TAIL(suites, suite_item, entries);
+ } else if (strcmp(elem, "testcase") == 0) {
+ TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
+ } else if (strcmp(elem, "error") == 0) {
+ error_flag = 0;
+ } else if (strcmp(elem, "system-out") == 0) {
+ system_out_flag = 0;
+ } else if (strcmp(elem, "system-err") == 0) {
+ system_err_flag = 0;
+ }
+}
+
+void
+data_handler(void *data, const char *txt, int txtlen) {
+ (void)data;
+
+ if (error_flag == 1) {
+ /* TODO */
+ test_item->error = (char*)NULL;
+ };
+ if (system_out_flag == 1) {
+ /* TODO */
+ test_item->system_out = (char*)NULL;
+ };
+ if (system_err_flag == 1) {
+ /* TODO */
+ test_item->system_err = (char*)NULL;
+ };
+}
+
+struct suiteq *
+parse_junit(FILE * f)
+{
+ XML_Parser p = XML_ParserCreate(NULL);
+ if (!p) {
+ fprintf(stderr, "Couldn't allocate memory for parser\n");
+ return NULL;
+ }
+ suites = calloc(1, sizeof(struct suiteq));
+ if (suites == NULL) {
+ perror("malloc failed");
+ }
+ TAILQ_INIT(suites);
+
+ XML_UseParserAsHandlerArg(p);
+ XML_SetElementHandler(p, start_handler, end_handler);
+ XML_SetCharacterDataHandler(p, data_handler);
+
+ for (;;) {
+ int len, done;
+ len = fread(buf, 1, BUFFSIZE, f);
+ if (ferror(f)) {
+ fprintf(stderr, "Read error\n");
+ exit(-1);
+ }
+ done = feof(f);
+
+ if (XML_Parse(p, buf, len, done) == XML_STATUS_ERROR) {
+ fprintf(stderr,
+ "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber(p),
+ XML_ErrorString(XML_GetErrorCode(p)));
+ free(test_item);
+ free(suite_item);
+ free_suites(suites);
+ exit(-1);
+ }
+ if (done) {
+ break;
+ }
+ }
+ XML_ParserFree(p);
+
+ return suites;
+}
blob - /dev/null
blob + afe24652dfd93b0aeb5b1d7b1e9dfa0d0336489c (mode 644)
--- /dev/null
+++ libtestoutput/parse_junit.h
+/*
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PARSE_JUNIT_H
+#define PARSE_JUNIT_H
+
+#include <expat.h>
+
+#include "parse_common.h"
+
+struct suiteq *parse_junit(FILE *f);
+
+#endif /* PARSE_JUNIT_H */
blob - /dev/null
blob + bceeb32256adc179553703fb69365c11573cb15c (mode 644)
--- /dev/null
+++ libtestoutput/parse_subunit_v1.c
+/*
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "parse_subunit_v1.h"
+
+const char *
+directive_string(enum directive dir) {
+
+ switch (dir) {
+ case DIR_TEST:
+ return "DIR_TEST";
+ case DIR_SUCCESS:
+ return "DIR_SUCCESS";
+ case DIR_FAILURE:
+ return "DIR_FAILURE";
+ case DIR_ERROR:
+ return "DIR_ERROR";
+ case DIR_SKIP:
+ return "DIR_SKIP";
+ case DIR_XFAIL:
+ return "DIR_XFAIL";
+ case DIR_UXSUCCESS:
+ return "DIR_UXSUCCESS";
+ case DIR_PROGRESS:
+ return "DIR_PROGRESS";
+ case DIR_TAGS:
+ return "DIR_TAGS";
+ case DIR_TIME:
+ return "DIR_TIME";
+ default:
+ return "DIR_UNKNOWN";
+ }
+}
+
+enum directive
+resolve_directive(char * string) {
+
+ assert(string != (char*)NULL);
+
+ if ((strcasecmp(string, "test") == 0) ||
+ (strcasecmp(string, "testing") == 0) ||
+ (strcasecmp(string, "test:") == 0) ||
+ (strcasecmp(string, "testing:") == 0)) {
+ return DIR_TEST;
+ } else if ((strcasecmp(string, "success") == 0) ||
+ (strcasecmp(string, "success:") == 0) ||
+ (strcasecmp(string, "successful") == 0) ||
+ (strcasecmp(string, "successful:") == 0)) {
+ return DIR_SUCCESS;
+ } else if (strcasecmp(string, "failure:") == 0) {
+ return DIR_FAILURE;
+ } else if (strcasecmp(string, "error:") == 0) {
+ return DIR_ERROR;
+ } else if ((strcasecmp(string, "skip") == 0) ||
+ (strcasecmp(string, "skip:") == 0)) {
+ return DIR_SKIP;
+ } else if ((strcasecmp(string, "xfail") == 0) ||
+ (strcasecmp(string, "xfail:") == 0)) {
+ return DIR_XFAIL;
+ } else if ((strcasecmp(string, "uxsuccess") == 0) ||
+ (strcasecmp(string, "uxsuccess:") == 0)) {
+ return DIR_UXSUCCESS;
+ } else if (strcasecmp(string, "progress:") == 0) {
+ return DIR_PROGRESS;
+ } else if (strcasecmp(string, "tags:") == 0) {
+ return DIR_TAGS;
+ } else if (strcasecmp(string, "time:") == 0) {
+ return DIR_TIME;
+ } else {
+ /* unknown directive */
+ }
+
+ return DIR_TEST;
+}
+
+struct tm* parse_iso8601_time(char* date_str, char* time_str) {
+ assert(date_str != (char*)NULL);
+ assert(time_str != (char*)NULL);
+
+ struct tm * t;
+ t = malloc(sizeof(struct tm));
+ if (t == NULL) {
+ perror("failed to malloc");
+ return NULL;
+ }
+ if (sscanf(date_str, "%d-%d-%d", &t->tm_year, &t->tm_mon, &t->tm_mday) == 3) {
+ assert(t->tm_year > 2000);
+ assert((t->tm_mon <= 12) && (t->tm_mon >= 0));
+ assert((t->tm_mday <= 31) && (t->tm_mday >= 0));
+ }
+
+ if (sscanf(time_str, "%d:%d:%dZ", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3) {
+ assert((t->tm_hour <= 23) && (t->tm_hour >= 0));
+ assert((t->tm_min <= 60) && (t->tm_min >= 0));
+ assert((t->tm_sec <= 60) && (t->tm_sec >= 0));
+ }
+
+ return t;
+}
+
+void read_tok() {
+ char* token = (char*)NULL;
+ while (token != NULL) { token = strtok(NULL, " \t"); };
+}
+
+tailq_test* read_test() {
+
+ tailq_test *test_item = NULL;
+ test_item = calloc(1, sizeof(tailq_test));
+ if (test_item == NULL) {
+ perror("failed to malloc");
+ return NULL;
+ }
+
+ char *token, *name;
+ token = strtok(NULL, " \t");
+ if (strcmp(token, "test") == 0) {
+ token = strtok(NULL, " \t");
+ assert(token != NULL);
+ }
+ name = (char*)calloc(strlen(token) + 1, sizeof(char));
+ strcpy(name, token);
+ test_item->name = name;
+
+ read_tok();
+
+ return test_item;
+}
+
+tailq_test* parse_line_subunit_v1(char* string) {
+
+ assert(string != (char*)NULL);
+
+ char *dir;
+ char buffer[1024];
+ strcpy(buffer, string);
+ dir = strtok(buffer, " \t");
+
+ tailq_test *test_item = NULL;
+ enum directive d;
+ switch (d = resolve_directive(dir)) {
+ case DIR_TEST:
+ /* testline is useless, but we should check conformance to spec */
+ read_tok();
+ break;
+ case DIR_SUCCESS:
+ test_item = read_test();
+ test_item->status = STATUS_SUCCESS;
+ break;
+ case DIR_FAILURE:
+ test_item = read_test();
+ test_item->status = STATUS_FAILURE;
+ break;
+ case DIR_ERROR:
+ test_item = read_test();
+ test_item->status = STATUS_FAILED;
+ break;
+ case DIR_SKIP:
+ test_item = read_test();
+ test_item->status = STATUS_SKIPPED;
+ break;
+ case DIR_XFAIL:
+ test_item = read_test();
+ test_item->status = STATUS_XFAILURE;
+ break;
+ case DIR_UXSUCCESS:
+ test_item = read_test();
+ test_item->status = STATUS_UXSUCCESS;
+ break;
+ case DIR_PROGRESS:
+ /* testline is useless, but we should check conformance to spec */
+ read_tok();
+ break;
+ case DIR_TAGS:
+ /* testline is useless, but we should check conformance to spec */
+ read_tok();
+ break;
+ case DIR_TIME:
+ /* testline is useless, but we should check conformance to spec */
+ /*
+ char *date = strtok(NULL, " \t");
+ assert(date != (char*)NULL);
+ char *time = strtok(NULL, " \t");
+ assert(time != (char*)NULL);
+ struct tm *t = parse_iso8601_time(date, time);
+ printf("Time: %s\n", asctime(t));
+ */
+
+ read_tok();
+ break;
+ default:
+ read_tok();
+ return NULL;
+ }
+
+ return test_item;
+}
+
+struct suiteq* parse_subunit_v1(FILE *stream) {
+
+ tailq_suite *suite_item;
+ suite_item = calloc(1, sizeof(tailq_suite));
+ if (suite_item == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
+ /* TODO: n_errors, n_failures */
+ suite_item->tests = calloc(1, sizeof(struct testq));
+ if (suite_item->tests == NULL) {
+ perror("malloc failed");
+ free(suite_item);
+ return NULL;
+ };
+ TAILQ_INIT(suite_item->tests);
+
+ char line[1024];
+ tailq_test *test_item = NULL;
+ while (fgets(line, sizeof(line), stream)) {
+ test_item = parse_line_subunit_v1(line);
+ if (test_item != NULL) {
+ TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
+ }
+ if (feof(stream)) {
+ break;
+ }
+ }
+
+ struct suiteq *suites = NULL;
+ suites = calloc(1, sizeof(struct suiteq));
+ if (suites == NULL) {
+ perror("malloc failed");
+ };
+ TAILQ_INIT(suites);
+ TAILQ_INSERT_TAIL(suites, suite_item, entries);
+
+ return suites;
+}
blob - /dev/null
blob + 48343a4ba6c96a3cee80604105d629445af8fa21 (mode 644)
--- /dev/null
+++ libtestoutput/parse_subunit_v1.h
+/*
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PARSE_SUBUNIT_V1_H
+#define PARSE_SUBUNIT_V1_H
+
+#include "parse_common.h"
+
+enum directive {
+ DIR_TEST,
+ DIR_SUCCESS,
+ DIR_FAILURE,
+ DIR_ERROR,
+ DIR_SKIP,
+ DIR_XFAIL,
+ DIR_UXSUCCESS,
+ DIR_PROGRESS,
+ DIR_TAGS,
+ DIR_TIME
+};
+
+tailq_test* parse_line_subunit_v1(char* string);
+struct suiteq* parse_subunit_v1(FILE* stream);
+struct tm* parse_iso8601_time(char* date_str, char* time_str);
+enum directive resolve_directive(char* string);
+const char* directive_string(enum directive dir);
+void read_tok();
+tailq_test* read_test();
+
+#endif /* PARSE_SUBUNIT_V1_H */
blob - /dev/null
blob + 36b2df8bee0459bc4ddb56d66a00278479cfd188 (mode 644)
--- /dev/null
+++ libtestoutput/parse_subunit_v2.c
+/*
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <zlib.h>
+
+#include "parse_subunit_v2.h"
+
+// https://github.com/testing-cabal/subunit/blob/master/python/subunit/v2.py#L412
+// https://github.com/testing-cabal/subunit
+
+#define HI(x) ((x) >> 8)
+#define LO(x) ((x) & 0xFF)
+
+int is_subunit_v2(char* path)
+{
+ FILE *file;
+ file = fopen(path, "r");
+ if (file == NULL) {
+ printf("failed to open file %s\n", path);
+ return -1;
+ }
+
+ uint8_t signature = 0;
+ int n_bytes = 0;
+ n_bytes = fread(&signature, 1, 1, file);
+ fclose(file);
+ if (n_bytes == 0) {
+ return -1;
+ }
+ if (signature == SUBUNIT_SIGNATURE) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+uint32_t read_field(FILE * stream)
+{
+
+ uint32_t field_value = 0;
+ uint8_t byte = 0, byte0 = 0;
+ uint16_t buf = 0;
+ uint8_t prefix = 0;
+
+ int n_bytes = 0;
+
+ n_bytes = fread(&byte, 1, 1, stream);
+ if (n_bytes == 0) {
+ return 0;
+ }
+ prefix = byte >> 6;
+ byte0 = byte & 0x3f;
+ if (prefix == 0x00) {
+ field_value = byte0;
+ } else if (prefix == 0x40) {
+ n_bytes = fread(&byte, 1, 1, stream);
+ if (n_bytes == 0) {
+ return 0;
+ }
+ field_value = (byte0 << 8) | byte;
+ } else if (prefix == 0x80) {
+ n_bytes = fread(&buf, 2, 1, stream);
+ if (n_bytes == 0) {
+ return 0;
+ }
+ field_value = (byte << 16) | buf;
+ } else {
+ n_bytes = fread(&buf, 1, 2, stream);
+ if (n_bytes == 0) {
+ return 0;
+ }
+ field_value = (byte0 << 24) | buf << 8;
+
+ n_bytes = fread(&byte, 1, 1, stream);
+ if (n_bytes == 0) {
+ return 0;
+ }
+ field_value = field_value | byte;
+ };
+
+ return field_value;
+}
+
+struct suiteq *
+parse_subunit_v2(FILE * stream)
+{
+ tailq_suite *suite_item;
+ suite_item = calloc(1, sizeof(tailq_suite));
+ if (suite_item == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
+
+ suite_item->tests = calloc(1, sizeof(struct testq));
+ if (suite_item->tests == NULL) {
+ perror("malloc failed");
+ free_suite(suite_item);
+ return NULL;
+ }
+
+ TAILQ_INIT(suite_item->tests);
+ tailq_test *test_item = NULL;
+
+ test_item = read_subunit_v2_packet(stream);
+ if (test_item != NULL)
+ TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
+
+ /*
+ while (!feof(stream)) {
+ test_item = read_packet(stream);
+ if (test_item != NULL)
+ TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
+ else
+ {
+ free_tests(suite_item->tests);
+ free_suite(suite_item);
+ return NULL;
+ }
+ }
+ */
+
+ struct suiteq *suites = NULL;
+ suites = calloc(1, sizeof(struct suiteq));
+ if (suites == NULL) {
+ perror("malloc failed");
+ free_suite(suite_item);
+ }
+ TAILQ_INIT(suites);
+ TAILQ_INSERT_TAIL(suites, suite_item, entries);
+
+ return suites;
+}
+
+tailq_test *
+read_subunit_v2_packet(FILE * stream)
+{
+ subunit_header header;
+ int n_bytes = 0;
+ n_bytes = fread(&header, sizeof(subunit_header), 1, stream);
+ if ((n_bytes == 0) || (n_bytes < (int)sizeof(subunit_header))) {
+ return NULL;
+ }
+ tailq_test *test_item;
+ test_item = calloc(1, sizeof(tailq_test));
+ if (test_item == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
+
+ uint16_t flags = htons(header.flags);
+ printf("SIGNATURE: %02hhX\n", header.signature);
+ printf("FLAGS: %02hX\n", flags);
+ assert(header.signature == SUBUNIT_SIGNATURE);
+
+ int8_t version;
+ version = HI(flags) >> 4;
+ printf("\tVERSION: %d\n", version);
+ assert(version == SUBUNIT_VERSION);
+
+ /*
+ int8_t status;
+ status = flags & 0x0007;
+ printf("\tSTATUS: %d\n", status);
+ test_item->status = status;
+ assert(status <= 0x0007);
+
+ uint32_t field_value;
+ field_value = read_field(stream);
+ printf("TOTAL LENGTH: %u\n", field_value);
+ assert(field_value < PACKET_MAX_LENGTH);
+
+ if (flags & FLAG_TIMESTAMP) {
+ printf("FLAG_TIMESTAMP ");
+ field_value = read_field(stream);
+ printf("%08X\n", field_value);
+ };
+ if (flags & FLAG_TEST_ID) {
+ printf("FLAG_TEST_ID ");
+ field_value = read_field(stream);
+ printf("%08X\n", field_value);
+ };
+ if (flags & FLAG_TAGS) {
+ printf("FLAG_TAGS ");
+ field_value = read_field(stream);
+ printf("%02X\n", field_value);
+ };
+ if (flags & FLAG_MIME_TYPE) {
+ printf("FLAG_MIME_TYPE ");
+ field_value = read_field(stream);
+ printf("%02X\n", field_value);
+ };
+ if (flags & FLAG_FILE_CONTENT) {
+ printf("FLAG_FILE_CONTENT ");
+ field_value = read_field(stream);
+ printf("%08X\n", field_value);
+ };
+ if (flags & FLAG_ROUTE_CODE) {
+ printf("FLAG_ROUTE_CODE ");
+ field_value = read_field(stream);
+ printf("%08X\n", field_value);
+ };
+ if (flags & FLAG_EOF) {
+ printf("FLAG_EOF\n");
+ };
+ if (flags & FLAG_RUNNABLE) {
+ printf("FLAG_RUNNABLE\n");
+ };
+ printf("CRC32: ");
+ field_value = read_field(stream);
+ printf("%08X\n", field_value);
+ */
+
+ return test_item;
+}
+
+
+/*
+
+CRC32
+const char *s = "0xb30x2901b329010c03666f6f";
+printf("%lX, should be %X\n", crc32(0, (const void*)s, strlen(s)), sample_crc32);
+http://bxr.su/OpenBSD/bin/md5/crc.c
+
+https://rosettacode.org/wiki/CRC-32#C
+http://csbruce.com/software/crc32.c
+
+Parse timestamp
+int y, M, d, h, m;
+float sec;
+char *dateStr = "2014-11-12T19:12:14.505Z";
+sscanf(dateStr, "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &sec);
+https://github.com/mlabbe/c_date_parse
+
+UTF-8
+https://github.com/benkasminbullock/unicode-c/blob/master/unicode.c
+https://github.com/clibs/cutef8
+
+*/
blob - /dev/null
blob + dab7dd56d19d153daff3ed9ed2453733fa616559 (mode 644)
--- /dev/null
+++ libtestoutput/parse_subunit_v2.h
+/*
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PARSE_SUBUNIT_V2_H
+#define PARSE_SUBUNIT_V2_H
+
+#include <stdint.h>
+
+#include "parse_common.h"
+
+#define SUBUNIT_SIGNATURE 0xB3
+#define SUBUNIT_VERSION 0x02
+#define PACKET_MAX_LENGTH 4194303
+
+#define FLAG_TEST_ID 0x0800
+#define FLAG_ROUTE_CODE 0x0400
+#define FLAG_TIMESTAMP 0x0200
+#define FLAG_RUNNABLE 0x0100
+#define FLAG_TAGS 0x0080
+#define FLAG_MIME_TYPE 0x0020
+#define FLAG_EOF 0x0010
+#define FLAG_FILE_CONTENT 0x0040
+
+struct subunit_header {
+ uint8_t signature;
+ uint16_t flags;
+} __attribute__ ((packed));
+
+typedef struct subunit_header subunit_header;
+
+typedef uint32_t timestamp;
+
+uint32_t read_field(FILE *stream);
+tailq_test *read_subunit_v2_packet(FILE *stream);
+struct suiteq *parse_subunit_v2(FILE *stream);
+int is_subunit_v2(char* path);
+
+#endif /* PARSE_SUBUNIT_V2_H */
blob - /dev/null
blob + b00ba88cb5f99aba4c095d5b51e2a9adc60f6831 (mode 644)
--- /dev/null
+++ libtestoutput/parse_testanything.c
+/*
+ * Copyright © 2015-2017 Katherine Flavel <kate@elide.org>
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <string.h>
+#include <strings.h>
+
+#include "parse_common.h"
+#include "parse_testanything.h"
+
+const char *
+ast_status(enum ast_status status)
+{
+ switch (status) {
+ case AST_OK:return "ok";
+ case AST_NOTOK:
+ return "not ok";
+ case AST_MISSING:
+ return "missing";
+ case AST_TODO:
+ return "todo";
+ case AST_SKIP:
+ return "skip";
+
+ default:
+ return "?";
+ }
+}
+
+enum test_status
+test_status(enum ast_status status)
+{
+ switch (status) {
+ case AST_OK:return STATUS_OK;
+ case AST_NOTOK:
+ return STATUS_NOTOK;
+ case AST_MISSING:
+ return STATUS_MISSING;
+ case AST_TODO:
+ return STATUS_TODO;
+ case AST_SKIP:
+ return STATUS_SKIP;
+ default:
+ return STATUS_MISSING;
+ }
+}
+
+struct ast_line *
+ast_line(struct ast_line ** head, const char *text)
+{
+ struct ast_line **tail, *new;
+ size_t z;
+
+ assert(head != NULL);
+ assert(text != NULL);
+
+ z = strlen(text);
+
+ new = malloc(sizeof *new + z + 1);
+ if (new == NULL) {
+ return NULL;
+ }
+ new->text = strcpy((char *) new + sizeof *new, text);
+
+ for (tail = head; *tail != NULL; tail = &(*tail)->next);
+
+ new->next = *tail;
+ *tail = new;
+
+ return new;
+}
+
+struct ast_test *
+ast_test(struct ast_test ** head, enum ast_status status, const char *name)
+{
+ struct ast_test **tail, *new;
+
+ assert(head != NULL);
+
+ new = malloc(sizeof *new +
+ (name == NULL ? 0 : strlen(name) + 1));
+ if (new == NULL) {
+ return NULL;
+ }
+ if (name == NULL) {
+ new->name = NULL;
+ } else {
+ new->name = strcpy((char *) new + sizeof *new, name);
+ }
+
+ new->rep = 1;
+ new->line = NULL;
+ new->status = status;
+
+ for (tail = head; *tail != NULL; tail = &(*tail)->next);
+
+ new->next = *tail;
+ *tail = new;
+
+ return new;
+}
+
+static void
+rtrim(char *s)
+{
+ char *p;
+
+ assert(s != NULL);
+
+ if (*s == '\0') {
+ return;
+ }
+ p = s + strlen(s) - 1;
+
+ assert(strlen(s) > 0);
+
+ while (p >= s && isspace((unsigned char) *p)) {
+ *p-- = '\0';
+ }
+}
+
+static void
+plan(const char *line, int *a, int *b)
+{
+ assert(line != NULL);
+ assert(a != NULL);
+ assert(b != NULL);
+
+ if (*b != -1) {
+ fprintf(stderr, "syntax error: duplicate plan: %s\n", line);
+ exit(1);
+ }
+ if (2 != sscanf(line, "%d..%d", a, b)) {
+ fprintf(stderr, "syntax error: missing a..b\n");
+ exit(1);
+ }
+ if (*a < 0 && *b < *a) {
+ fprintf(stderr, "error: invalid plan: %d..%d\n", *a, *b);
+ exit(1);
+ }
+}
+
+static void
+yaml(struct ast_test * test, const char *line)
+{
+ assert(test != NULL);
+
+ while (test->next != NULL)
+ test = test->next;
+
+ if (!ast_line(&test->line, line)) {
+ perror("ast_line");
+ exit(1);
+ }
+}
+
+static void
+gap(struct ast_test ** head, int *a, int b)
+{
+ struct ast_test *new;
+
+ assert(head != NULL);
+ assert(a != NULL);
+ assert(*a <= b);
+
+ while (*a < b) {
+ new = ast_test(head, AST_MISSING, NULL);
+ if (new == NULL) {
+ perror("ast_test");
+ exit(1);
+ }
+ *a += 1;
+ }
+}
+
+static void
+starttest(struct ast_test ** head, const char *line, int *a, int b)
+{
+ struct ast_test *new;
+ enum ast_status status;
+ int i;
+ int n;
+
+ assert(a != NULL);
+ assert(head != NULL);
+ assert(line != NULL);
+ assert(b == -1 || *a <= b);
+
+ if (0 == strncmp(line, "not ", 4)) {
+ line += 4;
+ status = AST_NOTOK;
+ } else {
+ status = AST_OK;
+ }
+
+ if (1 != sscanf(line, "ok %d - %n", &i, &n)) {
+ fprintf(stderr, "syntax error: expected 'ok - ': %s\n", line);
+ exit(1);
+ }
+ line += n;
+
+ if (i < *a || (b != -1 && i > b)) {
+ fprintf(stderr, "error: test %d out of order; expected %d\n", i, *a);
+ exit(1);
+ }
+ gap(head, a, i);
+
+ new = ast_test(head, status, line);
+ if (new == NULL) {
+ perror("ast_test");
+ exit(1);
+ }
+ *a += 1;
+}
+
+void
+print(FILE * f, const struct ast_test * tests)
+{
+ const struct ast_test *test;
+ const struct ast_line *line;
+ unsigned int n;
+
+ assert(f != NULL);
+ assert(tests != NULL);
+
+ for (test = tests, n = 1; test != NULL; test = test->next, n++) {
+ fprintf(f, "\t<test status='%s'",
+ ast_status(test->status));
+
+ fprintf(f, " n='%u'", n);
+
+ if (test->rep > 1) {
+ fprintf(f, " rep='%u'", test->rep);
+ }
+ if (test->name != NULL) {
+ fprintf(f, " name='");
+ fprintf(f, "%s", test->name);
+ fprintf(f, "'");
+ }
+ fprintf(f, "%s>\n", test->line != NULL ? "" : "/");
+
+ if (test->line == NULL) {
+ continue;
+ }
+ for (line = test->line; line != NULL; line = line->next) {
+ fprintf(f, "%s%s",
+ line->text,
+ line->next != NULL ? "\n" : "");
+ }
+ }
+}
+
+struct ast_test *
+parse_testanything_raw(FILE * f)
+{
+ struct ast_test *tests = NULL;
+ int a, b;
+ int fold = 0;
+
+ {
+ char *line, *comment;
+ size_t n;
+
+ line = NULL;
+ a = 1;
+ b = -1; /* no plan */
+ n = 0;
+
+ while (-1 != getline(&line, &n, f)) {
+ line[strcspn(line, "\n")] = '\0';
+
+ comment = strchr(line, '#');
+ if (comment != NULL) {
+ *comment++ = '\0';
+ }
+ rtrim(line);
+
+ if (comment != NULL) {
+ comment += strspn(comment, " \t");
+
+ /* TODO: only if we're actually in a test */
+
+ if (0 == strncasecmp(comment, "todo", 4)) {
+ tests->status = AST_TODO;
+ }
+ if (0 == strncasecmp(comment, "skip", 4)) {
+ tests->status = AST_SKIP;
+ }
+ /* TODO: add comment line anyway */
+ /*
+ * TODO: add as yaml line printf("\t<!-- %s
+ * -->\n", comment);
+ */
+ }
+ switch (line[0]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ plan(line, &a, &b);
+ continue;
+
+ case 'n':
+ case 'o':
+ starttest(&tests, line, &a, b);
+ continue;
+
+ case '\v':
+ case '\t':
+ case '\f':
+ case '\r':
+ case '\n':
+ case ' ':
+ if (tests == NULL) {
+ fprintf(stderr, "stray text: %s\n", line);
+ continue;
+ }
+ yaml(tests, line);
+ continue;
+ }
+ }
+
+ gap(&tests, &a, b + 1);
+ }
+
+ if (fold) {
+ struct ast_test *test, *next;
+
+ for (test = tests; test != NULL; test = next) {
+ next = test->next;
+ if (next == NULL) {
+ continue;
+ }
+ if (0 != strcmp(test->name, next->name)) {
+ continue;
+ }
+ if (test->status != next->status) {
+ continue;
+ }
+ if (test->line != NULL || next->line != NULL) {
+ continue;
+ }
+ test->rep++;
+ test->next = next->next;
+ next = test;
+
+ /* TODO: free next */
+ }
+ }
+ /* TODO: warn about duplicate test names */
+ /* TODO: remove ast_test * tests here */
+
+ /* print(stdout, tests); */
+ return tests;
+}
+
+struct suiteq *
+parse_testanything(FILE * f)
+{
+ tailq_suite *suite_item = NULL;
+ suite_item = calloc(1, sizeof(tailq_suite));
+ if (suite_item == NULL) {
+ perror("malloc failed");
+ }
+ suite_item->n_errors = 0;
+ suite_item->n_failures = 0;
+ suite_item->tests = calloc(1, sizeof(struct testq));
+ if (suite_item->tests == NULL) {
+ perror("malloc failed");
+ free(suite_item);
+ }
+ TAILQ_INIT(suite_item->tests);
+
+ struct ast_test *tests, *current;
+ tests = parse_testanything_raw(f);
+ tailq_test *test_item;
+ current = tests;
+ while (current != NULL) {
+ test_item = calloc(1, sizeof(tailq_test));
+ if (test_item == NULL) {
+ perror("malloc failed");
+ free_tests(suite_item->tests);
+ free(suite_item);
+ return NULL;
+ }
+ char *name = calloc(strlen(current->name) + 1, sizeof(char));
+ if (name == NULL) {
+ perror("malloc failed");
+ free_tests(suite_item->tests);
+ free(suite_item);
+ free(test_item);
+ return NULL;
+ }
+ test_item->name = strcpy(name, current->name);
+ test_item->status = test_status(current->status);
+ TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
+ current = current->next;
+ /* TODO: remove ast_test item */
+ }
+
+ struct suiteq *suites;
+ suites = calloc(1, sizeof(struct suiteq));
+ if (suites == NULL) {
+ free_tests(suite_item->tests);
+ free(suite_item);
+ perror("malloc failed");
+ return NULL;
+ }
+ TAILQ_INIT(suites);
+ TAILQ_INSERT_TAIL(suites, suite_item, entries);
+
+ return suites;
+}
blob - /dev/null
blob + be3329125d21b053e7d6935519d45bb48347f934 (mode 644)
--- /dev/null
+++ libtestoutput/parse_testanything.h
+/*
+ * Copyright © 2015-2017 Katherine Flavel <kate@elide.org>
+ * Copyright © 2018 Sergey Bronnikov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PARSE_TESTANYTHING_H
+#define PARSE_TESTANYTHING_H
+
+enum ast_status {
+ AST_OK,
+ AST_NOTOK,
+ AST_MISSING,
+ AST_TODO,
+ AST_SKIP
+};
+
+struct ast_line {
+ /* TODO: comment flag */
+ const char *text;
+ struct ast_line *next;
+};
+
+struct ast_test {
+ const char *name;
+ enum ast_status status;
+ unsigned int rep;
+ struct ast_line *line;
+ struct ast_test *next;
+};
+
+const char *
+ast_status(enum ast_status status);
+
+struct ast_line *
+ast_line(struct ast_line **head, const char *text);
+
+struct ast_test *
+ast_test(struct ast_test **head, enum ast_status status, const char *name);
+
+void
+print(FILE *f, const struct ast_test *tests);
+
+struct ast_test *parse_testanything_raw(FILE *f);
+struct suiteq *parse_testanything(FILE *f);
+
+#endif /* PARSE_TESTANYTHING_H */
blob - /dev/null
blob + cc52dcf96354ebde280ad8a5f144a841070257ff (mode 644)
--- /dev/null
+++ libtestoutput/sha1.c
+/* from valgrind tests */
+
+/* ================ sha1.c ================ */
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#if defined __x86_64__
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#define SHA1HANDSOFF
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <sys/param.h>
+
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+#define blk0(i) block->l[i]
+#else
+#error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
+{
+ uint32_t a, b, c, d, e;
+ typedef union {
+ unsigned char c[64];
+ uint32_t l[16];
+ } CHAR64LONG16;
+#ifdef SHA1HANDSOFF
+ CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+ memcpy(block, buffer, 64);
+#else
+ /* The following had better never be used because it causes the
+ * pointer-to-const buffer to be cast into a pointer to non-const.
+ * And the result is written through. I threw a "const" in, hoping
+ * this will cause a diagnostic.
+ */
+ CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+ memset(block, '\0', sizeof(block));
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)
+{
+ uint32_t i, j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+ unsigned i;
+ unsigned char finalcount[8];
+ unsigned char c;
+
+#if 0 /* untested "improvement" by DHR */
+ /* Convert context->count to a sequence of bytes
+ * in finalcount. Second element first, but
+ * big-endian order within element.
+ * But we do it all backwards.
+ */
+ unsigned char *fcp = &finalcount[8];
+
+ for (i = 0; i < 2; i++)
+ {
+ uint32_t t = context->count[i];
+ int j;
+
+ for (j = 0; j < 4; t >>= 8, j++)
+ *--fcp = (unsigned char) t;
+ }
+#else
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+#endif
+ c = 0200;
+ SHA1Update(context, &c, 1);
+ while ((context->count[0] & 504) != 448) {
+ c = 0000;
+ SHA1Update(context, &c, 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
+/* ================ end of sha1.c ================ */
blob - /dev/null
blob + bab0c44368bb83af338fd9696362713379d471f4 (mode 644)
--- /dev/null
+++ libtestoutput/sha1.h
+#ifndef SHA1_H
+#define SHA1_H
+
+/*
+ * SHA-1 in C By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ */
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#endif /* SHA1_H */
blob - /dev/null
blob + 0e076364854abcf210afb061b587a0626e755885 (mode 644)
--- /dev/null
+++ libtestoutput/tests/CMakeLists.txt
+cmake_minimum_required (VERSION 3.9.2)
+
+set(MODULE_NAME "TestLibTestOutput")
+set(MODULE_PREFIX "TEST_LIB_TEST_OUTPUT")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestParseJUnit.c
+ TestParseSubunitV1.c
+ TestParseSubunitV2.c
+ TestParseTestanything.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+include_directories(..)
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+set(${MODULE_PREFIX}_LIBS testoutput ${EXPAT_LIBRARIES} m)
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
blob - /dev/null
blob + 6c5b962dc5e3b7e4c37c492d42d42a17f8e6e1f7 (mode 644)
--- /dev/null
+++ libtestoutput/tests/TestParseJUnit.c
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "parse_common.h"
+#include "parse_junit.h"
+
+#define SAMPLE_FILE_JUNIT "samples/junit.xml"
+
+void TestParseJUnit()
+{
+ FILE *file;
+ const char *name = SAMPLE_FILE_JUNIT;
+
+ file = fopen(name, "r");
+ assert(file != NULL);
+ struct suiteq *report = parse_junit(file);
+ assert(report != NULL);
+ fclose(file);
+}
blob - /dev/null
blob + 1447d07375029cc37b95714424fa4e5b1b9f14b8 (mode 644)
--- /dev/null
+++ libtestoutput/tests/TestParseSubunitV1.c
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "parse_common.h"
+#include "parse_subunit_v1.h"
+
+#define SAMPLE_FILE_SUBUNIT_V1 "samples/subunit_v1.subunit"
+
+void TestParseSubunitV1()
+{
+ const char *name = SAMPLE_FILE_SUBUNIT_V1;
+ FILE *file;
+
+ file = fopen(name, "r");
+ assert(file == NULL);
+
+ struct suiteq *suites;
+ suites = parse_subunit_v1(file);
+
+ fclose(file);
+ free(suites);
+}
+
+void test_parse_subunit_v1_line()
+{
+ const char *test_sample[] = {
+ "test test LABEL",
+ "testing test LABEL",
+ "test: test LABEL",
+ "testing: test LABEL",
+ "success test LABEL",
+ "success: test LABEL",
+ "successful test LABEL",
+ "successful: test LABEL",
+ "failure: test LABEL",
+ "failure: test LABEL DETAILS",
+ "error: test LABEL",
+ "error: test LABEL DETAILS",
+ "skip test LABEL",
+ "skip: test LABEL",
+ "skip test LABEL DETAILS",
+ "skip: test LABEL DETAILS",
+ "xfail test LABEL",
+ "xfail: test LABEL",
+ "xfail test LABEL DETAILS",
+ "xfail: test LABEL DETAILS",
+ "uxsuccess test LABEL",
+ "uxsuccess: test LABEL",
+ "uxsuccess test LABEL DETAILS",
+ "uxsuccess: test LABEL DETAILS",
+ "progress: +10",
+ "progress: -14",
+ "progress: push",
+ "progress: pop",
+ "tags: -small +big",
+ "time: 2018-09-10 23:59:29Z" };
+
+ const char** qq = test_sample;
+ for (int i = 0; i < (int)(sizeof(test_sample)/sizeof(char*)); ++i) {
+ parse_line_subunit_v1((char*)*qq);
+ ++qq;
+ }
+}
blob - /dev/null
blob + 5e64adac93eca52e82b8ed4ddd3d2081e713d605 (mode 644)
--- /dev/null
+++ libtestoutput/tests/TestParseSubunitV2.c
+#define _POSIX_C_SOURCE 200809L
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "parse_common.h"
+#include "parse_subunit_v2.h"
+
+#define SAMPLE_FILE_SUBUNIT_V1 "samples/subunit_v1.subunit"
+#define SAMPLE_FILE_SUBUNIT_V2 "samples/subunit_v2.subunit"
+
+void TestParseSubunitV2()
+{
+ // Packet sample, with test id, runnable set, status=enumeration.
+ // Spaces below are to visually break up:
+ // signature / flags / length / testid / crc32
+ // b3 2901 0c 03666f6f 08555f1b
+ // echo 03666f6f | xxd -p -r
+
+ subunit_header sample_header = { .signature = 0xb3, .flags = ntohs(0x2901) };
+ uint16_t sample_length = 0x0c;
+ uint32_t sample_testid = 0x03666f6f;
+ uint32_t sample_crc32 = 0x08555f1b;
+
+ char* buf = NULL;
+ size_t buf_size = 0;
+ tailq_test * test;
+ FILE* stream = open_memstream(&buf, &buf_size);
+ fwrite(&sample_header, 1, sizeof(sample_header), stream);
+ fwrite(&sample_length, 1, sizeof(sample_length), stream);
+ fwrite(&sample_testid, 1, sizeof(sample_testid), stream);
+ fwrite(&sample_crc32, 1, sizeof(sample_crc32), stream);
+
+ test = read_subunit_v2_packet(stream);
+ fclose(stream);
+
+ assert(strcmp(test->name, "") == 0);
+
+ free(buf);
+ free(test);
+}
+
+void test_is_subunit_v2()
+{
+ const char *file_subunit_v1 = SAMPLE_FILE_SUBUNIT_V1;
+ const char *file_subunit_v2 = SAMPLE_FILE_SUBUNIT_V2;
+
+ assert(is_subunit_v2((char*)file_subunit_v1) == 1);
+ assert(is_subunit_v2((char*)file_subunit_v2) == 0);
+}
+
+void test_parse_subunit_v2()
+{
+ const char *name = SAMPLE_FILE_SUBUNIT_V2;
+ FILE *file;
+
+ file = fopen(name, "r");
+ assert(file == NULL);
+
+ struct suiteq *suites;
+ suites = parse_subunit_v2(file);
+ fclose(file);
+ free(suites);
+}
blob - /dev/null
blob + e696ac518225abf05b15324bd464d584c68fd878 (mode 644)
--- /dev/null
+++ libtestoutput/tests/TestParseTestanything.c
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "parse_common.h"
+#include "parse_testanything.h"
+
+#define SAMPLE_FILE_TESTANYTHING "samples/testanything.tap"
+
+void TestParseTestanything()
+{
+ const char *name = SAMPLE_FILE_TESTANYTHING;
+ FILE *file;
+ file = fopen(name, "r");
+ assert(file == NULL);
+ parse_testanything(file);
+ fclose(file);
+}
blob - 9c558639ec2de2094d577db9f4a1fc7fc73f29ef
blob + cea5f157d1f95acd2f6b996777149973a5f908cd
--- src/CMakeLists.txt
+++ src/CMakeLists.txt
cmake_minimum_required(VERSION 3.9.2)
-set(BIN_SOURCES
+set(SOURCE_FILES
testres.c
metrics.c
ui_common.c
ui_http.c
)
-set(LIB_SOURCES
-parse_common.h
-parse_common.c
-parse_subunit_v1.h
-parse_subunit_v1.c
-parse_subunit_v2.h
-parse_subunit_v2.c
-parse_junit.h
-parse_junit.c
-parse_subunit_v2.c
-parse_testanything.h
-parse_testanything.c
-sha1.h
-sha1.c
-)
-
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wextra -Wfloat-equal")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wundef -Wpointer-arith -Wcast-align -Wshadow")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-enum -Wunreachable-code -Winit-self")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter -Werror -pedantic")
-if (CMAKE_BUILD_TYPE EQUAL "DEBUG")
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
-endif()
-
-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O3")
-set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O0 -g")
-
include(FindEXPAT)
find_package(EXPAT REQUIRED)
-include_directories(${EXPAT_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
-
-add_library(${PROJECT_NAME}-lib ${LIB_SOURCES})
-add_executable(${PROJECT_NAME} ${BIN_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}-lib ${EXPAT_LIBRARIES} m)
+include_directories(${EXPAT_INCLUDE_DIRS} "../libtestoutput")
+add_executable(${PROJECT_NAME} ${SOURCE_FILES})
+target_link_libraries(${PROJECT_NAME} testoutput ${EXPAT_LIBRARIES} m)
blob - af399d8f5bf082b8fbebc952689d7022be0a6307
blob + 806b5dc569fee48d277fd829bb213be0f69829d2
--- src/metrics.c
+++ src/metrics.c
*/
#include <math.h>
+#include <parse_common.h>
#include "metrics.h"
+#include "testres.h"
/* FIXME: passed, failed and skipped calculated twice */
double metric_pass_rate(struct tailq_report *report) {
blob - 76c97ecf12f3f6c639e3c98de9f4f83b413a88f7
blob + c48bee422a42ddd5e241f71b53a60d9a8524d07e
--- src/metrics.h
+++ src/metrics.h
#ifndef METRICS_H
#define METRICS_H
-#include "parse_common.h"
+struct tailq_report;
+struct reportq;
int metric_apfd(struct reportq *reports, char *tc_name);
double metric_tc_avg_time(struct reportq *reports, char *tc_name);
blob - be2d5761df37a96757759ab7d9b343dbac704c39 (mode 644)
blob + /dev/null
--- src/parse_common.c
+++ /dev/null
-/*
- * Copyright © 2018-2019 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <dirent.h>
-#include <stdlib.h>
-
-#include "parse_common.h"
-#include "parse_junit.h"
-#include "parse_subunit_v1.h"
-#include "parse_subunit_v2.h"
-#include "parse_testanything.h"
-#include "sha1.h"
-#include "testres.h"
-
-void
-free_reports(struct reportq * reports)
-{
- tailq_report *report_item = NULL;
- while ((report_item = TAILQ_FIRST(reports))) {
- if (report_item->suites != NULL) {
- free_suites(report_item->suites);
- }
- TAILQ_REMOVE(reports, report_item, entries);
- free_report(report_item);
- }
-}
-
-void
-free_report(tailq_report *report)
-{
- if (report->suites != NULL) {
- free_suites(report->suites);
- }
- free(report->path);
- free(report->id);
- free(report);
-}
-
-void
-free_suites(struct suiteq * suites)
-{
- tailq_suite *suite_item = NULL;
- while ((suite_item = TAILQ_FIRST(suites))) {
- TAILQ_REMOVE(suites, suite_item, entries);
- free_suite(suite_item);
- }
-}
-
-void
-free_suite(tailq_suite * suite)
-{
- if (suite->name) {
- free((char*)suite->name);
- }
- if (suite->hostname) {
- free((char*)suite->hostname);
- }
- if (suite->timestamp) {
- free((char*)suite->timestamp);
- }
- if (!TAILQ_EMPTY(suite->tests)) {
- free_tests(suite->tests);
- }
-
- free(suite);
-}
-
-void
-free_tests(struct testq * tests)
-{
- tailq_test *test_item;
- while ((test_item = TAILQ_FIRST(tests))) {
- TAILQ_REMOVE(tests, test_item, entries);
- free_test(test_item);
- }
-}
-
-void
-free_test(tailq_test * test)
-{
- if (test->name) {
- free((char*)test->name);
- }
- if (test->time) {
- free((char*)test->time);
- }
- if (test->comment) {
- free((char*)test->comment);
- }
- if (test->error) {
- free((char*)test->error);
- }
- if (test->system_out) {
- free((char*)test->system_out);
- }
- if (test->system_err) {
- free((char*)test->system_err);
- }
- free(test);
-}
-
-char *
-get_filename_ext(const char *filename)
-{
- char *dot = strrchr(filename, '.');
- if (!dot || dot == filename)
- return (char *) NULL;
-
- return dot + 1;
-}
-
-enum test_format
-detect_format(char *path)
-{
- char *file_ext;
- file_ext = get_filename_ext(basename(path));
- if (file_ext == NULL) {
- return FORMAT_UNKNOWN;
- }
-
- if (strcasecmp("xml", file_ext) == 0) {
- return FORMAT_JUNIT;
- } else if (strcasecmp("tap", file_ext) == 0) {
- return FORMAT_TAP13;
- } else if (strcasecmp("subunit", file_ext) == 0) {
- if (is_subunit_v2(path) == 0) {
- return FORMAT_SUBUNIT_V2;
- } else {
- return FORMAT_SUBUNIT_V1;
- }
- } else {
- return FORMAT_UNKNOWN;
- }
-}
-
-unsigned char *digest_to_str(unsigned char *str, unsigned char digest[], unsigned int n) {
- int r;
- if (n == 0) return 0;
- if (n == 1) r = sprintf((char*)str, "%x", digest[0]);
- else r = sprintf((char*)str, "%x", digest[0]);
- digest_to_str(str + r, digest + 1, n - 1);
-
- return str;
-}
-
-tailq_report *
-process_file(char *path)
-{
- FILE *file;
- file = fopen(path, "r");
- if (file == NULL) {
- printf("failed to open file %s\n", path);
- return NULL;
- }
- tailq_report *report = NULL;
- report = calloc(1, sizeof(tailq_report));
- if (report == NULL) {
- perror("malloc failed");
- fclose(file);
- return NULL;
- }
- enum test_format format;
- format = detect_format(path);
- switch (format) {
- case FORMAT_JUNIT:
- report->format = FORMAT_JUNIT;
- report->suites = parse_junit(file);
- break;
- case FORMAT_TAP13:
- report->format = FORMAT_TAP13;
- report->suites = parse_testanything(file);
- break;
- case FORMAT_SUBUNIT_V1:
- report->format = FORMAT_SUBUNIT_V1;
- report->suites = parse_subunit_v1(file);
- break;
- case FORMAT_SUBUNIT_V2:
- report->format = FORMAT_SUBUNIT_V2;
- report->suites = parse_subunit_v2(file);
- break;
- case FORMAT_UNKNOWN:
- report->format = FORMAT_UNKNOWN;
- return report;
- }
- fclose(file);
-
- report->path = (unsigned char*)strdup(path);
-
- int length = 20;
- unsigned char digest[length];
- SHA1_CTX ctx;
- SHA1Init(&ctx);
- SHA1Update(&ctx, report->path, strlen(path));
- SHA1Final(digest, &ctx);
-
- report->id = calloc(length, sizeof(unsigned char*));
- digest_to_str(report->id, digest, length);
-
- struct stat sb;
- if (stat(path, &sb) == -1) {
- perror("cannot open specified path");
- return NULL;
- }
- report->time = sb.st_mtime;
-
- return report;
-}
-
-struct tailq_report *is_report_exists(struct reportq *reports, const char* report_id) {
-
- tailq_report *report_item = NULL;
- TAILQ_FOREACH(report_item, reports, entries) {
- if (strcmp(report_id, (char*)report_item->id) == 0) {
- break;
- }
- }
-
- return report_item;
-}
-
-/*
-static int cmp_date(const void *p1, const void *p2) {
- return strcmp(* (char * const *) p1, * (char * const *) p2);
-}
-
-struct reportq *sort_reports(struct reportq *reports) {
- return reports;
-}
-*/
-
-int num_by_status_class(struct tailq_report *report, enum test_status_class c) {
-
- int number = 0;
- if (report->suites != NULL) {
- tailq_suite *suite_item = NULL;
- TAILQ_FOREACH(suite_item, report->suites, entries) {
- if (!TAILQ_EMPTY(suite_item->tests)) {
- tailq_test *test_item = NULL;
- TAILQ_FOREACH(test_item, suite_item->tests, entries) {
- if (class_by_status(test_item->status) == c) number++;
- }
- }
- }
- }
-
- return number;
-}
-
-enum test_status_class class_by_status(enum test_status status) {
-
- switch (status) {
- case STATUS_OK:
- return STATUS_CLASS_PASS;
- case STATUS_PASS:
- return STATUS_CLASS_PASS;
- case STATUS_SUCCESS:
- return STATUS_CLASS_PASS;
- case STATUS_NOTOK:
- return STATUS_CLASS_FAIL;
- case STATUS_ERROR:
- return STATUS_CLASS_FAIL;
- case STATUS_FAILURE:
- return STATUS_CLASS_FAIL;
- case STATUS_FAILED:
- return STATUS_CLASS_FAIL;
- case STATUS_XFAILURE:
- return STATUS_CLASS_FAIL;
- case STATUS_UXSUCCESS:
- return STATUS_CLASS_FAIL;
- case STATUS_MISSING:
- return STATUS_CLASS_SKIP;
- case STATUS_TODO:
- return STATUS_CLASS_SKIP;
- case STATUS_SKIP:
- return STATUS_CLASS_SKIP;
- case STATUS_SKIPPED:
- return STATUS_CLASS_SKIP;
- case STATUS_UNDEFINED:
- return STATUS_CLASS_SKIP;
- case STATUS_ENUMERATION:
- return STATUS_CLASS_SKIP;
- case STATUS_INPROGRESS:
- return STATUS_CLASS_SKIP;
- default:
- return STATUS_CLASS_SKIP;
- }
-}
-
-struct reportq*
-process_dir(char *path) {
-
- DIR *d;
- int fd;
-
- fd = open(path, O_RDONLY);
- if ((d = fdopendir(fd)) == NULL) {
- printf("failed to open dir %s\n", path);
- close(fd);
- return NULL;
- }
-
- struct reportq *reports;
- reports = calloc(1, sizeof(struct reportq));
- if (reports == NULL) {
- return NULL;
- }
- TAILQ_INIT(reports);
-
- struct dirent *dir;
- char *path_file = (char *) NULL;
- tailq_report *report_item;
- while ((dir = readdir(d)) != NULL) {
- char *basename;
- basename = dir->d_name;
- if ((strcmp("..", basename) == 0) || (strcmp(".", basename) == 0)) {
- continue;
- }
- /* TODO: recursive search in directories */
- int path_len = strlen(path) + strlen(basename) + 2;
- path_file = calloc(path_len, sizeof(char));
- if (path_file == NULL) {
- return NULL;
- }
- snprintf(path_file, path_len, "%s/%s", path, basename);
-
- struct stat path_st;
- if (stat(path, &path_st) == -1) {
- perror("cannot open specified path");
- return NULL;
- }
- if (S_ISREG(path_st.st_mode)) {
- continue;
- }
- report_item = process_file(path_file);
- if (report_item->format != FORMAT_UNKNOWN) {
- TAILQ_INSERT_TAIL(reports, report_item, entries);
- }
- free(path_file);
- }
- close(fd);
- closedir(d);
-
- return reports;
-}
-
-struct reportq*
-process_db(char *path)
-{
- /* not implemented */
- return NULL;
-}
-
-int
-check_sqlite(char *path)
-{
- /* not implemented */
- /* see https://www.sqlite.org/fileformat.html */
- return 1;
-}
-
-struct reportq *filter_reports(struct reportq *reports, const char *qsearch) {
-
- if (qsearch == NULL || reports == NULL) {
- return NULL;
- }
-
- struct reportq *filtered;
- filtered = calloc(1, sizeof(struct reportq));
- if (filtered == NULL) {
- return NULL;
- }
- TAILQ_INIT(filtered);
-
- tailq_report *report_item = NULL;
- TAILQ_FOREACH(report_item, reports, entries) {
- if (report_item->suites != NULL) {
- tailq_suite *suite_item = NULL;
- int matched = 0;
- TAILQ_FOREACH(suite_item, report_item->suites, entries) {
- if (matched == 1) {
- break;
- }
- if (!TAILQ_EMPTY(suite_item->tests)) {
- tailq_test *test_item = NULL;
- TAILQ_FOREACH(test_item, suite_item->tests, entries) {
- if (strstr(test_item->name, qsearch) != NULL) {
- TAILQ_INSERT_TAIL(filtered, report_item, entries);
- matched = 1;
- break;
- }
- }
- }
- }
- }
- }
-
- return reports;
-}
-
-int cgi_parse(char *query_string, struct config *conf) {
- if (query_string == NULL) {
- conf->cgi_action = (char*)"/";
- return 0;
- }
- conf->cgi_action = strtok(query_string, "=");
- conf->cgi_args = strtok(NULL, "=");
- if (conf->cgi_action == NULL) {
- return 1;
- }
-
- return 0;
-}
blob - 60af253910fde52663b4b501496049e6423e2b11 (mode 644)
blob + /dev/null
--- src/parse_common.h
+++ /dev/null
-/*
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef PARSE_COMMON_H
-#define PARSE_COMMON_H
-
-#include <fcntl.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/queue.h>
-
-#include "testres.h"
-
-enum test_format {
- FORMAT_UNKNOWN,
- FORMAT_TAP13,
- FORMAT_JUNIT,
- FORMAT_SUBUNIT_V1,
- FORMAT_SUBUNIT_V2
-};
-
-enum test_status {
- STATUS_OK, /* TestAnythingProtocol */
- STATUS_NOTOK, /* TestAnythingProtocol */
- STATUS_MISSING, /* TestAnythingProtocol */
- STATUS_TODO, /* TestAnythingProtocol */
- STATUS_SKIP, /* TestAnythingProtocol */
-
- STATUS_UNDEFINED, /* Subunit */
- STATUS_ENUMERATION, /* Subunit */
- STATUS_INPROGRESS, /* Subunit */
- STATUS_SUCCESS, /* Subunit */
- STATUS_UXSUCCESS, /* Subunit */
- STATUS_SKIPPED, /* Subunit */
- STATUS_FAILED, /* Subunit */
- STATUS_XFAILURE, /* Subunit */
-
- STATUS_ERROR, /* JUnit */
- STATUS_FAILURE, /* JUnit */
- STATUS_PASS /* JUnit */
-};
-
-enum test_status_class {
- STATUS_CLASS_PASS,
- STATUS_CLASS_FAIL,
- STATUS_CLASS_SKIP
-};
-
-struct tailq_test {
- const char *name;
- const char *time;
- const char *comment;
- const char *error;
- const char *system_out;
- const char *system_err;
- enum test_status status;
- TAILQ_ENTRY(tailq_test) entries;
-};
-
-TAILQ_HEAD(testq, tailq_test);
-
-struct tailq_suite {
- const char *name;
- const char *hostname;
- const char *timestamp;
- int n_failures;
- int n_errors;
- double time;
- struct testq *tests;
- TAILQ_ENTRY(tailq_suite) entries;
-};
-
-TAILQ_HEAD(suiteq, tailq_suite);
-
-struct tailq_report {
- enum test_format format;
- struct suiteq *suites;
- time_t time;
- unsigned char *id;
- unsigned char *path;
- TAILQ_ENTRY(tailq_report) entries;
-};
-
-TAILQ_HEAD(reportq, tailq_report);
-
-typedef struct tailq_test tailq_test;
-typedef struct tailq_suite tailq_suite;
-typedef struct tailq_report tailq_report;
-
-/* cleanup */
-void free_reports(struct reportq *reports);
-void free_suites(struct suiteq *suites);
-void free_tests(struct testq *tests);
-
-void free_report(tailq_report * report);
-void free_suite(tailq_suite * suite);
-void free_test(tailq_test * test);
-
-
-char *get_filename_ext(const char *filename);
-enum test_format detect_format(char *path);
-int check_sqlite(char *path);
-struct reportq *process_db(char *path);
-struct reportq *process_dir(char *path);
-tailq_report *process_file(char *path);
-tailq_test *make_test(char *name, char *time, char *comment);
-unsigned char *digest_to_str(unsigned char *str, unsigned char digest[], unsigned int n);
-struct tailq_report *is_report_exists(struct reportq *reports, const char* report_id);
-int cgi_parse(char *query_string, struct config *conf);
-
-/*
-static int cmp_date(const void *p1, const void *p2);
-struct reportq *sort_reports(struct reportq *reports);
-*/
-
-int num_by_status_class(struct tailq_report *report, enum test_status_class c);
-enum test_status_class class_by_status(enum test_status status);
-struct reportq *filter_reports(struct reportq *reports, const char *qsearch);
-
-#endif /* PARSE_COMMON_H */
blob - 42eb77426f9c77c82a6a034f977e2c22673f7782 (mode 644)
blob + /dev/null
--- src/parse_junit.c
+++ /dev/null
-/*
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-#include "parse_junit.h"
-
-#ifdef XML_LARGE_SIZE
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
-#define XML_FMT_INT_MOD "I64"
-#else
-#define XML_FMT_INT_MOD "ll"
-#endif
-#else
-#define XML_FMT_INT_MOD "l"
-#endif
-
-#ifdef XML_UNICODE_WCHAR_T
-#define XML_FMT_STR "ls"
-#else
-#define XML_FMT_STR "s"
-#endif
-
-#define BUFFSIZE 8192
-
-/* https://github.com/kristapsdz/divecmd/blob/master/parser.c */
-
-char buf[BUFFSIZE];
-
-tailq_test *test_item;
-tailq_suite *suite_item;
-struct suiteq *suites;
-
-int system_out_flag = 0;
-int system_err_flag = 0;
-int error_flag = 0;
-
-const XML_Char *
-name_to_value(const XML_Char ** attr, const char attr_name[])
-{
- XML_Char *attr_value = NULL;
- int i;
- for (i = 0; attr[i]; i += 2) {
- if (strcmp(attr[i], attr_name) == 0) {
- attr_value = calloc(strlen(attr[i + 1]) + 1, sizeof(XML_Char));
- if (attr_value == NULL) {
- perror("malloc failed");
- return (char *) NULL;
- }
- strcpy(attr_value, attr[i + 1]);
- break;
- }
- }
- return attr_value;
-}
-
-static void XMLCALL
-start_handler(void *data, const XML_Char * elem, const XML_Char ** attr)
-{
- (void) data;
- if (strcmp(elem, "testsuite") == 0) {
- suite_item = calloc(1, sizeof(tailq_suite));
- if (suite_item == NULL) {
- perror("malloc failed");
- }
- suite_item->name = name_to_value(attr, "name");
- suite_item->hostname = name_to_value(attr, "hostname");
- suite_item->n_errors = atoi(name_to_value(attr, "errors"));
- suite_item->n_failures = atoi(name_to_value(attr, "failures"));
- suite_item->time = atof(name_to_value(attr, "time"));
- suite_item->timestamp = name_to_value(attr, "timestamp");
- suite_item->tests = calloc(1, sizeof(struct testq));
- if (suite_item->tests == NULL) {
- perror("malloc failed");
- }
- TAILQ_INIT(suite_item->tests);
- } else if (strcmp(elem, "testcase") == 0) {
- test_item = calloc(1, sizeof(tailq_test));
- if (test_item == NULL) {
- perror("malloc failed");
- };
- test_item->name = name_to_value(attr, "name");
- test_item->time = name_to_value(attr, "time");
- test_item->status = STATUS_PASS;
- } else if (strcmp(elem, "error") == 0) {
- error_flag = 1;
- test_item->status = STATUS_ERROR;
- test_item->comment = name_to_value(attr, "comment");
- } else if (strcmp(elem, "failure") == 0) {
- test_item->status = STATUS_FAILURE;
- test_item->comment = name_to_value(attr, "comment");
- } else if (strcmp(elem, "skipped") == 0) {
- test_item->status = STATUS_SKIPPED;
- test_item->comment = name_to_value(attr, "comment");
- } else if (strcmp(elem, "system-out") == 0) {
- system_out_flag = 1;
- } else if (strcmp(elem, "system-err") == 0) {
- system_err_flag = 1;
- }
-}
-
-static void XMLCALL
-end_handler(void *data, const XML_Char * elem)
-{
- (void) data;
- (void) elem;
-
- if (strcmp(elem, "testsuite") == 0) {
- /* TODO: check a number of failures and errors */
- TAILQ_INSERT_TAIL(suites, suite_item, entries);
- } else if (strcmp(elem, "testcase") == 0) {
- TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
- } else if (strcmp(elem, "error") == 0) {
- error_flag = 0;
- } else if (strcmp(elem, "system-out") == 0) {
- system_out_flag = 0;
- } else if (strcmp(elem, "system-err") == 0) {
- system_err_flag = 0;
- }
-}
-
-void
-data_handler(void *data, const char *txt, int txtlen) {
- (void)data;
-
- if (error_flag == 1) {
- /* TODO */
- test_item->error = (char*)NULL;
- };
- if (system_out_flag == 1) {
- /* TODO */
- test_item->system_out = (char*)NULL;
- };
- if (system_err_flag == 1) {
- /* TODO */
- test_item->system_err = (char*)NULL;
- };
-}
-
-struct suiteq *
-parse_junit(FILE * f)
-{
- XML_Parser p = XML_ParserCreate(NULL);
- if (!p) {
- fprintf(stderr, "Couldn't allocate memory for parser\n");
- return NULL;
- }
- suites = calloc(1, sizeof(struct suiteq));
- if (suites == NULL) {
- perror("malloc failed");
- }
- TAILQ_INIT(suites);
-
- XML_UseParserAsHandlerArg(p);
- XML_SetElementHandler(p, start_handler, end_handler);
- XML_SetCharacterDataHandler(p, data_handler);
-
- for (;;) {
- int len, done;
- len = fread(buf, 1, BUFFSIZE, f);
- if (ferror(f)) {
- fprintf(stderr, "Read error\n");
- exit(-1);
- }
- done = feof(f);
-
- if (XML_Parse(p, buf, len, done) == XML_STATUS_ERROR) {
- fprintf(stderr,
- "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(p),
- XML_ErrorString(XML_GetErrorCode(p)));
- free(test_item);
- free(suite_item);
- free_suites(suites);
- exit(-1);
- }
- if (done) {
- break;
- }
- }
- XML_ParserFree(p);
-
- return suites;
-}
blob - afe24652dfd93b0aeb5b1d7b1e9dfa0d0336489c (mode 644)
blob + /dev/null
--- src/parse_junit.h
+++ /dev/null
-/*
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef PARSE_JUNIT_H
-#define PARSE_JUNIT_H
-
-#include <expat.h>
-
-#include "parse_common.h"
-
-struct suiteq *parse_junit(FILE *f);
-
-#endif /* PARSE_JUNIT_H */
blob - bceeb32256adc179553703fb69365c11573cb15c (mode 644)
blob + /dev/null
--- src/parse_subunit_v1.c
+++ /dev/null
-/*
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <time.h>
-
-#include "parse_subunit_v1.h"
-
-const char *
-directive_string(enum directive dir) {
-
- switch (dir) {
- case DIR_TEST:
- return "DIR_TEST";
- case DIR_SUCCESS:
- return "DIR_SUCCESS";
- case DIR_FAILURE:
- return "DIR_FAILURE";
- case DIR_ERROR:
- return "DIR_ERROR";
- case DIR_SKIP:
- return "DIR_SKIP";
- case DIR_XFAIL:
- return "DIR_XFAIL";
- case DIR_UXSUCCESS:
- return "DIR_UXSUCCESS";
- case DIR_PROGRESS:
- return "DIR_PROGRESS";
- case DIR_TAGS:
- return "DIR_TAGS";
- case DIR_TIME:
- return "DIR_TIME";
- default:
- return "DIR_UNKNOWN";
- }
-}
-
-enum directive
-resolve_directive(char * string) {
-
- assert(string != (char*)NULL);
-
- if ((strcasecmp(string, "test") == 0) ||
- (strcasecmp(string, "testing") == 0) ||
- (strcasecmp(string, "test:") == 0) ||
- (strcasecmp(string, "testing:") == 0)) {
- return DIR_TEST;
- } else if ((strcasecmp(string, "success") == 0) ||
- (strcasecmp(string, "success:") == 0) ||
- (strcasecmp(string, "successful") == 0) ||
- (strcasecmp(string, "successful:") == 0)) {
- return DIR_SUCCESS;
- } else if (strcasecmp(string, "failure:") == 0) {
- return DIR_FAILURE;
- } else if (strcasecmp(string, "error:") == 0) {
- return DIR_ERROR;
- } else if ((strcasecmp(string, "skip") == 0) ||
- (strcasecmp(string, "skip:") == 0)) {
- return DIR_SKIP;
- } else if ((strcasecmp(string, "xfail") == 0) ||
- (strcasecmp(string, "xfail:") == 0)) {
- return DIR_XFAIL;
- } else if ((strcasecmp(string, "uxsuccess") == 0) ||
- (strcasecmp(string, "uxsuccess:") == 0)) {
- return DIR_UXSUCCESS;
- } else if (strcasecmp(string, "progress:") == 0) {
- return DIR_PROGRESS;
- } else if (strcasecmp(string, "tags:") == 0) {
- return DIR_TAGS;
- } else if (strcasecmp(string, "time:") == 0) {
- return DIR_TIME;
- } else {
- /* unknown directive */
- }
-
- return DIR_TEST;
-}
-
-struct tm* parse_iso8601_time(char* date_str, char* time_str) {
- assert(date_str != (char*)NULL);
- assert(time_str != (char*)NULL);
-
- struct tm * t;
- t = malloc(sizeof(struct tm));
- if (t == NULL) {
- perror("failed to malloc");
- return NULL;
- }
- if (sscanf(date_str, "%d-%d-%d", &t->tm_year, &t->tm_mon, &t->tm_mday) == 3) {
- assert(t->tm_year > 2000);
- assert((t->tm_mon <= 12) && (t->tm_mon >= 0));
- assert((t->tm_mday <= 31) && (t->tm_mday >= 0));
- }
-
- if (sscanf(time_str, "%d:%d:%dZ", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3) {
- assert((t->tm_hour <= 23) && (t->tm_hour >= 0));
- assert((t->tm_min <= 60) && (t->tm_min >= 0));
- assert((t->tm_sec <= 60) && (t->tm_sec >= 0));
- }
-
- return t;
-}
-
-void read_tok() {
- char* token = (char*)NULL;
- while (token != NULL) { token = strtok(NULL, " \t"); };
-}
-
-tailq_test* read_test() {
-
- tailq_test *test_item = NULL;
- test_item = calloc(1, sizeof(tailq_test));
- if (test_item == NULL) {
- perror("failed to malloc");
- return NULL;
- }
-
- char *token, *name;
- token = strtok(NULL, " \t");
- if (strcmp(token, "test") == 0) {
- token = strtok(NULL, " \t");
- assert(token != NULL);
- }
- name = (char*)calloc(strlen(token) + 1, sizeof(char));
- strcpy(name, token);
- test_item->name = name;
-
- read_tok();
-
- return test_item;
-}
-
-tailq_test* parse_line_subunit_v1(char* string) {
-
- assert(string != (char*)NULL);
-
- char *dir;
- char buffer[1024];
- strcpy(buffer, string);
- dir = strtok(buffer, " \t");
-
- tailq_test *test_item = NULL;
- enum directive d;
- switch (d = resolve_directive(dir)) {
- case DIR_TEST:
- /* testline is useless, but we should check conformance to spec */
- read_tok();
- break;
- case DIR_SUCCESS:
- test_item = read_test();
- test_item->status = STATUS_SUCCESS;
- break;
- case DIR_FAILURE:
- test_item = read_test();
- test_item->status = STATUS_FAILURE;
- break;
- case DIR_ERROR:
- test_item = read_test();
- test_item->status = STATUS_FAILED;
- break;
- case DIR_SKIP:
- test_item = read_test();
- test_item->status = STATUS_SKIPPED;
- break;
- case DIR_XFAIL:
- test_item = read_test();
- test_item->status = STATUS_XFAILURE;
- break;
- case DIR_UXSUCCESS:
- test_item = read_test();
- test_item->status = STATUS_UXSUCCESS;
- break;
- case DIR_PROGRESS:
- /* testline is useless, but we should check conformance to spec */
- read_tok();
- break;
- case DIR_TAGS:
- /* testline is useless, but we should check conformance to spec */
- read_tok();
- break;
- case DIR_TIME:
- /* testline is useless, but we should check conformance to spec */
- /*
- char *date = strtok(NULL, " \t");
- assert(date != (char*)NULL);
- char *time = strtok(NULL, " \t");
- assert(time != (char*)NULL);
- struct tm *t = parse_iso8601_time(date, time);
- printf("Time: %s\n", asctime(t));
- */
-
- read_tok();
- break;
- default:
- read_tok();
- return NULL;
- }
-
- return test_item;
-}
-
-struct suiteq* parse_subunit_v1(FILE *stream) {
-
- tailq_suite *suite_item;
- suite_item = calloc(1, sizeof(tailq_suite));
- if (suite_item == NULL) {
- perror("malloc failed");
- return NULL;
- }
- /* TODO: n_errors, n_failures */
- suite_item->tests = calloc(1, sizeof(struct testq));
- if (suite_item->tests == NULL) {
- perror("malloc failed");
- free(suite_item);
- return NULL;
- };
- TAILQ_INIT(suite_item->tests);
-
- char line[1024];
- tailq_test *test_item = NULL;
- while (fgets(line, sizeof(line), stream)) {
- test_item = parse_line_subunit_v1(line);
- if (test_item != NULL) {
- TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
- }
- if (feof(stream)) {
- break;
- }
- }
-
- struct suiteq *suites = NULL;
- suites = calloc(1, sizeof(struct suiteq));
- if (suites == NULL) {
- perror("malloc failed");
- };
- TAILQ_INIT(suites);
- TAILQ_INSERT_TAIL(suites, suite_item, entries);
-
- return suites;
-}
blob - 48343a4ba6c96a3cee80604105d629445af8fa21 (mode 644)
blob + /dev/null
--- src/parse_subunit_v1.h
+++ /dev/null
-/*
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef PARSE_SUBUNIT_V1_H
-#define PARSE_SUBUNIT_V1_H
-
-#include "parse_common.h"
-
-enum directive {
- DIR_TEST,
- DIR_SUCCESS,
- DIR_FAILURE,
- DIR_ERROR,
- DIR_SKIP,
- DIR_XFAIL,
- DIR_UXSUCCESS,
- DIR_PROGRESS,
- DIR_TAGS,
- DIR_TIME
-};
-
-tailq_test* parse_line_subunit_v1(char* string);
-struct suiteq* parse_subunit_v1(FILE* stream);
-struct tm* parse_iso8601_time(char* date_str, char* time_str);
-enum directive resolve_directive(char* string);
-const char* directive_string(enum directive dir);
-void read_tok();
-tailq_test* read_test();
-
-#endif /* PARSE_SUBUNIT_V1_H */
blob - 36b2df8bee0459bc4ddb56d66a00278479cfd188 (mode 644)
blob + /dev/null
--- src/parse_subunit_v2.c
+++ /dev/null
-/*
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <arpa/inet.h>
-#include <zlib.h>
-
-#include "parse_subunit_v2.h"
-
-// https://github.com/testing-cabal/subunit/blob/master/python/subunit/v2.py#L412
-// https://github.com/testing-cabal/subunit
-
-#define HI(x) ((x) >> 8)
-#define LO(x) ((x) & 0xFF)
-
-int is_subunit_v2(char* path)
-{
- FILE *file;
- file = fopen(path, "r");
- if (file == NULL) {
- printf("failed to open file %s\n", path);
- return -1;
- }
-
- uint8_t signature = 0;
- int n_bytes = 0;
- n_bytes = fread(&signature, 1, 1, file);
- fclose(file);
- if (n_bytes == 0) {
- return -1;
- }
- if (signature == SUBUNIT_SIGNATURE) {
- return 0;
- } else {
- return 1;
- }
-}
-
-uint32_t read_field(FILE * stream)
-{
-
- uint32_t field_value = 0;
- uint8_t byte = 0, byte0 = 0;
- uint16_t buf = 0;
- uint8_t prefix = 0;
-
- int n_bytes = 0;
-
- n_bytes = fread(&byte, 1, 1, stream);
- if (n_bytes == 0) {
- return 0;
- }
- prefix = byte >> 6;
- byte0 = byte & 0x3f;
- if (prefix == 0x00) {
- field_value = byte0;
- } else if (prefix == 0x40) {
- n_bytes = fread(&byte, 1, 1, stream);
- if (n_bytes == 0) {
- return 0;
- }
- field_value = (byte0 << 8) | byte;
- } else if (prefix == 0x80) {
- n_bytes = fread(&buf, 2, 1, stream);
- if (n_bytes == 0) {
- return 0;
- }
- field_value = (byte << 16) | buf;
- } else {
- n_bytes = fread(&buf, 1, 2, stream);
- if (n_bytes == 0) {
- return 0;
- }
- field_value = (byte0 << 24) | buf << 8;
-
- n_bytes = fread(&byte, 1, 1, stream);
- if (n_bytes == 0) {
- return 0;
- }
- field_value = field_value | byte;
- };
-
- return field_value;
-}
-
-struct suiteq *
-parse_subunit_v2(FILE * stream)
-{
- tailq_suite *suite_item;
- suite_item = calloc(1, sizeof(tailq_suite));
- if (suite_item == NULL) {
- perror("malloc failed");
- return NULL;
- }
-
- suite_item->tests = calloc(1, sizeof(struct testq));
- if (suite_item->tests == NULL) {
- perror("malloc failed");
- free_suite(suite_item);
- return NULL;
- }
-
- TAILQ_INIT(suite_item->tests);
- tailq_test *test_item = NULL;
-
- test_item = read_subunit_v2_packet(stream);
- if (test_item != NULL)
- TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
-
- /*
- while (!feof(stream)) {
- test_item = read_packet(stream);
- if (test_item != NULL)
- TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
- else
- {
- free_tests(suite_item->tests);
- free_suite(suite_item);
- return NULL;
- }
- }
- */
-
- struct suiteq *suites = NULL;
- suites = calloc(1, sizeof(struct suiteq));
- if (suites == NULL) {
- perror("malloc failed");
- free_suite(suite_item);
- }
- TAILQ_INIT(suites);
- TAILQ_INSERT_TAIL(suites, suite_item, entries);
-
- return suites;
-}
-
-tailq_test *
-read_subunit_v2_packet(FILE * stream)
-{
- subunit_header header;
- int n_bytes = 0;
- n_bytes = fread(&header, sizeof(subunit_header), 1, stream);
- if ((n_bytes == 0) || (n_bytes < (int)sizeof(subunit_header))) {
- return NULL;
- }
- tailq_test *test_item;
- test_item = calloc(1, sizeof(tailq_test));
- if (test_item == NULL) {
- perror("malloc failed");
- return NULL;
- }
-
- uint16_t flags = htons(header.flags);
- printf("SIGNATURE: %02hhX\n", header.signature);
- printf("FLAGS: %02hX\n", flags);
- assert(header.signature == SUBUNIT_SIGNATURE);
-
- int8_t version;
- version = HI(flags) >> 4;
- printf("\tVERSION: %d\n", version);
- assert(version == SUBUNIT_VERSION);
-
- /*
- int8_t status;
- status = flags & 0x0007;
- printf("\tSTATUS: %d\n", status);
- test_item->status = status;
- assert(status <= 0x0007);
-
- uint32_t field_value;
- field_value = read_field(stream);
- printf("TOTAL LENGTH: %u\n", field_value);
- assert(field_value < PACKET_MAX_LENGTH);
-
- if (flags & FLAG_TIMESTAMP) {
- printf("FLAG_TIMESTAMP ");
- field_value = read_field(stream);
- printf("%08X\n", field_value);
- };
- if (flags & FLAG_TEST_ID) {
- printf("FLAG_TEST_ID ");
- field_value = read_field(stream);
- printf("%08X\n", field_value);
- };
- if (flags & FLAG_TAGS) {
- printf("FLAG_TAGS ");
- field_value = read_field(stream);
- printf("%02X\n", field_value);
- };
- if (flags & FLAG_MIME_TYPE) {
- printf("FLAG_MIME_TYPE ");
- field_value = read_field(stream);
- printf("%02X\n", field_value);
- };
- if (flags & FLAG_FILE_CONTENT) {
- printf("FLAG_FILE_CONTENT ");
- field_value = read_field(stream);
- printf("%08X\n", field_value);
- };
- if (flags & FLAG_ROUTE_CODE) {
- printf("FLAG_ROUTE_CODE ");
- field_value = read_field(stream);
- printf("%08X\n", field_value);
- };
- if (flags & FLAG_EOF) {
- printf("FLAG_EOF\n");
- };
- if (flags & FLAG_RUNNABLE) {
- printf("FLAG_RUNNABLE\n");
- };
- printf("CRC32: ");
- field_value = read_field(stream);
- printf("%08X\n", field_value);
- */
-
- return test_item;
-}
-
-
-/*
-
-CRC32
-const char *s = "0xb30x2901b329010c03666f6f";
-printf("%lX, should be %X\n", crc32(0, (const void*)s, strlen(s)), sample_crc32);
-http://bxr.su/OpenBSD/bin/md5/crc.c
-
-https://rosettacode.org/wiki/CRC-32#C
-http://csbruce.com/software/crc32.c
-
-Parse timestamp
-int y, M, d, h, m;
-float sec;
-char *dateStr = "2014-11-12T19:12:14.505Z";
-sscanf(dateStr, "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &sec);
-https://github.com/mlabbe/c_date_parse
-
-UTF-8
-https://github.com/benkasminbullock/unicode-c/blob/master/unicode.c
-https://github.com/clibs/cutef8
-
-*/
blob - dab7dd56d19d153daff3ed9ed2453733fa616559 (mode 644)
blob + /dev/null
--- src/parse_subunit_v2.h
+++ /dev/null
-/*
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef PARSE_SUBUNIT_V2_H
-#define PARSE_SUBUNIT_V2_H
-
-#include <stdint.h>
-
-#include "parse_common.h"
-
-#define SUBUNIT_SIGNATURE 0xB3
-#define SUBUNIT_VERSION 0x02
-#define PACKET_MAX_LENGTH 4194303
-
-#define FLAG_TEST_ID 0x0800
-#define FLAG_ROUTE_CODE 0x0400
-#define FLAG_TIMESTAMP 0x0200
-#define FLAG_RUNNABLE 0x0100
-#define FLAG_TAGS 0x0080
-#define FLAG_MIME_TYPE 0x0020
-#define FLAG_EOF 0x0010
-#define FLAG_FILE_CONTENT 0x0040
-
-struct subunit_header {
- uint8_t signature;
- uint16_t flags;
-} __attribute__ ((packed));
-
-typedef struct subunit_header subunit_header;
-
-typedef uint32_t timestamp;
-
-uint32_t read_field(FILE *stream);
-tailq_test *read_subunit_v2_packet(FILE *stream);
-struct suiteq *parse_subunit_v2(FILE *stream);
-int is_subunit_v2(char* path);
-
-#endif /* PARSE_SUBUNIT_V2_H */
blob - b00ba88cb5f99aba4c095d5b51e2a9adc60f6831 (mode 644)
blob + /dev/null
--- src/parse_testanything.c
+++ /dev/null
-/*
- * Copyright © 2015-2017 Katherine Flavel <kate@elide.org>
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#define _POSIX_C_SOURCE 200809L
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <assert.h>
-#include <unistd.h>
-#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <string.h>
-#include <strings.h>
-
-#include "parse_common.h"
-#include "parse_testanything.h"
-
-const char *
-ast_status(enum ast_status status)
-{
- switch (status) {
- case AST_OK:return "ok";
- case AST_NOTOK:
- return "not ok";
- case AST_MISSING:
- return "missing";
- case AST_TODO:
- return "todo";
- case AST_SKIP:
- return "skip";
-
- default:
- return "?";
- }
-}
-
-enum test_status
-test_status(enum ast_status status)
-{
- switch (status) {
- case AST_OK:return STATUS_OK;
- case AST_NOTOK:
- return STATUS_NOTOK;
- case AST_MISSING:
- return STATUS_MISSING;
- case AST_TODO:
- return STATUS_TODO;
- case AST_SKIP:
- return STATUS_SKIP;
- default:
- return STATUS_MISSING;
- }
-}
-
-struct ast_line *
-ast_line(struct ast_line ** head, const char *text)
-{
- struct ast_line **tail, *new;
- size_t z;
-
- assert(head != NULL);
- assert(text != NULL);
-
- z = strlen(text);
-
- new = malloc(sizeof *new + z + 1);
- if (new == NULL) {
- return NULL;
- }
- new->text = strcpy((char *) new + sizeof *new, text);
-
- for (tail = head; *tail != NULL; tail = &(*tail)->next);
-
- new->next = *tail;
- *tail = new;
-
- return new;
-}
-
-struct ast_test *
-ast_test(struct ast_test ** head, enum ast_status status, const char *name)
-{
- struct ast_test **tail, *new;
-
- assert(head != NULL);
-
- new = malloc(sizeof *new +
- (name == NULL ? 0 : strlen(name) + 1));
- if (new == NULL) {
- return NULL;
- }
- if (name == NULL) {
- new->name = NULL;
- } else {
- new->name = strcpy((char *) new + sizeof *new, name);
- }
-
- new->rep = 1;
- new->line = NULL;
- new->status = status;
-
- for (tail = head; *tail != NULL; tail = &(*tail)->next);
-
- new->next = *tail;
- *tail = new;
-
- return new;
-}
-
-static void
-rtrim(char *s)
-{
- char *p;
-
- assert(s != NULL);
-
- if (*s == '\0') {
- return;
- }
- p = s + strlen(s) - 1;
-
- assert(strlen(s) > 0);
-
- while (p >= s && isspace((unsigned char) *p)) {
- *p-- = '\0';
- }
-}
-
-static void
-plan(const char *line, int *a, int *b)
-{
- assert(line != NULL);
- assert(a != NULL);
- assert(b != NULL);
-
- if (*b != -1) {
- fprintf(stderr, "syntax error: duplicate plan: %s\n", line);
- exit(1);
- }
- if (2 != sscanf(line, "%d..%d", a, b)) {
- fprintf(stderr, "syntax error: missing a..b\n");
- exit(1);
- }
- if (*a < 0 && *b < *a) {
- fprintf(stderr, "error: invalid plan: %d..%d\n", *a, *b);
- exit(1);
- }
-}
-
-static void
-yaml(struct ast_test * test, const char *line)
-{
- assert(test != NULL);
-
- while (test->next != NULL)
- test = test->next;
-
- if (!ast_line(&test->line, line)) {
- perror("ast_line");
- exit(1);
- }
-}
-
-static void
-gap(struct ast_test ** head, int *a, int b)
-{
- struct ast_test *new;
-
- assert(head != NULL);
- assert(a != NULL);
- assert(*a <= b);
-
- while (*a < b) {
- new = ast_test(head, AST_MISSING, NULL);
- if (new == NULL) {
- perror("ast_test");
- exit(1);
- }
- *a += 1;
- }
-}
-
-static void
-starttest(struct ast_test ** head, const char *line, int *a, int b)
-{
- struct ast_test *new;
- enum ast_status status;
- int i;
- int n;
-
- assert(a != NULL);
- assert(head != NULL);
- assert(line != NULL);
- assert(b == -1 || *a <= b);
-
- if (0 == strncmp(line, "not ", 4)) {
- line += 4;
- status = AST_NOTOK;
- } else {
- status = AST_OK;
- }
-
- if (1 != sscanf(line, "ok %d - %n", &i, &n)) {
- fprintf(stderr, "syntax error: expected 'ok - ': %s\n", line);
- exit(1);
- }
- line += n;
-
- if (i < *a || (b != -1 && i > b)) {
- fprintf(stderr, "error: test %d out of order; expected %d\n", i, *a);
- exit(1);
- }
- gap(head, a, i);
-
- new = ast_test(head, status, line);
- if (new == NULL) {
- perror("ast_test");
- exit(1);
- }
- *a += 1;
-}
-
-void
-print(FILE * f, const struct ast_test * tests)
-{
- const struct ast_test *test;
- const struct ast_line *line;
- unsigned int n;
-
- assert(f != NULL);
- assert(tests != NULL);
-
- for (test = tests, n = 1; test != NULL; test = test->next, n++) {
- fprintf(f, "\t<test status='%s'",
- ast_status(test->status));
-
- fprintf(f, " n='%u'", n);
-
- if (test->rep > 1) {
- fprintf(f, " rep='%u'", test->rep);
- }
- if (test->name != NULL) {
- fprintf(f, " name='");
- fprintf(f, "%s", test->name);
- fprintf(f, "'");
- }
- fprintf(f, "%s>\n", test->line != NULL ? "" : "/");
-
- if (test->line == NULL) {
- continue;
- }
- for (line = test->line; line != NULL; line = line->next) {
- fprintf(f, "%s%s",
- line->text,
- line->next != NULL ? "\n" : "");
- }
- }
-}
-
-struct ast_test *
-parse_testanything_raw(FILE * f)
-{
- struct ast_test *tests = NULL;
- int a, b;
- int fold = 0;
-
- {
- char *line, *comment;
- size_t n;
-
- line = NULL;
- a = 1;
- b = -1; /* no plan */
- n = 0;
-
- while (-1 != getline(&line, &n, f)) {
- line[strcspn(line, "\n")] = '\0';
-
- comment = strchr(line, '#');
- if (comment != NULL) {
- *comment++ = '\0';
- }
- rtrim(line);
-
- if (comment != NULL) {
- comment += strspn(comment, " \t");
-
- /* TODO: only if we're actually in a test */
-
- if (0 == strncasecmp(comment, "todo", 4)) {
- tests->status = AST_TODO;
- }
- if (0 == strncasecmp(comment, "skip", 4)) {
- tests->status = AST_SKIP;
- }
- /* TODO: add comment line anyway */
- /*
- * TODO: add as yaml line printf("\t<!-- %s
- * -->\n", comment);
- */
- }
- switch (line[0]) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- plan(line, &a, &b);
- continue;
-
- case 'n':
- case 'o':
- starttest(&tests, line, &a, b);
- continue;
-
- case '\v':
- case '\t':
- case '\f':
- case '\r':
- case '\n':
- case ' ':
- if (tests == NULL) {
- fprintf(stderr, "stray text: %s\n", line);
- continue;
- }
- yaml(tests, line);
- continue;
- }
- }
-
- gap(&tests, &a, b + 1);
- }
-
- if (fold) {
- struct ast_test *test, *next;
-
- for (test = tests; test != NULL; test = next) {
- next = test->next;
- if (next == NULL) {
- continue;
- }
- if (0 != strcmp(test->name, next->name)) {
- continue;
- }
- if (test->status != next->status) {
- continue;
- }
- if (test->line != NULL || next->line != NULL) {
- continue;
- }
- test->rep++;
- test->next = next->next;
- next = test;
-
- /* TODO: free next */
- }
- }
- /* TODO: warn about duplicate test names */
- /* TODO: remove ast_test * tests here */
-
- /* print(stdout, tests); */
- return tests;
-}
-
-struct suiteq *
-parse_testanything(FILE * f)
-{
- tailq_suite *suite_item = NULL;
- suite_item = calloc(1, sizeof(tailq_suite));
- if (suite_item == NULL) {
- perror("malloc failed");
- }
- suite_item->n_errors = 0;
- suite_item->n_failures = 0;
- suite_item->tests = calloc(1, sizeof(struct testq));
- if (suite_item->tests == NULL) {
- perror("malloc failed");
- free(suite_item);
- }
- TAILQ_INIT(suite_item->tests);
-
- struct ast_test *tests, *current;
- tests = parse_testanything_raw(f);
- tailq_test *test_item;
- current = tests;
- while (current != NULL) {
- test_item = calloc(1, sizeof(tailq_test));
- if (test_item == NULL) {
- perror("malloc failed");
- free_tests(suite_item->tests);
- free(suite_item);
- return NULL;
- }
- char *name = calloc(strlen(current->name) + 1, sizeof(char));
- if (name == NULL) {
- perror("malloc failed");
- free_tests(suite_item->tests);
- free(suite_item);
- free(test_item);
- return NULL;
- }
- test_item->name = strcpy(name, current->name);
- test_item->status = test_status(current->status);
- TAILQ_INSERT_TAIL(suite_item->tests, test_item, entries);
- current = current->next;
- /* TODO: remove ast_test item */
- }
-
- struct suiteq *suites;
- suites = calloc(1, sizeof(struct suiteq));
- if (suites == NULL) {
- free_tests(suite_item->tests);
- free(suite_item);
- perror("malloc failed");
- return NULL;
- }
- TAILQ_INIT(suites);
- TAILQ_INSERT_TAIL(suites, suite_item, entries);
-
- return suites;
-}
blob - be3329125d21b053e7d6935519d45bb48347f934 (mode 644)
blob + /dev/null
--- src/parse_testanything.h
+++ /dev/null
-/*
- * Copyright © 2015-2017 Katherine Flavel <kate@elide.org>
- * Copyright © 2018 Sergey Bronnikov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef PARSE_TESTANYTHING_H
-#define PARSE_TESTANYTHING_H
-
-enum ast_status {
- AST_OK,
- AST_NOTOK,
- AST_MISSING,
- AST_TODO,
- AST_SKIP
-};
-
-struct ast_line {
- /* TODO: comment flag */
- const char *text;
- struct ast_line *next;
-};
-
-struct ast_test {
- const char *name;
- enum ast_status status;
- unsigned int rep;
- struct ast_line *line;
- struct ast_test *next;
-};
-
-const char *
-ast_status(enum ast_status status);
-
-struct ast_line *
-ast_line(struct ast_line **head, const char *text);
-
-struct ast_test *
-ast_test(struct ast_test **head, enum ast_status status, const char *name);
-
-void
-print(FILE *f, const struct ast_test *tests);
-
-struct ast_test *parse_testanything_raw(FILE *f);
-struct suiteq *parse_testanything(FILE *f);
-
-#endif /* PARSE_TESTANYTHING_H */
blob - cc52dcf96354ebde280ad8a5f144a841070257ff (mode 644)
blob + /dev/null
--- src/sha1.c
+++ /dev/null
-/* from valgrind tests */
-
-/* ================ sha1.c ================ */
-/*
-SHA-1 in C
-By Steve Reid <steve@edmweb.com>
-100% Public Domain
-
-Test Vectors (from FIPS PUB 180-1)
-"abc"
- A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
-"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
- 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
-A million repetitions of "a"
- 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
-*/
-
-/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
-/* #define SHA1HANDSOFF * Copies data before messing with it. */
-
-#if defined __x86_64__
-#define BYTE_ORDER LITTLE_ENDIAN
-#endif
-#define SHA1HANDSOFF
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#include <sys/param.h>
-
-#include "sha1.h"
-
-#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-/* blk0() and blk() perform the initial expand. */
-/* I got the idea of expanding during the round function from SSLeay */
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
- |(rol(block->l[i],8)&0x00FF00FF))
-#elif BYTE_ORDER == BIG_ENDIAN
-#define blk0(i) block->l[i]
-#else
-#error "Endianness not defined!"
-#endif
-#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
- ^block->l[(i+2)&15]^block->l[i&15],1))
-
-/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
-#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
-
-
-/* Hash a single 512-bit block. This is the core of the algorithm. */
-
-void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
-{
- uint32_t a, b, c, d, e;
- typedef union {
- unsigned char c[64];
- uint32_t l[16];
- } CHAR64LONG16;
-#ifdef SHA1HANDSOFF
- CHAR64LONG16 block[1]; /* use array to appear as a pointer */
- memcpy(block, buffer, 64);
-#else
- /* The following had better never be used because it causes the
- * pointer-to-const buffer to be cast into a pointer to non-const.
- * And the result is written through. I threw a "const" in, hoping
- * this will cause a diagnostic.
- */
- CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
-#endif
- /* Copy context->state[] to working vars */
- a = state[0];
- b = state[1];
- c = state[2];
- d = state[3];
- e = state[4];
- /* 4 rounds of 20 operations each. Loop unrolled. */
- R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
- R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
- R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
- R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
- R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
- R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
- R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
- R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
- R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
- R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
- R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
- R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
- R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
- R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
- R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
- R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
- R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
- R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
- R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
- R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
- /* Add the working vars back into context.state[] */
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
- state[4] += e;
- /* Wipe variables */
- a = b = c = d = e = 0;
-#ifdef SHA1HANDSOFF
- memset(block, '\0', sizeof(block));
-#endif
-}
-
-
-/* SHA1Init - Initialize new context */
-
-void SHA1Init(SHA1_CTX* context)
-{
- /* SHA1 initialization constants */
- context->state[0] = 0x67452301;
- context->state[1] = 0xEFCDAB89;
- context->state[2] = 0x98BADCFE;
- context->state[3] = 0x10325476;
- context->state[4] = 0xC3D2E1F0;
- context->count[0] = context->count[1] = 0;
-}
-
-
-/* Run your data through this. */
-
-void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)
-{
- uint32_t i, j;
-
- j = context->count[0];
- if ((context->count[0] += len << 3) < j)
- context->count[1]++;
- context->count[1] += (len>>29);
- j = (j >> 3) & 63;
- if ((j + len) > 63) {
- memcpy(&context->buffer[j], data, (i = 64-j));
- SHA1Transform(context->state, context->buffer);
- for ( ; i + 63 < len; i += 64) {
- SHA1Transform(context->state, &data[i]);
- }
- j = 0;
- }
- else i = 0;
- memcpy(&context->buffer[j], &data[i], len - i);
-}
-
-
-/* Add padding and return the message digest. */
-
-void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
-{
- unsigned i;
- unsigned char finalcount[8];
- unsigned char c;
-
-#if 0 /* untested "improvement" by DHR */
- /* Convert context->count to a sequence of bytes
- * in finalcount. Second element first, but
- * big-endian order within element.
- * But we do it all backwards.
- */
- unsigned char *fcp = &finalcount[8];
-
- for (i = 0; i < 2; i++)
- {
- uint32_t t = context->count[i];
- int j;
-
- for (j = 0; j < 4; t >>= 8, j++)
- *--fcp = (unsigned char) t;
- }
-#else
- for (i = 0; i < 8; i++) {
- finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
- >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
- }
-#endif
- c = 0200;
- SHA1Update(context, &c, 1);
- while ((context->count[0] & 504) != 448) {
- c = 0000;
- SHA1Update(context, &c, 1);
- }
- SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
- for (i = 0; i < 20; i++) {
- digest[i] = (unsigned char)
- ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
- }
- /* Wipe variables */
- memset(context, '\0', sizeof(*context));
- memset(&finalcount, '\0', sizeof(finalcount));
-}
-/* ================ end of sha1.c ================ */
blob - bab0c44368bb83af338fd9696362713379d471f4 (mode 644)
blob + /dev/null
--- src/sha1.h
+++ /dev/null
-#ifndef SHA1_H
-#define SHA1_H
-
-/*
- * SHA-1 in C By Steve Reid <steve@edmweb.com>
- * 100% Public Domain
- */
-
-typedef struct {
- uint32_t state[5];
- uint32_t count[2];
- unsigned char buffer[64];
-} SHA1_CTX;
-
-void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
-void SHA1Init(SHA1_CTX* context);
-void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);
-void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
-
-#endif /* SHA1_H */
blob - 8ed6d72e0fa32ea9a9f7a7024703807968db0505
blob + e495103a2bb4c1a2bf2c2651d66106754e8e7ae4
--- src/testres.c
+++ src/testres.c
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
+#include <parse_common.h>
#include "metrics.h"
-#include "parse_common.h"
#include "testres.h"
#include "ui_console.h"
#include "ui_http.h"
blob - 9a2bad9bb570ac49e9ee2267a0dc3db3fe6d900a
blob + a1277d70f7ec91de84b48b5ef142a82c7212b306
--- src/ui_console.c
+++ src/ui_console.c
*/
#include "metrics.h"
+#include "testres.h"
#include "parse_common.h"
#include "ui_console.h"
#include "ui_common.h"
blob - 1ba93c8ea848033593eb1be781853d04c087608a
blob + becfa9a6440abd7e18ed012cef46bd52ecc6f9c6
--- src/ui_http.c
+++ src/ui_http.c
}
printf("</pre>\n");
}
+
+int cgi_parse(char *query_string, struct config *conf) {
+ if (query_string == NULL) {
+ conf->cgi_action = (char*)"/";
+ return 0;
+ }
+ conf->cgi_action = strtok(query_string, "=");
+ conf->cgi_args = strtok(NULL, "=");
+ if (conf->cgi_action == NULL) {
+ return 1;
+ }
+
+ return 0;
+}
blob - 8653417e0381286810e03b84494672e5c2551fbf
blob + 3baccae5e830aea7458c4d9ad6d481a52fefe56f
--- src/ui_http.h
+++ src/ui_http.h
void print_html_suites(struct suiteq * suites);
void print_html_tests(struct testq * tests);
void print_html_env();
-
void print_plot(struct reportq *reports);
+int cgi_parse(char *query_string, struct config *conf);
+
#endif /* UI_HTTP_H */
blob - 23b8afb7d729882f888f330c997293b09127dd4c (mode 644)
blob + /dev/null
--- tests/CMakeLists.txt
+++ /dev/null
-cmake_minimum_required (VERSION 3.9.2)
-
-set(CMAKE_C_FLAGS "-std=c99 -O0 -Wall -Wextra -Wimplicit")
-
-include(FindEXPAT)
-find_package(EXPAT REQUIRED)
-
-include_directories(${${PROJECT_NAME}_SOURCE_DIR}/src
- ${EXPAT_INCLUDE_DIRS}
- "/usr/local/include")
-link_directories("/usr/local/lib/")
-add_executable(${PROJECT_NAME}-tests testres_tests.c)
-target_link_libraries(${PROJECT_NAME}-tests
- ${EXPAT_LIBRARIES}
- ${PROJECT_NAME}-lib
- expat
- cunit
- m)
-
-add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}-tests WORKING_DIRECTORY tests/)
blob - 47ba471743272616ea98829b4f693871e6fb2b04 (mode 644)
blob + /dev/null
--- tests/testres_tests.c
+++ /dev/null
-#define _POSIX_C_SOURCE 200809L
-
-#include <stdio.h>
-#include <string.h>
-#include <arpa/inet.h>
-
-#include "CUnit/Basic.h"
-
-#include "parse_common.h"
-#include "parse_junit.h"
-#include "parse_testanything.h"
-#include "parse_subunit_v1.h"
-#include "parse_subunit_v2.h"
-#include "sha1.h"
-
-#define SAMPLE_FILE_JUNIT "samples/junit.xml"
-#define SAMPLE_FILE_SUBUNIT_V1 "samples/subunit_v1.subunit"
-#define SAMPLE_FILE_SUBUNIT_V2 "samples/subunit_v2.subunit"
-#define SAMPLE_FILE_TESTANYTHING "samples/testanything.tap"
-
-static void test_parse_testanything()
-{
- char *name = SAMPLE_FILE_TESTANYTHING;
- FILE *file;
- file = fopen(name, "r");
- CU_ASSERT_NOT_EQUAL_FATAL(file, NULL);
- parse_testanything(file);
- fclose(file);
-}
-
-static void test_read_subunit_v2_packet()
-{
- // Packet sample, with test id, runnable set, status=enumeration.
- // Spaces below are to visually break up:
- // signature / flags / length / testid / crc32
- // b3 2901 0c 03666f6f 08555f1b
- // echo 03666f6f | xxd -p -r
-
- CU_FAIL_FATAL("not implemented");
-
- subunit_header sample_header = { .signature = 0xb3, .flags = ntohs(0x2901) };
- uint16_t sample_length = 0x0c;
- uint32_t sample_testid = 0x03666f6f;
- uint32_t sample_crc32 = 0x08555f1b;
-
- char* buf = NULL;
- size_t buf_size = 0;
- tailq_test * test;
- FILE* stream = open_memstream(&buf, &buf_size);
- fwrite(&sample_header, 1, sizeof(sample_header), stream);
- fwrite(&sample_length, 1, sizeof(sample_length), stream);
- fwrite(&sample_testid, 1, sizeof(sample_testid), stream);
- fwrite(&sample_crc32, 1, sizeof(sample_crc32), stream);
-
- test = read_subunit_v2_packet(stream);
- fclose(stream);
-
- CU_ASSERT_STRING_EQUAL(test->name, "");
-
- free(buf);
- free(test);
-}
-
-static void test_is_subunit_v2()
-{
- char *file_subunit_v1 = SAMPLE_FILE_SUBUNIT_V1;
- char *file_subunit_v2 = SAMPLE_FILE_SUBUNIT_V2;
-
- CU_ASSERT(is_subunit_v2(file_subunit_v1) == 1);
- CU_ASSERT(is_subunit_v2(file_subunit_v2) == 0);
-}
-
-static void test_parse_subunit_v2()
-{
- CU_FAIL_FATAL("not implemented");
-
- char *name = SAMPLE_FILE_SUBUNIT_V2;
- FILE *file;
-
- file = fopen(name, "r");
- CU_ASSERT_NOT_EQUAL_FATAL(file, NULL);
-
- struct suiteq *suites;
- suites = parse_subunit_v2(file);
- fclose(file);
- free(suites);
-}
-
-static void test_parse_subunit_v1()
-{
- char *name = SAMPLE_FILE_SUBUNIT_V1;
- FILE *file;
-
- file = fopen(name, "r");
- CU_ASSERT_NOT_EQUAL_FATAL(file, NULL);
-
- struct suiteq *suites;
- suites = parse_subunit_v1(file);
-
- fclose(file);
- free(suites);
-}
-
-static void test_parse_subunit_v1_line()
-{
- char *test_sample[] = {
- "test test LABEL",
- "testing test LABEL",
- "test: test LABEL",
- "testing: test LABEL",
- "success test LABEL",
- "success: test LABEL",
- "successful test LABEL",
- "successful: test LABEL",
- "failure: test LABEL",
- "failure: test LABEL DETAILS",
- "error: test LABEL",
- "error: test LABEL DETAILS",
- "skip test LABEL",
- "skip: test LABEL",
- "skip test LABEL DETAILS",
- "skip: test LABEL DETAILS",
- "xfail test LABEL",
- "xfail: test LABEL",
- "xfail test LABEL DETAILS",
- "xfail: test LABEL DETAILS",
- "uxsuccess test LABEL",
- "uxsuccess: test LABEL",
- "uxsuccess test LABEL DETAILS",
- "uxsuccess: test LABEL DETAILS",
- "progress: +10",
- "progress: -14",
- "progress: push",
- "progress: pop",
- "tags: -small +big",
- "time: 2018-09-10 23:59:29Z" };
-
- char** qq = test_sample;
- for (int i = 0; i < (int)(sizeof(test_sample)/sizeof(char*)); ++i) {
- parse_line_subunit_v1(*qq);
- ++qq;
- }
-}
-
-static void test_parse_junit()
-{
- FILE *file;
- char *name = SAMPLE_FILE_JUNIT;
-
- file = fopen(name, "r");
- CU_ASSERT_NOT_EQUAL_FATAL(file, NULL);
- parse_junit(file);
- fclose(file);
-}
-
-static void test_sha1()
-{
-
- struct {
- char *word;
- char *digest;
- } tests[] = {
- /* Test Vectors (from FIPS PUB 180-1) */
- { "abc", "a9993e364706816aba3e25717850c26c9cd0d89d" },
- { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1" },
- { NULL, NULL },
- };
-
- int i, length = 20;
- unsigned char digest[length];
- char *str = calloc(length, sizeof(unsigned char*));
- for (i = 0; tests[i].word != NULL; i++) {
- const char *word = tests[i].word;
- SHA1_CTX ctx;
- SHA1Init(&ctx);
- SHA1Update(&ctx, (const unsigned char*)word, strlen(word));
- SHA1Final(digest, &ctx);
- /*
- if (digest_to_str(str, digest, length) != tests[i].digest) {
- CU_get_error();
- }
- */
- }
- free(str);
-}
-
-int main()
-{
- CU_pSuite pSuite = NULL;
-
- /* initialize the CUnit test registry */
- if (CUE_SUCCESS != CU_initialize_registry())
- return CU_get_error();
-
- /* add a suite to the registry */
- pSuite = CU_add_suite("Suite_1", NULL, NULL);
- if (NULL == pSuite) {
- CU_cleanup_registry();
- return CU_get_error();
- }
-
- /* add the tests to the suite */
- if ((NULL == CU_add_test(pSuite, "test_parse_junit()", test_parse_junit)) ||
- (NULL == CU_add_test(pSuite, "test_parse_subunit_v1()", test_parse_subunit_v1)) ||
- (NULL == CU_add_test(pSuite, "test_parse_subunit_v1_line()", test_parse_subunit_v1_line)) ||
- (NULL == CU_add_test(pSuite, "test_parse_subunit_v2()", test_parse_subunit_v2)) ||
- (NULL == CU_add_test(pSuite, "test_read_subunit_v2_packet()", test_read_subunit_v2_packet)) ||
- (NULL == CU_add_test(pSuite, "test_is_subunit_v2()", test_is_subunit_v2)) ||
- (NULL == CU_add_test(pSuite, "test_parse_testanything()", test_parse_testanything)) ||
- (NULL == CU_add_test(pSuite, "test_sha1()", test_sha1)))
- {
- CU_cleanup_registry();
- return CU_get_error();
- }
-
- /* Run all tests using the CUnit Basic interface */
- CU_basic_set_mode(CU_BRM_VERBOSE);
- CU_basic_run_tests();
- CU_cleanup_registry();
- return CU_get_error();
-}