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