1/*-
2 * Copyright (c) 2011 Tim Kientzle
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25#include "test.h"
26__FBSDID("$FreeBSD$");
27
28#define __LIBARCHIVE_TEST
29#include "archive_string.h"
30
31#define EXTENT 32
32
33#define assertStringSizes(strlen, buflen, as) \
34	assertEqualInt(strlen, (as).length); \
35	assertEqualInt(buflen, (as).buffer_length);
36
37#define assertExactString(strlen, buflen, data, as) \
38	do { \
39		assertStringSizes(strlen, buflen, as); \
40		assertEqualString(data, (as).s); \
41	} while (0)
42
43#define assertNonNULLString(strlen, buflen, as) \
44	do { \
45		assertStringSizes(strlen, buflen, as); \
46		assert(NULL != (as).s); \
47	} while (0)
48
49static void
50test_archive_string_ensure(void)
51{
52	struct archive_string s;
53
54	archive_string_init(&s);
55	assertExactString(0, 0, NULL, s);
56
57	/* single-extent allocation */
58	assert(&s == archive_string_ensure(&s, 5));
59	assertNonNULLString(0, EXTENT, s);
60
61	/* what happens around extent boundaries? */
62	assert(&s == archive_string_ensure(&s, EXTENT - 1));
63	assertNonNULLString(0, EXTENT, s);
64
65	assert(&s == archive_string_ensure(&s, EXTENT));
66	assertNonNULLString(0, EXTENT, s);
67
68	assert(&s == archive_string_ensure(&s, EXTENT + 1));
69	assertNonNULLString(0, 2 * EXTENT, s);
70
71	archive_string_free(&s);
72}
73
74static void
75test_archive_strcat(void)
76{
77	struct archive_string s;
78
79	archive_string_init(&s);
80	assertExactString(0, 0, NULL, s);
81
82	/* null target, empty source */
83	assert(&s == archive_strcat(&s, ""));
84	assertExactString(0, EXTENT, "", s);
85
86	/* empty target, empty source */
87	assert(&s == archive_strcat(&s, ""));
88	assertExactString(0, EXTENT, "", s);
89
90	/* empty target, non-empty source */
91	assert(&s == archive_strcat(&s, "fubar"));
92	assertExactString(5, EXTENT, "fubar", s);
93
94	/* non-empty target, non-empty source */
95	assert(&s == archive_strcat(&s, "baz"));
96	assertExactString(8, EXTENT, "fubarbaz", s);
97
98	archive_string_free(&s);
99}
100
101static void
102test_archive_strappend_char(void)
103{
104	struct archive_string s;
105
106	archive_string_init(&s);
107	assertExactString(0, 0, NULL, s);
108
109	/* null target */
110	archive_strappend_char(&s, 'X');
111	assertExactString(1, EXTENT, "X", s);
112
113	/* non-empty target */
114	archive_strappend_char(&s, 'Y');
115	assertExactString(2, EXTENT, "XY", s);
116
117	archive_string_free(&s);
118}
119
120/* archive_strnXXX() tests focus on length handling.
121 * other behaviors are tested by proxy through archive_strXXX()
122 */
123
124static void
125test_archive_strncat(void)
126{
127	struct archive_string s;
128
129	archive_string_init(&s);
130	assertExactString(0, 0, NULL, s);
131
132	/* perfect length */
133	assert(&s == archive_strncat(&s, "snafu", 5));
134	assertExactString(5, EXTENT, "snafu", s);
135
136	/* short read */
137	assert(&s == archive_strncat(&s, "barbazqux", 3));
138	assertExactString(8, EXTENT, "snafubar", s);
139
140	/* long read is ok too! */
141	assert(&s == archive_strncat(&s, "snafu", 8));
142	assertExactString(13, EXTENT, "snafubarsnafu", s);
143
144	archive_string_free(&s);
145}
146
147static void
148test_archive_strncpy(void)
149{
150	struct archive_string s;
151
152	archive_string_init(&s);
153	assertExactString(0, 0, NULL, s);
154
155	/* perfect length */
156	assert(&s == archive_strncpy(&s, "fubar", 5));
157	assertExactString(5, EXTENT, "fubar", s);
158
159	/* short read */
160	assert(&s == archive_strncpy(&s, "snafubar", 5));
161	assertExactString(5, EXTENT, "snafu", s);
162
163	/* long read is ok too! */
164	assert(&s == archive_strncpy(&s, "snafu", 8));
165	assertExactString(5, EXTENT, "snafu", s);
166
167	archive_string_free(&s);
168}
169
170static void
171test_archive_strcpy(void)
172{
173	struct archive_string s;
174
175	archive_string_init(&s);
176	assertExactString(0, 0, NULL, s);
177
178	/* null target */
179	assert(&s == archive_strcpy(&s, "snafu"));
180	assertExactString(5, EXTENT, "snafu", s);
181
182	/* dirty target */
183	assert(&s == archive_strcpy(&s, "foo"));
184	assertExactString(3, EXTENT, "foo", s);
185
186	/* dirty target, empty source */
187	assert(&s == archive_strcpy(&s, ""));
188	assertExactString(0, EXTENT, "", s);
189
190	archive_string_free(&s);
191}
192
193static void
194test_archive_string_concat(void)
195{
196	struct archive_string s, t, u, v;
197
198	archive_string_init(&s);
199	assertExactString(0, 0, NULL, s);
200	archive_string_init(&t);
201	assertExactString(0, 0, NULL, t);
202	archive_string_init(&u);
203	assertExactString(0, 0, NULL, u);
204	archive_string_init(&v);
205	assertExactString(0, 0, NULL, v);
206
207	/* null target, null source */
208	archive_string_concat(&t, &s);
209	assertExactString(0, 0, NULL, s);
210	assertExactString(0, EXTENT, "", t);
211
212	/* null target, empty source */
213	assert(&s == archive_strcpy(&s, ""));
214	archive_string_concat(&u, &s);
215	assertExactString(0, EXTENT, "", s);
216	assertExactString(0, EXTENT, "", u);
217
218	/* null target, non-empty source */
219	assert(&s == archive_strcpy(&s, "foo"));
220	archive_string_concat(&v, &s);
221	assertExactString(3, EXTENT, "foo", s);
222	assertExactString(3, EXTENT, "foo", v);
223
224	/* empty target, empty source */
225	assert(&s == archive_strcpy(&s, ""));
226	assert(&t == archive_strcpy(&t, ""));
227	archive_string_concat(&t, &s);
228	assertExactString(0, EXTENT, "", s);
229	assertExactString(0, EXTENT, "", t);
230
231	/* empty target, non-empty source */
232	assert(&s == archive_strcpy(&s, "snafu"));
233	assert(&t == archive_strcpy(&t, ""));
234	archive_string_concat(&t, &s);
235	assertExactString(5, EXTENT, "snafu", s);
236	assertExactString(5, EXTENT, "snafu", t);
237
238	archive_string_free(&v);
239	archive_string_free(&u);
240	archive_string_free(&t);
241	archive_string_free(&s);
242}
243
244static void
245test_archive_string_copy(void)
246{
247	struct archive_string s, t, u, v;
248
249	archive_string_init(&s);
250	assertExactString(0, 0, NULL, s);
251	archive_string_init(&t);
252	assertExactString(0, 0, NULL, t);
253	archive_string_init(&u);
254	assertExactString(0, 0, NULL, u);
255	archive_string_init(&v);
256	assertExactString(0, 0, NULL, v);
257
258	/* null target, null source */
259	archive_string_copy(&t, &s);
260	assertExactString(0, 0, NULL, s);
261	assertExactString(0, EXTENT, "", t);
262
263	/* null target, empty source */
264	archive_string_copy(&u, &t);
265	assertExactString(0, EXTENT, "", t);
266	assertExactString(0, EXTENT, "", u);
267
268	/* empty target, empty source */
269	archive_string_copy(&u, &t);
270	assertExactString(0, EXTENT, "", t);
271	assertExactString(0, EXTENT, "", u);
272
273	/* null target, non-empty source */
274	assert(NULL != archive_strcpy(&s, "snafubar"));
275	assertExactString(8, EXTENT, "snafubar", s);
276
277	archive_string_copy(&v, &s);
278	assertExactString(8, EXTENT, "snafubar", s);
279	assertExactString(8, EXTENT, "snafubar", v);
280
281	/* empty target, non-empty source */
282	assertExactString(0, EXTENT, "", t);
283	archive_string_copy(&t, &s);
284	assertExactString(8, EXTENT, "snafubar", s);
285	assertExactString(8, EXTENT, "snafubar", t);
286
287	/* non-empty target, non-empty source */
288	assert(NULL != archive_strcpy(&s, "fubar"));
289	assertExactString(5, EXTENT, "fubar", s);
290
291	archive_string_copy(&t, &s);
292	assertExactString(5, EXTENT, "fubar", s);
293	assertExactString(5, EXTENT, "fubar", t);
294
295	archive_string_free(&v);
296	archive_string_free(&u);
297	archive_string_free(&t);
298	archive_string_free(&s);
299}
300
301static void
302test_archive_string_sprintf(void)
303{
304	struct archive_string s;
305#define S16 "0123456789abcdef"
306#define S32 S16 S16
307#define S64 S32 S32
308#define S128 S64 S64
309	const char *s32 = S32;
310	const char *s33 = S32 "0";
311	const char *s64 = S64;
312	const char *s65 = S64 "0";
313	const char *s128 = S128;
314	const char *s129 = S128 "0";
315#undef S16
316#undef S32
317#undef S64
318#undef S128
319
320	archive_string_init(&s);
321	assertExactString(0, 0, NULL, s);
322
323	archive_string_sprintf(&s, "%s", "");
324	assertExactString(0, 2 * EXTENT, "", s);
325
326	archive_string_empty(&s);
327	archive_string_sprintf(&s, "%s", s32);
328	assertExactString(32, 2 * EXTENT, s32, s);
329
330	archive_string_empty(&s);
331	archive_string_sprintf(&s, "%s", s33);
332	assertExactString(33, 2 * EXTENT, s33, s);
333
334	archive_string_empty(&s);
335	archive_string_sprintf(&s, "%s", s64);
336	assertExactString(64, 4 * EXTENT, s64, s);
337
338	archive_string_empty(&s);
339	archive_string_sprintf(&s, "%s", s65);
340	assertExactString(65, 4 * EXTENT, s65, s);
341
342	archive_string_empty(&s);
343	archive_string_sprintf(&s, "%s", s128);
344	assertExactString(128, 8 * EXTENT, s128, s);
345
346	archive_string_empty(&s);
347	archive_string_sprintf(&s, "%s", s129);
348	assertExactString(129, 8 * EXTENT, s129, s);
349
350	archive_string_empty(&s);
351	archive_string_sprintf(&s, "%d", 1234567890);
352	assertExactString(10, 8 * EXTENT, "1234567890", s);
353
354	archive_string_free(&s);
355}
356
357DEFINE_TEST(test_archive_string)
358{
359	test_archive_string_ensure();
360	test_archive_strcat();
361	test_archive_strappend_char();
362	test_archive_strncat();
363	test_archive_strncpy();
364	test_archive_strcpy();
365	test_archive_string_concat();
366	test_archive_string_copy();
367	test_archive_string_sprintf();
368}
369
370static const char *strings[] =
371{
372  "dir/path",
373  "dir/path2",
374  "dir/path3",
375  "dir/path4",
376  "dir/path5",
377  "dir/path6",
378  "dir/path7",
379  "dir/path8",
380  "dir/path9",
381  "dir/subdir/path",
382  "dir/subdir/path2",
383  "dir/subdir/path3",
384  "dir/subdir/path4",
385  "dir/subdir/path5",
386  "dir/subdir/path6",
387  "dir/subdir/path7",
388  "dir/subdir/path8",
389  "dir/subdir/path9",
390  "dir2/path",
391  "dir2/path2",
392  "dir2/path3",
393  "dir2/path4",
394  "dir2/path5",
395  "dir2/path6",
396  "dir2/path7",
397  "dir2/path8",
398  "dir2/path9",
399  NULL
400};
401
402DEFINE_TEST(test_archive_string_sort)
403{
404  unsigned int i, j, size;
405  char **test_strings, *tmp;
406
407  srand((unsigned int)time(NULL));
408  size = sizeof(strings) / sizeof(char *);
409  assert((test_strings = (char **)calloc(1, sizeof(strings))) != NULL);
410  for (i = 0; i < (size - 1); i++)
411    assert((test_strings[i] = strdup(strings[i])) != NULL);
412
413  /* Shuffle the test strings */
414  for (i = 0; i < (size - 1); i++)
415  {
416    j = rand() % ((size - 1) - i);
417    j += i;
418    tmp = test_strings[i];
419    test_strings[i] = test_strings[j];
420    test_strings[j] = tmp;
421  }
422
423  /* Sort and test */
424  assertEqualInt(ARCHIVE_OK, archive_utility_string_sort(test_strings));
425  for (i = 0; i < (size - 1); i++)
426    assertEqualString(test_strings[i], strings[i]);
427
428  for (i = 0; i < (size - 1); i++)
429    free(test_strings[i]);
430  free(test_strings);
431}
432