1 /*	$NetBSD: dynstr_test.c,v 1.3 2014/12/10 04:38:03 christos Exp $	*/
2 
3 /*
4  * Automated Testing Framework (atf)
5  *
6  * Copyright (c) 2008 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
19  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <stdarg.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include <atf-c.h>
39 
40 #include "dynstr.h"
41 #include "test_helpers.h"
42 
43 /* ---------------------------------------------------------------------
44  * Tests for the "atf_dynstr" type.
45  * --------------------------------------------------------------------- */
46 
47 /*
48  * Constructors and destructors.
49  */
50 
51 ATF_TC(init);
52 ATF_TC_HEAD(init, tc)
53 {
54     atf_tc_set_md_var(tc, "descr", "Checks the empty constructor");
55 }
56 ATF_TC_BODY(init, tc)
57 {
58     atf_dynstr_t str;
59 
60     RE(atf_dynstr_init(&str));
61     ATF_REQUIRE_EQ(atf_dynstr_length(&str), 0);
62     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "") == 0);
63     atf_dynstr_fini(&str);
64 }
65 
66 static
67 void
68 init_fmt(atf_dynstr_t *str, const char *fmt, ...)
69 {
70     va_list ap;
71 
72     va_start(ap, fmt);
73     RE(atf_dynstr_init_ap(str, fmt, ap));
74     va_end(ap);
75 }
76 
77 ATF_TC(init_ap);
78 ATF_TC_HEAD(init_ap, tc)
79 {
80     atf_tc_set_md_var(tc, "descr", "Checks the formatted constructor using "
81                       "a va_list argument");
82 }
83 ATF_TC_BODY(init_ap, tc)
84 {
85     atf_dynstr_t str;
86 
87     init_fmt(&str, "String 1");
88     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 1") == 0);
89     atf_dynstr_fini(&str);
90 
91     init_fmt(&str, "String %d", 2);
92     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 2") == 0);
93     atf_dynstr_fini(&str);
94 
95     init_fmt(&str, "%s %d", "String", 3);
96     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 3") == 0);
97     atf_dynstr_fini(&str);
98 
99     init_fmt(&str, "%s%s%s%s%s%s%s", "This ", "should ", "be ", "a ",
100              "large ", "string ", "aaaabbbbccccdddd");
101     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str),
102                      "This should be a large string "
103                      "aaaabbbbccccdddd") == 0);
104     atf_dynstr_fini(&str);
105 }
106 
107 ATF_TC(init_fmt);
108 ATF_TC_HEAD(init_fmt, tc)
109 {
110     atf_tc_set_md_var(tc, "descr", "Checks the formatted constructor using "
111                       "a variable list of parameters");
112 }
113 ATF_TC_BODY(init_fmt, tc)
114 {
115     atf_dynstr_t str;
116 
117     RE(atf_dynstr_init_fmt(&str, "String 1"));
118     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 1") == 0);
119     atf_dynstr_fini(&str);
120 
121     RE(atf_dynstr_init_fmt(&str, "String %d", 2));
122     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 2") == 0);
123     atf_dynstr_fini(&str);
124 
125     RE(atf_dynstr_init_fmt(&str, "%s %d", "String", 3));
126     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 3") == 0);
127     atf_dynstr_fini(&str);
128 
129     RE(atf_dynstr_init_fmt(&str, "%s%s%s%s%s%s%s", "This ", "should ",
130                            "be ", "a ", "large ", "string ",
131                            "aaaabbbbccccdddd"));
132     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str),
133                      "This should be a large string "
134                      "aaaabbbbccccdddd") == 0);
135     atf_dynstr_fini(&str);
136 }
137 
138 ATF_TC(init_raw);
139 ATF_TC_HEAD(init_raw, tc)
140 {
141     atf_tc_set_md_var(tc, "descr", "Checks the construction of a string "
142                       "using a raw memory pointer");
143 }
144 ATF_TC_BODY(init_raw, tc)
145 {
146     const char *src = "String 1, String 2";
147     atf_dynstr_t str;
148 
149     RE(atf_dynstr_init_raw(&str, src, 0));
150     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "") == 0);
151     atf_dynstr_fini(&str);
152 
153     RE(atf_dynstr_init_raw(&str, src, 8));
154     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 1") == 0);
155     atf_dynstr_fini(&str);
156 
157     RE(atf_dynstr_init_raw(&str, src + 10, 8));
158     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String 2") == 0);
159     atf_dynstr_fini(&str);
160 
161     RE(atf_dynstr_init_raw(&str, "String\0Lost", 11));
162     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "String") == 0);
163     atf_dynstr_fini(&str);
164 
165     {
166         atf_error_t err = atf_dynstr_init_raw(&str, "NULL", SIZE_MAX - 1);
167         ATF_REQUIRE(atf_is_error(err));
168         ATF_REQUIRE(atf_error_is(err, "no_memory"));
169         atf_error_free(err);
170     }
171 }
172 
173 ATF_TC(init_rep);
174 ATF_TC_HEAD(init_rep, tc)
175 {
176     atf_tc_set_md_var(tc, "descr", "Checks the construction of a string by "
177                       "repeating characters");
178 }
179 ATF_TC_BODY(init_rep, tc)
180 {
181     const size_t maxlen = 8192;
182     char buf[maxlen + 1];
183     size_t i;
184 
185     buf[0] = '\0';
186 
187     for (i = 0; i < maxlen; i++) {
188         atf_dynstr_t str;
189 
190         RE(atf_dynstr_init_rep(&str, i, 'a'));
191 
192         if (strcmp(atf_dynstr_cstring(&str), buf) != 0) {
193             fprintf(stderr, "Failed at iteration %zd\n", i);
194             atf_tc_fail("Failed to construct dynstr by repeating %zd "
195                         "times the '%c' character", i, 'a');
196         }
197 
198         atf_dynstr_fini(&str);
199 
200         strcat(buf, "a");
201     }
202 
203     {
204         atf_dynstr_t str;
205         atf_error_t err;
206 
207         err = atf_dynstr_init_rep(&str, SIZE_MAX, 'a');
208         ATF_REQUIRE(atf_is_error(err));
209         ATF_REQUIRE(atf_error_is(err, "no_memory"));
210         atf_error_free(err);
211 
212         err = atf_dynstr_init_rep(&str, SIZE_MAX - 1, 'a');
213         ATF_REQUIRE(atf_is_error(err));
214         ATF_REQUIRE(atf_error_is(err, "no_memory"));
215         atf_error_free(err);
216     }
217 }
218 
219 ATF_TC(init_substr);
220 ATF_TC_HEAD(init_substr, tc)
221 {
222     atf_tc_set_md_var(tc, "descr", "Checks the construction of a string "
223                       "using a substring of another one");
224 }
225 ATF_TC_BODY(init_substr, tc)
226 {
227     atf_dynstr_t src;
228     atf_dynstr_t str;
229 
230     RE(atf_dynstr_init_fmt(&src, "Str 1, Str 2"));
231 
232     RE(atf_dynstr_init_substr(&str, &src, 0, 0));
233     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "") == 0);
234     atf_dynstr_fini(&str);
235 
236     RE(atf_dynstr_init_substr(&str, &src, 0, atf_dynstr_npos));
237     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "Str 1, Str 2") == 0);
238     atf_dynstr_fini(&str);
239 
240     RE(atf_dynstr_init_substr(&str, &src, 0, 100));
241     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "Str 1, Str 2") == 0);
242     atf_dynstr_fini(&str);
243 
244     RE(atf_dynstr_init_substr(&str, &src, 0, 5));
245     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "Str 1") == 0);
246     atf_dynstr_fini(&str);
247 
248     RE(atf_dynstr_init_substr(&str, &src, 100, atf_dynstr_npos));
249     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "") == 0);
250     atf_dynstr_fini(&str);
251 
252     RE(atf_dynstr_init_substr(&str, &src, 7, atf_dynstr_npos));
253     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "Str 2") == 0);
254     atf_dynstr_fini(&str);
255 
256     atf_dynstr_fini(&src);
257 }
258 
259 ATF_TC(copy);
260 ATF_TC_HEAD(copy, tc)
261 {
262     atf_tc_set_md_var(tc, "descr", "Checks the atf_dynstr_copy constructor");
263 }
264 ATF_TC_BODY(copy, tc)
265 {
266     atf_dynstr_t str, str2;
267 
268     RE(atf_dynstr_init_fmt(&str, "Test string"));
269     RE(atf_dynstr_copy(&str2, &str));
270 
271     ATF_REQUIRE(atf_equal_dynstr_dynstr(&str, &str2));
272 
273     RE(atf_dynstr_append_fmt(&str2, " non-shared text"));
274 
275     ATF_REQUIRE(!atf_equal_dynstr_dynstr(&str, &str2));
276 
277     atf_dynstr_fini(&str2);
278     atf_dynstr_fini(&str);
279 }
280 
281 ATF_TC(fini_disown);
282 ATF_TC_HEAD(fini_disown, tc)
283 {
284     atf_tc_set_md_var(tc, "descr", "Checks grabbing ownership of the "
285                       "internal plain C string");
286 }
287 ATF_TC_BODY(fini_disown, tc)
288 {
289     const char *cstr;
290     char *cstr2;
291     atf_dynstr_t str;
292 
293     RE(atf_dynstr_init_fmt(&str, "Test string 1"));
294     cstr = atf_dynstr_cstring(&str);
295     cstr2 = atf_dynstr_fini_disown(&str);
296 
297     ATF_REQUIRE_EQ(cstr, cstr2);
298     free(cstr2);
299 }
300 
301 /*
302  * Getters.
303  */
304 
305 ATF_TC(cstring);
306 ATF_TC_HEAD(cstring, tc)
307 {
308     atf_tc_set_md_var(tc, "descr", "Checks the method to obtain a plain C "
309                       "string");
310 }
311 ATF_TC_BODY(cstring, tc)
312 {
313     const char *cstr;
314     atf_dynstr_t str;
315 
316     RE(atf_dynstr_init_fmt(&str, "Test string 1"));
317     cstr = atf_dynstr_cstring(&str);
318     ATF_REQUIRE(cstr != NULL);
319     ATF_REQUIRE(strcmp(cstr, "Test string 1") == 0);
320     atf_dynstr_fini(&str);
321 
322     RE(atf_dynstr_init_fmt(&str, "Test string 2"));
323     cstr = atf_dynstr_cstring(&str);
324     ATF_REQUIRE(cstr != NULL);
325     ATF_REQUIRE(strcmp(cstr, "Test string 2") == 0);
326     atf_dynstr_fini(&str);
327 }
328 
329 ATF_TC(length);
330 ATF_TC_HEAD(length, tc)
331 {
332     atf_tc_set_md_var(tc, "descr", "Checks the method to obtain the length");
333 }
334 ATF_TC_BODY(length, tc)
335 {
336     size_t i;
337 
338     for (i = 0; i < 8192; i++) {
339         atf_dynstr_t str;
340         RE(atf_dynstr_init_rep(&str, i, 'a'));
341         ATF_REQUIRE_EQ(atf_dynstr_length(&str), i);
342         atf_dynstr_fini(&str);
343     }
344 }
345 
346 ATF_TC(rfind_ch);
347 ATF_TC_HEAD(rfind_ch, tc)
348 {
349     atf_tc_set_md_var(tc, "descr", "Checks the method to locate the first "
350                       "occurrence of a character starting from the end");
351 }
352 ATF_TC_BODY(rfind_ch, tc)
353 {
354     atf_dynstr_t str;
355 
356     RE(atf_dynstr_init_fmt(&str, "Foo1/Bar2/,.Baz"));
357 
358     ATF_REQUIRE_EQ(atf_dynstr_rfind_ch(&str, '\0'), atf_dynstr_npos);
359 
360     ATF_REQUIRE_EQ(atf_dynstr_rfind_ch(&str, '0'), atf_dynstr_npos);
361     ATF_REQUIRE_EQ(atf_dynstr_rfind_ch(&str, 'b'), atf_dynstr_npos);
362 
363     ATF_REQUIRE_EQ(atf_dynstr_rfind_ch(&str, 'F'), 0);
364     ATF_REQUIRE_EQ(atf_dynstr_rfind_ch(&str, '/'), 9);
365     ATF_REQUIRE_EQ(atf_dynstr_rfind_ch(&str, 'a'), 13);
366     ATF_REQUIRE_EQ(atf_dynstr_rfind_ch(&str, 'z'), 14);
367 
368     atf_dynstr_fini(&str);
369 }
370 
371 /*
372  * Modifiers.
373  */
374 
375 static
376 void
377 check_append(atf_error_t (*append)(atf_dynstr_t *, const char *, ...))
378 {
379     const size_t maxlen = 8192;
380     char buf[maxlen + 1];
381     size_t i;
382     atf_dynstr_t str;
383 
384     printf("Appending with plain string\n");
385     buf[0] = '\0';
386     RE(atf_dynstr_init(&str));
387     for (i = 0; i < maxlen; i++) {
388         if (strcmp(atf_dynstr_cstring(&str), buf) != 0) {
389             fprintf(stderr, "Failed at iteration %zd\n", i);
390             atf_tc_fail("Failed to append character at iteration %zd", i);
391         }
392 
393         RE(append(&str, "a"));
394         strcat(buf, "a");
395     }
396     atf_dynstr_fini(&str);
397 
398     printf("Appending with formatted string\n");
399     buf[0] = '\0';
400     RE(atf_dynstr_init(&str));
401     for (i = 0; i < maxlen; i++) {
402         if (strcmp(atf_dynstr_cstring(&str), buf) != 0) {
403             fprintf(stderr, "Failed at iteration %zd\n", i);
404             atf_tc_fail("Failed to append character at iteration %zd", i);
405         }
406 
407         RE(append(&str, "%s", "a"));
408         strcat(buf, "a");
409     }
410     atf_dynstr_fini(&str);
411 }
412 
413 static
414 atf_error_t
415 append_ap_aux(atf_dynstr_t *str, const char *fmt, ...)
416 {
417     va_list ap;
418     atf_error_t err;
419 
420     va_start(ap, fmt);
421     err = atf_dynstr_append_ap(str, fmt, ap);
422     va_end(ap);
423 
424     return err;
425 }
426 
427 ATF_TC(append_ap);
428 ATF_TC_HEAD(append_ap, tc)
429 {
430     atf_tc_set_md_var(tc, "descr", "Checks that appending a string to "
431                       "another one works");
432 }
433 ATF_TC_BODY(append_ap, tc)
434 {
435     check_append(append_ap_aux);
436 }
437 
438 ATF_TC(append_fmt);
439 ATF_TC_HEAD(append_fmt, tc)
440 {
441     atf_tc_set_md_var(tc, "descr", "Checks that appending a string to "
442                       "another one works");
443 }
444 ATF_TC_BODY(append_fmt, tc)
445 {
446     check_append(atf_dynstr_append_fmt);
447 }
448 
449 ATF_TC(clear);
450 ATF_TC_HEAD(clear, tc)
451 {
452     atf_tc_set_md_var(tc, "descr", "Checks clearing a string");
453 }
454 ATF_TC_BODY(clear, tc)
455 {
456     atf_dynstr_t str;
457 
458     printf("Clear an empty string\n");
459     RE(atf_dynstr_init(&str));
460     atf_dynstr_clear(&str);
461     ATF_REQUIRE_EQ(atf_dynstr_length(&str), 0);
462     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "") == 0);
463     atf_dynstr_fini(&str);
464 
465     printf("Clear a non-empty string\n");
466     RE(atf_dynstr_init_fmt(&str, "Not empty"));
467     ATF_REQUIRE_EQ(atf_dynstr_length(&str), strlen("Not empty"));
468     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "Not empty") == 0);
469     atf_dynstr_clear(&str);
470     ATF_REQUIRE_EQ(atf_dynstr_length(&str), 0);
471     ATF_REQUIRE(strcmp(atf_dynstr_cstring(&str), "") == 0);
472     atf_dynstr_fini(&str);
473 }
474 
475 static
476 void
477 check_prepend(atf_error_t (*prepend)(atf_dynstr_t *, const char *, ...))
478 {
479     const size_t maxlen = 8192;
480     char buf[maxlen + 1];
481     size_t i;
482     atf_dynstr_t str;
483 
484     printf("Prepending with plain string\n");
485     buf[0] = '\0';
486     RE(atf_dynstr_init(&str));
487     for (i = 0; i < maxlen; i++) {
488         if (strcmp(atf_dynstr_cstring(&str), buf) != 0) {
489             fprintf(stderr, "Failed at iteration %zd\n", i);
490             atf_tc_fail("Failed to prepend character at iteration %zd", i);
491         }
492 
493         memmove(buf + 1, buf, i + 1);
494         if (i % 2 == 0) {
495             RE(prepend(&str, "%s", "a"));
496             buf[0] = 'a';
497         } else {
498             RE(prepend(&str, "%s", "b"));
499             buf[0] = 'b';
500         }
501     }
502     atf_dynstr_fini(&str);
503 
504     printf("Prepending with formatted string\n");
505     buf[0] = '\0';
506     RE(atf_dynstr_init(&str));
507     for (i = 0; i < maxlen; i++) {
508         if (strcmp(atf_dynstr_cstring(&str), buf) != 0) {
509             fprintf(stderr, "Failed at iteration %zd\n", i);
510             atf_tc_fail("Failed to prepend character at iteration %zd", i);
511         }
512 
513         memmove(buf + 1, buf, i + 1);
514         if (i % 2 == 0) {
515             RE(prepend(&str, "%s", "a"));
516             buf[0] = 'a';
517         } else {
518             RE(prepend(&str, "%s", "b"));
519             buf[0] = 'b';
520         }
521     }
522     atf_dynstr_fini(&str);
523 }
524 
525 static
526 atf_error_t
527 prepend_ap_aux(atf_dynstr_t *str, const char *fmt, ...)
528 {
529     va_list ap;
530     atf_error_t err;
531 
532     va_start(ap, fmt);
533     err = atf_dynstr_prepend_ap(str, fmt, ap);
534     va_end(ap);
535 
536     return err;
537 }
538 
539 ATF_TC(prepend_ap);
540 ATF_TC_HEAD(prepend_ap, tc)
541 {
542     atf_tc_set_md_var(tc, "descr", "Checks that prepending a string to "
543                       "another one works");
544 }
545 ATF_TC_BODY(prepend_ap, tc)
546 {
547     check_prepend(prepend_ap_aux);
548 }
549 
550 ATF_TC(prepend_fmt);
551 ATF_TC_HEAD(prepend_fmt, tc)
552 {
553     atf_tc_set_md_var(tc, "descr", "Checks that prepending a string to "
554                       "another one works");
555 }
556 ATF_TC_BODY(prepend_fmt, tc)
557 {
558     check_prepend(atf_dynstr_prepend_fmt);
559 }
560 
561 /*
562  * Operators.
563  */
564 
565 ATF_TC(equal_cstring);
566 ATF_TC_HEAD(equal_cstring, tc)
567 {
568     atf_tc_set_md_var(tc, "descr", "Checks the atf_equal_dynstr_cstring "
569                       "function");
570 }
571 ATF_TC_BODY(equal_cstring, tc)
572 {
573     atf_dynstr_t str;
574 
575     RE(atf_dynstr_init(&str));
576     ATF_REQUIRE( atf_equal_dynstr_cstring(&str, ""));
577     ATF_REQUIRE(!atf_equal_dynstr_cstring(&str, "Test"));
578     atf_dynstr_fini(&str);
579 
580     RE(atf_dynstr_init_fmt(&str, "Test"));
581     ATF_REQUIRE( atf_equal_dynstr_cstring(&str, "Test"));
582     ATF_REQUIRE(!atf_equal_dynstr_cstring(&str, ""));
583     ATF_REQUIRE(!atf_equal_dynstr_cstring(&str, "Tes"));
584     ATF_REQUIRE(!atf_equal_dynstr_cstring(&str, "Test "));
585     atf_dynstr_fini(&str);
586 }
587 
588 ATF_TC(equal_dynstr);
589 ATF_TC_HEAD(equal_dynstr, tc)
590 {
591     atf_tc_set_md_var(tc, "descr", "Checks the atf_equal_dynstr_dynstr "
592                       "function");
593 }
594 ATF_TC_BODY(equal_dynstr, tc)
595 {
596     atf_dynstr_t str, str2;
597 
598     RE(atf_dynstr_init(&str));
599     RE(atf_dynstr_init_fmt(&str2, "Test"));
600     ATF_REQUIRE( atf_equal_dynstr_dynstr(&str, &str));
601     ATF_REQUIRE(!atf_equal_dynstr_dynstr(&str, &str2));
602     atf_dynstr_fini(&str2);
603     atf_dynstr_fini(&str);
604 }
605 
606 /* ---------------------------------------------------------------------
607  * Main.
608  * --------------------------------------------------------------------- */
609 
610 ATF_TP_ADD_TCS(tp)
611 {
612     /* Constructors and destructors. */
613     ATF_TP_ADD_TC(tp, init);
614     ATF_TP_ADD_TC(tp, init_ap);
615     ATF_TP_ADD_TC(tp, init_fmt);
616     ATF_TP_ADD_TC(tp, init_raw);
617     ATF_TP_ADD_TC(tp, init_rep);
618     ATF_TP_ADD_TC(tp, init_substr);
619     ATF_TP_ADD_TC(tp, copy);
620     ATF_TP_ADD_TC(tp, fini_disown);
621 
622     /* Getters. */
623     ATF_TP_ADD_TC(tp, cstring);
624     ATF_TP_ADD_TC(tp, length);
625     ATF_TP_ADD_TC(tp, rfind_ch);
626 
627     /* Modifiers. */
628     ATF_TP_ADD_TC(tp, append_ap);
629     ATF_TP_ADD_TC(tp, append_fmt);
630     ATF_TP_ADD_TC(tp, clear);
631     ATF_TP_ADD_TC(tp, prepend_ap);
632     ATF_TP_ADD_TC(tp, prepend_fmt);
633 
634     /* Operators. */
635     ATF_TP_ADD_TC(tp, equal_cstring);
636     ATF_TP_ADD_TC(tp, equal_dynstr);
637 
638     return atf_no_error();
639 }
640