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