| 1 | /* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. | 
| 2 |  | 
| 3 |    This program is free software; you can redistribute it and/or | 
| 4 |    modify it under the terms of the GNU General Public License as | 
| 5 |    published by the Free Software Foundation; version 2 of the License. | 
| 6 |  | 
| 7 |    This program is distributed in the hope that it will be useful, but | 
| 8 |    WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 9 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
| 10 |    General Public License for more details. | 
| 11 |  | 
| 12 |    You should have received a copy of the GNU General Public License | 
| 13 |    along with this program; if not, write to the Free Software | 
| 14 |    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */ | 
| 15 |  | 
| 16 | #include <my_global.h> | 
| 17 | #include <m_string.h> | 
| 18 | #include <tap.h> | 
| 19 |  | 
| 20 | char buf[1024]; /* let's hope that's enough */ | 
| 21 |  | 
| 22 | static void test_w_len(const char *res, size_t buflen, const char *fmt, ...) | 
| 23 | { | 
| 24 |   va_list args; | 
| 25 |   size_t len; | 
| 26 |   va_start(args,fmt); | 
| 27 |   len= my_vsnprintf(buf, buflen, fmt, args); | 
| 28 |   va_end(args); | 
| 29 |   ok(strlen(res) == len && strcmp(buf, res) == 0, "\"%s\"" , buf); | 
| 30 | } | 
| 31 |  | 
| 32 | static void test1(const char *res, const char *fmt, ...) | 
| 33 | { | 
| 34 |   va_list args; | 
| 35 |   size_t len; | 
| 36 |   va_start(args,fmt); | 
| 37 |   len= my_vsnprintf(buf, sizeof(buf)-1, fmt, args); | 
| 38 |   va_end(args); | 
| 39 |   ok(strlen(res) == len && strcmp(buf, res) == 0, "\"%s\"" , buf); | 
| 40 | } | 
| 41 |  | 
| 42 | static void test_many(const char **res, const char *fmt, ...) | 
| 43 | { | 
| 44 |   va_list args; | 
| 45 |   size_t len; | 
| 46 |   va_start(args,fmt); | 
| 47 |   len= my_vsnprintf(buf, sizeof(buf)-1, fmt, args); | 
| 48 |   va_end(args); | 
| 49 |  | 
| 50 |   for (; *res ; res++) | 
| 51 |   { | 
| 52 |     if (strlen(*res) == len && strcmp(buf, *res) == 0) | 
| 53 |     { | 
| 54 |       ok(1, "\"%s\"" , buf); | 
| 55 |       return; | 
| 56 |     } | 
| 57 |   } | 
| 58 |   ok(0, "\"%s\"" , buf); | 
| 59 | } | 
| 60 |  | 
| 61 |  | 
| 62 | int main(void) | 
| 63 | { | 
| 64 |   plan(39); | 
| 65 |  | 
| 66 |   test1("Constant string" , | 
| 67 |         "Constant string" ); | 
| 68 |  | 
| 69 |   test1("Format specifier s works" , | 
| 70 |         "Format specifier s %s" , "works" ); | 
| 71 |   test1("Format specifier b works (mysql extension)" , | 
| 72 |         "Format specifier b %.5b (mysql extension)" , "works!!!" ); | 
| 73 |   test1("Format specifier c !" , | 
| 74 |         "Format specifier c %c" , '!'); | 
| 75 |   test1("Format specifier d 1" , | 
| 76 |         "Format specifier d %d" , 1); | 
| 77 |   test1("Format specifier i 1" , | 
| 78 |         "Format specifier i %i" , 1); | 
| 79 |   test1("Format specifier u 2" , | 
| 80 |         "Format specifier u %u" , 2); | 
| 81 |   test1("Format specifier o 375" , | 
| 82 |         "Format specifier o %o" , 0375); | 
| 83 |   test1("Format specifier x a" , | 
| 84 |         "Format specifier x %x" , 10); | 
| 85 |   test1("Format specifier X B" , | 
| 86 |         "Format specifier X %X" , 11); | 
| 87 |   test1("Format specifier p 0x5" , | 
| 88 |         "Format specifier p %p" , 5); | 
| 89 |   test1("Format specifier f 3.141593" , | 
| 90 |         "Format specifier f %f" , 3.1415926); | 
| 91 |   test1("Format specifier g 3.1416" , | 
| 92 |         "Format specifier g %g" , 3.1415926); | 
| 93 |  | 
| 94 |   test1("Flag '-' is ignored <   1>" , | 
| 95 |         "Flag '-' is ignored <%-4d>" , 1); | 
| 96 |   test1("Flag '0' works <0006>" , | 
| 97 |         "Flag '0' works <%04d>" , 6); | 
| 98 |  | 
| 99 |   test1("Width is ignored for strings <x> <y>" , | 
| 100 |         "Width is ignored for strings <%04s> <%5s>" , "x" , "y" ); | 
| 101 |  | 
| 102 |   test1("Precision works for strings <abcde>" , | 
| 103 |         "Precision works for strings <%.5s>" , "abcdef!" ); | 
| 104 |  | 
| 105 |   test1("Flag '`' (backtick) works: `abcd` `op``q` (mysql extension)" , | 
| 106 |         "Flag '`' (backtick) works: %`s %`.4s (mysql extension)" , | 
| 107 |         "abcd" , "op`qrst" ); | 
| 108 |  | 
| 109 |   test1("Length modifiers work: 1 * -1 * 2 * 3" , | 
| 110 |         "Length modifiers work: %d * %ld * %lld * %zd" , 1, -1L, 2LL, (size_t)3); | 
| 111 |  | 
| 112 |   test1("Length modifiers work: 1 * -1 * 2 * 3" , | 
| 113 |         "Length modifiers work: %i * %li * %lli * %zd" , 1, -1L, 2LL, (size_t)3); | 
| 114 |  | 
| 115 |   test1("long long X: 123456789abcdef0" , | 
| 116 |         "long long X: %llx" , 0x123456789abcdef0LL); | 
| 117 |  | 
| 118 |   test1("(null) pointer is fine" , | 
| 119 |         "%s pointer is fine" , NULL); | 
| 120 |  | 
| 121 |   test1("Positional arguments work: on the dark side they are" , | 
| 122 |         "Positional arguments work: %3$s %1$s %2$s" , | 
| 123 |         "they" , "are" , "on the dark side" ); | 
| 124 |  | 
| 125 |   test1("Asterisk '*' as a width works: <    4>" , | 
| 126 |         "Asterisk '*' as a width works: <%*d>" , 5, 4); | 
| 127 |  | 
| 128 |   test1("Asterisk '*' as a precision works: <qwerty>" , | 
| 129 |         "Asterisk '*' as a precision works: <%.*s>" , 6, "qwertyuiop" ); | 
| 130 |  | 
| 131 |   test1("Positional arguments for a width: <    4>" , | 
| 132 |         "Positional arguments for a width: <%1$*2$d>" , 4, 5); | 
| 133 |  | 
| 134 |   test1("Positional arguments for a precision: <qwerty>" , | 
| 135 |         "Positional arguments for a precision: <%1$.*2$s>" , "qwertyuiop" , 6); | 
| 136 |  | 
| 137 |   test1("Positional arguments and a width: <0000ab>" , | 
| 138 |         "Positional arguments and a width: <%1$06x>" , 0xab); | 
| 139 |  | 
| 140 |   test1("Positional arguments octal: <7777>" , | 
| 141 |         "Positional arguments octal: <%1$o>" , 07777); | 
| 142 |  | 
| 143 |   /* Can't use int arguments, as they may be different size from pointers */ | 
| 144 |  | 
| 145 |   test1("Padding and %p <0x12> <0x034> <0x0000ab> <    0xcd>" , | 
| 146 |         "Padding and %%p <%04p> <%05p> <%08p> <%8p>" , | 
| 147 |         (void*) 0x12, (void*) 0x34, (void*) 0xab, (void*) 0xcd); | 
| 148 |  | 
| 149 |   test1("F with a width (ignored) and precision: <12.34568>" , | 
| 150 |         "F with a width (ignored) and precision: <%10.5f>" , 12.3456789); | 
| 151 |   test1("G with a width (ignored) and precision: <12.35>" , | 
| 152 |         "G with a width (ignored) and precision: <%10.5g>" , 12.3456789); | 
| 153 |  | 
| 154 |   { | 
| 155 |     /* Test that %M works */ | 
| 156 |     const char *results[]= | 
| 157 |     { | 
| 158 |       "Error 1 \"Operation not permitted\"" ,    /* Linux */ | 
| 159 |       "Error 1 \"Not owner\"" ,                  /* Solaris */ | 
| 160 |       NullS | 
| 161 |     }; | 
| 162 |     test_many(results, "Error %M" , 1); | 
| 163 |   } | 
| 164 |  | 
| 165 |   test1("M with 0 error code: 0 \"Internal error/check (Not system error)\"" , | 
| 166 |         "M with 0 error code: %M" , 0); | 
| 167 |  | 
| 168 |   test1("M with positional: 0 \"Internal error/check (Not system error)\"" , | 
| 169 |         "M with positional: %1$M" , 0); | 
| 170 |  | 
| 171 |   test1("M with width: 0 \"Internal error/ch" , | 
| 172 |         "M with width: %.20M" , 0); | 
| 173 |   test1("M with width positional: 0 \"Internal error/ch" , | 
| 174 |         "M with width positional: %2$.*1$M" , 20, 0); | 
| 175 |  | 
| 176 |   test_w_len("M small buf: 0 \"In" , | 
| 177 |          19, "M small buf: %M" , 0); | 
| 178 |   test_w_len("M small buf positional: 0 \"In" , | 
| 179 |          30, "M small buf positional: %1$M" , 0); | 
| 180 |  | 
| 181 |   return exit_status(); | 
| 182 | } | 
| 183 |  | 
| 184 |  |