1/*-
2 *   BSD LICENSE
3 *
4 *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
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 *
11 *     * Redistributions of source code must retain the above copyright
12 *       notice, this list of conditions and the following disclaimer.
13 *     * Redistributions in binary form must reproduce the above copyright
14 *       notice, this list of conditions and the following disclaimer in
15 *       the documentation and/or other materials provided with the
16 *       distribution.
17 *     * Neither the name of Intel Corporation nor the names of its
18 *       contributors may be used to endorse or promote products derived
19 *       from this software without specific prior written permission.
20 *
21 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <stdio.h>
35#include <string.h>
36#include <inttypes.h>
37
38#include <rte_common.h>
39#include <rte_string_fns.h>
40
41#include <cmdline_parse.h>
42#include <cmdline_parse_string.h>
43
44#include "test_cmdline.h"
45
46/* structures needed to run tests */
47
48struct string_elt_str {
49	const char * str;	/* parsed string */
50	const char * result;	/* expected string */
51	int idx;	/* position at which result is expected to be */
52};
53
54struct string_elt_str string_elt_strs[] = {
55		{"one#two#three", "three", 2},
56		{"one#two with spaces#three", "three", 2},
57		{"one#two\twith\ttabs#three", "three", 2},
58		{"one#two\rwith\rreturns#three", "three", 2},
59		{"one#two\nwith\nnewlines#three", "three", 2},
60		{"one#two#three", "one", 0},
61		{"one#two#three", "two", 1},
62		{"one#two\0three", "two", 1},
63		{"one#two with spaces#three", "two with spaces", 1},
64		{"one#two\twith\ttabs#three", "two\twith\ttabs", 1},
65		{"one#two\rwith\rreturns#three", "two\rwith\rreturns", 1},
66		{"one#two\nwith\nnewlines#three", "two\nwith\nnewlines", 1},
67};
68
69#if (CMDLINE_TEST_BUFSIZE < STR_TOKEN_SIZE) \
70|| (CMDLINE_TEST_BUFSIZE < STR_MULTI_TOKEN_SIZE)
71#undef CMDLINE_TEST_BUFSIZE
72#define CMDLINE_TEST_BUFSIZE RTE_MAX(STR_TOKEN_SIZE, STR_MULTI_TOKEN_SIZE)
73#endif
74
75struct string_nb_str {
76	const char * str;	/* parsed string */
77	int nb_strs;	/* expected number of strings in str */
78};
79
80struct string_nb_str string_nb_strs[] = {
81		{"one#two#three", 3},
82		{"one", 1},
83		{"one# \t two \r # three \n #four", 4},
84};
85
86
87
88struct string_parse_str {
89	const char * str;	/* parsed string */
90	const char * fixed_str;	/* parsing mode (any, fixed or multi) */
91	const char * result;	/* expected result */
92};
93
94struct string_parse_str string_parse_strs[] = {
95		{"one", NULL, "one"},	/* any string */
96		{"two", "one#two#three", "two"},	/* multiple choice string */
97		{"three", "three", "three"},	/* fixed string */
98		{"three", "one#two with\rgarbage\tcharacters\n#three", "three"},
99		{"two with\rgarbage\tcharacters\n",
100				"one#two with\rgarbage\tcharacters\n#three",
101				"two with\rgarbage\tcharacters\n"},
102		{"one two", "one", "one"}, /* fixed string */
103		{"one two", TOKEN_STRING_MULTI, "one two"}, /* multi string */
104		{"one two", NULL, "one"}, /* any string */
105		{"one two #three", TOKEN_STRING_MULTI, "one two "},
106		/* multi string with comment */
107};
108
109
110
111struct string_invalid_str {
112	const char * str;	/* parsed string */
113	const char * fixed_str;	/* parsing mode (any, fixed or multi) */
114};
115
116struct string_invalid_str string_invalid_strs[] = {
117		{"invalid", "one"},	/* fixed string */
118		{"invalid", "one#two#three"},	/* multiple choice string */
119		{"invalid", "invalidone"},	/* string that starts the same */
120		{"invalidone", "invalid"},	/* string that starts the same */
121		{"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
122		 "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
123		 "toolong!!!", NULL },
124		{"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
125		 "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
126		 "toolong!!!", "fixed" },
127		{"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
128		 "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
129		 "toolong!!!", "multi#choice#string" },
130		{"invalid",
131		 "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
132		 "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!"
133		 "toolong!!!" },
134		 {"", "invalid"}
135};
136
137
138
139const char * string_help_strs[] = {
140		NULL,
141		"fixed_str",
142		"multi#str",
143};
144
145
146
147#define STRING_PARSE_STRS_SIZE \
148	(sizeof(string_parse_strs) / sizeof(string_parse_strs[0]))
149#define STRING_HELP_STRS_SIZE \
150	(sizeof(string_help_strs) / sizeof(string_help_strs[0]))
151#define STRING_ELT_STRS_SIZE \
152	(sizeof(string_elt_strs) / sizeof(string_elt_strs[0]))
153#define STRING_NB_STRS_SIZE \
154	(sizeof(string_nb_strs) / sizeof(string_nb_strs[0]))
155#define STRING_INVALID_STRS_SIZE \
156	(sizeof(string_invalid_strs) / sizeof(string_invalid_strs[0]))
157
158#define SMALL_BUF 8
159
160/* test invalid parameters */
161int
162test_parse_string_invalid_param(void)
163{
164	cmdline_parse_token_string_t token;
165	int result;
166	char buf[CMDLINE_TEST_BUFSIZE];
167
168	memset(&token, 0, sizeof(token));
169
170	snprintf(buf, sizeof(buf), "buffer");
171
172	/* test null token */
173	if (cmdline_get_help_string(
174		NULL, buf, 0) != -1) {
175		printf("Error: function accepted null token!\n");
176		return -1;
177	}
178	if (cmdline_complete_get_elt_string(
179			NULL, 0, buf, 0) != -1) {
180		printf("Error: function accepted null token!\n");
181		return -1;
182	}
183	if (cmdline_complete_get_nb_string(NULL) != -1) {
184		printf("Error: function accepted null token!\n");
185		return -1;
186	}
187	if (cmdline_parse_string(NULL, buf, NULL, 0) != -1) {
188		printf("Error: function accepted null token!\n");
189		return -1;
190	}
191	/* test null buffer */
192	if (cmdline_complete_get_elt_string(
193			(cmdline_parse_token_hdr_t*)&token, 0, NULL, 0) != -1) {
194		printf("Error: function accepted null buffer!\n");
195		return -1;
196	}
197	if (cmdline_parse_string(
198			(cmdline_parse_token_hdr_t*)&token, NULL,
199			(void*)&result, sizeof(result)) != -1) {
200		printf("Error: function accepted null buffer!\n");
201		return -1;
202	}
203	if (cmdline_get_help_string(
204			(cmdline_parse_token_hdr_t*)&token, NULL, 0) != -1) {
205		printf("Error: function accepted null buffer!\n");
206		return -1;
207	}
208	/* test null result */
209	if (cmdline_parse_string(
210			(cmdline_parse_token_hdr_t*)&token, buf, NULL, 0) == -1) {
211		printf("Error: function rejected null result!\n");
212		return -1;
213	}
214	/* test negative index */
215	if (cmdline_complete_get_elt_string(
216			(cmdline_parse_token_hdr_t*)&token, -1, buf, 0) != -1) {
217		printf("Error: function accepted negative index!\n");
218		return -1;
219	}
220	return 0;
221}
222
223/* test valid parameters but invalid data */
224int
225test_parse_string_invalid_data(void)
226{
227	cmdline_parse_token_string_t token;
228	cmdline_parse_token_string_t help_token;
229	char buf[CMDLINE_TEST_BUFSIZE];
230	char help_str[CMDLINE_TEST_BUFSIZE];
231	char small_buf[SMALL_BUF];
232	unsigned i;
233
234	/* test parsing invalid strings */
235	for (i = 0; i < STRING_INVALID_STRS_SIZE; i++) {
236		memset(&token, 0, sizeof(token));
237		memset(buf, 0, sizeof(buf));
238
239		/* prepare test token data */
240		token.string_data.str = string_invalid_strs[i].fixed_str;
241
242		if (cmdline_parse_string((cmdline_parse_token_hdr_t*)&token,
243				string_invalid_strs[i].str, (void*)buf,
244				sizeof(buf)) != -1) {
245			memset(help_str, 0, sizeof(help_str));
246			memset(&help_token, 0, sizeof(help_token));
247
248			help_token.string_data.str = string_invalid_strs[i].fixed_str;
249
250			/* get parse type so we can give a good error message */
251			cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str,
252					sizeof(help_str));
253
254			printf("Error: parsing %s as %s succeeded!\n",
255					string_invalid_strs[i].str, help_str);
256			return -1;
257		}
258	}
259
260	/* misc tests (big comments signify test cases) */
261	memset(&token, 0, sizeof(token));
262	memset(small_buf, 0, sizeof(small_buf));
263
264	/*
265	 * try to get element from a null token
266	 */
267	token.string_data.str = NULL;
268	if (cmdline_complete_get_elt_string(
269			(cmdline_parse_token_hdr_t*)&token, 1,
270			buf, sizeof(buf)) != -1) {
271		printf("Error: getting token from null token string!\n");
272		return -1;
273	}
274
275	/*
276	 * try to get element into a buffer that is too small
277	 */
278	token.string_data.str = "too_small_buffer";
279	if (cmdline_complete_get_elt_string(
280			(cmdline_parse_token_hdr_t*)&token, 0,
281			small_buf, sizeof(small_buf)) != -1) {
282		printf("Error: writing token into too small a buffer succeeded!\n");
283		return -1;
284	}
285
286	/*
287	 * get help string written into a buffer smaller than help string
288	 * truncation should occur
289	 */
290	token.string_data.str = NULL;
291	if (cmdline_get_help_string(
292			(cmdline_parse_token_hdr_t*)&token,
293			small_buf, sizeof(small_buf)) == -1) {
294		printf("Error: writing help string into too small a buffer failed!\n");
295		return -1;
296	}
297	/* get help string for "any string" so we can compare it with small_buf */
298	cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str,
299			sizeof(help_str));
300	if (strncmp(small_buf, help_str, sizeof(small_buf) - 1)) {
301		printf("Error: help string mismatch!\n");
302		return -1;
303	}
304	/* check null terminator */
305	if (small_buf[sizeof(small_buf) - 1] != '\0') {
306		printf("Error: small buffer doesn't have a null terminator!\n");
307		return -1;
308	}
309
310	/*
311	 * try to count tokens in a null token
312	 */
313	token.string_data.str = NULL;
314	if (cmdline_complete_get_nb_string(
315			(cmdline_parse_token_hdr_t*)&token) != 0) {
316		printf("Error: getting token count from null token succeeded!\n");
317		return -1;
318	}
319
320	return 0;
321}
322
323/* test valid parameters and data */
324int
325test_parse_string_valid(void)
326{
327	cmdline_parse_token_string_t token;
328	cmdline_parse_token_string_t help_token;
329	char buf[CMDLINE_TEST_BUFSIZE];
330	char help_str[CMDLINE_TEST_BUFSIZE];
331	unsigned i;
332
333	/* test parsing strings */
334	for (i = 0; i < STRING_PARSE_STRS_SIZE; i++) {
335		memset(&token, 0, sizeof(token));
336		memset(buf, 0, sizeof(buf));
337
338		token.string_data.str = string_parse_strs[i].fixed_str;
339
340		if (cmdline_parse_string((cmdline_parse_token_hdr_t*)&token,
341				string_parse_strs[i].str, (void*)buf,
342				sizeof(buf)) < 0) {
343
344			/* clean help data */
345			memset(&help_token, 0, sizeof(help_token));
346			memset(help_str, 0, sizeof(help_str));
347
348			/* prepare help token */
349			help_token.string_data.str = string_parse_strs[i].fixed_str;
350
351			/* get help string so that we get an informative error message */
352			cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str,
353					sizeof(help_str));
354
355			printf("Error: parsing %s as %s failed!\n",
356					string_parse_strs[i].str, help_str);
357			return -1;
358		}
359		if (strcmp(buf, string_parse_strs[i].result) != 0) {
360			printf("Error: result mismatch!\n");
361			return -1;
362		}
363	}
364
365	/* get number of string tokens and verify it's correct */
366	for (i = 0; i < STRING_NB_STRS_SIZE; i++) {
367		memset(&token, 0, sizeof(token));
368
369		token.string_data.str = string_nb_strs[i].str;
370
371		if (cmdline_complete_get_nb_string(
372				(cmdline_parse_token_hdr_t*)&token) <
373				string_nb_strs[i].nb_strs) {
374			printf("Error: strings count mismatch!\n");
375			return -1;
376		}
377	}
378
379	/* get token at specified position and verify it's correct */
380	for (i = 0; i < STRING_ELT_STRS_SIZE; i++) {
381		memset(&token, 0, sizeof(token));
382		memset(buf, 0, sizeof(buf));
383
384		token.string_data.str = string_elt_strs[i].str;
385
386		if (cmdline_complete_get_elt_string(
387				(cmdline_parse_token_hdr_t*)&token, string_elt_strs[i].idx,
388				buf, sizeof(buf)) < 0) {
389			printf("Error: getting string element failed!\n");
390			return -1;
391		}
392		if (strncmp(buf, string_elt_strs[i].result,
393				sizeof(buf)) != 0) {
394			printf("Error: result mismatch!\n");
395			return -1;
396		}
397	}
398
399	/* cover all cases with help strings */
400	for (i = 0; i < STRING_HELP_STRS_SIZE; i++) {
401		memset(&help_token, 0, sizeof(help_token));
402		memset(help_str, 0, sizeof(help_str));
403		help_token.string_data.str = string_help_strs[i];
404		if (cmdline_get_help_string((cmdline_parse_token_hdr_t*)&help_token,
405				help_str, sizeof(help_str)) < 0) {
406			printf("Error: help operation failed!\n");
407			return -1;
408		}
409	}
410
411	return 0;
412}
413