xref: /freebsd/contrib/openpam/t/t_openpam_readword.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
1 /*-
2  * Copyright (c) 2012 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  * $Id: t_openpam_readword.c 648 2013-03-05 17:54:27Z des $
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35 
36 #include <err.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 #include <security/pam_appl.h>
43 #include <security/openpam.h>
44 
45 #include "t.h"
46 
47 /*
48  * Read a word from the temp file and verify that the result matches our
49  * expectations: whether a word was read at all, how many lines were read
50  * (in case of quoted or escaped newlines), whether we reached the end of
51  * the file and whether we reached the end of the line.
52  */
53 static int
54 orw_expect(struct t_file *tf, const char *expected, int lines, int eof, int eol)
55 {
56 	int ch, lineno = 0;
57 	char *got;
58 	size_t len;
59 
60 	got = openpam_readword(tf->file, &lineno, &len);
61 	if (t_ferror(tf))
62 		err(1, "%s(): %s", __func__, tf->name);
63 	if (expected != NULL && got == NULL) {
64 		t_verbose("expected <<%s>>, got nothing\n", expected);
65 		return (0);
66 	}
67 	if (expected == NULL && got != NULL) {
68 		t_verbose("expected nothing, got <<%s>>\n", got);
69 		return (0);
70 	}
71 	if (expected != NULL && got != NULL && strcmp(expected, got) != 0) {
72 		t_verbose("expected <<%s>>, got <<%s>>\n", expected, got);
73 		return (0);
74 	}
75 	if (lineno != lines) {
76 		t_verbose("expected to advance %d lines, advanced %d lines\n",
77 		    lines, lineno);
78 		return (0);
79 	}
80 	if (eof && !t_feof(tf)) {
81 		t_verbose("expected EOF, but didn't get it\n");
82 		return (0);
83 	}
84 	if (!eof && t_feof(tf)) {
85 		t_verbose("didn't expect EOF, but got it anyway\n");
86 		return (0);
87 	}
88 	ch = fgetc(tf->file);
89 	if (t_ferror(tf))
90 		err(1, "%s(): %s", __func__, tf->name);
91 	if (eol && ch != '\n') {
92 		t_verbose("expected EOL, but didn't get it\n");
93 		return (0);
94 	}
95 	if (!eol && ch == '\n') {
96 		t_verbose("didn't expect EOL, but got it anyway\n");
97 		return (0);
98 	}
99 	if (ch != EOF)
100 		ungetc(ch, tf->file);
101 	return (1);
102 }
103 
104 
105 /***************************************************************************
106  * Lines without words
107  */
108 
109 T_FUNC(empty_input, "empty input")
110 {
111 	struct t_file *tf;
112 	int ret;
113 
114 	tf = t_fopen(NULL);
115 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
116 	t_fclose(tf);
117 	return (ret);
118 }
119 
120 T_FUNC(empty_line, "empty line")
121 {
122 	struct t_file *tf;
123 	int ret;
124 
125 	tf = t_fopen(NULL);
126 	t_fprintf(tf, "\n");
127 	t_frewind(tf);
128 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
129 	t_fclose(tf);
130 	return (ret);
131 }
132 
133 T_FUNC(unterminated_line, "unterminated line")
134 {
135 	struct t_file *tf;
136 	int ret;
137 
138 	tf = t_fopen(NULL);
139 	t_fprintf(tf, " ");
140 	t_frewind(tf);
141 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
142 	t_fclose(tf);
143 	return (ret);
144 }
145 
146 T_FUNC(single_whitespace, "single whitespace")
147 {
148 	struct t_file *tf;
149 	int ret;
150 
151 	tf = t_fopen(NULL);
152 	t_fprintf(tf, " \n");
153 	t_frewind(tf);
154 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
155 	t_fclose(tf);
156 	return (ret);
157 }
158 
159 T_FUNC(multiple_whitespace, "multiple whitespace")
160 {
161 	struct t_file *tf;
162 	int ret;
163 
164 	tf = t_fopen(NULL);
165 	t_fprintf(tf, " \t\r\n");
166 	t_frewind(tf);
167 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
168 	t_fclose(tf);
169 	return (ret);
170 }
171 
172 T_FUNC(comment, "comment")
173 {
174 	struct t_file *tf;
175 	int ret;
176 
177 	tf = t_fopen(NULL);
178 	t_fprintf(tf, "# comment\n");
179 	t_frewind(tf);
180 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
181 	t_fclose(tf);
182 	return (ret);
183 }
184 
185 T_FUNC(whitespace_before_comment, "whitespace before comment")
186 {
187 	struct t_file *tf;
188 	int ret;
189 
190 	tf = t_fopen(NULL);
191 	t_fprintf(tf, " # comment\n");
192 	t_frewind(tf);
193 	ret = orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
194 	t_fclose(tf);
195 	return (ret);
196 }
197 
198 
199 /***************************************************************************
200  * Simple cases - no quotes or escapes
201  */
202 
203 T_FUNC(single_word, "single word")
204 {
205 	const char *word = "hello";
206 	struct t_file *tf;
207 	int ret;
208 
209 	tf = t_fopen(NULL);
210 	t_fprintf(tf, "%s\n", word);
211 	t_frewind(tf);
212 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
213 	t_fclose(tf);
214 	return (ret);
215 }
216 
217 T_FUNC(single_whitespace_before_word, "single whitespace before word")
218 {
219 	const char *word = "hello";
220 	struct t_file *tf;
221 	int ret;
222 
223 	tf = t_fopen(NULL);
224 	t_fprintf(tf, " %s\n", word);
225 	t_frewind(tf);
226 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
227 	t_fclose(tf);
228 	return (ret);
229 }
230 
231 T_FUNC(double_whitespace_before_word, "double whitespace before word")
232 {
233 	const char *word = "hello";
234 	struct t_file *tf;
235 	int ret;
236 
237 	tf = t_fopen(NULL);
238 	t_fprintf(tf, "  %s\n", word);
239 	t_frewind(tf);
240 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
241 	t_fclose(tf);
242 	return (ret);
243 }
244 
245 T_FUNC(single_whitespace_after_word, "single whitespace after word")
246 {
247 	const char *word = "hello";
248 	struct t_file *tf;
249 	int ret;
250 
251 	tf = t_fopen(NULL);
252 	t_fprintf(tf, "%s \n", word);
253 	t_frewind(tf);
254 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
255 	t_fclose(tf);
256 	return (ret);
257 }
258 
259 T_FUNC(double_whitespace_after_word, "double whitespace after word")
260 {
261 	const char *word = "hello";
262 	struct t_file *tf;
263 	int ret;
264 
265 	tf = t_fopen(NULL);
266 	t_fprintf(tf, "%s  \n", word);
267 	t_frewind(tf);
268 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
269 	t_fclose(tf);
270 	return (ret);
271 }
272 
273 T_FUNC(comment_after_word, "comment after word")
274 {
275 	const char *word = "hello";
276 	struct t_file *tf;
277 	int ret;
278 
279 	tf = t_fopen(NULL);
280 	t_fprintf(tf, "%s # comment\n", word);
281 	t_frewind(tf);
282 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
283 	    orw_expect(tf, NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
284 	t_fclose(tf);
285 	return (ret);
286 }
287 
288 T_FUNC(word_containing_hash, "word containing hash")
289 {
290 	const char *word = "hello#world";
291 	struct t_file *tf;
292 	int ret;
293 
294 	tf = t_fopen(NULL);
295 	t_fprintf(tf, "%s\n", word);
296 	t_frewind(tf);
297 	ret = orw_expect(tf, word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
298 	t_fclose(tf);
299 	return (ret);
300 }
301 
302 T_FUNC(two_words, "two words")
303 {
304 	const char *word[] = { "hello", "world" };
305 	struct t_file *tf;
306 	int ret;
307 
308 	tf = t_fopen(NULL);
309 	t_fprintf(tf, "%s %s\n", word[0], word[1]);
310 	t_frewind(tf);
311 	ret = orw_expect(tf, word[0], 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
312 	    orw_expect(tf, word[1], 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
313 	t_fclose(tf);
314 	return (ret);
315 }
316 
317 
318 /***************************************************************************
319  * Escapes
320  */
321 
322 T_FUNC(naked_escape, "naked escape")
323 {
324 	struct t_file *tf;
325 	int ret;
326 
327 	tf = t_fopen(NULL);
328 	t_fprintf(tf, "\\");
329 	t_frewind(tf);
330 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
331 	t_fclose(tf);
332 	return (ret);
333 }
334 
335 T_FUNC(escaped_escape, "escaped escape")
336 {
337 	struct t_file *tf;
338 	int ret;
339 
340 	tf = t_fopen(NULL);
341 	t_fprintf(tf, "\\\\\n");
342 	t_frewind(tf);
343 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
344 	t_fclose(tf);
345 	return (ret);
346 }
347 
348 T_FUNC(escaped_whitespace, "escaped whitespace")
349 {
350 	struct t_file *tf;
351 	int ret;
352 
353 	tf = t_fopen(NULL);
354 	t_fprintf(tf, "\\  \\\t \\\r \\\n\n");
355 	t_frewind(tf);
356 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
357 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
358 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
359 	    /* this last one is a line continuation */
360 	    orw_expect(tf, NULL, 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
361 	t_fclose(tf);
362 	return (ret);
363 }
364 
365 T_FUNC(escaped_newline_before_word, "escaped newline before word")
366 {
367 	struct t_file *tf;
368 	int ret;
369 
370 	tf = t_fopen(NULL);
371 	t_fprintf(tf, "\\\nhello world\n");
372 	t_frewind(tf);
373 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
374 	t_fclose(tf);
375 	return (ret);
376 }
377 
378 T_FUNC(escaped_newline_within_word, "escaped newline within word")
379 {
380 	struct t_file *tf;
381 	int ret;
382 
383 	tf = t_fopen(NULL);
384 	t_fprintf(tf, "hello\\\nworld\n");
385 	t_frewind(tf);
386 	ret = orw_expect(tf, "helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
387 	t_fclose(tf);
388 	return (ret);
389 }
390 
391 T_FUNC(escaped_newline_after_word, "escaped newline after word")
392 {
393 	struct t_file *tf;
394 	int ret;
395 
396 	tf = t_fopen(NULL);
397 	t_fprintf(tf, "hello\\\n world\n");
398 	t_frewind(tf);
399 	ret = orw_expect(tf, "hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
400 	t_fclose(tf);
401 	return (ret);
402 }
403 
404 T_FUNC(escaped_letter, "escaped letter")
405 {
406 	struct t_file *tf;
407 	int ret;
408 
409 	tf = t_fopen(NULL);
410 	t_fprintf(tf, "\\z\n");
411 	t_frewind(tf);
412 	ret = orw_expect(tf, "z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
413 	t_fclose(tf);
414 	return (ret);
415 }
416 
417 
418 /***************************************************************************
419  * Quotes
420  */
421 
422 T_FUNC(naked_single_quote, "naked single quote")
423 {
424 	struct t_file *tf;
425 	int ret;
426 
427 	tf = t_fopen(NULL);
428 	t_fprintf(tf, "'");
429 	t_frewind(tf);
430 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
431 	t_fclose(tf);
432 	return (ret);
433 }
434 
435 T_FUNC(naked_double_quote, "naked double quote")
436 {
437 	struct t_file *tf;
438 	int ret;
439 
440 	tf = t_fopen(NULL);
441 	t_fprintf(tf, "\"");
442 	t_frewind(tf);
443 	ret = orw_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
444 	t_fclose(tf);
445 	return (ret);
446 }
447 
448 T_FUNC(empty_single_quotes, "empty single quotes")
449 {
450 	struct t_file *tf;
451 	int ret;
452 
453 	tf = t_fopen(NULL);
454 	t_fprintf(tf, "''\n");
455 	t_frewind(tf);
456 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
457 	t_fclose(tf);
458 	return (ret);
459 }
460 
461 T_FUNC(empty_double_quotes, "empty double quotes")
462 {
463 	struct t_file *tf;
464 	int ret;
465 
466 	tf = t_fopen(NULL);
467 	t_fprintf(tf, "\"\"\n");
468 	t_frewind(tf);
469 	ret = orw_expect(tf, "", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
470 	t_fclose(tf);
471 	return (ret);
472 }
473 
474 T_FUNC(single_quotes_within_double_quotes, "single quotes within double quotes")
475 {
476 	struct t_file *tf;
477 	int ret;
478 
479 	tf = t_fopen(NULL);
480 	t_fprintf(tf, "\"' '\"\n");
481 	t_frewind(tf);
482 	ret = orw_expect(tf, "' '", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
483 	t_fclose(tf);
484 	return (ret);
485 }
486 
487 T_FUNC(double_quotes_within_single_quotes, "double quotes within single quotes")
488 {
489 	struct t_file *tf;
490 	int ret;
491 
492 	tf = t_fopen(NULL);
493 	t_fprintf(tf, "'\" \"'\n");
494 	t_frewind(tf);
495 	ret = orw_expect(tf, "\" \"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
496 	t_fclose(tf);
497 	return (ret);
498 }
499 
500 T_FUNC(single_quoted_whitespace, "single-quoted whitespace")
501 {
502 	struct t_file *tf;
503 	int ret;
504 
505 	tf = t_fopen(NULL);
506 	t_fprintf(tf, "' ' '\t' '\r' '\n'\n");
507 	t_frewind(tf);
508 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
509 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
510 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
511 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
512 	t_fclose(tf);
513 	return (ret);
514 }
515 
516 T_FUNC(double_quoted_whitespace, "double-quoted whitespace")
517 {
518 	struct t_file *tf;
519 	int ret;
520 
521 	tf = t_fopen(NULL);
522 	t_fprintf(tf, "\" \" \"\t\" \"\r\" \"\n\"\n");
523 	t_frewind(tf);
524 	ret = orw_expect(tf, " ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
525 	    orw_expect(tf, "\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
526 	    orw_expect(tf, "\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
527 	    orw_expect(tf, "\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
528 	t_fclose(tf);
529 	return (ret);
530 }
531 
532 T_FUNC(single_quoted_words, "single-quoted words")
533 {
534 	struct t_file *tf;
535 	int ret;
536 
537 	tf = t_fopen(NULL);
538 	t_fprintf(tf, "'hello world'\n");
539 	t_frewind(tf);
540 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
541 	t_fclose(tf);
542 	return (ret);
543 }
544 
545 T_FUNC(double_quoted_words, "double-quoted words")
546 {
547 	struct t_file *tf;
548 	int ret;
549 
550 	tf = t_fopen(NULL);
551 	t_fprintf(tf, "\"hello world\"\n");
552 	t_frewind(tf);
553 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
554 	t_fclose(tf);
555 	return (ret);
556 }
557 
558 
559 /***************************************************************************
560  * Combinations of quoted and unquoted text
561  */
562 
563 T_FUNC(single_quote_before_word, "single quote before word")
564 {
565 	struct t_file *tf;
566 	int ret;
567 
568 	tf = t_fopen(NULL);
569 	t_fprintf(tf, "'hello 'world\n");
570 	t_frewind(tf);
571 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
572 	t_fclose(tf);
573 	return (ret);
574 }
575 
576 T_FUNC(double_quote_before_word, "double quote before word")
577 {
578 	struct t_file *tf;
579 	int ret;
580 
581 	tf = t_fopen(NULL);
582 	t_fprintf(tf, "\"hello \"world\n");
583 	t_frewind(tf);
584 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
585 	t_fclose(tf);
586 	return (ret);
587 }
588 
589 T_FUNC(single_quote_within_word, "single quote within word")
590 {
591 	struct t_file *tf;
592 	int ret;
593 
594 	tf = t_fopen(NULL);
595 	t_fprintf(tf, "hello' 'world\n");
596 	t_frewind(tf);
597 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
598 	t_fclose(tf);
599 	return (ret);
600 }
601 
602 T_FUNC(double_quote_within_word, "double quote within word")
603 {
604 	struct t_file *tf;
605 	int ret;
606 
607 	tf = t_fopen(NULL);
608 	t_fprintf(tf, "hello\" \"world\n");
609 	t_frewind(tf);
610 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
611 	t_fclose(tf);
612 	return (ret);
613 }
614 
615 T_FUNC(single_quote_after_word, "single quote after word")
616 {
617 	struct t_file *tf;
618 	int ret;
619 
620 	tf = t_fopen(NULL);
621 	t_fprintf(tf, "hello' world'\n");
622 	t_frewind(tf);
623 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
624 	t_fclose(tf);
625 	return (ret);
626 }
627 
628 T_FUNC(double_quote_after_word, "double quote after word")
629 {
630 	struct t_file *tf;
631 	int ret;
632 
633 	tf = t_fopen(NULL);
634 	t_fprintf(tf, "hello\" world\"\n");
635 	t_frewind(tf);
636 	ret = orw_expect(tf, "hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
637 	t_fclose(tf);
638 	return (ret);
639 }
640 
641 
642 /***************************************************************************
643  * Combinations of escape and quotes
644  */
645 
646 T_FUNC(escaped_single_quote,
647     "escaped single quote")
648 {
649 	struct t_file *tf;
650 	int ret;
651 
652 	tf = t_fopen(NULL);
653 	t_fprintf(tf, "\\'\n");
654 	t_frewind(tf);
655 	ret = orw_expect(tf, "'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
656 	t_fclose(tf);
657 	return (ret);
658 }
659 
660 T_FUNC(escaped_double_quote,
661     "escaped double quote")
662 {
663 	struct t_file *tf;
664 	int ret;
665 
666 	tf = t_fopen(NULL);
667 	t_fprintf(tf, "\\\"\n");
668 	t_frewind(tf);
669 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
670 	t_fclose(tf);
671 	return (ret);
672 }
673 
674 T_FUNC(escaped_whitespace_within_single_quotes,
675     "escaped whitespace within single quotes")
676 {
677 	struct t_file *tf;
678 	int ret;
679 
680 	tf = t_fopen(NULL);
681 	t_fprintf(tf, "'\\ ' '\\\t' '\\\r' '\\\n'\n");
682 	t_frewind(tf);
683 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
684 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
685 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
686 	    orw_expect(tf, "\\\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
687 	t_fclose(tf);
688 	return (ret);
689 }
690 
691 T_FUNC(escaped_whitespace_within_double_quotes,
692     "escaped whitespace within double quotes")
693 {
694 	struct t_file *tf;
695 	int ret;
696 
697 	tf = t_fopen(NULL);
698 	t_fprintf(tf, "\"\\ \" \"\\\t\" \"\\\r\" \"\\\n\"\n");
699 	t_frewind(tf);
700 	ret = orw_expect(tf, "\\ ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
701 	    orw_expect(tf, "\\\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
702 	    orw_expect(tf, "\\\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
703 	    /* this last one is a line continuation */
704 	    orw_expect(tf, "", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
705 	t_fclose(tf);
706 	return (ret);
707 }
708 
709 T_FUNC(escaped_letter_within_single_quotes,
710     "escaped letter within single quotes")
711 {
712 	struct t_file *tf;
713 	int ret;
714 
715 	tf = t_fopen(NULL);
716 	t_fprintf(tf, "'\\z'\n");
717 	t_frewind(tf);
718 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
719 	t_fclose(tf);
720 	return (ret);
721 }
722 
723 T_FUNC(escaped_letter_within_double_quotes,
724     "escaped letter within double quotes")
725 {
726 	struct t_file *tf;
727 	int ret;
728 
729 	tf = t_fopen(NULL);
730 	t_fprintf(tf, "\"\\z\"\n");
731 	t_frewind(tf);
732 	ret = orw_expect(tf, "\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
733 	t_fclose(tf);
734 	return (ret);
735 }
736 
737 T_FUNC(escaped_escape_within_single_quotes,
738     "escaped escape within single quotes")
739 {
740 	struct t_file *tf;
741 	int ret;
742 
743 	tf = t_fopen(NULL);
744 	t_fprintf(tf, "'\\\\'\n");
745 	t_frewind(tf);
746 	ret = orw_expect(tf, "\\\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
747 	t_fclose(tf);
748 	return (ret);
749 }
750 
751 T_FUNC(escaped_escape_within_double_quotes,
752     "escaped escape within double quotes")
753 {
754 	struct t_file *tf;
755 	int ret;
756 
757 	tf = t_fopen(NULL);
758 	t_fprintf(tf, "\"\\\\\"\n");
759 	t_frewind(tf);
760 	ret = orw_expect(tf, "\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
761 	t_fclose(tf);
762 	return (ret);
763 }
764 
765 T_FUNC(escaped_single_quote_within_single_quotes,
766     "escaped single quote within single quotes")
767 {
768 	struct t_file *tf;
769 	int ret;
770 
771 	tf = t_fopen(NULL);
772 	t_fprintf(tf, "'\\''\n");
773 	t_frewind(tf);
774 	ret = orw_expect(tf, NULL, 1 /*lines*/, 1 /*eof*/, 0 /*eol*/);
775 	t_fclose(tf);
776 	return (ret);
777 }
778 
779 T_FUNC(escaped_double_quote_within_single_quotes,
780     "escaped double quote within single quotes")
781 {
782 	struct t_file *tf;
783 	int ret;
784 
785 	tf = t_fopen(NULL);
786 	t_fprintf(tf, "'\\\"'\n");
787 	t_frewind(tf);
788 	ret = orw_expect(tf, "\\\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
789 	t_fclose(tf);
790 	return (ret);
791 }
792 
793 T_FUNC(escaped_single_quote_within_double_quotes,
794     "escaped single quote within double quotes")
795 {
796 	struct t_file *tf;
797 	int ret;
798 
799 	tf = t_fopen(NULL);
800 	t_fprintf(tf, "\"\\'\"\n");
801 	t_frewind(tf);
802 	ret = orw_expect(tf, "\\'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
803 	t_fclose(tf);
804 	return (ret);
805 }
806 
807 T_FUNC(escaped_double_quote_within_double_quotes,
808     "escaped double quote within double quotes")
809 {
810 	struct t_file *tf;
811 	int ret;
812 
813 	tf = t_fopen(NULL);
814 	t_fprintf(tf, "\"\\\"\"\n");
815 	t_frewind(tf);
816 	ret = orw_expect(tf, "\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
817 	t_fclose(tf);
818 	return (ret);
819 }
820 
821 
822 /***************************************************************************
823  * Boilerplate
824  */
825 
826 static const struct t_test *t_plan[] = {
827 	T(empty_input),
828 	T(empty_line),
829 	T(single_whitespace),
830 	T(multiple_whitespace),
831 	T(comment),
832 	T(whitespace_before_comment),
833 
834 	T(single_word),
835 	T(single_whitespace_before_word),
836 	T(double_whitespace_before_word),
837 	T(single_whitespace_after_word),
838 	T(double_whitespace_after_word),
839 	T(comment_after_word),
840 	T(word_containing_hash),
841 	T(two_words),
842 
843 	T(naked_escape),
844 	T(escaped_escape),
845 	T(escaped_whitespace),
846 	T(escaped_newline_before_word),
847 	T(escaped_newline_within_word),
848 	T(escaped_newline_after_word),
849 	T(escaped_letter),
850 
851 	T(naked_single_quote),
852 	T(naked_double_quote),
853 	T(empty_single_quotes),
854 	T(empty_double_quotes),
855 	T(single_quotes_within_double_quotes),
856 	T(double_quotes_within_single_quotes),
857 	T(single_quoted_whitespace),
858 	T(double_quoted_whitespace),
859 	T(single_quoted_words),
860 	T(double_quoted_words),
861 
862 	T(single_quote_before_word),
863 	T(double_quote_before_word),
864 	T(single_quote_within_word),
865 	T(double_quote_within_word),
866 	T(single_quote_after_word),
867 	T(double_quote_after_word),
868 
869 	T(escaped_single_quote),
870 	T(escaped_double_quote),
871 	T(escaped_whitespace_within_single_quotes),
872 	T(escaped_whitespace_within_double_quotes),
873 	T(escaped_letter_within_single_quotes),
874 	T(escaped_letter_within_double_quotes),
875 	T(escaped_escape_within_single_quotes),
876 	T(escaped_escape_within_double_quotes),
877 	T(escaped_single_quote_within_single_quotes),
878 	T(escaped_double_quote_within_single_quotes),
879 	T(escaped_single_quote_within_double_quotes),
880 	T(escaped_double_quote_within_double_quotes),
881 
882 	NULL
883 };
884 
885 const struct t_test **
886 t_prepare(int argc, char *argv[])
887 {
888 
889 	(void)argc;
890 	(void)argv;
891 	return (t_plan);
892 }
893 
894 void
895 t_cleanup(void)
896 {
897 }
898