32 bool ignoreDateTimeChanges;
41 void add(
bool onlyWords,
const char *regEx,
GB_CASE case_flag,
const char *replacement) {
46 replace[count] = replacement;
47 wordsOnly[count] = onlyWords;
53 static bool is_word_char(
char c) {
return isalnum(c) || c ==
'_'; }
57 mutable bool may_involved;
58 static GBS_regexPtr contains_May;
60 void avoid_may_problems(
const char *
str)
const {
65 fprintf(stderr,
"Loosening month comparison: 'May' involved in '%s'\n", str);
74 ignoreDateTimeChanges(ignoreDateTimeChanges_),
79 memset(reg, 0,
sizeof(reg));
80 if (ignoreDateTimeChanges) {
81 add(
false,
"[0-9]{2}:[0-9]{2}:[0-9]{2}",
GB_MIND_CASE,
"<TIME>");
82 add(
true,
"(Mon|Tue|Wed|Thu|Fri|Sat|Sun)",
GB_IGNORE_CASE,
"<DOW>");
84 add(
true,
"(January|February|March|April|May|June|July|August|September|October|November|December)",
GB_IGNORE_CASE,
"<Month>");
85 add(
true,
"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)",
GB_IGNORE_CASE,
"<MON>");
88 add(
false,
"<Month>[ -][0-9]{4}",
GB_IGNORE_CASE,
"<Month> <YEAR>");
92 add(
false,
"<MON>[ -][0-9 ]?[0-9]",
GB_IGNORE_CASE,
"<MON> <DAY>");
93 add(
false,
"<Month>[ -][0-9 ]?[0-9]",
GB_IGNORE_CASE,
"<Month> <DAY>");
95 add(
false,
"[0-9]{2}[ -\\.]+<MON>",
GB_IGNORE_CASE,
"<DAY> <MON>");
96 add(
false,
"[0-9]{2}[ -\\.]+<Month>",
GB_IGNORE_CASE,
"<DAY> <Month>");
102 for (
int i = 0; i<count; ++i) {
112 void replaceAll(
char*& str)
const {
113 for (
int i = 0; i<count; ++i) {
119 const char *suffix = matched+matchlen;
123 if (prefix[0] != 0 && is_word_char(matched[-1])) do_repl =
false;
124 else if (suffix[0] != 0 && is_word_char(suffix[0])) do_repl =
false;
135 avoid_may_problems(str1);
136 avoid_may_problems(str2);
146 char *lf = strchr(s,
'\n');
151 if (*line1++ !=
'-')
return false;
152 if (*line2++ !=
'+')
return false;
160 mode.replaceAll(dup1, dup2);
162 bool equalNow = strcmp(dup1, dup2) == 0;
174 typedef std::list<std::string> Lines;
175 typedef Lines::iterator LinesIter;
176 typedef Lines::const_iterator LinesCIter;
181 LinesIter added_last_checked;
182 LinesIter deleted_last_checked;
184 static LinesIter next(LinesIter iter) { advance(iter, 1);
return iter; }
185 static LinesIter last(Lines& lines) {
return (++lines.rbegin()).base(); }
188 added_last_checked = last(added_lines);
189 deleted_last_checked = last(deleted_lines);
195 bool add(
const char *diffline) {
197 switch (diffline[0]) {
198 case '-': deleted_lines.push_back(diffline);
break;
199 case '+': added_lines.push_back(diffline);
break;
200 default : did_add =
false;
break;
206 int added()
const {
return added_lines.size(); }
207 int deleted()
const {
return deleted_lines.size(); }
210 LinesIter d = next(deleted_last_checked);
211 LinesIter dEnd = deleted_lines.end();
212 LinesIter a = next(added_last_checked);
213 LinesIter aEnd = added_lines.end();
216 while (d != dEnd && a != aEnd) {
218 d = deleted_lines.erase(d);
219 a = added_lines.erase(a);
229 void print_from(FILE *out, LinesCIter a, LinesCIter d)
const {
230 LinesCIter dEnd = deleted_lines.end();
231 LinesCIter aEnd = added_lines.end();
233 while (d != dEnd && a != aEnd) {
234 fputs(d->c_str(), out); ++d;
235 fputs(a->c_str(), out); ++a;
237 while (d != dEnd) {
fputs(d->c_str(), out); ++d; }
238 while (a != aEnd) {
fputs(a->c_str(), out); ++a; }
242 LinesCIter d = deleted_lines.begin();
243 LinesCIter a = added_lines.begin();
258 const char *error =
NULp;
264 FILE *diffout = popen(cmd,
"r");
267 #define BUFSIZE 20000
276 while (!error && !feof(diffout)) {
280 #if defined(ASSERTION_USED)
281 size_t len = strlen(line);
286 if (strstr(line,
"differ")) {
287 error =
"attempt to compare binary files";
291 bool remove_now =
true;
292 if (strncmp(line,
"@@", 2) == 0) inHunk =
true;
293 else if (!inHunk && strncmp(line,
"Index: ", 7) == 0) inHunk =
false;
295 remove_now = !diff_lines.
add(line);
305 int added = diff_lines.
added();
306 int deleted = diff_lines.
deleted();
307 bool dump_diffs =
false;
309 if (added != deleted) {
310 error =
GBS_global_string(
"added lines (=%i) differ from deleted lines(=%i)", added, deleted);
315 bool matches_expected = added == expected_difflines;
318 if (matches_expected != want_expected) {
321 want_expected ?
"" :
"not ",
324 dump_diffs = added != 0;
329 fputs(
"Different lines:\n", stdout);
330 diff_lines.
print(stdout);
345 if (error) printf(
"ARB_textfiles_have_difflines(%s, %s) fails: %s\n", file1, file2, error);
352 size_t ARB_test_mem_equal(
const unsigned char *buf1,
const unsigned char *buf2,
size_t common,
size_t blockStartAddress) {
354 if (memcmp(buf1, buf2, common) == 0) {
355 equal_bytes = common;
360 while (buf1[x] == buf2[x]) {
365 const size_t DUMP = 7;
366 size_t y1 = x >= DUMP ? x-DUMP : 0;
367 size_t y2 = (x+2*DUMP)>common ? common : (x+2*DUMP);
368 size_t blockstart = blockStartAddress+equal_bytes-x;
370 for (
size_t y = y1;
y <= y2;
y++) {
371 fprintf(stderr,
"[0x%04zx]", blockstart+
y);
375 if (buf1[
y] != buf2[
y])
fputs(
" <- diff", stderr);
379 fputs(
"[end of block - truncated]\n", stderr);
385 static GB_ERROR compare_files(
const char *file1,
const char *file2,
bool error_if_different) {
386 const char *error =
NULp;
387 FILE *fp1 = fopen(file1,
"rb");
390 printf(
"can't open '%s'\n", file1);
394 FILE *fp2 = fopen(file2,
"rb");
396 printf(
"can't open '%s'\n", file2);
400 const int BLOCKSIZE = 4096;
401 unsigned char *buf1 = ARB_alloc<unsigned char>(BLOCKSIZE);
402 unsigned char *buf2 = ARB_alloc<unsigned char>(BLOCKSIZE);
403 size_t equal_bytes = 0;
406 int read1 = fread(buf1, 1, BLOCKSIZE, fp1);
407 int read2 = fread(buf2, 1, BLOCKSIZE, fp2);
408 size_t common = read1<read2 ? read1 : read2;
411 if (read1 != read2) error =
"filesize differs";
416 if (eqCount != common) {
417 error =
"content differs";
419 equal_bytes += eqCount;
422 if (error) printf(
"compare_files: equal_bytes=%zu\n", equal_bytes);
429 if (!error_if_different) error = error ?
NULp :
"files are equal";
439 GB_ERROR error = compare_files(file1, file2,
true);
440 if (error) printf(
"ARB_files_are_equal(%s, %s) fails: %s\n", file1, file2, error);
444 GB_ERROR error = compare_files(file1, file2,
false);
445 if (error) printf(
"ARB_files_differ(%s, %s) fails: %s\n", file1, file2, error);
449 void TEST_diff_files() {
451 const char *file =
"diff/base.input";
452 const char *file_swapped =
"diff/swapped.input";
453 const char *file_date_swapped =
"diff/date_swapped.input";
455 const char *file_date_changed =
"diff/date_changed.input";
458 const char *file_missing =
"diff/nosuch.input";
489 const char *binary =
"TEST_gpt.arb.expected";
490 const char *binary2 =
"TEST_gpt.arb.pt.expected";
491 const char *text = file;
517 #pragma GCC diagnostic ignored "-Wlogical-op"
520 #define FOR_ANY_BOOL(name) for (int name = 0; name<2; ++name)
539 FOR_ANY_BOOL(kermitIsFrog) {
540 FOR_ANY_BOOL(kermitIsGreen) {
541 bool allFrogsAreGreen =
implicated(kermitIsFrog, kermitIsGreen);
542 bool onlyFrogsAreGreen =
implicated(kermitIsGreen, kermitIsFrog);
554 correlated(kermitIsGreen, kermitIsFrog),
555 allFrogsAreGreen && onlyFrogsAreGreen
566 double zero = num-num;
567 double inf = num/zero;
575 #define TEST_ISINF(isinf_fun) \
576 TEST_EXPECT(isinf_fun(inf)); \
577 TEST_EXPECT(!!isinf_fun(ninf)); \
578 TEST_EXPECT(isinf_fun(INFINITY)); \
579 TEST_EXPECT(!isinf_fun(nan)); \
580 TEST_EXPECT(!isinf_fun(NAN)); \
581 TEST_EXPECT(!isinf_fun(num)); \
582 TEST_EXPECT(!isinf_fun(zero))
584 #define TEST_ISNAN(isnan_fun) \
585 TEST_EXPECT(isnan_fun(nan)); \
586 TEST_EXPECT(isnan_fun(NAN)); \
587 TEST_EXPECT(!isnan_fun(inf)); \
588 TEST_EXPECT(!isnan_fun(ninf)); \
589 TEST_EXPECT(!isnan_fun(INFINITY)); \
590 TEST_EXPECT(!isnan_fun(zero)); \
591 TEST_EXPECT(!isnan_fun(num))
593 #define TEST_ISNORMAL(isnormal_fun) \
594 TEST_EXPECT(isnormal_fun(num)); \
595 TEST_EXPECT(!isnormal_fun(zero)); \
596 TEST_EXPECT(!isnormal_fun(inf)); \
597 TEST_EXPECT(!isnormal_fun(ninf)); \
598 TEST_EXPECT(!isnormal_fun(nan)); \
599 TEST_EXPECT(!isnormal_fun(INFINITY)); \
600 TEST_EXPECT(!isnormal_fun(NAN))
609 # if (GCC_PATCHLEVEL_CODE < 50301)
613 # if (GCC_PATCHLEVEL_CODE >= 40403 && GCC_PATCHLEVEL_CODE <= 40407 && defined(DEBUG))
624 TEST_ISNAN(std::isnan);
625 TEST_ISINF(std::isinf);
626 TEST_ISNORMAL(std::isnormal);
void print(FILE *out) const
void remove_accepted_lines(const difflineMode &mode)
#define implicated(hypothesis, conclusion)
bool ARB_files_differ(const char *file1, const char *file2)
size_t ARB_test_mem_equal(const unsigned char *buf1, const unsigned char *buf2, size_t common, size_t blockStartAddress)
GBS_regex * GBS_compile_regexpr(const char *regexpr, GB_CASE case_flag, GB_ERROR *error)
bool ARB_files_are_equal(const char *file1, const char *file2)
static void cutEOL(char *s)
const char * get_error() const
char * ARB_strdup(const char *str)
void replaceAll(char *&str1, char *&str2) const
const char * GBS_global_string(const char *templat,...)
static GB_ERROR static_error
char * ARB_strpartdup(const char *start, const char *end)
char buffer[MESSAGE_BUFFERSIZE]
#define TEST_EXPECT(cond)
#define TEST_REJECT(cond)
bool add(const char *diffline)
static void error(const char *msg)
void print_from(FILE *out, LinesCIter a, LinesCIter d) const
bool ARB_textfiles_have_difflines(const char *file1, const char *file2, int expected_difflines, TextDiffMode tdmode)
const char * GBS_regmatch_compiled(const char *str, GBS_regex *comreg, size_t *matchlen)
fputs(TRACE_PREFIX, stderr)
void print_pair(T1 t1, T2 t2)
#define IF_ASSERTION_USED(x)
difflineMode(bool ignoreDateTimeChanges_)
static bool test_accept_diff_lines(const char *line1, const char *line2, const difflineMode &mode)
void GBS_free_regexpr(GBS_regex *toFree)
bool GB_is_regularfile(const char *path)
#define TEST_EXPECT_DIFFERENT(expr, want)
bool ARB_strBeginsWith(const char *str, const char *with)
#define TEST_EXPECT_EQUAL(expr, want)
#define TEST_EXPECT__BROKEN(cond)
char * GBS_global_string_copy(const char *templat,...)
void print_hex_pair(T1 t1, T2 t2)
GB_write_int const char s