array_insert(failures, -1, &failure);
}
+/**
+ * Collect warning information, add failure_t to array
+ */
+static bool collect_warning_info(array_t *warnings, char *name, int i)
+{
+ failure_t warning = {
+ .name = name,
+ .i = i,
+ };
+
+ warning.line = test_warning_get(warning.msg, sizeof(warning.msg),
+ &warning.file);
+ if (warning.line)
+ {
+ array_insert(warnings, -1, &warning);
+ }
+ return warning.line;
+}
+
/**
* Print array of collected failure_t to stderr
*/
-static void print_failures(array_t *failures)
+static void print_failures(array_t *failures, bool warnings)
{
failure_t failure;
while (array_remove(failures, 0, &failure))
{
- fprintf(stderr, " %sFailure in '%s': %s (",
- TTY(RED), failure.name, failure.msg);
+ if (warnings)
+ {
+ fprintf(stderr, " %sWarning in '%s': %s (",
+ TTY(YELLOW), failure.name, failure.msg);
+ }
+ else
+ {
+ fprintf(stderr, " %sFailure in '%s': %s (",
+ TTY(RED), failure.name, failure.msg);
+ }
if (failure.line)
{
fprintf(stderr, "%s:%d, ", failure.file, failure.line);
enumerator_t *enumerator;
test_function_t *tfun;
int passed = 0;
- array_t *failures;
+ array_t *failures, *warnings;
failures = array_create(sizeof(failure_t), 0);
+ warnings = array_create(sizeof(failure_t), 0);
fprintf(stderr, " Running case '%s': ", tcase->name);
fflush(stderr);
if (!leaks)
{
rounds++;
- fprintf(stderr, "%s+%s", TTY(GREEN), TTY(DEF));
+ if (!collect_warning_info(warnings, tfun->name, i))
+ {
+ fprintf(stderr, "%s+%s", TTY(GREEN), TTY(DEF));
+ }
+ else
+ {
+ fprintf(stderr, "%s~%s", TTY(YELLOW), TTY(DEF));
+ }
}
}
else
fprintf(stderr, "\n");
- print_failures(failures);
+ print_failures(warnings, TRUE);
+ print_failures(failures, FALSE);
array_destroy(failures);
+ array_destroy(warnings);
return passed == array_count(tcase->functions);
}
*/
static bool worker_failed;
+/**
+ * Warning message buf
+ */
+static char warning_buf[4096];
+
+/**
+ * Source file warning was issued
+ */
+static const char *warning_file;
+
+/**
+ * Line of source file warning was issued
+ */
+static int warning_line;
+
/**
* See header.
*/
test_failure();
}
+
+/**
+ * See header.
+ */
+void test_warn_msg(const char *file, int line, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(warning_buf, sizeof(warning_buf), fmt, args);
+ warning_line = line;
+ warning_file = file;
+ va_end(args);
+}
+
/**
* See header.
*/
return failure_line;
}
+/**
+ * See header.
+ */
+int test_warning_get(char *msg, int len, const char **file)
+{
+ int line = warning_line;
+
+ if (!line)
+ {
+ return 0;
+ }
+ strncpy(msg, warning_buf, len - 1);
+ msg[len - 1] = 0;
+ *file = warning_file;
+ /* reset state */
+ warning_line = 0;
+ return line;
+}
+
/**
* See header.
*/
*/
int test_failure_get(char *msg, int len, const char **file);
+/**
+ * Get info about a warning if one was issued during the test. Resets the
+ * warning state.
+ *
+ * @param msg buffer receiving warning
+ * @param len size of msg buffer
+ * @param file pointer receiving source code file
+ * @return source code line number, 0 if no warning issued
+ */
+int test_warning_get(char *msg, int len, const char **file);
+
/**
* Get a backtrace for a failure.
*
*/
void test_fail_msg(const char *file, int line, char *fmt, ...);
+/**
+ * Issue a warning for a particular test with a message using printf style
+ * arguments. This does not fail the test, and only the last warning for each
+ * test is kept.
+ *
+ * @param file source code file name
+ * @param line source code line number
+ * @param fmt printf format string
+ * @param ... arguments for fmt
+ */
+void test_warn_msg(const char *file, int line, char *fmt, ...);
+
/**
* Let a test fail if one of the worker threads has failed (only if called from
* the main thread).
#define ck_assert_msg test_assert_msg
#define ck_assert_str_eq test_str_eq
#define ck_assert_chunk_eq test_chunk_eq
+#define warn(fmt, ...) test_warn_msg(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define fail(fmt, ...) test_fail_msg(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define fail_if(x, fmt, ...) \
({ \