Line data Source code
1 : /*
2 : * This file originated in realmd
3 : *
4 : * Copyright 2012 Red Hat Inc
5 : *
6 : * This program is free software: you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as published
8 : * by the Free Software Foundation; either version 2 of the licence or (at
9 : * your option) any later version.
10 : *
11 : * See the included COPYING file for more information.
12 : *
13 : * Author: Stef Walter <stefw@redhat.com>
14 : */
15 :
16 : #include "config.h"
17 :
18 : #include "src/util/safe-format-string.h"
19 :
20 : #include <check.h>
21 : #include <popt.h>
22 : #include <string.h>
23 : #include <talloc.h>
24 :
25 : #ifndef ck_assert_int_ge
26 : #define ck_assert_int_ge(X, Y) _ck_assert_int(X, >=, Y)
27 : #endif
28 :
29 : #ifndef ck_assert_int_lt
30 : #define ck_assert_int_lt(X, Y) _ck_assert_int(X, <, Y)
31 : #endif
32 :
33 : typedef struct {
34 : const char *format;
35 : const char *args[8];
36 : const char *result;
37 : } Fixture;
38 :
39 : static const Fixture fixtures[] = {
40 : {
41 : /* Just a bog standard string */
42 : "%s", { "blah", NULL, },
43 : "blah"
44 : },
45 : {
46 : /* Empty to print */
47 : "%s", { "", NULL, },
48 : ""
49 : },
50 : {
51 : /* Nothing to print */
52 : "", { "blah", NULL, },
53 : ""
54 : },
55 : {
56 : /* Width right aligned */
57 : "%8s", { "blah", NULL, },
58 : " blah"
59 : },
60 : {
61 : /* Width left aligned */
62 : "whoop %-8s doo", { "dee", NULL, },
63 : "whoop dee doo"
64 : },
65 : {
66 : /* Width space aligned (ignored) */
67 : "whoop % 8s doo", { "dee", NULL, },
68 : "whoop dee doo"
69 : },
70 : {
71 : /* Width left space aligned (ignored) */
72 : "whoop % -8s doo", { "dee", NULL, },
73 : "whoop dee doo"
74 : },
75 : {
76 : /* Precision 1 digit */
77 : "whoop %.3s doo", { "deedle-dee", NULL, },
78 : "whoop dee doo"
79 : },
80 : {
81 : /* Precision, N digits */
82 : "whoop %.10s doo", { "deedle-dee-deedle-do-deedle-dum", NULL, },
83 : "whoop deedle-dee doo"
84 : },
85 : {
86 : /* Precision, zero digits */
87 : "whoop %.s doo", { "deedle", NULL, },
88 : "whoop doo"
89 : },
90 : {
91 : /* Multiple simple arguments */
92 : "space %s %s", { "man", "dances", NULL, },
93 : "space man dances"
94 : },
95 : {
96 : /* Literal percent */
97 : "100%% of space folk dance", { NULL, },
98 : "100% of space folk dance"
99 : },
100 : {
101 : /* Multiple simple arguments */
102 : "space %2$s %1$s", { "dances", "man", NULL, },
103 : "space man dances"
104 : },
105 : {
106 : /* Skipping an argument (not supported by standard printf) */
107 : "space %2$s dances", { "dances", "man", NULL, },
108 : "space man dances"
109 : },
110 :
111 : /* Failures start here */
112 :
113 : {
114 : /* Unsupported conversion */
115 : "%x", { "blah", NULL, },
116 : NULL
117 : },
118 : {
119 : /* Bad positional argument */
120 : "space %55$s dances", { "dances", "man", NULL, },
121 : NULL
122 : },
123 : {
124 : /* Zero positional argument */
125 : "space %0$s dances", { "dances", "man", NULL, },
126 : NULL
127 : },
128 : {
129 : /* Too many args used */
130 : "%s %s dances", { "space", NULL, },
131 : NULL
132 : },
133 : {
134 : /* Too many digits used */
135 : "%1234567890s dances", { "space", NULL, },
136 : NULL
137 : },
138 : };
139 :
140 :
141 : static void
142 43 : callback(void *data, const char *piece, size_t len)
143 : {
144 43 : char **str = data;
145 43 : *str = talloc_strndup_append(*str, piece, len);
146 43 : }
147 :
148 19 : START_TEST(test_safe_format_string_cb)
149 : {
150 : const Fixture *fixture;
151 : char *out;
152 : int num_args;
153 : int ret;
154 : void *mem_ctx;
155 :
156 19 : fixture = &fixtures[_i];
157 19 : mem_ctx = talloc_init("safe-printf");
158 :
159 61 : for (num_args = 0; fixture->args[num_args] != NULL; )
160 23 : num_args++;
161 :
162 19 : out = talloc_strdup(mem_ctx, "");
163 19 : ret = safe_format_string_cb(callback, &out, fixture->format,
164 19 : (const char * const*)fixture->args, num_args);
165 19 : if (fixture->result) {
166 14 : ck_assert_int_ge(ret, 0);
167 14 : ck_assert_str_eq(out, fixture->result);
168 14 : ck_assert_int_eq(ret, strlen(out));
169 : } else {
170 5 : ck_assert_int_lt(ret, 0);
171 : }
172 :
173 19 : talloc_free(mem_ctx);
174 : }
175 19 : END_TEST
176 :
177 1 : START_TEST(test_safe_format_string)
178 : {
179 : char buffer[8];
180 : int ret;
181 :
182 1 : ret = safe_format_string(buffer, 8, "%s", "space", "man", NULL);
183 1 : ck_assert_int_eq(ret, 5);
184 1 : ck_assert_str_eq(buffer, "space");
185 :
186 1 : ret = safe_format_string(buffer, 8, "", "space", "man", NULL);
187 1 : ck_assert_int_eq(ret, 0);
188 1 : ck_assert_str_eq(buffer, "");
189 :
190 1 : ret = safe_format_string(buffer, 8, "the %s %s dances away", "space", "man", NULL);
191 1 : ck_assert_int_eq(ret, 25);
192 1 : ck_assert_str_eq(buffer, "the spa");
193 :
194 1 : ret = safe_format_string(NULL, 0, "the %s %s dances away", "space", "man", NULL);
195 1 : ck_assert_int_eq(ret, 25);
196 :
197 1 : ret = safe_format_string(buffer, 8, "%5$s", NULL);
198 1 : ck_assert_int_lt(ret, 0);
199 : }
200 1 : END_TEST
201 :
202 : static Suite *
203 1 : create_safe_format_suite(void)
204 : {
205 1 : Suite *s = suite_create("safe-format");
206 1 : TCase *tc_format = tcase_create("safe-format-string");
207 :
208 : /* One for each fixture */
209 1 : tcase_add_loop_test(tc_format, test_safe_format_string_cb, 0,
210 : (sizeof (fixtures) / sizeof (fixtures[0])));
211 :
212 1 : tcase_add_test(tc_format, test_safe_format_string);
213 :
214 1 : suite_add_tcase(s, tc_format);
215 :
216 1 : return s;
217 : }
218 :
219 : int
220 1 : main(int argc, const char *argv[])
221 : {
222 : int opt;
223 : poptContext pc;
224 : int failure_count;
225 : Suite *suite;
226 : SRunner *sr;
227 :
228 1 : struct poptOption long_options[] = {
229 : POPT_AUTOHELP
230 : POPT_TABLEEND
231 : };
232 :
233 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
234 1 : while((opt = poptGetNextOpt(pc)) != -1) {
235 : switch(opt) {
236 : default:
237 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
238 : poptBadOption(pc, 0), poptStrerror(opt));
239 0 : poptPrintUsage(pc, stderr, 0);
240 0 : return 1;
241 : }
242 : }
243 1 : poptFreeContext(pc);
244 :
245 1 : suite = create_safe_format_suite();
246 1 : sr = srunner_create(suite);
247 : /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
248 1 : srunner_run_all(sr, CK_ENV);
249 1 : failure_count = srunner_ntests_failed(sr);
250 1 : srunner_free(sr);
251 1 : return (failure_count==0 ? EXIT_SUCCESS : EXIT_FAILURE);
252 : }
|