t_openpam_readword.c revision 294192
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 */
53static int
54orw_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
109T_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
120T_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
133T_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
146T_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
159T_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
172T_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
185T_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
203T_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
217T_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
231T_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
245T_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
259T_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
273T_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
288T_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
302T_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
322T_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
335T_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
348T_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
365T_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
378T_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
391T_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
404T_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
422T_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
435T_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
448T_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
461T_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
474T_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
487T_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
500T_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
516T_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
532T_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
545T_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
563T_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
576T_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
589T_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
602T_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
615T_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
628T_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
646T_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
660T_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
674T_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
691T_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
709T_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
723T_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
737T_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
751T_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
765T_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
779T_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
793T_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
807T_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
826static 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
885const struct t_test **
886t_prepare(int argc, char *argv[])
887{
888
889	(void)argc;
890	(void)argv;
891	return (t_plan);
892}
893
894void
895t_cleanup(void)
896{
897}
898