/*
* Automated Testing Framework (atf)
*
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* 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
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* ---------------------------------------------------------------------
* Auxiliary functions.
* --------------------------------------------------------------------- */
enum expect_type {
};
struct context {
const char *resfile;
int expect_exitcode;
int expect_signo;
};
static void check_fatal_error(atf_error_t);
static void report_fatal_error(const char *, ...)
static atf_error_t write_resfile(const int, const char *, const int,
const atf_dynstr_t *);
static void create_resfile(const char *, const char *, const int,
atf_dynstr_t *);
static void error_in_expect(struct context *, const char *, ...)
static void validate_expect(struct context *);
const char *, va_list);
const char *, ...);
const int, const char *, const bool,
void (*)(struct context *, atf_dynstr_t *));
static atf_error_t check_prog_in_dir(const char *, void *);
static void
{
ctx->fail_count = 0;
ctx->expect_fail_count = 0;
ctx->expect_exitcode = 0;
ctx->expect_signo = 0;
}
static void
{
if (atf_is_error(err)) {
abort();
}
}
static void
{
abort();
}
/** Writes to a results file.
*
* The results file is supposed to be already open.
*
* This function returns an error code instead of exiting in case of error
* because the caller needs to clean up the reason object before terminating.
*/
static atf_error_t
const atf_dynstr_t *reason)
{
const char *r;
int count = 0;
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
if (arg != -1) {
}
r = atf_dynstr_cstring(reason);
}
continue; /* Retry. */
if (ret != -1)
return atf_no_error();
return atf_libc_error(
}
/** Creates a results file.
*
* The input reason is released in all cases.
*
* An error in this function is considered to be fatal, hence why it does
* not return any error code.
*/
static void
{
} else {
if (fd == -1) {
resfile);
} else {
}
}
}
/** Fails a test case if validate_expect fails. */
static void
{
}
/** Ensures that the "expect" state is correct.
*
* Call this function before modifying the current value of expect.
*/
static void
{
"but it continued execution");
"continued execution");
"were raised");
else
/* Nothing to validate. */
"signal but it continued execution");
"execution");
} else
}
static void
{
}
static void
{
} else {
}
}
static void
{
ctx->expect_fail_count++;
ctx->fail_count++;
} else {
}
}
static void
{
"a pass instead");
} else {
"not expecting such condition");
}
}
static void
{
} else {
"expect pass mode");
}
}
*
* The formatted reason is stored in out_reason. out_reason is initialized
* in this function and is supposed to be released by the caller. In general,
* the reason will eventually be fed to create_resfile, which will release
* it.
*
* Errors in this function are fatal. Rationale being: reasons are used to
* create results files; if we can't format the reason correctly, the result
* of the test program will be bogus. So it's better to just exit with a
* fatal error.
*/
static void
{
if (source_file != NULL) {
} else {
PRE(source_line == 0);
}
if (!atf_is_error(err)) {
}
}
static void
const char *reason, ...)
{
}
static void
const bool expr_result,
{
if (expr_result) {
if (exp_errno != actual_errno) {
}
} else {
expr_str);
}
}
struct prog_found_pair {
const char *prog;
bool found;
};
static atf_error_t
{
err = atf_no_error();
else {
if (atf_is_error(err))
goto out_p;
if (!atf_is_error(err))
else {
err = atf_no_error();
}
atf_fs_path_fini(&p);
}
return err;
}
static atf_error_t
{
if (atf_is_error(err))
goto out;
if (atf_fs_path_is_absolute(&p)) {
if (atf_is_error(err)) {
atf_fs_path_fini(&p);
"not be found", prog);
}
} else {
if (atf_is_error(err))
goto out_p;
atf_fs_path_fini(&p);
report_fatal_error("Relative paths are not allowed when searching "
"for a program (%s)", prog);
}
if (atf_is_error(err))
goto out_bp;
atf_fs_path_fini(&p);
"not be found in the PATH", prog);
}
}
atf_fs_path_fini(&p);
out:
return err;
}
/* ---------------------------------------------------------------------
* The "atf_tc" type.
* --------------------------------------------------------------------- */
struct atf_tc_impl {
const char *m_ident;
};
/*
*/
const char *const *config)
{
err = atf_no_memory_error();
goto err;
}
if (atf_is_error(err))
goto err;
if (atf_is_error(err))
goto err_vars;
if (atf_is_error(err))
goto err_map;
if (atf_is_error(err))
goto err_map;
}
/* XXX Should the head be able to return error codes? */
report_fatal_error("Test case head modified the read-only 'ident' "
"property");
}
return err;
err:
return err;
}
const char *const *config)
{
}
void
{
}
/*
* Getters.
*/
const char *
{
}
const char *
{
const char *val;
return val;
}
const char *
const char *defval)
{
const char *val;
else
return val;
}
bool
{
bool val;
const char *strval;
if (atf_is_error(err)) {
atf_tc_fail("Configuration variable %s does not have a valid "
}
return val;
}
bool
const bool defval)
{
bool val;
else
return val;
}
long
{
long val;
const char *strval;
if (atf_is_error(err)) {
atf_tc_fail("Configuration variable %s does not have a valid "
}
return val;
}
long
const long defval)
{
long val;
else
return val;
}
const char *
{
const char *val;
return val;
}
char **
{
}
bool
{
}
bool
{
}
/*
* Modifiers.
*/
{
char *value;
if (!atf_is_error(err))
else
return err;
}
/* ---------------------------------------------------------------------
* Free functions, as they should be publicly but they can't.
* --------------------------------------------------------------------- */
const char *, va_list);
static void _atf_tc_fail_requirement(struct context *, const char *,
static void _atf_tc_require_prog(struct context *, const char *);
const int, const char *, const bool);
const int, const char *, const bool);
static void _atf_tc_expect_pass(struct context *);
static void _atf_tc_expect_exit(struct context *, const int, const char *,
va_list);
static void _atf_tc_expect_signal(struct context *, const int, const char *,
va_list);
static void _atf_tc_expect_death(struct context *, const char *,
va_list);
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
const bool expr_result)
{
}
static void
const bool expr_result)
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
/* ---------------------------------------------------------------------
* Free functions.
* --------------------------------------------------------------------- */
{
if (Current.fail_count > 0) {
} else if (Current.expect_fail_count > 0) {
} else {
}
return atf_no_error();
}
{
return atf_no_error(); /* XXX */
}
/* ---------------------------------------------------------------------
* Free functions that depend on Current.
* --------------------------------------------------------------------- */
/*
* All the functions below provide delegates to other internal functions
* (prefixed by _) that take the current test case as an argument to
* prevent them from accessing global state. This is to keep the side-
* effects of the internal functions clearer and easier to understand.
*
* The public API should never have hid the fact that it needs access to
* the current test case (other than maybe in the macros), but changing it
* is hard. TODO: Revisit in the future.
*/
void
{
}
void
{
}
void
{
}
void
const char *fmt, ...)
{
}
void
atf_tc_pass(void)
{
}
void
{
}
void
{
}
void
const char *expr_str, const bool expr_result)
{
}
void
const char *expr_str, const bool expr_result)
{
}
void
atf_tc_expect_pass(void)
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}