Changeset 6816

Show
Ignore:
Timestamp:
09/09/10 22:40:57 (17 months ago)
Author:
westram
Message:
  • unit-test improvements (merged [6757] [6758] [6759] [6760] [6761] [6762] [6764] [6791] [6795] [6798] [6799] [6800] [6801] [6802] [6809] [6810])
    • moved file compare to test_unit.h
    • fake report for skipped tests
    • added templates for char compare
    • perform minihexdump
    • flush output
    • added
      • TEST_ASSERT_FILES_EQUAL__BROKEN
      • TEST_ASSERT_ZERO_OR_SHOW_ERRNO
    • create a fake.patch if there are no changes
    • all code affecting assertions in UNIT_TESTS-mode went to test_global.h
      • overwrites arb_assert()
    • undefine UNIT_TESTS for GDE submakefiles (foreign code there)
    • arb_test::FlushedOutput::errorf raises assertion itself
    • test against I/O errors
    • moved test code
    • refactored message printing
    • unit-tester switches to run directory itself
      • eliminates path hack for valgrind
    • control leak-check by variable
    • added global test-environment (does nothing yet)
Location:
trunk
Files:
11 modified
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/ARBDB/ad_save_load.cxx

    r6682 r6816  
    12931293#include <test_unit.h> 
    12941294 
    1295 static bool files_are_equal(const char *file1, const char *file2) { 
    1296     GB_ERROR   error     = NULL; 
    1297     FILE      *fp1       = fopen(file1, "rb"); 
    1298  
    1299     // @@@ FIXME:  use GB_IO_error() here later 
    1300     if (!fp1) error = GBS_global_string("can't open '%s'", file1); 
    1301     else { 
    1302         FILE *fp2 = fopen(file2, "rb"); 
    1303         if (!fp2) error = GBS_global_string("can't open '%s'", file2); 
    1304         else { 
    1305             const int BLOCKSIZE = 4096; 
    1306             char *buf1 = (char*)malloc(BLOCKSIZE); 
    1307             char *buf2 = (char*)malloc(BLOCKSIZE); 
    1308  
    1309             while (!error) { 
    1310                 int read1 = fread(buf1, 1, BLOCKSIZE, fp1); 
    1311                 int read2 = fread(buf2, 1, BLOCKSIZE, fp2); 
    1312  
    1313                 if (read1 != read2) error = "filesizes differ"; 
    1314                 else { 
    1315                     if (!read1) break; // done 
    1316                     if (memcmp(buf1, buf2, read1) != 0) error = "content differs"; 
    1317                 } 
    1318             } 
    1319             free(buf2); 
    1320             free(buf1); 
    1321             fclose(fp2); 
    1322         } 
    1323         fclose(fp1); 
    1324     } 
    1325  
    1326     if (error) TEST_WARNING("%s", GBS_global_string("files_are_equal(%s, %s): %s", file1, file2, error)); 
    1327     return !error; 
    1328 } 
    1329  
    13301295#define SAVE_AND_COMPARE(gbd, save_as, savetype, compare_with) \ 
    13311296    TEST_ASSERT_NO_ERROR(GB_save_as(gbd, save_as, savetype));  \ 
    1332     TEST_ASSERT(files_are_equal(save_as, compare_with)) 
     1297    TEST_ASSERT_FILES_EQUAL(save_as, compare_with) 
    13331298 
    13341299static GB_ERROR modify_db(GBDATA *gb_main) { 
     
    13421307        if (!gb_entry) error = GB_await_error(); 
    13431308        else    error        = GB_write_string(gb_entry, "text"); 
     1309        // else    error        = GB_write_string(gb_entry, "bla"); // provoke error in file compare 
    13441310    } 
    13451311    return error; 
     
    14251391#endif // TEST_AUTO_UPDATE 
    14261392 
    1427         TEST_ASSERT(files_are_equal("TEST_loadsave_quick.a00", "a2b.a00")); 
    1428         TEST_ASSERT(files_are_equal("a2b.a00", "b2b.a00")); 
     1393        TEST_ASSERT_FILES_EQUAL("TEST_loadsave_quick.a00", "a2b.a00"); 
     1394        TEST_ASSERT_FILES_EQUAL("a2b.a00", "b2b.a00"); 
    14291395 
    14301396        TEST_ASSERT_NO_ERROR(GB_save_quick_as(gb_a2b, "a2b.arb")); 
  • trunk/ARBDB/arb_assert.h

    r6813 r6816  
    180180 
    181181#if (UNIT_TESTS == 1) 
    182 # if defined(DEVEL_RELEASE) 
    183 #  error Unit testing not allowed in release 
    184 # else 
    185  
    186 #  ifdef __cplusplus 
    187  
    188 #ifndef _CPP_CSTDLIB 
    189 #include <cstdlib> 
    190 #endif 
    191  
    192 namespace arb_test { 
    193     class GlobalTestData { 
    194         GlobalTestData() 
    195             : show_warnings(true), 
    196               assertion_failed(false), 
    197               warnings(0) 
    198         {} 
    199  
    200         static GlobalTestData *instance(bool erase) { 
    201             static GlobalTestData *data = 0; // singleton 
    202             if (erase) { 
    203                 delete data; 
    204                 data = 0; 
    205             } 
    206             else { 
    207                 if (!data) data = new GlobalTestData; 
    208             } 
    209             return data; 
    210         } 
    211  
    212     public: 
    213         bool show_warnings; 
    214         bool assertion_failed; 
    215  
    216         // counters 
    217         size_t warnings; 
    218  
    219         static GlobalTestData& get_instance() { return *instance(false); } 
    220         static void erase_instance() { instance(true); } 
    221     }; 
    222  
    223     inline GlobalTestData& test_data() { return GlobalTestData::get_instance(); } 
    224 }; 
    225  
    226 #   define ASSERTION_HAS_FAILED() arb_test::test_data().assertion_failed = true   
    227  
    228 #  else 
    229 #   define ASSERTION_HAS_FAILED() // impossible in C 
    230 #  endif 
    231  
    232 #  define test_assert(cond)                                     \ 
    233     do {                                                        \ 
    234         if (!(cond)) {                                          \ 
    235             fflush(stdout);                                     \ 
    236             fflush(stderr);                                     \ 
    237             fprintf(stderr, "%s:%i: Assertion '%s' failed\n",   \ 
    238                     __FILE__, __LINE__, #cond);                 \ 
    239             fflush(stderr);                                     \ 
    240             ASSERTION_HAS_FAILED();                             \ 
    241             ARB_SIGSEGV(0);                                     \ 
    242         }                                                       \ 
    243     } while(0) 
    244  
    245 #  if defined(ASSERTION_USED) 
    246 #   undef arb_assert 
    247 #   define arb_assert(cond) test_assert(cond) 
    248 #  endif 
    249  
    250 # endif 
     182#ifndef TEST_GLOBAL_H 
     183#include <test_global.h> // overrides arb_assert()! 
     184#endif 
    251185#endif 
    252186 
  • trunk/GDE/Makefile

    r5872 r6816  
    3939 
    4040# -------------------------------------------------------------------------------- 
    41 # no warnings in this subtree 
     41# modify cflags for submakefiles  
    4242 
    43 RAISE_WARNINGS=0 
     43RAISE_WARNINGS=0# no warnings in this subtree 
     44UNIT_TESTS=0# no warnings in this subtree 
     45 
     46sub_cflags:=$(cflags) 
    4447 
    4548ifeq ('$(RAISE_WARNINGS)','0') 
    46 sub_cflags:=$(subst -W -Wall,-w,$(cflags)) 
    47 else 
    48 sub_cflags:=$(cflags) 
     49sub_cflags:=$(subst -W -Wall,-w,$(sub_cflags)) 
     50endif 
     51ifeq ('$(UNIT_TESTS)','0') 
     52sub_cflags:=$(subst -DUNIT_TESTS,,$(sub_cflags)) 
    4953endif 
    5054 
  • trunk/SOURCE_TOOLS/arb_create_patch.sh

    r6718 r6816  
    1717            PATCHNAME=${NAME}_$DATE 
    1818            PATCH=$PATCHDIR/$PATCHNAME.patch 
     19            FAKEPATCH=$PATCHDIR/fake.patch 
     20            RECENT_PATCH=$ARBHOME/latest.patch 
    1921 
    2022            cd $ARBHOME 
     
    2426                if [ ! -s $PATCH ]; then 
    2527                    rm $PATCH 
     28                    if [ ! -e $FAKEPATCH ]; then 
     29                        echo "Index: No changes" > $FAKEPATCH 
     30                        echo "===================================================================" >> $FAKEPATCH 
     31                    fi 
     32                    ln --force $FAKEPATCH $RECENT_PATCH 
     33                    touch $FAKEPATCH 
    2634                    echo "No patch generated (no diff)" 
    2735                else 
    28                     RECENT_PATCH=$ARBHOME/latest.patch 
    2936                    ln --force $PATCH $RECENT_PATCH 
    3037                    ls -alh $PATCH $RECENT_PATCH 
  • trunk/SOURCE_TOOLS/generate_all_links.sh

    r6813 r6816  
    254254symlink_file ../STAT/st_window.hxx INCLUDE/st_window.hxx && 
    255255symlink_file ../UNIT_TESTER/test_unit.h INCLUDE/test_unit.h && 
     256symlink_file ../UNIT_TESTER/test_global.h INCLUDE/test_global.h && 
    256257symlink_file ../WINDOW/aw_advice.hxx INCLUDE/aw_advice.hxx && 
    257258symlink_file ../WINDOW/aw_awars.hxx INCLUDE/aw_awars.hxx && 
  • trunk/UNIT_TESTER

    • Property svn:ignore
      •  

        old new  
        55*.gcno 
        66logs 
         7test_environment 
  • trunk/UNIT_TESTER/Makefile

    r6699 r6816  
    22.SUFFIXES: .o .cxx .depend 
    33 
    4 CPP_OBJECTS = \ 
     4TESTER_OBJECTS = \ 
    55        UnitTester.o \ 
    66 
     7GLOBAL_OBJECTS = \ 
     8        TestEnvironment.o \ 
    79 
    8 $(MAIN): $(CPP_OBJECTS) 
    9         $(LINK_STATIC_LIB) $(MAIN) $(CPP_OBJECTS) 
     10CPP_OBJECTS = $(TESTER_OBJECTS) $(GLOBAL_OBJECTS) 
     11 
     12$(MAIN): $(TESTER_OBJECTS) test_environment 
     13        $(LINK_STATIC_LIB) $(MAIN) $(TESTER_OBJECTS) 
     14 
     15test_environment: $(GLOBAL_OBJECTS) $(TESTER_OBJECTS) 
     16        $(LINK_EXECUTABLE) test_environment $(GLOBAL_OBJECTS) $(TESTER_OBJECTS) $(LIBPATH) $(ARBDB_LIB)   
     17 
    1018.cxx.o: 
    1119        $(CPP) $(cflags) -c $<  $(CPPINCLUDES) 
    1220 
    1321clean: 
    14         rm -f $(CPP_OBJECTS)  
     22        rm -f $(CPP_OBJECTS) *.a test_environment  
    1523        $(MAKE) -f Makefile.test clean 
     24 
    1625 
    1726DEPENDS = $(CPP_OBJECTS:.o=.depend) 
     
    3241# For formatting issues see SOURCE_TOOLS/fix_depends.pl 
    3342 
     43TestEnvironment.o: test_global.h 
     44TestEnvironment.o: test_unit.h 
     45TestEnvironment.o: UnitTester.hxx 
     46TestEnvironment.o: $(ARBHOME)/INCLUDE/ad_k_prot.h 
     47TestEnvironment.o: $(ARBHOME)/INCLUDE/ad_prot.h 
     48TestEnvironment.o: $(ARBHOME)/INCLUDE/arb_assert.h 
     49TestEnvironment.o: $(ARBHOME)/INCLUDE/arb_core.h 
     50TestEnvironment.o: $(ARBHOME)/INCLUDE/arb_defs.h 
     51TestEnvironment.o: $(ARBHOME)/INCLUDE/arb_error.h 
     52TestEnvironment.o: $(ARBHOME)/INCLUDE/arb_str.h 
     53TestEnvironment.o: $(ARBHOME)/INCLUDE/arbdb.h 
     54TestEnvironment.o: $(ARBHOME)/INCLUDE/arbdb_base.h 
     55TestEnvironment.o: $(ARBHOME)/INCLUDE/arbtools.h 
     56TestEnvironment.o: $(ARBHOME)/INCLUDE/attributes.h 
     57TestEnvironment.o: $(ARBHOME)/INCLUDE/dupstr.h 
     58TestEnvironment.o: $(ARBHOME)/INCLUDE/smartptr.h 
     59 
     60UnitTester.o: test_global.h 
    3461UnitTester.o: test_unit.h 
    3562UnitTester.o: UnitTester.hxx 
  • trunk/UNIT_TESTER/Makefile.test

    r6812 r6816  
    1515# ---------------------------------------------------------- 
    1616 
     17# @@@ valgrind makes tests fail atm 
     18# (most likely two pt-servers try to start parallel on the same port) 
     19 
    1720VALGRIND=0# only test 
    1821#VALGRIND=1# run valgrind after sucessful test 
    1922#VALGRIND=2# run valgrind before test (useful if test traps w/o any helpful information) 
     23 
     24#CHECK_LEAKS=0# check no leaks 
     25CHECK_LEAKS=1# check definite leaks 
     26#CHECK_LEAKS=2# check reachable leaks 
    2027 
    2128# ---------------------------------------------------------- 
     
    2936# 
    3037RESTRICT_LIB=# run all tests 
     38#RESTRICT_LIB=AWTC# test only this library 
    3139#RESTRICT_LIB=mkptypes# test only these libraries 
    3240#RESTRICT_LIB=client:arb_probe:AWTC# test only these libraries 
     
    8189 
    8290DESTDIR=tests 
    83 RUNDIR=run 
    84 RUN2HERE=..# prefix from RUNDIR to here (UNIT_TESTER) 
     91RUNDIR=run# see also UnitTester.cxx@chdir 
    8592 
    8693SYMLIST=$(DESTDIR)/$(UNIQUE_NAME).sym 
     
    152159        @echo "LINKDEPS       ='$(LINKDEPS)'" 
    153160 
     161ifeq ($(CHECK_LEAKS),0) 
     162        LEAKS:= 
     163else 
     164ifeq ($(CHECK_LEAKS),1) 
     165        LEAKS:=-l 
     166else 
     167        LEAKS:=-l -r 
     168endif 
     169endif 
     170 
    154171valgrind: 
    155172        echo "Valgrinding.." 
    156         cd $(RUNDIR);$(ARBHOME)/SOURCE_TOOLS/arb_valgrind -q -l -r -c 15 $(RUN2HERE)/$(TEST_EXE) 
     173        $(ARBHOME)/SOURCE_TOOLS/arb_valgrind -q $(LEAKS) -c 15 $(TEST_EXE) 
    157174 
    158175perform_test: $(TEST_EXE) 
     
    161178        $(MAKE) -f Makefile.test valgrind 
    162179endif 
    163         cd $(RUNDIR);$(RUN2HERE)/$(TEST_EXE) 
     180        $(TEST_EXE)  
    164181ifeq ($(COVERAGE),1) 
    165182        @echo "-------------------- test-coverage for $(UNITLIBNAME)" 
     
    173190 
    174191skip_test: 
    175         @echo "unit-tests completely skipped for '$(UNITLIBNAME)'" 
     192        @echo "UnitTester: $(UNITLIBNAME) tests=0 (skipped via RESTRICT_LIB)" 
    176193 
    177194# -------------------- 
  • trunk/UNIT_TESTER/UnitTester.cxx

    r6743 r6816  
    5151// -------------------------------------------------------------------------------- 
    5252 
    53 enum UnitTestResult { 
    54     TEST_OK, 
    55     TEST_TRAPPED, 
    56 }; 
    57  
    5853static const char *readable_result[] = { 
    5954    "OK", 
     
    7974#define SECOND 1000000 
    8075 
    81 static UnitTestResult execute_guarded(UnitTest_function fun, long *duration_usec) { 
     76UnitTestResult execute_guarded(UnitTest_function fun, long *duration_usec) { 
    8277    SigHandler old_handler = INSTALL_SIGHANDLER(SIGSEGV, UNITTEST_sigsegv_handler, "execute_guarded"); 
    8378     
     
    215210    // it is invoked from code generated by sym2testcode.pl@InvokeUnitTester 
    216211 
     212    TEST_ASSERT_ZERO_OR_SHOW_ERRNO(chdir("run")); 
     213     
    217214    size_t tests  = 0; 
    218215    size_t passed = 0; 
     
    238235                             duration_ms, global.warnings)); 
    239236    } 
    240      
     237 
    241238    arb_test::GlobalTestData::erase_instance(); 
    242239    exit(tests == passed ? EXIT_SUCCESS : EXIT_FAILURE); 
  • trunk/UNIT_TESTER/UnitTester.hxx

    r6743 r6816  
    2424    const char        *location; 
    2525}; 
     26enum UnitTestResult { 
     27    TEST_OK, 
     28    TEST_TRAPPED, 
     29}; 
    2630 
    2731struct UnitTester { 
     
    2933}; 
    3034 
     35UnitTestResult execute_guarded(UnitTest_function fun, long *duration_usec); 
     36 
    3137#else 
    3238#error UnitTester.hxx included twice 
  • trunk/UNIT_TESTER/test_global.h

    r6791 r6816  
    2020#include <cstdio> 
    2121#endif 
     22#ifndef _CPP_CERRNO 
     23#include <cerrno> 
     24#endif 
     25#ifndef _CPP_CSTRING 
     26#include <cstring> 
     27#endif 
    2228 
     29#if (UNIT_TESTS == 1) 
     30 
     31# if defined(DEVEL_RELEASE) 
     32#  error Unit testing not allowed in release 
     33# endif 
     34 
     35# ifdef __cplusplus 
     36 
     37#  define SET_ASSERTION_FAILED_FLAG() arb_test::test_data().assertion_failed = true   
     38#  define PRINT_ASSERTION_FAILED_MSG(cond) arb_test::GlobalTestData::assertfailmsg(__FILE__, __LINE__, #cond)   
     39 
     40# else 
     41#  define SET_ASSERTION_FAILED_FLAG() // impossible in C (assertions in C code will be handled like normal SEGV) 
     42#  define PRINT_ASSERTION_FAILED_MSG(cond)                      \ 
     43    do {                                                        \ 
     44        fflush(stdout);                                         \ 
     45        fflush(stderr);                                         \ 
     46        fprintf(stderr, "%s:%i: Assertion '%s' failed [C]\n",   \ 
     47                __FILE__, __LINE__, #cond);                     \ 
     48        fflush(stderr);                                         \ 
     49    } while(0) 
     50# endif 
     51 
     52# define TRIGGER_ASSERTION()                            \ 
     53    do {                                                \ 
     54        SET_ASSERTION_FAILED_FLAG();                    \ 
     55        ARB_SIGSEGV(0);                                 \ 
     56    } while(0) 
    2357 
    2458namespace arb_test { 
     59    class FlushedOutputNoLF { 
     60        inline void flushall() { fflush(stdout); fflush(stderr); } 
     61    public: 
     62        FlushedOutputNoLF() { flushall(); } 
     63        ~FlushedOutputNoLF() { flushall(); } 
     64    }; 
     65    struct FlushedOutput : public FlushedOutputNoLF { 
     66        ~FlushedOutput() { fputc('\n', stderr); } 
     67    }; 
     68 
    2569    class GlobalTestData { 
    2670        GlobalTestData() 
     
    5195        static GlobalTestData& get_instance() { return *instance(false); } 
    5296        static void erase_instance() { instance(true); } 
     97         
     98        static void assertfailmsg(const char *filename, int lineno, const char *condition) { 
     99            FlushedOutput yes; 
     100            fprintf(stderr, "%s:%i: Assertion '%s' failed", filename, lineno, condition); 
     101        } 
    53102    }; 
    54103 
    55104    inline GlobalTestData& test_data() { return GlobalTestData::get_instance(); } 
     105}; 
    56106 
    57      
    58     class FlushedOutput { 
    59         inline void flushall() { fflush(stdout); fflush(stderr); } 
    60     public: 
    61         FlushedOutput() { flushall(); } 
    62         ~FlushedOutput() { flushall(); } 
    63          
    64 #define VPRINTFORMAT(format) do { va_list parg; va_start(parg, format); vfprintf(stderr, format, parg); va_end(parg); } while(0) 
    65      
    66         static void printf(const char *format, ...) __attribute__((format(printf, 1, 2))) { 
    67             FlushedOutput yes; 
    68             VPRINTFORMAT(format); 
    69         } 
    70         static void messagef(const char *filename, int lineno, const char *format, ...) __attribute__((format(printf, 3, 4))) { 
    71             FlushedOutput yes; 
    72             fprintf(stderr, "%s:%i: ", filename, lineno); 
    73             fputc('\n', stderr); 
    74             VPRINTFORMAT(format); 
    75         } 
    76         static void warningf(const char *filename, int lineno, const char *format, ...) __attribute__((format(printf, 3, 4))) { 
    77             GlobalTestData& global = test_data(); 
    78             if (global.show_warnings) { 
    79                 FlushedOutput yes; 
    80                 fprintf(stderr, "%s:%i: Warning: ", filename, lineno); 
    81                 VPRINTFORMAT(format); 
    82                 fputc('\n', stderr); 
    83                 global.warnings++; 
    84             } 
    85         } 
    86         static void errorf(const char *filename, int lineno, const char *format, ...) __attribute__((format(printf, 3, 4))) { 
    87             FlushedOutput yes; 
    88             fprintf(stderr, "%s:%i: Error: ", filename, lineno); 
    89             VPRINTFORMAT(format); 
    90             fputc('\n', stderr); 
    91         } 
    92 #undef VPRINTFORMAT 
    93     }; 
     107// -------------------------------------------------------------------------------- 
    94108 
    95 }; 
     109// special assert for unit tests (additionally to SEGV it sets a global flag) 
     110# define test_assert(cond)                      \ 
     111    do {                                        \ 
     112        if (!(cond)) {                          \ 
     113            PRINT_ASSERTION_FAILED_MSG(cond);   \ 
     114            TRIGGER_ASSERTION();                \ 
     115        }                                       \ 
     116    } while(0) 
     117 
     118 
     119// redefine arb_assert with test_assert when compiling for unit tests 
     120# if defined(ASSERTION_USED) 
     121#  undef arb_assert 
     122#  define arb_assert(cond) test_assert(cond) 
     123# endif 
     124 
     125#else // UNIT_TESTS != 1 
     126#error test_global.h may only be included if UNIT_TESTS is 1 
     127#endif 
    96128 
    97129#else 
  • trunk/UNIT_TESTER/test_unit.h

    r6750 r6816  
    1919#include <cstdarg> 
    2020#endif 
     21#ifndef ERRNO_H 
     22#include <errno.h> 
     23#endif 
    2124 
    2225#define ENABLE_CRASH_TESTS // comment out this line to get rid of provoked SEGVs (e.g. while debugging test-code) 
     
    3336 
    3437namespace arb_test { 
    35     class FlushedOutput { 
    36         inline void flushall() { fflush(stdout); fflush(stderr); } 
     38 
     39    class StaticCode { 
     40        static void vcompiler_msg(const char *filename, int lineno, const char *message_type, const char *format, va_list parg) { 
     41            fprintf(stderr, "%s:%i: ", filename, lineno); 
     42            if (message_type) fprintf(stderr, "%s: ", message_type); 
     43            vfprintf(stderr, format, parg); 
     44        } 
     45 
     46#define WITHVALISTFROM(format,CODE)             do { va_list parg; va_start(parg, format); CODE; va_end(parg); } while(0) 
     47#define VPRINTFORMAT(format)                    WITHVALISTFROM(format, vfprintf(stderr, format, parg)) 
     48#define VCOMPILERMSG(file,line,msgtype,format)  WITHVALISTFROM(format, vcompiler_msg(file, line, msgtype, format, parg)) 
     49         
    3750    public: 
    38         FlushedOutput() { flushall(); } 
    39         ~FlushedOutput() { flushall(); } 
    40          
    41 #define VPRINTFORMAT(format) do { va_list parg; va_start(parg, format); vfprintf(stderr, format, parg); va_end(parg); } while(0) 
    42      
     51 
    4352        static void printf(const char *format, ...) __attribute__((format(printf, 1, 2))) { 
    44             FlushedOutput yes; 
    45             VPRINTFORMAT(format); 
    46         } 
    47         static void messagef(const char *filename, int lineno, const char *format, ...) __attribute__((format(printf, 3, 4))) { 
    48             FlushedOutput yes; 
    49             fprintf(stderr, "%s:%i: ", filename, lineno); 
     53            FlushedOutputNoLF yes; 
    5054            VPRINTFORMAT(format); 
    5155        } 
     
    5458            if (global.show_warnings) { 
    5559                FlushedOutput yes; 
    56                 fprintf(stderr, "%s:%i: Warning: ", filename, lineno); 
    57                 VPRINTFORMAT(format); 
     60                VCOMPILERMSG(filename, lineno, "Warning", format); 
    5861                global.warnings++; 
    5962            } 
     
    6164        static void errorf(const char *filename, int lineno, const char *format, ...) __attribute__((format(printf, 3, 4))) { 
    6265            FlushedOutput yes; 
    63             fprintf(stderr, "%s:%i: Error: ", filename, lineno); 
    64             VPRINTFORMAT(format); 
     66            VCOMPILERMSG(filename, lineno, "Error", format); 
     67            TRIGGER_ASSERTION(); // fake an assertion failure 
     68        } 
     69        static void ioerrorf(const char *filename, int lineno, const char *format, ...) __attribute__((format(printf, 3, 4))) { 
     70            FlushedOutput yes; 
     71            VCOMPILERMSG(filename, lineno, "Error", format); 
     72            fprintf(stderr, " (errno=%i='%s')", errno, strerror(errno)); 
     73            TRIGGER_ASSERTION(); // fake an assertion failure 
    6574        } 
    6675#undef VPRINTFORMAT 
     76#undef VCOMPILERMSG 
     77#undef WITHVALISTFROM 
    6778    }; 
    6879 
     
    7586    inline void print(size_t z)              { fprintf(stderr, "%zu", z); } 
    7687    inline void print_hex(size_t z)          { fprintf(stderr, "0x%zx", z); } 
     88     
     89    inline void print(unsigned char c)       { fprintf(stderr, "'%c'", c); } 
     90    inline void print_hex(unsigned char c)   { print_hex(size_t(c)); } 
     91 
     92    inline void print(char c)                { print((unsigned char)c); } 
     93    inline void print_hex(char c)            { print_hex((unsigned char)c); } 
     94 
     95    // dont dup size_t: 
    7796#ifdef ARB_64 
    7897    inline void print(unsigned u)            { fprintf(stderr, "%u", u); } 
     
    82101    inline void print_hex(long unsigned u)   { fprintf(stderr, "0x%lux", u); } 
    83102#endif 
    84      
     103 
    85104    template <typename T1, typename T2> void print_pair(T1 t1, T2 t2) { 
    86105        print(t1); 
     
    94113    } 
    95114    template <typename T1, typename T2> void print_failed_equal(T1 t1, T2 t2) { 
    96         FlushedOutput yes; 
     115        FlushedOutputNoLF yes; 
    97116        fputs("is_equal(", stderr); 
    98117        print_pair(t1, t2); 
     
    108127#define NAMEOFTYPE(type) template <> inline const char * nameoftype<>(type) { return #type; } 
    109128    NAMEOFTYPE(bool); 
     129    NAMEOFTYPE(char); 
     130    NAMEOFTYPE(unsigned char); 
    110131    NAMEOFTYPE(int); 
    111132    NAMEOFTYPE(unsigned int); 
     
    135156        bool equal = strnullequal(s1, s2); 
    136157        if (!equal) { 
    137             FlushedOutput::printf("str_equal('%s',\n" 
    138                                   "          '%s') returns false\n", s1, s2); 
     158            StaticCode::printf("str_equal('%s',\n" 
     159                               "          '%s') returns false\n", s1, s2); 
    139160        } 
    140161        return equal; 
     
    158179        bool different = !strnullequal(s1, s2); 
    159180        if (!different) { 
    160             FlushedOutput::printf("str_different('%s', ..) returns false\n", s1); 
     181            StaticCode::printf("str_different('%s', ..) returns false\n", s1); 
    161182        } 
    162183        return different; 
     
    169190        bool in_epsilon_range = diff < epsilon; 
    170191        if (!in_epsilon_range) { 
    171             FlushedOutput::printf("is_similar(%f,%f,%f) returns false\n", d1, d2, epsilon); 
     192            StaticCode::printf("is_similar(%f,%f,%f) returns false\n", d1, d2, epsilon); 
    172193        } 
    173194        return in_epsilon_range; 
     
    178199    } 
    179200 
     201 
     202 
     203    inline bool files_are_equal(const char *file1, const char *file2) { 
     204        const char        *error = NULL; 
     205        FILE              *fp1   = fopen(file1, "rb"); 
     206        FlushedOutputNoLF  yes; 
     207 
     208        if (!fp1) { 
     209            StaticCode::printf("can't open '%s'", file1); 
     210            error = "i/o error"; 
     211        } 
     212        else { 
     213            FILE *fp2 = fopen(file2, "rb"); 
     214            if (!fp2) { 
     215                StaticCode::printf("can't open '%s'", file2); 
     216                error = "i/o error"; 
     217            } 
     218            else { 
     219                const int      BLOCKSIZE    = 4096; 
     220                unsigned char *buf1         = (unsigned char*)malloc(BLOCKSIZE); 
     221                unsigned char *buf2         = (unsigned char*)malloc(BLOCKSIZE); 
     222                int            equal_bytes  = 0; 
     223                bool           repositioned = false; 
     224 
     225                while (!error) { 
     226                    int read1  = fread(buf1, 1, BLOCKSIZE, fp1); 
     227                    int read2  = fread(buf2, 1, BLOCKSIZE, fp2); 
     228                    int common = read1<read2 ? read1 : read2; 
     229 
     230                    if (!common) { 
     231                        if (read1 != read2) error = "filesize differs"; 
     232                        break; 
     233                    } 
     234 
     235                    if (memcmp(buf1, buf2, common) == 0) { 
     236                        equal_bytes += common; 
     237                    } 
     238                    else { 
     239                        int x = 0; 
     240                        while (buf1[x] == buf2[x]) { 
     241                            x++; 
     242                            equal_bytes++; 
     243                        } 
     244                        error = "content differs"; 
     245 
     246                        // x is the position inside the current block 
     247                        const int DUMP       = 7; 
     248                        int       y1         = x >= DUMP ? x-DUMP : 0; 
     249                        int       y2         = (x+DUMP)>common ? common : (x+DUMP); 
     250                        int       blockstart = equal_bytes-x; 
     251 
     252                        for (int y = y1; y <= y2; y++) { 
     253                            fprintf(stderr, "[0x%04x]", blockstart+y); 
     254                            print_pair(buf1[y], buf2[y]); 
     255                            fputc(' ', stderr); 
     256                            print_hex_pair(buf1[y], buf2[y]); 
     257                            if (x == y) fputs("                     <- diff", stderr); 
     258                            fputc('\n', stderr); 
     259                        } 
     260                        if (y2 == common) { 
     261                            fputs("[end of block - truncated]\n", stderr); 
     262                        } 
     263                    } 
     264                } 
     265 
     266                if (error) StaticCode::printf("files_are_equal: equal_bytes=%i\n", equal_bytes); 
     267                test_assert(error || equal_bytes); // comparing empty files is nonsense 
     268 
     269                free(buf2); 
     270                free(buf1); 
     271                fclose(fp2); 
     272            } 
     273            fclose(fp1); 
     274        } 
     275 
     276        if (error) StaticCode::printf("files_are_equal(%s, %s) fails: %s\n", file1, file2, error); 
     277        return !error; 
     278    } 
     279     
    180280}; 
    181281 
    182282// -------------------------------------------------------------------------------- 
    183283 
    184 #define TEST_MSG(format,strarg)           arb_test::FlushedOutput::messagef(__FILE__, __LINE__, format, (strarg)) 
    185 #define TEST_MSG2(format,strarg1,strarg2) arb_test::FlushedOutput::messagef(__FILE__, __LINE__, format, (strarg1), (strarg2)) 
    186  
    187 #define TEST_WARNING(format,strarg)           arb_test::FlushedOutput::warningf(__FILE__, __LINE__, format, (strarg)) 
    188 #define TEST_WARNING2(format,strarg1,strarg2) arb_test::FlushedOutput::warningf(__FILE__, __LINE__, format, (strarg1), (strarg2)) 
    189  
    190 #define TEST_ERROR(format,strarg)           do { arb_test::FlushedOutput::errorf(__FILE__, __LINE__, format, (strarg)); TEST_ASSERT(0); } while(0) 
    191 #define TEST_ERROR2(format,strarg1,strarg2) do { arb_test::FlushedOutput::errorf(__FILE__, __LINE__, format, (strarg1), (strarg2)); TEST_ASSERT(0); } while(0) 
     284#define TEST_WARNING(format,strarg)           arb_test::StaticCode::warningf(__FILE__, __LINE__, format, (strarg)) 
     285#define TEST_WARNING2(format,strarg1,strarg2) arb_test::StaticCode::warningf(__FILE__, __LINE__, format, (strarg1), (strarg2)) 
     286 
     287#define TEST_ERROR(format,strarg)           arb_test::StaticCode::errorf(__FILE__, __LINE__, format, (strarg)) 
     288#define TEST_ERROR2(format,strarg1,strarg2) arb_test::StaticCode::errorf(__FILE__, __LINE__, format, (strarg1), (strarg2)) 
     289#define TEST_IOERROR(format,strarg)         arb_test::StaticCode::ioerrorf(__FILE__, __LINE__, format, (strarg)) 
    192290 
    193291// -------------------------------------------------------------------------------- 
     
    206304#define TEST_ASSERT_ZERO(cond)         TEST_ASSERT((cond)         == 0) 
    207305#define TEST_ASSERT_ZERO__BROKEN(cond) TEST_ASSERT__BROKEN((cond) == 0) 
     306 
     307#define TEST_ASSERT_ZERO_OR_SHOW_ERRNO(iocond)                  \ 
     308    do {                                                        \ 
     309        if ((iocond))                                           \ 
     310            TEST_IOERROR("I/O-failure in '%s'", #iocond);       \ 
     311    } while(0) 
    208312 
    209313// -------------------------------------------------------------------------------- 
     
    350454#define TEST_ASSERT_SIMILAR__BROKEN(t1,t2,epsilon) TEST_ASSERT__BROKEN(arb_test::is_similar(t1, t2, epsilon)) 
    351455 
     456#define TEST_ASSERT_FILES_EQUAL(f1,f2)         TEST_ASSERT(arb_test::files_are_equal(f1,f2)) 
     457#define TEST_ASSERT_FILES_EQUAL__BROKEN(f1,f2) TEST_ASSERT__BROKEN(arb_test::files_are_equal(f1,f2)) 
     458 
    352459#else 
    353460#error test_unit.h included twice