/*
* Copyright (c) 2013 Vojtech Horky
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/** @file
*
* Common functions for test results reporting.
*/
#include "../internal.h"
#ifdef __helenos__
#include <mem.h>
#else
#pragma warning(push, 0)
#include <string.h>
#pragma warning(pop)
#endif
#pragma warning(push, 0)
#include <stdio.h>
#pragma warning(pop)
/** Currently used report ops. */
static pcut_report_ops_t *report_ops = NULL;
/** Call a report function if it is available.
*
* @param op Operation to be called on the pcut_report_ops_t.
* @param ... Arguments to the operation.
*/
#define REPORT_CALL(op, ...) \
if ((report_ops != NULL) && (report_ops->op != NULL)) report_ops->op(__VA_ARGS__)
/** Call a report function if it is available.
*
* @param op Operation to be called on the pcut_report_ops_t.
*/
#define REPORT_CALL_NO_ARGS(op) \
if ((report_ops != NULL) && (report_ops->op != NULL)) report_ops->op()
/** Print error message.
*
* NULL or empty message is silently ignored.
*
* The message is printed with a special 3-zero-byte prefix to be later
* parsed when reporting the results from a different process.
*
* @param msg The message to be printed.
*/
void pcut_print_fail_message(const char *msg) {
if (msg == NULL) {
return;
}
if (pcut_str_size(msg) == 0) {
return;
}
printf("%c%c%c%s\n%c", 0, 0, 0, msg, 0);
}
/** Size of buffer for storing error messages or extra test output. */
#define BUFFER_SIZE 4096
/** Buffer for stdout from the test. */
static char buffer_for_extra_output[BUFFER_SIZE];
/** Buffer for assertion and other error messages. */
static char buffer_for_error_messages[BUFFER_SIZE];
/** Parse output of a single test.
*
* @param full_output Full unparsed output.
* @param full_output_size Size of @p full_output in bytes.
* @param stdio_buffer Where to store normal output from the test.
* @param stdio_buffer_size Size of @p stdio_buffer in bytes.
* @param error_buffer Where to store error messages from the test.
* @param error_buffer_size Size of @p error_buffer in bytes.
*/
static void parse_command_output(const char *full_output, size_t full_output_size,
char *stdio_buffer, size_t stdio_buffer_size,
char *error_buffer, size_t error_buffer_size) {
memset(stdio_buffer, 0, stdio_buffer_size);
memset(error_buffer, 0, error_buffer_size);
/* Ensure that we do not read past the full_output. */
if (full_output[full_output_size - 1] != 0) {
/* FIXME: can this happen? */
return;
}
while (1) {
size_t message_length;
/* First of all, count number of zero bytes before the text. */
size_t cont_zeros_count = 0;
while (full_output[0] == 0) {
cont_zeros_count++;
full_output++;
full_output_size--;
if (full_output_size == 0) {
return;
}
}
/* Determine the length of the text after the zeros. */
message_length = pcut_str_size(full_output);
if (cont_zeros_count < 2) {
/* Okay, standard I/O. */
if (message_length > stdio_buffer_size) {
/* TODO: handle gracefully */
return;
}
memcpy(stdio_buffer, full_output, message_length);
stdio_buffer += message_length;
stdio_buffer_size -= message_length;
} else {
/* Error message. */
if (message_length > error_buffer_size) {
/* TODO: handle gracefully */
return;
}
memcpy(error_buffer, full_output, message_length);
error_buffer += message_length;
error_buffer_size -= message_length;
}
full_output += message_length + 1;
full_output_size -= message_length + 1;
}
}
/** Use given set of functions for error reporting.
*
* @param ops Functions to use.
*/
void pcut_report_register_handler(pcut_report_ops_t *ops) {
report_ops = ops;
}
/** Initialize the report.
*
* @param all_items List of all tests that could be run.
*/
void pcut_report_init(pcut_item_t *all_items) {
REPORT_CALL(init, all_items);
}
/** Report that a test suite was started.
*
* @param suite Suite that was just started.
*/
void pcut_report_suite_start(pcut_item_t *suite) {
REPORT_CALL(suite_start, suite);
}
/** Report that a test suite was completed.
*
* @param suite Suite that just completed.
*/
void pcut_report_suite_done(pcut_item_t *suite) {
REPORT_CALL(suite_done, suite);
}
/** Report that a test is about to start.
*
* @param test Test to be run just about now.
*/
void pcut_report_test_start(pcut_item_t *test) {
REPORT_CALL(test_start, test);
}
/** Report that a test was completed.
*
* @param test Test that just finished.
* @param outcome Outcome of the test.
* @param error_message Buffer with error message.
* @param teardown_error_message Buffer with error message from a tear-down function.
* @param extra_output Extra output from the test (stdout).
*/
void pcut_report_test_done(pcut_item_t *test, int outcome,
const char *error_message, const char *teardown_error_message,
const char *extra_output) {
REPORT_CALL(test_done, test, outcome, error_message, teardown_error_message,
extra_output);
}
/** Report that a test was completed with unparsed test output.
*
* @param test Test that just finished
* @param outcome Outcome of the test.
* @param unparsed_output Buffer with all the output from the test.
* @param unparsed_output_size Size of @p unparsed_output in bytes.
*/
void pcut_report_test_done_unparsed(pcut_item_t *test, int outcome,
const char *unparsed_output, size_t unparsed_output_size) {
parse_command_output(unparsed_output, unparsed_output_size,
buffer_for_extra_output, BUFFER_SIZE,
buffer_for_error_messages, BUFFER_SIZE);
pcut_report_test_done(test, outcome, buffer_for_error_messages, NULL, buffer_for_extra_output);
}
/** Close the report.
*
*/
void pcut_report_done(void) {
REPORT_CALL_NO_ARGS(done);
}