blob: 4d9ddc8a04480ca80a377586c932df47efcb4680 [file] [log] [blame]
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
#ifndef SVN_TEST_H
#define SVN_TEST_H
#ifndef SVN_ENABLE_DEPRECATION_WARNINGS_IN_TESTS
#undef SVN_DEPRECATED
#define SVN_DEPRECATED
#endif /* ! SVN_ENABLE_DEPRECATION_WARNINGS_IN_TESTS */
#include <stdio.h>
#include <apr_pools.h>
#include "svn_delta.h"
#include "svn_path.h"
#include "svn_types.h"
#include "svn_error.h"
#include "svn_string.h"
#include "svn_auth.h"
#include "svn_time.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** Handy macro to test a condition, returning SVN_ERR_TEST_FAILED if FALSE
*
* This macro should be used in place of SVN_ERR_ASSERT() since we don't
* want to core-dump the test.
*/
#define SVN_TEST_ASSERT(expr) \
do { \
if (!(expr)) \
return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, \
"assertion '%s' failed at %s:%d", \
#expr, __FILE__, __LINE__); \
} while (0)
/**
* Macro for testing assumptions when the context does not allow
* returning an svn_error_t*.
*
* Will write to stderr and cause a segfault if EXPR is false.
*/
#define SVN_TEST_ASSERT_NO_RETURN(expr) \
do { \
if (!(expr)) \
{ \
unsigned int z_e_r_o_p_a_g_e__; \
fprintf(stderr, "TEST ASSERTION FAILED: %s\n", #expr); \
z_e_r_o_p_a_g_e__ = *(volatile unsigned int*)0; \
*(volatile unsigned int*)0 = z_e_r_o_p_a_g_e__; \
} \
} while (0)
/** Handy macro for testing an expected svn_error_t return value.
* EXPECTED must be a real error (neither SVN_NO_ERROR nor APR_SUCCESS).
* The error returned by EXPR will be cleared.
*/
#define SVN_TEST_ASSERT_ERROR(expr, expected) \
do { \
svn_error_t *err__ = (expr); \
SVN_ERR_ASSERT((expected)); \
if (err__ == SVN_NO_ERROR || err__->apr_err != (expected)) \
return err__ ? svn_error_createf(SVN_ERR_TEST_FAILED, err__, \
"Expected error %s but got %s", \
svn_error_symbolic_name(expected), \
svn_error_symbolic_name( \
err__->apr_err)) \
: svn_error_createf(SVN_ERR_TEST_FAILED, err__, \
"Expected error %s but got %s", \
svn_error_symbolic_name(expected), \
"SVN_NO_ERROR"); \
svn_error_clear(err__); \
} while (0)
/** Handy macro for testing that an svn_error_t is returned.
* The result must be neither SVN_NO_ERROR nor SVN_ERR_ASSERTION_FAIL.
* The error returned by EXPR will be cleared.
*/
#define SVN_TEST_ASSERT_ANY_ERROR(expr) \
do { \
svn_error_t *err__ = (expr); \
if (err__ == SVN_NO_ERROR || err__->apr_err == SVN_ERR_ASSERTION_FAIL)\
return err__ ? svn_error_createf(SVN_ERR_TEST_FAILED, err__, \
"Expected error but got %s", \
"SVN_ERR_ASSERTION_FAIL") \
: svn_error_createf(SVN_ERR_TEST_FAILED, err__, \
"Expected error but got %s", \
"SVN_NO_ERROR"); \
svn_error_clear(err__); \
} while (0)
/** Handy macro for testing string equality.
*
* EXPR and/or EXPECTED_EXPR may be NULL which compares equal to NULL and
* not equal to any non-NULL string.
*/
#define SVN_TEST_STRING_ASSERT(expr, expected_expr) \
do { \
const char *tst_str1 = (expr); \
const char *tst_str2 = (expected_expr); \
\
if (tst_str2 == NULL && tst_str1 == NULL) \
break; \
if ((tst_str1 == NULL) || (tst_str2 == NULL) \
|| (strcmp(tst_str2, tst_str1) != 0)) \
return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, \
"Strings not equal\n Expected: '%s'\n Found: '%s'" \
"\n at %s:%d", \
tst_str2, tst_str1, __FILE__, __LINE__); \
} while(0)
/** Handy macro for testing integer equality.
*/
#define SVN_TEST_INT_ASSERT(expr, expected_expr) \
do { \
apr_int64_t tst_int1 = (expr); \
apr_int64_t tst_int2 = (expected_expr); \
\
if (tst_int1 != tst_int2) \
return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, \
"Integers not equal\n" \
" Expected: %" APR_INT64_T_FMT "\n" \
" Found: %" APR_INT64_T_FMT "\n" \
" at %s:%d", \
tst_int2, tst_int1, __FILE__, __LINE__); \
} while(0)
/** Handy macro for testing apr_time_t equality.
*
* WITHIN_EXPR specifies the proximity of the comparison.
*/
#define SVN_TEST_TIME_ASSERT(expr, expected_expr, within_expr) \
do { \
apr_time_t actual_time = (expr); \
apr_time_t expected_time = (expected_expr); \
apr_interval_time_t within_time = (within_expr); \
\
if (actual_time < expected_time - within_time || \
actual_time > expected_time + within_time) \
{ \
svn_error_t *err = \
svn_error_create(SVN_ERR_TEST_FAILED, NULL, NULL); \
\
err->message = apr_psprintf( \
err->pool, \
"Time values not equal\n" \
" Expected: %s (%" APR_TIME_T_FMT ")\n" \
" Found: %s (%" APR_TIME_T_FMT ")\n" \
" Proximity: %" APR_TIME_T_FMT "ms\n" \
" at %s:%d", \
svn_time_to_cstring(expected_time, err->pool), \
expected_time, \
svn_time_to_cstring(actual_time, err->pool), \
actual_time, \
apr_time_as_msec(within_time), \
__FILE__, __LINE__); \
\
return err; \
} \
} while(0)
/* Baton for any arguments that need to be passed from main() to svn
* test functions.
*/
typedef struct svn_test_opts_t
{
/* The name of the application (to generate unique names) */
const char *prog_name;
/* Description of the fs backend that should be used for testing. */
const char *fs_type;
/* Config file. */
const char *config_file;
/* Source dir. */
const char *srcdir;
/* Repository dir: temporary directory to create repositories in as subdir */
const char *repos_dir;
/* Repository url: The url to access REPOS_DIR as */
const char *repos_url;
/* Memcached server. */
const char *memcached_server;
/* Repository template: pre-created repository to copy for tests */
const char *repos_template;
/* Minor version to use for servers and FS backends, or zero to use
the current latest version. */
int server_minor_version;
svn_boolean_t verbose;
/* Add future "arguments" here. */
} svn_test_opts_t;
/* Prototype for test driver functions. */
typedef svn_error_t* (*svn_test_driver2_t)(apr_pool_t *pool);
/* Prototype for test driver functions which need options. */
typedef svn_error_t* (*svn_test_driver_opts_t)(const svn_test_opts_t *opts,
apr_pool_t *pool);
/* Prototype for test predicate functions. */
typedef svn_boolean_t (*svn_test_predicate_func_t)(const svn_test_opts_t *opts,
const char *predicate_value,
apr_pool_t *pool);
/* Test modes. */
enum svn_test_mode_t
{
svn_test_pass,
svn_test_xfail,
svn_test_skip,
svn_test_all
};
/* Structure for runtime test predicates. */
struct svn_test_predicate_t
{
/* The predicate function. */
svn_test_predicate_func_t func;
/* The value that the predicate function tests. */
const char *value;
/* The test mode that's used if the predicate matches. */
enum svn_test_mode_t alternate_mode;
/* Description for the test log */
const char *description;
};
/* Each test gets a test descriptor, holding the function and other
* associated data.
*/
struct svn_test_descriptor_t
{
/* Is the test marked XFAIL? */
enum svn_test_mode_t mode;
/* A pointer to the test driver function. */
svn_test_driver2_t func2;
/* A pointer to the test driver function. */
svn_test_driver_opts_t func_opts;
/* A descriptive message for this test. */
const char *msg;
/* An optional description of a work-in-progress test. */
const char *wip;
/* An optional runtiume predicate. */
struct svn_test_predicate_t predicate;
};
/* All Subversion test programs include an array of svn_test_descriptor_t's
* (all of our sub-tests) that begins and ends with a SVN_TEST_NULL entry.
* This descriptor must be passed to the svn_test_main function.
*
* MAX_THREADS is the number of concurrent tests to run. Set to 1 if
* all tests must be executed serially. Numbers less than 1 mean
* "unbounded".
*/
int svn_test_main(int argc, const char *argv[], int max_threads,
struct svn_test_descriptor_t *test_funcs);
/* Boilerplate for the main function for each test program. */
#define SVN_TEST_MAIN \
int main(int argc, const char *argv[]) \
{ \
return svn_test_main(argc, argv, \
max_threads, test_funcs); \
}
/* A null initializer for the test descriptor. */
#define SVN_TEST_NULL {0}
/* Initializer for PASS tests */
#define SVN_TEST_PASS2(func, msg) {svn_test_pass, func, NULL, msg}
/* Initializer for XFAIL tests */
#define SVN_TEST_XFAIL2(func, msg) {svn_test_xfail, func, NULL, msg}
/* Initializer for conditional XFAIL tests */
#define SVN_TEST_XFAIL_COND2(func, p, msg) \
{(p) ? svn_test_xfail : svn_test_pass, func, NULL, msg}
/* Initializer for SKIP tests */
#define SVN_TEST_SKIP2(func, p, msg) \
{(p) ? svn_test_skip : svn_test_pass, func, NULL, msg}
/* Similar macros, but for tests needing options. */
#define SVN_TEST_OPTS_PASS(func, msg) {svn_test_pass, NULL, func, msg}
#define SVN_TEST_OPTS_XFAIL(func, msg) {svn_test_xfail, NULL, func, msg}
#define SVN_TEST_OPTS_XFAIL_COND(func, p, msg) \
{(p) ? svn_test_xfail : svn_test_pass, NULL, func, msg}
#define SVN_TEST_OPTS_XFAIL_OTOH(func, msg, predicate) \
{svn_test_xfail, NULL, func, msg, NULL, predicate}
#define SVN_TEST_OPTS_SKIP(func, p, msg) \
{(p) ? svn_test_skip : svn_test_pass, NULL, func, msg}
/* Initializer for XFAIL tests for works-in-progress. */
#define SVN_TEST_WIMP(func, msg, wip) \
{svn_test_xfail, func, NULL, msg, wip}
#define SVN_TEST_WIMP_COND(func, p, msg, wip) \
{(p) ? svn_test_xfail : svn_test_pass, func, NULL, msg, wip}
#define SVN_TEST_OPTS_WIMP(func, msg, wip) \
{svn_test_xfail, NULL, func, msg, wip}
#define SVN_TEST_OPTS_WIMP_COND(func, p, msg, wip) \
{(p) ? svn_test_xfail : svn_test_pass, NULL, func, msg, wip}
/* Return a pseudo-random number based on SEED, and modify SEED.
*
* This is a "good" pseudo-random number generator, intended to replace
* all those "bad" rand() implementations out there.
*/
apr_uint32_t svn_test_rand(apr_uint32_t *seed);
/* Add PATH to the test cleanup list. */
void svn_test_add_dir_cleanup(const char *path);
/* A simple representation for a tree node. */
typedef struct svn_test__tree_entry_t
{
const char *path; /* relpath of this node */
const char *contents; /* text contents, or NULL for a directory */
}
svn_test__tree_entry_t;
/* Wrapper for an array of svn_test__tree_entry_t's. */
typedef struct svn_test__tree_t
{
svn_test__tree_entry_t *entries;
int num_entries;
}
svn_test__tree_t;
/* The standard Greek tree, terminated by a node with path=NULL. */
extern const svn_test__tree_entry_t svn_test__greek_tree_nodes[21];
/* Returns a path to BASENAME within the transient data area for the
current test. */
const char *
svn_test_data_path(const char* basename, apr_pool_t *result_pool);
/* Some tests require the --srcdir option and should use this function
* to get it. If not provided, print a warning and attempt to run the
* tests under the assumption that --srcdir is the current directory. */
svn_error_t *
svn_test_get_srcdir(const char **srcdir,
const svn_test_opts_t *opts,
apr_pool_t *pool);
/* Initializes a standard auth baton for accessing the repositories */
svn_error_t *
svn_test__init_auth_baton(svn_auth_baton_t **baton,
apr_pool_t *result_pool);
/* Create a temp folder for test & schedule it for automatic cleanup.
* Uses POOL for all allocations. */
svn_error_t *
svn_test_make_sandbox_dir(const char **sb_dir_p,
const char *sb_name,
apr_pool_t *pool);
/*
* Test predicates
*/
#define SVN_TEST_PASS_IF_FS_TYPE_IS(fs_type) \
{ svn_test__fs_type_is, fs_type, svn_test_pass, \
"PASS if fs-type = " fs_type }
#define SVN_TEST_PASS_IF_FS_TYPE_IS_NOT(fs_type) \
{ svn_test__fs_type_not, fs_type, svn_test_pass, \
"PASS if fs-type != " fs_type }
/* Return TRUE if the fs-type in OPTS matches PREDICATE_VALUE. */
svn_boolean_t
svn_test__fs_type_is(const svn_test_opts_t *opts,
const char *predicate_value,
apr_pool_t *pool);
/* Return TRUE if the fs-type in OPTS does not matches PREDICATE_VALUE. */
svn_boolean_t
svn_test__fs_type_not(const svn_test_opts_t *opts,
const char *predicate_value,
apr_pool_t *pool);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_TEST_H */