xref: /netbsd-src/external/bsd/openpam/dist/t/t_openpam_readword.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*-
2  * Copyright (c) 2012-2017 Dag-Erling Smørgrav
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  * 3. The name of the author may not be used to endorse or promote
14  *    products derived from this software without specific prior written
15  *    permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $OpenPAM: t_openpam_readword.c 938 2017-04-30 21:34:42Z des $
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35 
36 #include <err.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include <cryb/test.h>
44 
45 #include <security/pam_appl.h>
46 #include <security/openpam.h>
47 
48 #define T_FUNC(n, d)							\
49 	static const char *t_ ## n ## _desc = d;			\
50 	static int t_ ## n ## _func(OPENPAM_UNUSED(char **desc),	\
51 	    OPENPAM_UNUSED(void *arg))
52 
53 #define T(n)								\
54 	t_add_test(&t_ ## n ## _func, NULL, "%s", t_ ## n ## _desc)
55 
56 /*
57  * Read a word from the temp file and verify that the result matches our
58  * expectations: whether a word was read at all, how many lines were read
59  * (in case of quoted or escaped newlines), whether we reached the end of
60  * the file and whether we reached the end of the line.
61  */
62 static int
63 orw_expect(struct t_file *tf, const char *expected, int lines, int eof, int eol)
64 {
65 	int ch, lineno = 0;
66 	char *got;
67 	size_t len;
68 	int ret;
69 
70 	got = openpam_readword(tf->file, &lineno, &len);
71 	ret = 1;
72 	if (t_ferror(tf))
73 		err(1, "%s(): %s", __func__, tf->name);
74 	if (expected != NULL && got == NULL) {
75 		t_printv("expected <<%s>>, got nothing\n", expected);
76 		ret = 0;
77 	} else if (expected == NULL && got != NULL) {
78 		t_printv("expected nothing, got <<%s>>\n", got);
79 		ret = 0;
80 	} else if (expected != NULL && got != NULL && strcmp(expected, got) != 0) {
81 		t_printv("expected <<%s>>, got <<%s>>\n", expected, got);
82 		ret = 0;
83 	}
84 	free(got);
85 	if (lineno != lines) {
86 		t_printv("expected to advance %d lines, advanced %d lines\n",
87 		    lines, lineno);
88 		ret = 0;
89 	}
90 	if (eof && !t_feof(tf)) {
91 		t_printv("expected EOF, but didn't get it\n");
92 		ret = 0;
93 	}
94 	if (!eof && t_feof(tf)) {
95 		t_printv("didn't expect EOF, but got it anyway\n");
96 		ret = 0;
97 	}
98 	ch = fgetc(tf->file);
99 	if (t_ferror(tf))
100 		err(1, "%s(): %s", __func__, tf->name);
101 	if (eol && ch != '\n') {
102 		t_printv("expected EOL, but didn't get it\n");
103 		ret = 0;
104 	} else if (!eol && ch == '\n') {
105 		t_printv("didn't expect EOL, but got it anyway\n");
106 		ret = 0;
107 	}
108 	if (ch != EOF)
109 		ungetc(ch, tf->file);
110 	return (ret);
111 }
112 
113 
114 /***************************************************************************
115  * Lines without words
116  */
117 
118 T_FUNC(empty_input, "empty input")
119 {
120 	struct t_file *tf;
121 	int ret;
122 
123 	tf = t_fopen(NULL);
124 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
125 	t_fclose(tf);
126 	return (ret);
127 }
128 
129 T_FUNC(empty_line, "empty line")
130 {
131 	struct t_file *tf;
132 	int ret;
133 
134 	tf = t_fopen(NULL);
135 	t_fprintf(tf, "\n");
136 	t_frewind(tf);
137 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
138 	t_fclose(tf);
139 	return (ret);
140 }
141 
142 T_FUNC(unterminated_line, "unterminated line")
143 {
144 	struct t_file *tf;
145 	int ret;
146 
147 	tf = t_fopen(NULL);
148 	t_fprintf(tf, " ");
149 	t_frewind(tf);
150 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
151 	t_fclose(tf);
152 	return (ret);
153 }
154 
155 T_FUNC(single_whitespace, "single whitespace")
156 {
157 	struct t_file *tf;
158 	int ret;
159 
160 	tf = t_fopen(NULL);
161 	t_fprintf(tf, " \n");
162 	t_frewind(tf);
163 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
164 	t_fclose(tf);
165 	return (ret);
166 }
167 
168 T_FUNC(multiple_whitespace, "multiple whitespace")
169 {
170 	struct t_file *tf;
171 	int ret;
172 
173 	tf = t_fopen(NULL);
174 	t_fprintf(tf, " \t\r\n");
175 	t_frewind(tf);
176 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
177 	t_fclose(tf);
178 	return (ret);
179 }
180 
181 T_FUNC(line_continuation_in_whitespace, "line continuation in whitespace")
182 {
183 	struct t_file *tf;
184 	int ret;
185 
186 	tf = t_fopen(NULL);
187 	t_fprintf(tf, " \\\n \n");
188 	t_frewind(tf);
189 	ret = orw_expect(tf, NULL, 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
190 	t_fclose(tf);
191 	return (ret);
192 }
193 
194 T_FUNC(comment, "comment")
195 {
196 	struct t_file *tf;
197 	int ret;
198 
199 	tf = t_fopen(NULL);
200 	t_fprintf(tf, "# comment\n");
201 	t_frewind(tf);
202 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
203 	t_fclose(tf);
204 	return (ret);
205 }
206 
207 T_FUNC(whitespace_before_comment, "whitespace before comment")
208 {
209 	struct t_file *tf;
210 	int ret;
211 
212 	tf = t_fopen(NULL);
213 	t_fprintf(tf, " # comment\n");
214 	t_frewind(tf);
215 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
216 	t_fclose(tf);
217 	return (ret);
218 }
219 
220 T_FUNC(single_quoted_comment, "single-quoted comment")
221 {
222 	struct t_file *tf;
223 	int ret;
224 
225 	tf = t_fopen(NULL);
226 	t_fprintf(tf, " '# comment'\n");
227 	t_frewind(tf);
228 	ret = orw_expect(tf, "# comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
229 	t_fclose(tf);
230 	return (ret);
231 }
232 
233 T_FUNC(double_quoted_comment, "double-quoted comment")
234 {
235 	struct t_file *tf;
236 	int ret;
237 
238 	tf = t_fopen(NULL);
239 	t_fprintf(tf, " \"# comment\"\n");
240 	t_frewind(tf);
241 	ret = orw_expect(tf, "# comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
242 	t_fclose(tf);
243 	return (ret);
244 }
245 
246 T_FUNC(comment_at_eof, "comment at end of file")
247 {
248 	struct t_file *tf;
249 	int ret;
250 
251 	tf = t_fopen(NULL);
252 	t_fprintf(tf, "# comment");
253 	t_frewind(tf);
254 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
255 	t_fclose(tf);
256 	return (ret);
257 }
258 
259 
260 /***************************************************************************
261  * Simple cases - no quotes or escapes
262  */
263 
264 T_FUNC(single_word, "single word")
265 {
266 	const char *word = "hello";
267 	struct t_file *tf;
268 	int ret;
269 
270 	tf = t_fopen(NULL);
271 	t_fprintf(tf, "%s\n", word);
272 	t_frewind(tf);
273 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
274 	t_fclose(tf);
275 	return (ret);
276 }
277 
278 T_FUNC(single_whitespace_before_word, "single whitespace before word")
279 {
280 	const char *word = "hello";
281 	struct t_file *tf;
282 	int ret;
283 
284 	tf = t_fopen(NULL);
285 	t_fprintf(tf, " %s\n", word);
286 	t_frewind(tf);
287 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
288 	t_fclose(tf);
289 	return (ret);
290 }
291 
292 T_FUNC(double_whitespace_before_word, "double whitespace before word")
293 {
294 	const char *word = "hello";
295 	struct t_file *tf;
296 	int ret;
297 
298 	tf = t_fopen(NULL);
299 	t_fprintf(tf, "  %s\n", word);
300 	t_frewind(tf);
301 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
302 	t_fclose(tf);
303 	return (ret);
304 }
305 
306 T_FUNC(single_whitespace_after_word, "single whitespace after word")
307 {
308 	const char *word = "hello";
309 	struct t_file *tf;
310 	int ret;
311 
312 	tf = t_fopen(NULL);
313 	t_fprintf(tf, "%s \n", word);
314 	t_frewind(tf);
315 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
316 	t_fclose(tf);
317 	return (ret);
318 }
319 
320 T_FUNC(double_whitespace_after_word, "double whitespace after word")
321 {
322 	const char *word = "hello";
323 	struct t_file *tf;
324 	int ret;
325 
326 	tf = t_fopen(NULL);
327 	t_fprintf(tf, "%s  \n", word);
328 	t_frewind(tf);
329 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
330 	t_fclose(tf);
331 	return (ret);
332 }
333 
334 T_FUNC(comment_after_word, "comment after word")
335 {
336 	const char *word = "hello";
337 	struct t_file *tf;
338 	int ret;
339 
340 	tf = t_fopen(NULL);
341 	t_fprintf(tf, "%s # comment\n", word);
342 	t_frewind(tf);
343 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
344 	    orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
345 	t_fclose(tf);
346 	return (ret);
347 }
348 
349 T_FUNC(word_containing_hash, "word containing hash")
350 {
351 	const char *word = "hello#world";
352 	struct t_file *tf;
353 	int ret;
354 
355 	tf = t_fopen(NULL);
356 	t_fprintf(tf, "%s\n", word);
357 	t_frewind(tf);
358 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
359 	t_fclose(tf);
360 	return (ret);
361 }
362 
363 T_FUNC(two_words, "two words")
364 {
365 	const char *word[] = { "hello", "world" };
366 	struct t_file *tf;
367 	int ret;
368 
369 	tf = t_fopen(NULL);
370 	t_fprintf(tf, "%s %s\n", word[0], word[1]);
371 	t_frewind(tf);
372 	ret = orw_expect(tf, word[0], 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
373 	    orw_expect(tf, word[1], 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
374 	t_fclose(tf);
375 	return (ret);
376 }
377 
378 
379 /***************************************************************************
380  * Escapes
381  */
382 
383 T_FUNC(naked_escape, "naked escape")
384 {
385 	struct t_file *tf;
386 	int ret;
387 
388 	tf = t_fopen(NULL);
389 	t_fprintf(tf, "\\");
390 	t_frewind(tf);
391 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
392 	t_fclose(tf);
393 	return (ret);
394 }
395 
396 T_FUNC(escaped_escape, "escaped escape")
397 {
398 	struct t_file *tf;
399 	int ret;
400 
401 	tf = t_fopen(NULL);
402 	t_fprintf(tf, "\\\\\n");
403 	t_frewind(tf);
404 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
405 	t_fclose(tf);
406 	return (ret);
407 }
408 
409 T_FUNC(escaped_whitespace, "escaped whitespace")
410 {
411 	struct t_file *tf;
412 	int ret;
413 
414 	tf = t_fopen(NULL);
415 	t_fprintf(tf, "\\  \\\t \\\r \\\n\n");
416 	t_frewind(tf);
417 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
418 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
419 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
420 	    /* this last one is a line continuation */
421 	    orw_expect(tf, NULL, 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
422 	t_fclose(tf);
423 	return (ret);
424 }
425 
426 T_FUNC(escaped_newline_before_word, "escaped newline before word")
427 {
428 	struct t_file *tf;
429 	int ret;
430 
431 	tf = t_fopen(NULL);
432 	t_fprintf(tf, "\\\nhello world\n");
433 	t_frewind(tf);
434 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
435 	t_fclose(tf);
436 	return (ret);
437 }
438 
439 T_FUNC(escaped_newline_within_word, "escaped newline within word")
440 {
441 	struct t_file *tf;
442 	int ret;
443 
444 	tf = t_fopen(NULL);
445 	t_fprintf(tf, "hello\\\nworld\n");
446 	t_frewind(tf);
447 	ret = orw_expect(tf, "helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
448 	t_fclose(tf);
449 	return (ret);
450 }
451 
452 T_FUNC(escaped_newline_after_word, "escaped newline after word")
453 {
454 	struct t_file *tf;
455 	int ret;
456 
457 	tf = t_fopen(NULL);
458 	t_fprintf(tf, "hello\\\n world\n");
459 	t_frewind(tf);
460 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
461 	t_fclose(tf);
462 	return (ret);
463 }
464 
465 T_FUNC(escaped_letter, "escaped letter")
466 {
467 	struct t_file *tf;
468 	int ret;
469 
470 	tf = t_fopen(NULL);
471 	t_fprintf(tf, "\\z\n");
472 	t_frewind(tf);
473 	ret = orw_expect(tf, "z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
474 	t_fclose(tf);
475 	return (ret);
476 }
477 
478 T_FUNC(escaped_comment, "escaped comment")
479 {
480 	struct t_file *tf;
481 	int ret;
482 
483 	tf = t_fopen(NULL);
484 	t_fprintf(tf, " \\# comment\n");
485 	t_frewind(tf);
486 	ret = orw_expect(tf, "#", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
487 	    orw_expect(tf, "comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
488 	t_fclose(tf);
489 	return (ret);
490 }
491 
492 T_FUNC(escape_at_eof, "escape at end of file")
493 {
494 	struct t_file *tf;
495 	int ret;
496 
497 	tf = t_fopen(NULL);
498 	t_fprintf(tf, "z\\");
499 	t_frewind(tf);
500 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
501 	t_fclose(tf);
502 	return (ret);
503 }
504 
505 
506 /***************************************************************************
507 T_FUNC(escaped_comment, "escaped comment")
508 {
509 	struct t_file *tf;
510 	int ret;
511 
512 	tf = t_fopen(NULL);
513 	t_fprintf(tf, " \\# comment\n");
514 	t_frewind(tf);
515 	ret = orw_expect(tf, "#", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
516 	    orw_expect(tf, "comment", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
517 	t_fclose(tf);
518 	return (ret);
519 }
520 
521 T_FUNC(escape_at_eof, "escape at end of file")
522 {
523 	struct t_file *tf;
524 	int ret;
525 
526 	tf = t_fopen(NULL);
527 	t_fprintf(tf, "z\\");
528 	t_frewind(tf);
529 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
530 	t_fclose(tf);
531 	return (ret);
532 }
533 
534  * Quotes
535  */
536 
537 T_FUNC(naked_single_quote, "naked single quote")
538 {
539 	struct t_file *tf;
540 	int ret;
541 
542 	tf = t_fopen(NULL);
543 	t_fprintf(tf, "'");
544 	t_frewind(tf);
545 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
546 	t_fclose(tf);
547 	return (ret);
548 }
549 
550 T_FUNC(naked_double_quote, "naked double quote")
551 {
552 	struct t_file *tf;
553 	int ret;
554 
555 	tf = t_fopen(NULL);
556 	t_fprintf(tf, "\"");
557 	t_frewind(tf);
558 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
559 	t_fclose(tf);
560 	return (ret);
561 }
562 
563 T_FUNC(empty_single_quotes, "empty single quotes")
564 {
565 	struct t_file *tf;
566 	int ret;
567 
568 	tf = t_fopen(NULL);
569 	t_fprintf(tf, "''\n");
570 	t_frewind(tf);
571 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
572 	t_fclose(tf);
573 	return (ret);
574 }
575 
576 T_FUNC(empty_double_quotes, "empty double quotes")
577 {
578 	struct t_file *tf;
579 	int ret;
580 
581 	tf = t_fopen(NULL);
582 	t_fprintf(tf, "\"\"\n");
583 	t_frewind(tf);
584 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
585 	t_fclose(tf);
586 	return (ret);
587 }
588 
589 T_FUNC(single_quotes_within_double_quotes, "single quotes within double quotes")
590 {
591 	struct t_file *tf;
592 	int ret;
593 
594 	tf = t_fopen(NULL);
595 	t_fprintf(tf, "\"' '\"\n");
596 	t_frewind(tf);
597 	ret = orw_expect(tf, "' '", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
598 	t_fclose(tf);
599 	return (ret);
600 }
601 
602 T_FUNC(double_quotes_within_single_quotes, "double quotes within single quotes")
603 {
604 	struct t_file *tf;
605 	int ret;
606 
607 	tf = t_fopen(NULL);
608 	t_fprintf(tf, "'\" \"'\n");
609 	t_frewind(tf);
610 	ret = orw_expect(tf, "\" \"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
611 	t_fclose(tf);
612 	return (ret);
613 }
614 
615 T_FUNC(single_quoted_whitespace, "single-quoted whitespace")
616 {
617 	struct t_file *tf;
618 	int ret;
619 
620 	tf = t_fopen(NULL);
621 	t_fprintf(tf, "' ' '\t' '\r' '\n'\n");
622 	t_frewind(tf);
623 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
624 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
625 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
626 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
627 	t_fclose(tf);
628 	return (ret);
629 }
630 
631 T_FUNC(double_quoted_whitespace, "double-quoted whitespace")
632 {
633 	struct t_file *tf;
634 	int ret;
635 
636 	tf = t_fopen(NULL);
637 	t_fprintf(tf, "\" \" \"\t\" \"\r\" \"\n\"\n");
638 	t_frewind(tf);
639 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
640 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
641 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
642 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
643 	t_fclose(tf);
644 	return (ret);
645 }
646 
647 T_FUNC(single_quoted_words, "single-quoted words")
648 {
649 	struct t_file *tf;
650 	int ret;
651 
652 	tf = t_fopen(NULL);
653 	t_fprintf(tf, "'hello world'\n");
654 	t_frewind(tf);
655 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
656 	t_fclose(tf);
657 	return (ret);
658 }
659 
660 T_FUNC(double_quoted_words, "double-quoted words")
661 {
662 	struct t_file *tf;
663 	int ret;
664 
665 	tf = t_fopen(NULL);
666 	t_fprintf(tf, "\"hello world\"\n");
667 	t_frewind(tf);
668 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
669 	t_fclose(tf);
670 	return (ret);
671 }
672 
673 
674 /***************************************************************************
675  * Combinations of quoted and unquoted text
676  */
677 
678 T_FUNC(single_quote_before_word, "single quote before word")
679 {
680 	struct t_file *tf;
681 	int ret;
682 
683 	tf = t_fopen(NULL);
684 	t_fprintf(tf, "'hello 'world\n");
685 	t_frewind(tf);
686 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
687 	t_fclose(tf);
688 	return (ret);
689 }
690 
691 T_FUNC(double_quote_before_word, "double quote before word")
692 {
693 	struct t_file *tf;
694 	int ret;
695 
696 	tf = t_fopen(NULL);
697 	t_fprintf(tf, "\"hello \"world\n");
698 	t_frewind(tf);
699 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
700 	t_fclose(tf);
701 	return (ret);
702 }
703 
704 T_FUNC(single_quote_within_word, "single quote within word")
705 {
706 	struct t_file *tf;
707 	int ret;
708 
709 	tf = t_fopen(NULL);
710 	t_fprintf(tf, "hello' 'world\n");
711 	t_frewind(tf);
712 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
713 	t_fclose(tf);
714 	return (ret);
715 }
716 
717 T_FUNC(double_quote_within_word, "double quote within word")
718 {
719 	struct t_file *tf;
720 	int ret;
721 
722 	tf = t_fopen(NULL);
723 	t_fprintf(tf, "hello\" \"world\n");
724 	t_frewind(tf);
725 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
726 	t_fclose(tf);
727 	return (ret);
728 }
729 
730 T_FUNC(single_quote_after_word, "single quote after word")
731 {
732 	struct t_file *tf;
733 	int ret;
734 
735 	tf = t_fopen(NULL);
736 	t_fprintf(tf, "hello' world'\n");
737 	t_frewind(tf);
738 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
739 	t_fclose(tf);
740 	return (ret);
741 }
742 
743 T_FUNC(double_quote_after_word, "double quote after word")
744 {
745 	struct t_file *tf;
746 	int ret;
747 
748 	tf = t_fopen(NULL);
749 	t_fprintf(tf, "hello\" world\"\n");
750 	t_frewind(tf);
751 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
752 	t_fclose(tf);
753 	return (ret);
754 }
755 
756 
757 /***************************************************************************
758  * Combinations of escape and quotes
759  */
760 
761 T_FUNC(escaped_single_quote,
762     "escaped single quote")
763 {
764 	struct t_file *tf;
765 	int ret;
766 
767 	tf = t_fopen(NULL);
768 	t_fprintf(tf, "\\'\n");
769 	t_frewind(tf);
770 	ret = orw_expect(tf, "'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
771 	t_fclose(tf);
772 	return (ret);
773 }
774 
775 T_FUNC(escaped_double_quote,
776     "escaped double quote")
777 {
778 	struct t_file *tf;
779 	int ret;
780 
781 	tf = t_fopen(NULL);
782 	t_fprintf(tf, "\\\"\n");
783 	t_frewind(tf);
784 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
785 	t_fclose(tf);
786 	return (ret);
787 }
788 
789 T_FUNC(escaped_whitespace_within_single_quotes,
790     "escaped whitespace within single quotes")
791 {
792 	struct t_file *tf;
793 	int ret;
794 
795 	tf = t_fopen(NULL);
796 	t_fprintf(tf, "'\\ ' '\\\t' '\\\r' '\\\n'\n");
797 	t_frewind(tf);
798 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
799 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
800 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
801 	    orw_expect(tf, "\\\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
802 	t_fclose(tf);
803 	return (ret);
804 }
805 
806 T_FUNC(escaped_whitespace_within_double_quotes,
807     "escaped whitespace within double quotes")
808 {
809 	struct t_file *tf;
810 	int ret;
811 
812 	tf = t_fopen(NULL);
813 	t_fprintf(tf, "\"\\ \" \"\\\t\" \"\\\r\" \"\\\n\"\n");
814 	t_frewind(tf);
815 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
816 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
817 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
818 	    /* this last one is a line continuation */
819 	    orw_expect(tf, "", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
820 	t_fclose(tf);
821 	return (ret);
822 }
823 
824 T_FUNC(escaped_letter_within_single_quotes,
825     "escaped letter within single quotes")
826 {
827 	struct t_file *tf;
828 	int ret;
829 
830 	tf = t_fopen(NULL);
831 	t_fprintf(tf, "'\\z'\n");
832 	t_frewind(tf);
833 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
834 	t_fclose(tf);
835 	return (ret);
836 }
837 
838 T_FUNC(escaped_letter_within_double_quotes,
839     "escaped letter within double quotes")
840 {
841 	struct t_file *tf;
842 	int ret;
843 
844 	tf = t_fopen(NULL);
845 	t_fprintf(tf, "\"\\z\"\n");
846 	t_frewind(tf);
847 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
848 	t_fclose(tf);
849 	return (ret);
850 }
851 
852 T_FUNC(escaped_escape_within_single_quotes,
853     "escaped escape within single quotes")
854 {
855 	struct t_file *tf;
856 	int ret;
857 
858 	tf = t_fopen(NULL);
859 	t_fprintf(tf, "'\\\\'\n");
860 	t_frewind(tf);
861 	ret = orw_expect(tf, "\\\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
862 	t_fclose(tf);
863 	return (ret);
864 }
865 
866 T_FUNC(escaped_escape_within_double_quotes,
867     "escaped escape within double quotes")
868 {
869 	struct t_file *tf;
870 	int ret;
871 
872 	tf = t_fopen(NULL);
873 	t_fprintf(tf, "\"\\\\\"\n");
874 	t_frewind(tf);
875 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
876 	t_fclose(tf);
877 	return (ret);
878 }
879 
880 T_FUNC(escaped_single_quote_within_single_quotes,
881     "escaped single quote within single quotes")
882 {
883 	struct t_file *tf;
884 	int ret;
885 
886 	tf = t_fopen(NULL);
887 	t_fprintf(tf, "'\\''\n");
888 	t_frewind(tf);
889 	ret = orw_expect(tf, NULL, 1 /*lines*/, 1 /*eof*/, 0 /*eol*/);
890 	t_fclose(tf);
891 	return (ret);
892 }
893 
894 T_FUNC(escaped_double_quote_within_single_quotes,
895     "escaped double quote within single quotes")
896 {
897 	struct t_file *tf;
898 	int ret;
899 
900 	tf = t_fopen(NULL);
901 	t_fprintf(tf, "'\\\"'\n");
902 	t_frewind(tf);
903 	ret = orw_expect(tf, "\\\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
904 	t_fclose(tf);
905 	return (ret);
906 }
907 
908 T_FUNC(escaped_single_quote_within_double_quotes,
909     "escaped single quote within double quotes")
910 {
911 	struct t_file *tf;
912 	int ret;
913 
914 	tf = t_fopen(NULL);
915 	t_fprintf(tf, "\"\\'\"\n");
916 	t_frewind(tf);
917 	ret = orw_expect(tf, "\\'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
918 	t_fclose(tf);
919 	return (ret);
920 }
921 
922 T_FUNC(escaped_double_quote_within_double_quotes,
923     "escaped double quote within double quotes")
924 {
925 	struct t_file *tf;
926 	int ret;
927 
928 	tf = t_fopen(NULL);
929 	t_fprintf(tf, "\"\\\"\"\n");
930 	t_frewind(tf);
931 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
932 	t_fclose(tf);
933 	return (ret);
934 }
935 
936 
937 /***************************************************************************
938  * Line continuation
939  */
940 
941 T_FUNC(line_continuation_within_whitespace, "line continuation within whitespace")
942 {
943 	struct t_file *tf;
944 	int ret;
945 
946 	tf = t_fopen(NULL);
947 	t_fprintf(tf, "hello \\\n world\n");
948 	t_frewind(tf);
949 	ret = orw_expect(tf, "hello", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
950 	    orw_expect(tf, "world", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
951 	t_fclose(tf);
952 	return (ret);
953 }
954 
955 T_FUNC(line_continuation_before_whitespace, "line continuation before whitespace")
956 {
957 	struct t_file *tf;
958 	int ret;
959 
960 	tf = t_fopen(NULL);
961 	t_fprintf(tf, "hello\\\n world\n");
962 	t_frewind(tf);
963 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
964 	    orw_expect(tf, "world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
965 	t_fclose(tf);
966 	return (ret);
967 }
968 
969 T_FUNC(line_continuation_after_whitespace, "line continuation after whitespace")
970 {
971 	struct t_file *tf;
972 	int ret;
973 
974 	tf = t_fopen(NULL);
975 	t_fprintf(tf, "hello \\\nworld\n");
976 	t_frewind(tf);
977 	ret = orw_expect(tf, "hello", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
978 	    orw_expect(tf, "world", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
979 	t_fclose(tf);
980 	return (ret);
981 }
982 
983 T_FUNC(line_continuation_within_word, "line continuation within word")
984 {
985 	struct t_file *tf;
986 	int ret;
987 
988 	tf = t_fopen(NULL);
989 	t_fprintf(tf, "hello\\\nworld\n");
990 	t_frewind(tf);
991 	ret = orw_expect(tf, "helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
992 	t_fclose(tf);
993 	return (ret);
994 }
995 
996 
997 /***************************************************************************
998  * Boilerplate
999  */
1000 
1001 static int
1002 t_prepare(int argc, char *argv[])
1003 {
1004 
1005 	(void)argc;
1006 	(void)argv;
1007 
1008 	T(empty_input);
1009 	T(empty_line);
1010 	T(unterminated_line);
1011 	T(single_whitespace);
1012 	T(multiple_whitespace);
1013 	T(comment);
1014 	T(whitespace_before_comment);
1015 	T(single_quoted_comment);
1016 	T(double_quoted_comment);
1017 	T(comment_at_eof);
1018 
1019 	T(single_word);
1020 	T(single_whitespace_before_word);
1021 	T(double_whitespace_before_word);
1022 	T(single_whitespace_after_word);
1023 	T(double_whitespace_after_word);
1024 	T(comment_after_word);
1025 	T(word_containing_hash);
1026 	T(two_words);
1027 
1028 	T(naked_escape);
1029 	T(escaped_escape);
1030 	T(escaped_whitespace);
1031 	T(escaped_newline_before_word);
1032 	T(escaped_newline_within_word);
1033 	T(escaped_newline_after_word);
1034 	T(escaped_letter);
1035 	T(escaped_comment);
1036 	T(escape_at_eof);
1037 
1038 	T(naked_single_quote);
1039 	T(naked_double_quote);
1040 	T(empty_single_quotes);
1041 	T(empty_double_quotes);
1042 	T(single_quotes_within_double_quotes);
1043 	T(double_quotes_within_single_quotes);
1044 	T(single_quoted_whitespace);
1045 	T(double_quoted_whitespace);
1046 	T(single_quoted_words);
1047 	T(double_quoted_words);
1048 
1049 	T(single_quote_before_word);
1050 	T(double_quote_before_word);
1051 	T(single_quote_within_word);
1052 	T(double_quote_within_word);
1053 	T(single_quote_after_word);
1054 	T(double_quote_after_word);
1055 
1056 	T(escaped_single_quote);
1057 	T(escaped_double_quote);
1058 	T(escaped_whitespace_within_single_quotes);
1059 	T(escaped_whitespace_within_double_quotes);
1060 	T(escaped_letter_within_single_quotes);
1061 	T(escaped_letter_within_double_quotes);
1062 	T(escaped_escape_within_single_quotes);
1063 	T(escaped_escape_within_double_quotes);
1064 	T(escaped_single_quote_within_single_quotes);
1065 	T(escaped_double_quote_within_single_quotes);
1066 	T(escaped_single_quote_within_double_quotes);
1067 	T(escaped_double_quote_within_double_quotes);
1068 
1069 	T(line_continuation_within_whitespace);
1070 	T(line_continuation_before_whitespace);
1071 	T(line_continuation_after_whitespace);
1072 	T(line_continuation_within_word);
1073 
1074 	return (0);
1075 }
1076 
1077 int
1078 main(int argc, char *argv[])
1079 {
1080 
1081 	t_main(t_prepare, NULL, argc, argv);
1082 }
1083