"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.
For more information about "gdtest.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.3.2_vs_2.3.3.
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 /* }}} */