1/*
2 * Automated Testing Framework (atf)
3 *
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <atf-c.h>
35
36#include "sanity.h"
37#include "test_helpers.h"
38#include "text.h"
39
40/* ---------------------------------------------------------------------
41 * Auxiliary functions.
42 * --------------------------------------------------------------------- */
43
44#define REQUIRE_ERROR(exp) \
45    do { \
46        atf_error_t err = exp; \
47        ATF_REQUIRE(atf_is_error(err)); \
48        atf_error_free(err); \
49    } while (0)
50
51static
52size_t
53array_size(const char *words[])
54{
55    size_t count;
56    const char **word;
57
58    count = 0;
59    for (word = words; *word != NULL; word++)
60        count++;
61
62    return count;
63}
64
65static
66void
67check_split(const char *str, const char *delim, const char *words[])
68{
69    atf_list_t list;
70    const char **word;
71    size_t i;
72
73    printf("Splitting '%s' with delimiter '%s'\n", str, delim);
74    CE(atf_text_split(str, delim, &list));
75
76    printf("Expecting %zd words\n", array_size(words));
77    ATF_CHECK_EQ(atf_list_size(&list), array_size(words));
78
79    for (word = words, i = 0; *word != NULL; word++, i++) {
80        printf("Word at position %zd should be '%s'\n", i, words[i]);
81        ATF_CHECK_STREQ((const char *)atf_list_index_c(&list, i), words[i]);
82    }
83
84    atf_list_fini(&list);
85}
86
87static
88atf_error_t
89word_acum(const char *word, void *data)
90{
91    char *acum = data;
92
93    strcat(acum, word);
94
95    return atf_no_error();
96}
97
98static
99atf_error_t
100word_count(const char *word ATF_DEFS_ATTRIBUTE_UNUSED, void *data)
101{
102    size_t *counter = data;
103
104    (*counter)++;
105
106    return atf_no_error();
107}
108
109struct fail_at {
110    int failpos;
111    int curpos;
112};
113
114static
115atf_error_t
116word_fail_at(const char *word ATF_DEFS_ATTRIBUTE_UNUSED, void *data)
117{
118    struct fail_at *fa = data;
119    atf_error_t err;
120
121    if (fa->failpos == fa->curpos)
122        err = atf_no_memory_error(); /* Just a random error. */
123    else {
124        fa->curpos++;
125        err = atf_no_error();
126    }
127
128    return err;
129}
130
131/* ---------------------------------------------------------------------
132 * Test cases for the free functions.
133 * --------------------------------------------------------------------- */
134
135ATF_TC(for_each_word);
136ATF_TC_HEAD(for_each_word, tc)
137{
138    atf_tc_set_md_var(tc, "descr", "Checks the atf_text_for_each_word"
139                      "function");
140}
141ATF_TC_BODY(for_each_word, tc)
142{
143    size_t cnt;
144    char acum[1024];
145
146    cnt = 0;
147    strcpy(acum, "");
148    RE(atf_text_for_each_word("1 2 3", " ", word_count, &cnt));
149    RE(atf_text_for_each_word("1 2 3", " ", word_acum, acum));
150    ATF_REQUIRE(cnt == 3);
151    ATF_REQUIRE(strcmp(acum, "123") == 0);
152
153    cnt = 0;
154    strcpy(acum, "");
155    RE(atf_text_for_each_word("1 2 3", ".", word_count, &cnt));
156    RE(atf_text_for_each_word("1 2 3", ".", word_acum, acum));
157    ATF_REQUIRE(cnt == 1);
158    ATF_REQUIRE(strcmp(acum, "1 2 3") == 0);
159
160    cnt = 0;
161    strcpy(acum, "");
162    RE(atf_text_for_each_word("1 2 3 4 5", " ", word_count, &cnt));
163    RE(atf_text_for_each_word("1 2 3 4 5", " ", word_acum, acum));
164    ATF_REQUIRE(cnt == 5);
165    ATF_REQUIRE(strcmp(acum, "12345") == 0);
166
167    cnt = 0;
168    strcpy(acum, "");
169    RE(atf_text_for_each_word("1 2.3.4 5", " .", word_count, &cnt));
170    RE(atf_text_for_each_word("1 2.3.4 5", " .", word_acum, acum));
171    ATF_REQUIRE(cnt == 5);
172    ATF_REQUIRE(strcmp(acum, "12345") == 0);
173
174    {
175        struct fail_at fa;
176        fa.failpos = 3;
177        fa.curpos = 0;
178        atf_error_t err = atf_text_for_each_word("a b c d e", " ",
179                                                 word_fail_at, &fa);
180        ATF_REQUIRE(atf_is_error(err));
181        ATF_REQUIRE(atf_error_is(err, "no_memory"));
182        ATF_REQUIRE(fa.curpos == 3);
183        atf_error_free(err);
184    }
185}
186
187ATF_TC(format);
188ATF_TC_HEAD(format, tc)
189{
190    atf_tc_set_md_var(tc, "descr", "Checks the construction of free-form "
191                      "strings using a variable parameters list");
192}
193ATF_TC_BODY(format, tc)
194{
195    char *str;
196    atf_error_t err;
197
198    err = atf_text_format(&str, "%s %s %d", "Test", "string", 1);
199    ATF_REQUIRE(!atf_is_error(err));
200    ATF_REQUIRE(strcmp(str, "Test string 1") == 0);
201    free(str);
202}
203
204static
205void
206format_ap(char **dest, const char *fmt, ...)
207{
208    va_list ap;
209    atf_error_t err;
210
211    va_start(ap, fmt);
212    err = atf_text_format_ap(dest, fmt, ap);
213    va_end(ap);
214
215    ATF_REQUIRE(!atf_is_error(err));
216}
217
218ATF_TC(format_ap);
219ATF_TC_HEAD(format_ap, tc)
220{
221    atf_tc_set_md_var(tc, "descr", "Checks the construction of free-form "
222                      "strings using a va_list argument");
223}
224ATF_TC_BODY(format_ap, tc)
225{
226    char *str;
227
228    format_ap(&str, "%s %s %d", "Test", "string", 1);
229    ATF_REQUIRE(strcmp(str, "Test string 1") == 0);
230    free(str);
231}
232
233ATF_TC(split);
234ATF_TC_HEAD(split, tc)
235{
236    atf_tc_set_md_var(tc, "descr", "Checks the split function");
237}
238ATF_TC_BODY(split, tc)
239{
240    {
241        const char *words[] = { NULL };
242        check_split("", " ", words);
243    }
244
245    {
246        const char *words[] = { NULL };
247        check_split(" ", " ", words);
248    }
249
250    {
251        const char *words[] = { NULL };
252        check_split("    ", " ", words);
253    }
254
255    {
256        const char *words[] = { "a", "b", NULL };
257        check_split("a b", " ", words);
258    }
259
260    {
261        const char *words[] = { "a", "b", "c", "d", NULL };
262        check_split("a b c d", " ", words);
263    }
264
265    {
266        const char *words[] = { "foo", "bar", NULL };
267        check_split("foo bar", " ", words);
268    }
269
270    {
271        const char *words[] = { "foo", "bar", "baz", "foobar", NULL };
272        check_split("foo bar baz foobar", " ", words);
273    }
274
275    {
276        const char *words[] = { "foo", "bar", NULL };
277        check_split(" foo bar", " ", words);
278    }
279
280    {
281        const char *words[] = { "foo", "bar", NULL };
282        check_split("foo  bar", " ", words);
283    }
284
285    {
286        const char *words[] = { "foo", "bar", NULL };
287        check_split("foo bar ", " ", words);
288    }
289
290    {
291        const char *words[] = { "foo", "bar", NULL };
292        check_split("  foo  bar  ", " ", words);
293    }
294}
295
296ATF_TC(split_delims);
297ATF_TC_HEAD(split_delims, tc)
298{
299    atf_tc_set_md_var(tc, "descr", "Checks the split function using "
300                      "different delimiters");
301}
302ATF_TC_BODY(split_delims, tc)
303{
304
305    {
306        const char *words[] = { NULL };
307        check_split("", "/", words);
308    }
309
310    {
311        const char *words[] = { " ", NULL };
312        check_split(" ", "/", words);
313    }
314
315    {
316        const char *words[] = { "    ", NULL };
317        check_split("    ", "/", words);
318    }
319
320    {
321        const char *words[] = { "a", "b", NULL };
322        check_split("a/b", "/", words);
323    }
324
325    {
326        const char *words[] = { "a", "bcd", "ef", NULL };
327        check_split("aLONGDELIMbcdLONGDELIMef", "LONGDELIM", words);
328    }
329}
330
331ATF_TC(to_bool);
332ATF_TC_HEAD(to_bool, tc)
333{
334    atf_tc_set_md_var(tc, "descr", "Checks the atf_text_to_bool function");
335}
336ATF_TC_BODY(to_bool, tc)
337{
338    bool b;
339
340    RE(atf_text_to_bool("true", &b)); ATF_REQUIRE(b);
341    RE(atf_text_to_bool("TRUE", &b)); ATF_REQUIRE(b);
342    RE(atf_text_to_bool("yes", &b)); ATF_REQUIRE(b);
343    RE(atf_text_to_bool("YES", &b)); ATF_REQUIRE(b);
344
345    RE(atf_text_to_bool("false", &b)); ATF_REQUIRE(!b);
346    RE(atf_text_to_bool("FALSE", &b)); ATF_REQUIRE(!b);
347    RE(atf_text_to_bool("no", &b)); ATF_REQUIRE(!b);
348    RE(atf_text_to_bool("NO", &b)); ATF_REQUIRE(!b);
349
350    b = false;
351    REQUIRE_ERROR(atf_text_to_bool("", &b));
352    ATF_REQUIRE(!b);
353    b = true;
354    REQUIRE_ERROR(atf_text_to_bool("", &b));
355    ATF_REQUIRE(b);
356
357    b = false;
358    REQUIRE_ERROR(atf_text_to_bool("tru", &b));
359    ATF_REQUIRE(!b);
360    b = true;
361    REQUIRE_ERROR(atf_text_to_bool("tru", &b));
362    ATF_REQUIRE(b);
363
364    b = false;
365    REQUIRE_ERROR(atf_text_to_bool("true2", &b));
366    ATF_REQUIRE(!b);
367    b = true;
368    REQUIRE_ERROR(atf_text_to_bool("true2", &b));
369    ATF_REQUIRE(b);
370
371    b = false;
372    REQUIRE_ERROR(atf_text_to_bool("fals", &b));
373    ATF_REQUIRE(!b);
374    b = true;
375    REQUIRE_ERROR(atf_text_to_bool("fals", &b));
376    ATF_REQUIRE(b);
377
378    b = false;
379    REQUIRE_ERROR(atf_text_to_bool("false2", &b));
380    ATF_REQUIRE(!b);
381    b = true;
382    REQUIRE_ERROR(atf_text_to_bool("false2", &b));
383    ATF_REQUIRE(b);
384}
385
386ATF_TC(to_long);
387ATF_TC_HEAD(to_long, tc)
388{
389    atf_tc_set_md_var(tc, "descr", "Checks the atf_text_to_long function");
390}
391ATF_TC_BODY(to_long, tc)
392{
393    long l;
394
395    RE(atf_text_to_long("0", &l)); ATF_REQUIRE_EQ(l, 0);
396    RE(atf_text_to_long("-5", &l)); ATF_REQUIRE_EQ(l, -5);
397    RE(atf_text_to_long("5", &l)); ATF_REQUIRE_EQ(l, 5);
398    RE(atf_text_to_long("123456789", &l)); ATF_REQUIRE_EQ(l, 123456789);
399
400    l = 1212;
401    REQUIRE_ERROR(atf_text_to_long("", &l));
402    ATF_REQUIRE_EQ(l, 1212);
403    REQUIRE_ERROR(atf_text_to_long("foo", &l));
404    ATF_REQUIRE_EQ(l, 1212);
405    REQUIRE_ERROR(atf_text_to_long("1234x", &l));
406    ATF_REQUIRE_EQ(l, 1212);
407}
408
409/* ---------------------------------------------------------------------
410 * Main.
411 * --------------------------------------------------------------------- */
412
413ATF_TP_ADD_TCS(tp)
414{
415    ATF_TP_ADD_TC(tp, for_each_word);
416    ATF_TP_ADD_TC(tp, format);
417    ATF_TP_ADD_TC(tp, format_ap);
418    ATF_TP_ADD_TC(tp, split);
419    ATF_TP_ADD_TC(tp, split_delims);
420    ATF_TP_ADD_TC(tp, to_bool);
421    ATF_TP_ADD_TC(tp, to_long);
422
423    return atf_no_error();
424}
425