1 /* 2 * ==================================================================== 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * ==================================================================== 20 */ 21 22 #ifndef SVN_TEST_H 23 #define SVN_TEST_H 24 25 #ifndef SVN_ENABLE_DEPRECATION_WARNINGS_IN_TESTS 26 #undef SVN_DEPRECATED 27 #define SVN_DEPRECATED 28 #endif /* ! SVN_ENABLE_DEPRECATION_WARNINGS_IN_TESTS */ 29 30 #include <stdio.h> 31 32 #include <apr_pools.h> 33 34 #include "svn_delta.h" 35 #include "svn_path.h" 36 #include "svn_types.h" 37 #include "svn_error.h" 38 #include "svn_string.h" 39 #include "svn_auth.h" 40 41 #ifdef __cplusplus 42 extern "C" { 43 #endif /* __cplusplus */ 44 45 46 /** Handy macro to test a condition, returning SVN_ERR_TEST_FAILED if FALSE 47 * 48 * This macro should be used in place of SVN_ERR_ASSERT() since we don't 49 * want to core-dump the test. 50 */ 51 #define SVN_TEST_ASSERT(expr) \ 52 do { \ 53 if (!(expr)) \ 54 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, \ 55 "assertion '%s' failed at %s:%d", \ 56 #expr, __FILE__, __LINE__); \ 57 } while (0) 58 59 /** 60 * Macro for testing assumptions when the context does not allow 61 * returning an svn_error_t*. 62 * 63 * Will write to stderr and cause a segfault if EXPR is false. 64 */ 65 #define SVN_TEST_ASSERT_NO_RETURN(expr) \ 66 do { \ 67 if (!(expr)) \ 68 { \ 69 unsigned int z_e_r_o_p_a_g_e__; \ 70 fprintf(stderr, "TEST ASSERTION FAILED: %s\n", #expr); \ 71 z_e_r_o_p_a_g_e__ = *(volatile unsigned int*)0; \ 72 *(volatile unsigned int*)0 = z_e_r_o_p_a_g_e__; \ 73 } \ 74 } while (0) 75 76 /** Handy macro for testing an expected svn_error_t return value. 77 * EXPECTED must be a real error (neither SVN_NO_ERROR nor APR_SUCCESS). 78 * The error returned by EXPR will be cleared. 79 */ 80 #define SVN_TEST_ASSERT_ERROR(expr, expected) \ 81 do { \ 82 svn_error_t *err__ = (expr); \ 83 SVN_ERR_ASSERT((expected)); \ 84 if (err__ == SVN_NO_ERROR || err__->apr_err != (expected)) \ 85 return err__ ? svn_error_createf(SVN_ERR_TEST_FAILED, err__, \ 86 "Expected error %s but got %s", \ 87 svn_error_symbolic_name(expected), \ 88 svn_error_symbolic_name( \ 89 err__->apr_err)) \ 90 : svn_error_createf(SVN_ERR_TEST_FAILED, err__, \ 91 "Expected error %s but got %s", \ 92 svn_error_symbolic_name(expected), \ 93 "SVN_NO_ERROR"); \ 94 svn_error_clear(err__); \ 95 } while (0) 96 97 /** Handy macro for testing that an svn_error_t is returned. 98 * The result must be neither SVN_NO_ERROR nor SVN_ERR_ASSERTION_FAIL. 99 * The error returned by EXPR will be cleared. 100 */ 101 #define SVN_TEST_ASSERT_ANY_ERROR(expr) \ 102 do { \ 103 svn_error_t *err__ = (expr); \ 104 if (err__ == SVN_NO_ERROR || err__->apr_err == SVN_ERR_ASSERTION_FAIL)\ 105 return err__ ? svn_error_createf(SVN_ERR_TEST_FAILED, err__, \ 106 "Expected error but got %s", \ 107 "SVN_ERR_ASSERTION_FAIL") \ 108 : svn_error_createf(SVN_ERR_TEST_FAILED, err__, \ 109 "Expected error but got %s", \ 110 "SVN_NO_ERROR"); \ 111 svn_error_clear(err__); \ 112 } while (0) 113 114 /** Handy macro for testing string equality. 115 * 116 * EXPR and/or EXPECTED_EXPR may be NULL which compares equal to NULL and 117 * not equal to any non-NULL string. 118 */ 119 #define SVN_TEST_STRING_ASSERT(expr, expected_expr) \ 120 do { \ 121 const char *tst_str1 = (expr); \ 122 const char *tst_str2 = (expected_expr); \ 123 \ 124 if (tst_str2 == NULL && tst_str1 == NULL) \ 125 break; \ 126 if ((tst_str1 == NULL) || (tst_str2 == NULL) \ 127 || (strcmp(tst_str2, tst_str1) != 0)) \ 128 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, \ 129 "Strings not equal\n Expected: '%s'\n Found: '%s'" \ 130 "\n at %s:%d", \ 131 tst_str2, tst_str1, __FILE__, __LINE__); \ 132 } while(0) 133 134 /** Handy macro for testing integer equality. 135 */ 136 #define SVN_TEST_INT_ASSERT(expr, expected_expr) \ 137 do { \ 138 apr_int64_t tst_int1 = (expr); \ 139 apr_int64_t tst_int2 = (expected_expr); \ 140 \ 141 if (tst_int1 != tst_int2) \ 142 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, \ 143 "Integers not equal\n" \ 144 " Expected: %" APR_INT64_T_FMT "\n" \ 145 " Found: %" APR_INT64_T_FMT "\n" \ 146 " at %s:%d", \ 147 tst_int2, tst_int1, __FILE__, __LINE__); \ 148 } while(0) 149 150 151 /* Baton for any arguments that need to be passed from main() to svn 152 * test functions. 153 */ 154 typedef struct svn_test_opts_t 155 { 156 /* The name of the application (to generate unique names) */ 157 const char *prog_name; 158 /* Description of the fs backend that should be used for testing. */ 159 const char *fs_type; 160 /* Config file. */ 161 const char *config_file; 162 /* Source dir. */ 163 const char *srcdir; 164 /* Repository dir: temporary directory to create repositories in as subdir */ 165 const char *repos_dir; 166 /* Repository url: The url to access REPOS_DIR as */ 167 const char *repos_url; 168 /* Memcached server. */ 169 const char *memcached_server; 170 /* Repository template: pre-created repository to copy for tests */ 171 const char *repos_template; 172 /* Minor version to use for servers and FS backends, or zero to use 173 the current latest version. */ 174 int server_minor_version; 175 svn_boolean_t verbose; 176 /* Add future "arguments" here. */ 177 } svn_test_opts_t; 178 179 /* Prototype for test driver functions. */ 180 typedef svn_error_t* (*svn_test_driver2_t)(apr_pool_t *pool); 181 182 /* Prototype for test driver functions which need options. */ 183 typedef svn_error_t* (*svn_test_driver_opts_t)(const svn_test_opts_t *opts, 184 apr_pool_t *pool); 185 186 /* Prototype for test predicate functions. */ 187 typedef svn_boolean_t (*svn_test_predicate_func_t)(const svn_test_opts_t *opts, 188 const char *predicate_value, 189 apr_pool_t *pool); 190 191 /* Test modes. */ 192 enum svn_test_mode_t 193 { 194 svn_test_pass, 195 svn_test_xfail, 196 svn_test_skip, 197 svn_test_all 198 }; 199 200 /* Structure for runtime test predicates. */ 201 struct svn_test_predicate_t 202 { 203 /* The predicate function. */ 204 svn_test_predicate_func_t func; 205 206 /* The value that the predicate function tests. */ 207 const char *value; 208 209 /* The test mode that's used if the predicate matches. */ 210 enum svn_test_mode_t alternate_mode; 211 212 /* Description for the test log */ 213 const char *description; 214 }; 215 216 217 /* Each test gets a test descriptor, holding the function and other 218 * associated data. 219 */ 220 struct svn_test_descriptor_t 221 { 222 /* Is the test marked XFAIL? */ 223 enum svn_test_mode_t mode; 224 225 /* A pointer to the test driver function. */ 226 svn_test_driver2_t func2; 227 228 /* A pointer to the test driver function. */ 229 svn_test_driver_opts_t func_opts; 230 231 /* A descriptive message for this test. */ 232 const char *msg; 233 234 /* An optional description of a work-in-progress test. */ 235 const char *wip; 236 237 /* An optional runtiume predicate. */ 238 struct svn_test_predicate_t predicate; 239 }; 240 241 /* All Subversion test programs include an array of svn_test_descriptor_t's 242 * (all of our sub-tests) that begins and ends with a SVN_TEST_NULL entry. 243 * This descriptor must be passed to the svn_test_main function. 244 * 245 * MAX_THREADS is the number of concurrent tests to run. Set to 1 if 246 * all tests must be executed serially. Numbers less than 1 mean 247 * "unbounded". 248 */ 249 int svn_test_main(int argc, const char *argv[], int max_threads, 250 struct svn_test_descriptor_t *test_funcs); 251 252 /* Boilerplate for the main function for each test program. */ 253 #define SVN_TEST_MAIN \ 254 int main(int argc, const char *argv[]) \ 255 { \ 256 return svn_test_main(argc, argv, \ 257 max_threads, test_funcs); \ 258 } 259 260 /* A null initializer for the test descriptor. */ 261 #define SVN_TEST_NULL {0} 262 263 /* Initializer for PASS tests */ 264 #define SVN_TEST_PASS2(func, msg) {svn_test_pass, func, NULL, msg} 265 266 /* Initializer for XFAIL tests */ 267 #define SVN_TEST_XFAIL2(func, msg) {svn_test_xfail, func, NULL, msg} 268 269 /* Initializer for conditional XFAIL tests */ 270 #define SVN_TEST_XFAIL_COND2(func, p, msg) \ 271 {(p) ? svn_test_xfail : svn_test_pass, func, NULL, msg} 272 273 /* Initializer for SKIP tests */ 274 #define SVN_TEST_SKIP2(func, p, msg) \ 275 {(p) ? svn_test_skip : svn_test_pass, func, NULL, msg} 276 277 /* Similar macros, but for tests needing options. */ 278 #define SVN_TEST_OPTS_PASS(func, msg) {svn_test_pass, NULL, func, msg} 279 #define SVN_TEST_OPTS_XFAIL(func, msg) {svn_test_xfail, NULL, func, msg} 280 #define SVN_TEST_OPTS_XFAIL_COND(func, p, msg) \ 281 {(p) ? svn_test_xfail : svn_test_pass, NULL, func, msg} 282 #define SVN_TEST_OPTS_XFAIL_OTOH(func, msg, predicate) \ 283 {svn_test_xfail, NULL, func, msg, NULL, predicate} 284 #define SVN_TEST_OPTS_SKIP(func, p, msg) \ 285 {(p) ? svn_test_skip : svn_test_pass, NULL, func, msg} 286 287 /* Initializer for XFAIL tests for works-in-progress. */ 288 #define SVN_TEST_WIMP(func, msg, wip) \ 289 {svn_test_xfail, func, NULL, msg, wip} 290 #define SVN_TEST_WIMP_COND(func, p, msg, wip) \ 291 {(p) ? svn_test_xfail : svn_test_pass, func, NULL, msg, wip} 292 #define SVN_TEST_OPTS_WIMP(func, msg, wip) \ 293 {svn_test_xfail, NULL, func, msg, wip} 294 #define SVN_TEST_OPTS_WIMP_COND(func, p, msg, wip) \ 295 {(p) ? svn_test_xfail : svn_test_pass, NULL, func, msg, wip} 296 297 298 /* Return a pseudo-random number based on SEED, and modify SEED. 299 * 300 * This is a "good" pseudo-random number generator, intended to replace 301 * all those "bad" rand() implementations out there. 302 */ 303 apr_uint32_t svn_test_rand(apr_uint32_t *seed); 304 305 306 /* Add PATH to the test cleanup list. */ 307 void svn_test_add_dir_cleanup(const char *path); 308 309 310 /* A simple representation for a tree node. */ 311 typedef struct svn_test__tree_entry_t 312 { 313 const char *path; /* relpath of this node */ 314 const char *contents; /* text contents, or NULL for a directory */ 315 } 316 svn_test__tree_entry_t; 317 318 /* Wrapper for an array of svn_test__tree_entry_t's. */ 319 typedef struct svn_test__tree_t 320 { 321 svn_test__tree_entry_t *entries; 322 int num_entries; 323 } 324 svn_test__tree_t; 325 326 327 /* The standard Greek tree, terminated by a node with path=NULL. */ 328 extern const svn_test__tree_entry_t svn_test__greek_tree_nodes[21]; 329 330 331 /* Returns a path to BASENAME within the transient data area for the 332 current test. */ 333 const char * 334 svn_test_data_path(const char* basename, apr_pool_t *result_pool); 335 336 337 /* Some tests require the --srcdir option and should use this function 338 * to get it. If not provided, print a warning and attempt to run the 339 * tests under the assumption that --srcdir is the current directory. */ 340 svn_error_t * 341 svn_test_get_srcdir(const char **srcdir, 342 const svn_test_opts_t *opts, 343 apr_pool_t *pool); 344 345 /* Initializes a standard auth baton for accessing the repositories */ 346 svn_error_t * 347 svn_test__init_auth_baton(svn_auth_baton_t **baton, 348 apr_pool_t *result_pool); 349 350 /* Create a temp folder for test & schedule it for automatic cleanup. 351 * Uses POOL for all allocations. */ 352 svn_error_t * 353 svn_test_make_sandbox_dir(const char **sb_dir_p, 354 const char *sb_name, 355 apr_pool_t *pool); 356 357 /* 358 * Test predicates 359 */ 360 361 #define SVN_TEST_PASS_IF_FS_TYPE_IS(fs_type) \ 362 { svn_test__fs_type_is, fs_type, svn_test_pass, \ 363 "PASS if fs-type = " fs_type } 364 365 #define SVN_TEST_PASS_IF_FS_TYPE_IS_NOT(fs_type) \ 366 { svn_test__fs_type_not, fs_type, svn_test_pass, \ 367 "PASS if fs-type != " fs_type } 368 369 /* Return TRUE if the fs-type in OPTS matches PREDICATE_VALUE. */ 370 svn_boolean_t 371 svn_test__fs_type_is(const svn_test_opts_t *opts, 372 const char *predicate_value, 373 apr_pool_t *pool); 374 375 376 /* Return TRUE if the fs-type in OPTS does not matches PREDICATE_VALUE. */ 377 svn_boolean_t 378 svn_test__fs_type_not(const svn_test_opts_t *opts, 379 const char *predicate_value, 380 apr_pool_t *pool); 381 382 383 #ifdef __cplusplus 384 } 385 #endif /* __cplusplus */ 386 387 #endif /* SVN_TEST_H */ 388