"Fossies" - the Fresh Open Source Software Archive 
Member "libgd-2.3.3/tests/gdtest/gdtest.c" (11 Sep 2021, 15782 Bytes) of package /linux/www/libgd-2.3.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 #include <assert.h>
5 #include <setjmp.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <math.h>
10 #include <limits.h>
11 #include <time.h>
12
13 #ifdef HAVE_DIRENT_H
14 #include <dirent.h>
15 #endif
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 #ifdef HAVE_SYS_STAT_H
20 #include <sys/stat.h>
21 #endif
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25
26 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
27 #include "readdir.h"
28 #include <errno.h>
29 #endif
30 #if defined(__MINGW32__) || defined(__MINGW64__)
31 # define lstat stat
32 #endif
33 #include "gd_intern.h"
34
35 /* GDTEST_TOP_DIR is defined in other compile ways except msys
36 * test_config.h is created by windows/msys/run_test.sh*/
37 #ifndef GDTEST_TOP_DIR
38 #include <test_config.h>
39 #endif
40
41 #include "gd.h"
42
43 #include "gdtest.h"
44
45 /* max is already defined in windows/msvc */
46 #ifndef max
47 static inline int max(int a, int b) {return a > b ? a : b;}
48 #endif
49
50 void gdSilence(int priority, const char *format, va_list args)
51 {
52 (void)priority;
53 (void)format;
54 (void)args;
55 }
56
57 gdImagePtr gdTestImageFromPng(const char *filename)
58 {
59 gdImagePtr image;
60 FILE *fp;
61
62 /* If the path is relative, then assume it's in the tests/ dir. */
63 if (filename[0] == '/' || filename[0] == '.'
64 #ifdef _WIN32
65 || filename[1] == ':'
66 #endif
67 ) {
68 fp = fopen(filename, "rb");
69 } else {
70 fp = gdTestFileOpen(filename);
71 }
72
73 if (fp == NULL) {
74 return NULL;
75 }
76
77 image = gdImageCreateFromPng(fp);
78 fclose(fp);
79 return image;
80 }
81
82 static char *tmpdir_base;
83 int gdTestIsDir(char *path) {
84 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
85 WIN32_FILE_ATTRIBUTE_DATA data;
86
87 if (!GetFileAttributesEx(path, GetFileExInfoStandard, &data)) {
88 return 0;
89 }
90 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
91 return 0;
92 } else {
93 return 1;
94 }
95 #else
96 struct stat st;
97 if (lstat(path, &st) != 0)
98
99 if (S_ISDIR(st.st_mode))
100 return 1;
101 return 0;
102 #endif
103 }
104 /* This is kind of hacky, but it's meant to be simple. */
105 static void _clean_dir(const char *dir)
106 {
107 DIR *d;
108 struct dirent *de;
109
110 d = opendir(dir);
111 if (d == NULL)
112 return;
113
114 if (chdir(dir) != 0)
115 goto done;
116
117 while ((de = readdir(d)) != NULL) {
118 struct stat st;
119
120 if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
121 continue;
122 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
123 {
124 WIN32_FILE_ATTRIBUTE_DATA data;
125
126 if (!GetFileAttributesEx(de->d_name, GetFileExInfoStandard, &data)) {
127 continue;
128 }
129 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
130 _clean_dir(de->d_name);
131 } else {
132 unlink(de->d_name);
133 }
134 }
135 #else
136 if (lstat(de->d_name, &st) != 0)
137 continue;
138
139 if (S_ISDIR(st.st_mode))
140 _clean_dir(de->d_name);
141 else
142 unlink(de->d_name);
143 #endif
144 }
145
146 if (chdir("..")) {
147 /* Ignore. */;
148 }
149
150 done:
151 closedir(d);
152 rmdir(dir);
153 }
154
155 static void tmpdir_cleanup(void)
156 {
157 _clean_dir(tmpdir_base);
158 free(tmpdir_base);
159 }
160
161 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
162
163
164 typedef VOID (WINAPI *MyGetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTime);
165
166 static MyGetSystemTimeAsFileTime get_time_func(void)
167 {
168 MyGetSystemTimeAsFileTime timefunc = NULL;
169 HMODULE hMod = GetModuleHandle("kernel32.dll");
170
171 if (hMod) {
172 /* Max possible resolution <1us, win8/server2012 */
173 timefunc = (MyGetSystemTimeAsFileTime)GetProcAddress(hMod, "GetSystemTimePreciseAsFileTime");
174
175 if(!timefunc) {
176 /* 100ns blocks since 01-Jan-1641 */
177 timefunc = (MyGetSystemTimeAsFileTime)GetProcAddress(hMod, "GetSystemTimeAsFileTime");
178 }
179 }
180
181 return timefunc;
182 }
183 static MyGetSystemTimeAsFileTime timefunc = NULL;
184 static int getfilesystemtime(struct timeval *tv)
185 {
186 FILETIME ft;
187 unsigned __int64 ff = 0;
188 ULARGE_INTEGER fft;
189
190 if (timefunc == NULL) {
191 timefunc = get_time_func();
192 }
193 timefunc(&ft);
194
195 /*
196 * Do not cast a pointer to a FILETIME structure to either a
197 * ULARGE_INTEGER* or __int64* value because it can cause alignment faults on 64-bit Windows.
198 * via http://technet.microsoft.com/en-us/library/ms724284(v=vs.85).aspx
199 */
200 fft.HighPart = ft.dwHighDateTime;
201 fft.LowPart = ft.dwLowDateTime;
202 ff = fft.QuadPart;
203
204 ff /= 10ULL; /* convert to microseconds */
205 ff -= 11644473600000000ULL; /* convert to unix epoch */
206
207 tv->tv_sec = (long)(ff / 1000000ULL);
208 tv->tv_usec = (long)(ff % 1000000ULL);
209
210 return 0;
211 }
212 #endif
213 #if defined(_WIN32)
214
215 static void randtemplate(char *template, size_t l) {
216 // just to avoid calls within the same second
217 srand(time (NULL) + (unsigned int)template);
218 for (size_t i = l - 6; i < l; i++) {
219 int r = rand();
220 if ((r / (RAND_MAX + 1)) > ((RAND_MAX + 1) / 2))
221 template[i] = 'A' + (double) rand () / (RAND_MAX + 1) * ('Z' - 'A');
222 else
223 template[i] = 'a' + (double) rand () / (RAND_MAX + 1) * ('z' - 'a');
224 }
225 }
226
227 char* strrstr (char* haystack, char* needle)
228 {
229 int needle_length = strlen(needle);
230 char * haystack_end = haystack + strlen(haystack) - needle_length;
231 char * p;
232 int i;
233
234 for(p = haystack_end; p >= haystack; --p)
235 {
236 for(i = 0; i < needle_length; ++i) {
237 if(p[i] != needle[i])
238 goto next;
239 }
240 return p;
241
242 next:;
243 }
244 return 0;
245 }
246
247
248 static char *
249 mkdtemp (char *tmpl)
250 {
251 size_t l;
252 char attempts = 8;
253 int res = 0;
254
255 if (tmpl == NULL) {
256 errno = EINVAL;
257 return NULL;
258 }
259
260 l = strlen (tmpl);
261 if (l < 6 || strcmp (&tmpl[l - 6], "XXXXXX") != 0) {
262 errno = EINVAL;
263 return NULL;
264 }
265 do {
266 randtemplate (tmpl, l);
267 res = mkdir(tmpl);
268 attempts--;
269 } while (attempts > 0 && res != 0 );
270
271 if (res == 0) {
272 return tmpl;
273 }
274 if (errno != EEXIST) {
275 printf("Failed to create tmp dir, last attempt %s.", tmpl);
276 return NULL;
277 }
278
279 /* We got out of the loop because we ran out of combinations to try. */
280 errno = EEXIST;
281 return NULL;
282 }
283 #endif
284
285 const char *gdTestTempDir(void)
286 {
287 if (tmpdir_base == NULL) {
288 char *tmpdir;
289 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
290 char tmpdir_root[MAXPATHLEN];
291 size_t tmpdir_root_len = GetTempPath(MAX_PATH, tmpdir_root);
292 if ((tmpdir_root_len + 30 > MAX_PATH) || (tmpdir_root_len == 0)) {
293 printf("Tmp dir path too long or 0 length <%s>\n", tmpdir_root);
294 return NULL;
295 }
296 #else
297 char *tmpdir_root;
298 tmpdir_root = getenv("TMPDIR");
299 if (tmpdir_root == NULL) {
300 // Mingw defines it
301 tmpdir_root = getenv("TMP");
302 if (tmpdir_root == NULL) {
303 // Fall back here.
304 tmpdir_root = "/tmp";
305 if (!gdTestIsDir(tmpdir_root)) {
306 printf("tmpdir failed to be used or initialized (%s).", tmpdir_root);
307 exit(2);
308 }
309 }
310 }
311 #endif
312
313 /* The constant here is a lazy over-estimate. */
314 tmpdir = malloc(strlen(tmpdir_root) + 30);
315 if (tmpdir == NULL) {
316 printf("cannot alloc tmpdir path.");
317 return NULL;
318 }
319
320 #if defined(_WIN32)
321 sprintf(tmpdir, "%sgdtest.XXXXXX", tmpdir_root);
322 #else
323 sprintf(tmpdir, "%s/gdtest.XXXXXX", tmpdir_root);
324 #endif
325
326 tmpdir_base = mkdtemp(tmpdir);
327 if (tmpdir_base == NULL) {
328 printf("failed to generate the tmp dir path (%s).", tmpdir);
329 return NULL;
330 }
331
332 atexit(tmpdir_cleanup);
333 }
334
335 return tmpdir_base;
336 }
337
338 char *gdTestTempFile(const char *template)
339 {
340 const char *tempdir = gdTestTempDir();
341 char *ret;
342 if (tempdir == NULL) {
343 return NULL;
344 }
345 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
346 {
347 char *tmpfilename;
348 UINT error;
349
350 ret = malloc(MAX_PATH);
351 if (ret == NULL) {
352 printf("Failed to alloc tmp path");
353 return NULL;
354 }
355 if (template == NULL) {
356 error = GetTempFileName(tempdir,
357 "gdtest",
358 0,
359 ret);
360 if (error = 0) {
361 printf("GetTempFileName failed.");
362 gdFree(ret);
363 return NULL;
364 }
365 } else {
366 sprintf(ret, "%s\\%s", tempdir, template);
367 }
368 }
369 #else
370 if (template == NULL) {
371 template = "gdtemp.XXXXXX";
372 }
373 ret = malloc(strlen(tempdir) + 10 + strlen(template));
374 if (ret == NULL) {
375 printf("Failed to alloc tmp path");
376 return NULL;
377 }
378 sprintf(ret, "%s/%s", tempdir, template);
379
380 if (strstr(template, "XXXXXX") != NULL) {
381 int fd = mkstemp(ret);
382 if (fd == -1) {
383 printf("mkstemp failed");
384 gdFree(ret);
385 return NULL;
386 }
387 close(fd);
388 }
389 #endif
390 return ret;
391 }
392
393 FILE *gdTestTempFp(void)
394 {
395 char *file = gdTestTempFile(NULL);
396 FILE *fp = fopen(file, "wb");
397 if (fp == NULL) {
398 printf("fail to open tmp file");
399 return NULL;
400 }
401 free(file);
402 return fp;
403 }
404
405 char *gdTestFilePathV(const char *path, va_list args)
406 {
407 size_t len;
408 const char *p;
409 char *file;
410 va_list args_len;
411
412 /* Figure out how much space we need. */
413 va_copy(args_len, args);
414 len = strlen(GDTEST_TOP_DIR) + 1;
415 p = path;
416 do {
417 len += strlen(p) + 1;
418 } while ((p = va_arg(args_len, const char *)) != NULL);
419 va_end(args_len);
420
421 /* Now build the path. */
422 file = malloc(len);
423 if (file == NULL) {
424 printf("failed to alloc path.");
425 return NULL;
426 }
427 strcpy(file, GDTEST_TOP_DIR);
428 p = path;
429 do {
430 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
431 strcat(file, "\\");
432 #else
433 strcat(file, "/");
434 #endif
435 strcat(file, p);
436
437 } while ((p = va_arg(args, const char *)) != NULL);
438 va_end(args);
439
440 return file;
441 }
442
443 char *gdTestFilePathX(const char *path, ...)
444 {
445 va_list args;
446 va_start(args, path);
447 return gdTestFilePathV(path, args);
448 }
449
450 FILE *gdTestFileOpenX(const char *path, ...)
451 {
452 va_list args;
453 FILE *fp;
454 char *file;
455
456 va_start(args, path);
457 file = gdTestFilePathV(path, args);
458 fp = fopen(file, "rb");
459 if (fp == NULL) {
460 printf("failed to open path (rb).");
461 return NULL;
462 }
463 free(file);
464 return fp;
465 }
466
467 /* Compare two buffers, returning the number of pixels that are
468 * different and the maximum difference of any single color channel in
469 * result_ret.
470 *
471 * This function should be rewritten to compare all formats supported by
472 * cairo_format_t instead of taking a mask as a parameter.
473 */
474 void gdTestImageDiff(gdImagePtr buf_a, gdImagePtr buf_b,
475 gdImagePtr buf_diff, CuTestImageResult *result_ret)
476 {
477 int x, y;
478 int c1, c2;
479 # define UP_DIFF(var) result_ret->max_diff = max((var), result_ret->max_diff)
480
481 for (y = 0; y < gdImageSY(buf_a); y++) {
482 for (x = 0; x < gdImageSX(buf_a); x++) {
483 c1 = gdImageGetTrueColorPixel(buf_a, x, y);
484 c2 = gdImageGetTrueColorPixel(buf_b, x, y);
485
486 /* check if the pixels are the same */
487 if (c1 != c2) {
488 int r1,b1,g1,a1,r2,b2,g2,a2;
489 unsigned int diff_a,diff_r,diff_g,diff_b;
490
491 a1 = gdTrueColorGetAlpha(c1);
492 a2 = gdTrueColorGetAlpha(c2);
493 diff_a = abs (a1 - a2);
494 diff_a *= 4; /* emphasize */
495
496 if (diff_a) {
497 diff_a += 128; /* make sure it's visible */
498 }
499 if (diff_a > gdAlphaMax) {
500 diff_a = gdAlphaMax/2;
501 }
502
503 r1 = gdTrueColorGetRed(c1);
504 r2 = gdTrueColorGetRed(c2);
505 diff_r = abs (r1 - r2);
506 // diff_r *= 4; /* emphasize */
507 if (diff_r) {
508 diff_r += gdRedMax/2; /* make sure it's visible */
509 }
510 if (diff_r > 255) {
511 diff_r = 255;
512 }
513 UP_DIFF(diff_r);
514
515 g1 = gdTrueColorGetGreen(c1);
516 g2 = gdTrueColorGetGreen(c2);
517 diff_g = abs (g1 - g2);
518
519 diff_g *= 4; /* emphasize */
520 if (diff_g) {
521 diff_g += gdGreenMax/2; /* make sure it's visible */
522 }
523 if (diff_g > 255) {
524 diff_g = 255;
525 }
526 UP_DIFF(diff_g);
527
528 b1 = gdTrueColorGetBlue(c1);
529 b2 = gdTrueColorGetBlue(c2);
530 diff_b = abs (b1 - b2);
531 diff_b *= 4; /* emphasize */
532 if (diff_b) {
533 diff_b += gdBlueMax/2; /* make sure it's visible */
534 }
535 if (diff_b > 255) {
536 diff_b = 255;
537 }
538 UP_DIFF(diff_b);
539
540 result_ret->pixels_changed++;
541 if (buf_diff) gdImageSetPixel(buf_diff, x,y, gdTrueColorAlpha(diff_r, diff_g, diff_b, diff_a));
542 } else {
543 if (buf_diff) gdImageSetPixel(buf_diff, x,y, gdTrueColorAlpha(255,255,255,0));
544 }
545 }
546 }
547 # undef UP_DIFF
548 }
549
550
551 /* Return the largest difference between two corresponding pixels and
552 * channels. */
553 unsigned int gdMaxPixelDiff(gdImagePtr a, gdImagePtr b)
554 {
555 int diff = 0;
556 int x, y;
557
558 if (a == NULL || b == NULL || a->sx != b->sx || a->sy != b->sy)
559 return UINT_MAX;
560
561 for (x = 0; x < a->sx; x++) {
562 for (y = 0; y < a->sy; y++) {
563 int c1, c2;
564
565 c1 = gdImageGetTrueColorPixel(a, x, y);
566 c2 = gdImageGetTrueColorPixel(b, x, y);
567 if (c1 == c2) continue;
568
569 diff = max(diff, abs(gdTrueColorGetAlpha(c1) - gdTrueColorGetAlpha(c2)));
570 diff = max(diff, abs(gdTrueColorGetRed(c1) - gdTrueColorGetRed(c2)));
571 diff = max(diff, abs(gdTrueColorGetGreen(c1) - gdTrueColorGetGreen(c2)));
572 diff = max(diff, abs(gdTrueColorGetBlue(c1) - gdTrueColorGetBlue(c2)));
573 }/* for */
574 }/* for */
575
576 return diff;
577 }
578
579 int gdTestImageCompareToImage(const char* file, unsigned int line, const char* message,
580 gdImagePtr expected, gdImagePtr actual)
581 {
582 unsigned int width_a, height_a;
583 unsigned int width_b, height_b;
584 gdImagePtr surface_diff = NULL;
585 CuTestImageResult result = {0, 0};
586
587 (void)message;
588
589 if (!actual) {
590 _gdTestErrorMsg(file, line, "Image is NULL\n");
591 goto fail;
592 }
593
594 width_a = gdImageSX(expected);
595 height_a = gdImageSY(expected);
596 width_b = gdImageSX(actual);
597 height_b = gdImageSY(actual);
598
599 if (width_a != width_b || height_a != height_b) {
600 _gdTestErrorMsg(file, line,
601 "Image size mismatch: (%ux%u) vs. (%ux%u)\n for %s vs. buffer\n",
602 width_a, height_a,
603 width_b, height_b,
604 file);
605 goto fail;
606 }
607
608 surface_diff = gdImageCreateTrueColor(width_a, height_a);
609
610 gdTestImageDiff(expected, actual, surface_diff, &result);
611 if (result.pixels_changed>0) {
612 char file_diff[255];
613 char file_out[1024];
614 FILE *fp;
615 int len, p;
616
617 _gdTestErrorMsg(file, line,
618 "Total pixels changed: %d with a maximum channel difference of %d.\n",
619 result.pixels_changed,
620 result.max_diff
621 );
622
623 p = len = strlen(file);
624 p--;
625
626 /* Use only the filename (and store it in the bld dir not the src dir
627 */
628 while(p > 0 && (file[p] != '/' && file[p] != '\\')) {
629 p--;
630 }
631 sprintf(file_diff, "%s_%u_diff.png", file + p + 1, line);
632 sprintf(file_out, "%s_%u_out.png", file + p + 1, line);
633
634 fp = fopen(file_diff, "wb");
635 if (!fp) goto fail;
636 gdImagePng(surface_diff,fp);
637 fclose(fp);
638 gdImageDestroy(surface_diff);
639
640 fp = fopen(file_out, "wb");
641 if (!fp) goto fail;
642 gdImagePng(actual, fp);
643 fclose(fp);
644 return 0;
645 } else {
646 if (surface_diff) {
647 gdImageDestroy(surface_diff);
648 }
649 return 1;
650 }
651
652 fail:
653 if (surface_diff) {
654 gdImageDestroy(surface_diff);
655 }
656 return 1;
657 }
658
659 int gdTestImageCompareToFile(const char* file, unsigned int line, const char* message,
660 const char *expected_file, gdImagePtr actual)
661 {
662 gdImagePtr expected = 0;
663 int res = 1;
664
665 expected = gdTestImageFromPng(expected_file);
666
667 if (!expected) {
668 _gdTestErrorMsg(file, line, "Cannot open PNG <%s>\n", expected_file);
669 res = 0;
670 } else {
671 res = gdTestImageCompareToImage(file, line, message, expected, actual);
672 gdImageDestroy(expected);
673 }
674 return res;
675 }
676
677 static int failureCount = 0;
678
679 int gdNumFailures() {
680 return failureCount;
681 }
682
683 int _gdTestAssert(const char* file, unsigned int line, int condition)
684 {
685 if (condition) return 1;
686 _gdTestErrorMsg(file, line, "Assert failed in <%s:%i>\n", file, line);
687
688 ++failureCount;
689
690 return 0;
691 }
692
693 int _gdTestAssertMsg(const char* file, unsigned int line, int condition, const char* message, ...)
694 {
695 va_list args;
696
697 if (condition) return 1;
698
699 fprintf(stderr, "%s:%u: ", file, line);
700 va_start(args, message);
701 vfprintf(stderr, message, args);
702 va_end(args);
703
704 fflush(stderr);
705
706 ++failureCount;
707
708 return 0;
709 }
710
711 int _gdTestErrorMsg(const char* file, unsigned int line, const char* format, ...) /* {{{ */
712 {
713 va_list args;
714
715 fprintf(stderr, "%s:%u: ", file, line);
716 va_start(args, format);
717 vfprintf(stderr, format, args);
718 va_end(args);
719 fflush(stderr);
720
721 ++failureCount;
722
723 return 0;
724 }
725 /* }}} */