FORS Pipeline Reference Manual 4.9.20
|
00001 /* * 00002 * This file is part of the ESO FORS package * 00003 * Copyright (C) 2004,2005 European Southern Observatory * 00004 * * 00005 * This library is free software; you can redistribute it and/or modify * 00006 * it under the terms of the GNU General Public License as published by * 00007 * the Free Software Foundation; either version 2 of the License, or * 00008 * (at your option) any later version. * 00009 * * 00010 * This program is distributed in the hope that it will be useful, * 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00013 * GNU General Public License for more details. * 00014 * * 00015 * You should have received a copy of the GNU General Public License * 00016 * along with this program; if not, write to the Free Software * 00017 * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA * 00018 * */ 00019 00020 #ifdef HAVE_CONFIG_H 00021 # include <config.h> 00022 #endif 00023 00024 /*----------------------------------------------------------------------------- 00025 Includes 00026 -----------------------------------------------------------------------------*/ 00027 00028 #include <test.h> 00029 00030 #include <fors_utils.h> 00031 00032 #include <cpl.h> 00033 #include <math.h> /* fabs() */ 00034 #include <string.h> /* strlen() */ 00035 00036 /*----------------------------------------------------------------------------*/ 00040 /*----------------------------------------------------------------------------*/ 00041 00042 /*----------------------------------------------------------------------------- 00043 Implementation 00044 -----------------------------------------------------------------------------*/ 00045 00049 static unsigned long test_nfail = 0; 00050 static cpl_errorstate error_init; 00051 00052 /*----------------------------------------------------------------------------*/ 00061 /*----------------------------------------------------------------------------*/ 00062 static void 00063 _test(int expression, const char *message, 00064 const char *function, const char *file, unsigned line) 00065 { 00066 const char *error_state = (cpl_error_get_code() != CPL_ERROR_NONE) ? 00067 cpl_sprintf(" (CPL-error state: '%s' at %s)", 00068 cpl_error_get_message(), cpl_error_get_where()) : 00069 NULL; 00070 00071 if (expression) { 00072 cpl_msg_debug(function, 00073 "OK at %s:%u%s: %s", 00074 file, line, error_state != NULL ? error_state : "", 00075 message); 00076 } else { 00077 if (test_nfail + 1 > test_nfail) { 00078 test_nfail++; 00079 } 00080 else { 00081 cpl_msg_error(function, "Number of errors (%lu) overflow!", 00082 test_nfail); 00083 } 00084 00085 cpl_msg_error(function, 00086 "Failure at %s:%u%s: %s", 00087 file, line, error_state != NULL ? error_state : "", 00088 message); 00089 } 00090 00091 if (error_state != NULL) 00092 { 00093 cpl_free((char *)error_state); 00094 } 00095 00096 return; 00097 } 00098 00099 00100 /*----------------------------------------------------------------------------*/ 00110 /*----------------------------------------------------------------------------*/ 00111 void 00112 test_macro(int expression, const char *expr_string, 00113 const char *function, const char *file, unsigned line) 00114 { 00115 const char *message = cpl_sprintf("(%s) = %d", expr_string, expression); 00116 00117 _test(expression, message, 00118 function, file, line); 00119 00120 cpl_free((char *)message); 00121 00122 return; 00123 } 00124 00125 /*----------------------------------------------------------------------------*/ 00137 /*----------------------------------------------------------------------------*/ 00138 void 00139 test_eq_macro(int first, const char *first_string, 00140 int second, const char *second_string, 00141 const char *function, const char *file, unsigned line) 00142 { 00143 const char *message = 00144 cpl_sprintf("(%s) = %d; (%s) = %d", 00145 first_string, first, 00146 second_string, second); 00147 00148 _test(first == second, message, 00149 function, file, line); 00150 00151 cpl_free((char *)message); 00152 00153 return; 00154 } 00155 00156 /*----------------------------------------------------------------------------*/ 00168 /*----------------------------------------------------------------------------*/ 00169 void 00170 test_eq_string_macro(const char *first, const char *first_string, 00171 const char *second, const char *second_string, 00172 const char *function, 00173 const char *file, unsigned line) 00174 { 00175 const char *message; 00176 00177 message = cpl_sprintf("%s = '%s'; %s = '%s'", 00178 first_string, first != NULL ? first : "NULL", 00179 second_string, second != NULL ? second : "NULL"); 00180 00181 _test(first != NULL && second != NULL && strcmp(first, second) == 0, 00182 message, 00183 function, file, line); 00184 00185 cpl_free((char *)message); 00186 00187 return; 00188 } 00189 00190 /*----------------------------------------------------------------------------*/ 00206 /*----------------------------------------------------------------------------*/ 00207 void 00208 test_abs_macro(double first, const char *first_string, 00209 double second, const char *second_string, 00210 double tolerance, const char *tolerance_string, 00211 const char *function, const char *file, unsigned line) 00212 { 00213 const char *message = 00214 cpl_sprintf("|%s - (%s)| = |%g - (%g)| <= %g = %s", 00215 first_string, second_string, first, second, 00216 tolerance, tolerance_string); 00217 00218 _test(fabs(first - second) <= tolerance, message, 00219 function, file, line); 00220 /* Note: fails if tolerance is negative */ 00221 00222 cpl_free((char *)message); 00223 00224 return; 00225 } 00226 00227 /*----------------------------------------------------------------------------*/ 00243 /*----------------------------------------------------------------------------*/ 00244 void 00245 test_rel_macro(double first, const char *first_string, 00246 double second, const char *second_string, 00247 double tolerance, const char *tolerance_string, 00248 const char *function, const char *file, unsigned line) 00249 { 00250 const char *message; 00251 00252 if (first == 0 || second == 0) { 00253 /* Division by zero -> fail */ 00254 message = cpl_sprintf("%s = %g; %s = %g (division by zero)", 00255 first_string, first, 00256 second_string, second); 00257 _test(0, message, 00258 function, file, line); 00259 } 00260 else { 00261 message = 00262 cpl_sprintf("|%s - (%s)|/|%s| = |%g - (%g)|/|%g| <= %g = %s and " 00263 "|%s - (%s)|/|%s| = |%g - (%g)|/|%g| <= %g = %s", 00264 first_string, second_string, first_string, 00265 first, second, first, tolerance, tolerance_string, 00266 first_string, second_string, second_string, 00267 first, second, second, tolerance, tolerance_string); 00268 00269 _test(fabs((first - second)/first ) <= tolerance && 00270 fabs((first - second)/second) <= tolerance, message, 00271 function, file, line); 00272 /* Note: fails if tolerance is negative */ 00273 } 00274 00275 cpl_free((char *)message); 00276 00277 return; 00278 } 00279 00280 00281 /*----------------------------------------------------------------------------*/ 00288 /*----------------------------------------------------------------------------*/ 00289 void 00290 test_init_macro(const char *file) 00291 { 00292 /* Build message domain + log filename 00293 from source file name */ 00294 00295 unsigned len = strlen(file); 00296 int able_to_parse_filename; 00297 00298 cpl_init(CPL_INIT_DEFAULT); 00299 error_init = cpl_errorstate_get(); 00300 srand(0); 00301 00302 if (len < strlen("s.c") || strcmp(file + len - strlen(".c"), ".c") != 0) 00303 { 00304 able_to_parse_filename = 0; 00305 /* Here, we should issue a warning but we need to 00306 initialize the CPL message system first */ 00307 } 00308 else 00309 { 00310 /* Form domain from filename by removing ".c" suffix 00311 and stripping any path prefix */ 00312 00313 const char dir_delimiter = '/'; /* UNIX only! */ 00314 unsigned path_length = 0; /* Length of path prefix 00315 including final '/' */ 00316 int i; 00317 00318 for (i = len - strlen(".c") - 1; i >= 0; i--) 00319 { 00320 if (file[i] == dir_delimiter && path_length == 0) 00321 { 00322 path_length = i + 1; 00323 } 00324 } 00325 00326 able_to_parse_filename = (len - path_length - strlen(".c") >= 1); 00327 if (able_to_parse_filename) 00328 { 00329 const char *logfile; 00330 char *domain; 00331 00332 domain = cpl_strdup(file + path_length); 00333 domain[len - path_length - strlen(".c")] = '\0'; 00334 00335 cpl_msg_set_domain(domain); 00336 00337 logfile = cpl_sprintf("%s.log", domain); 00338 cpl_msg_set_log_name(logfile); 00339 00340 cpl_free((char *)logfile); 00341 cpl_free(domain); 00342 } 00343 /* else: Use default domain + logfilename */ 00344 } 00345 00346 /* Adopt the policy that the unit test is quiet 00347 unless something is wrong. 00348 Dump debugging info to the log file */ 00349 cpl_msg_set_level(CPL_MSG_WARNING); 00350 cpl_msg_set_log_level(CPL_MSG_DEBUG); 00351 00352 if (!able_to_parse_filename) 00353 { 00354 cpl_msg_warning(cpl_func, 00355 "Source file name '%s' does not match [base].c. ", 00356 file); 00357 } 00358 00359 if (cpl_error_get_code() != CPL_ERROR_NONE) 00360 { 00361 cpl_msg_error(cpl_func, 00362 "Failure during initialization: %s at %s", 00363 cpl_error_get_message(), cpl_error_get_where()); 00364 } 00365 00366 return; 00367 } 00368 00369 /*----------------------------------------------------------------------------*/ 00379 /*----------------------------------------------------------------------------*/ 00380 unsigned 00381 test_end_macro(const char *function, const char *file, unsigned line) 00382 { 00383 const int memory_is_empty = cpl_memory_is_empty(); 00384 00385 test_eq_macro(cpl_error_get_code(), "cpl_error_get_code()", 00386 CPL_ERROR_NONE, "CPL_ERROR_NONE", 00387 function, file, line); 00388 00389 if (cpl_error_get_code() != CPL_ERROR_NONE) { 00390 cpl_errorstate_dump(error_init, CPL_FALSE, NULL); 00391 } 00392 00393 test_macro(memory_is_empty, 00394 "memory_is_empty", 00395 function, file, line); 00396 00397 if (!memory_is_empty) { 00398 cpl_msg_error(function, "Memory leak detected:"); 00399 cpl_memory_dump(); 00400 } 00401 00402 cpl_end(); 00403 00404 return test_nfail; 00405 } 00406 00407 00408 00409 00410 00411 #undef cleanup 00412 #define cleanup \ 00413 do { \ 00414 cpl_propertylist_delete(product_header); \ 00415 } while(0) 00416 /*----------------------------------------------------------------------------*/ 00426 /*----------------------------------------------------------------------------*/ 00427 void 00428 test_recipe_output(const cpl_frameset *frames, 00429 const char *const product_tags[], int n_prod, 00430 const char *main_product, 00431 const char *const qc[], int n_qc) 00432 { 00433 cpl_propertylist *product_header = NULL; 00434 00435 int i; 00436 for (i = 0; i < n_prod; i++) { 00437 const cpl_frame *product = cpl_frameset_find_const(frames, product_tags[i]); 00438 test( product != NULL ); 00439 test_eq( cpl_frame_get_group(product), CPL_FRAME_GROUP_PRODUCT ); 00440 00441 cpl_propertylist_delete(product_header); 00442 product_header = cpl_propertylist_load(cpl_frame_get_filename(product), 0); 00443 00444 assure( !cpl_error_get_code(), return, 00445 "Failed to load product header" ); 00446 00447 00448 if (strcmp(product_tags[i], main_product) == 0) { 00449 /* Must always be present */ 00450 test( cpl_propertylist_has(product_header, 00451 "ESO QC DID") ); 00452 } 00453 else { 00454 test( !cpl_propertylist_has(product_header, 00455 "ESO QC DID") ); 00456 } 00457 00458 int j; 00459 for (j = 0; j < n_qc; j++) { 00460 00461 const char *full_qc_name = cpl_sprintf("ESO %s", qc[j]); 00462 00463 cpl_msg_debug(cpl_func, 00464 "Looking for '%s' in '%s'", 00465 qc[j], product_tags[i]); 00466 00467 if (strcmp(product_tags[i], main_product) == 0) { 00468 test( cpl_propertylist_has(product_header, 00469 full_qc_name) ); 00470 } 00471 else { 00472 test( !cpl_propertylist_has(product_header, 00473 full_qc_name) ); 00474 } 00475 00476 cpl_free((void *)full_qc_name); 00477 } 00478 } 00479 00480 cleanup; 00481 return; 00482 } 00483