| 1 | #include "config.h" |
| 2 | |
| 3 | #include <assert.h> |
| 4 | #include <float.h> |
| 5 | #include <stdarg.h> |
| 6 | #include <stdio.h> |
| 7 | #include <stdlib.h> |
| 8 | #include <string.h> |
| 9 | |
| 10 | #include "dstr.h" |
| 11 | #include "macros.h" |
| 12 | |
| 13 | static int win = 0, lose = 0; |
| 14 | static dstr d = DSTR_INIT; |
| 15 | static char buf[1024]; |
| 16 | |
| 17 | static void check(const char *what, const char *want) |
| 18 | { |
| 19 | if (STRCMP(want, ==, d.buf)) |
| 20 | win++; |
| 21 | else { |
| 22 | lose++; |
| 23 | fprintf(stderr, "test failed: %s\n expected: %s\n found: %s\n", |
| 24 | what, want, d.buf); |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | static void PRINTF_LIKE(1, 2) format(const char *fmt, ...) |
| 29 | { |
| 30 | va_list ap; |
| 31 | va_start(ap, fmt); |
| 32 | dstr_reset(&d); |
| 33 | dstr_vputf(&d, fmt, &ap); |
| 34 | va_end(ap); |
| 35 | } |
| 36 | |
| 37 | static void PRINTF_LIKE(1, 2) prepare(const char *fmt, ...) |
| 38 | { |
| 39 | va_list ap; |
| 40 | int n; |
| 41 | |
| 42 | va_start(ap, fmt); |
| 43 | #ifdef HAVE_SNPRINTF |
| 44 | n = vsnprintf(buf, sizeof(buf), fmt, ap); |
| 45 | #else |
| 46 | n = vsprintf(buf, fmt, ap); |
| 47 | #endif |
| 48 | assert(0 <= n && n < sizeof(buf)); |
| 49 | } |
| 50 | |
| 51 | #define TEST1(fmtargs) do { \ |
| 52 | format fmtargs; \ |
| 53 | prepare fmtargs; \ |
| 54 | check(#fmtargs, buf); \ |
| 55 | } while (0) |
| 56 | |
| 57 | #define TEST2(fmtargs, want) do { \ |
| 58 | format fmtargs; \ |
| 59 | check(#fmtargs, want); \ |
| 60 | } while (0) |
| 61 | |
| 62 | #define LENGTHY \ |
| 63 | "This is a rather longer string than the code is expecting: will it fit?" |
| 64 | |
| 65 | int main(void) |
| 66 | { |
| 67 | TEST2(("Hello, world!"), "Hello, world!"); |
| 68 | TEST2(("just a ->%%<- sign"), "just a ->%<- sign"); |
| 69 | TEST2(("Testing, testing, %d, %d, %d.", 1, 2, 3), |
| 70 | "Testing, testing, 1, 2, 3."); |
| 71 | TEST2(("->%5d<-", 138), "-> 138<-"); |
| 72 | TEST2(("->%*d<-", 5, 138), "-> 138<-"); |
| 73 | TEST2(("->%-*d<-", 5, 138), "->138 <-"); |
| 74 | TEST2(("->%*d<-", -5, 138), "->138 <-"); |
| 75 | TEST2(("->%-*d<-", -5, 138), "->138 <-"); |
| 76 | TEST2(("->%.*s<-", 5, "truncate me"), "->trunc<-"); |
| 77 | TEST2(("->%.*s<-", -5, "don't truncate me"), "->don't truncate me<-"); |
| 78 | TEST2(("Truncation indirect: ->%.*s<-", 10, "a long string to be chopped"), |
| 79 | "Truncation indirect: ->a long str<-"); |
| 80 | TEST2(("%08lx:%s", 0x65604204ul, "tripe-ec"), "65604204:tripe-ec"); |
| 81 | TEST2(("%s", LENGTHY), LENGTHY); |
| 82 | |
| 83 | TEST1(("big float: ->%f<- and integer %d\n", DBL_MAX, 42)); |
| 84 | |
| 85 | TEST2(("Testing, testing, %3$d, %2$d, %1$d.", 3, 2, 1), |
| 86 | "Testing, testing, 1, 2, 3."); |
| 87 | TEST2(("Truncation indirect: ->%1$.*2$s<-", |
| 88 | "a long string to be chopped", 10), |
| 89 | "Truncation indirect: ->a long str<-"); |
| 90 | |
| 91 | if (!lose) printf("All tests successful.\n"); |
| 92 | else printf("FAILED %d of %d tests.\n", lose, win + lose); |
| 93 | return (!!lose); |
| 94 | } |