1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 // 1. Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright
13 //    notice, this list of conditions and the following disclaimer in the
14 //    documentation and/or other materials provided with the distribution.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 
30 #include <sstream>
31 
32 #include <atf-c++.hpp>
33 
34 #include "parser.hpp"
35 #include "test_helpers.hpp"
36 
37 // ------------------------------------------------------------------------
38 // Tests for the "parse_error" class.
39 // ------------------------------------------------------------------------
40 
41 ATF_TEST_CASE(parse_error_to_string);
42 ATF_TEST_CASE_HEAD(parse_error_to_string)
43 {
44     set_md_var("descr", "Tests the parse_error conversion to strings");
45 }
46 ATF_TEST_CASE_BODY(parse_error_to_string)
47 {
48     using tools::parser::parse_error;
49 
50     const parse_error e(123, "This is the message");
51     ATF_REQUIRE_EQ("123: This is the message", std::string(e));
52 }
53 
54 // ------------------------------------------------------------------------
55 // Tests for the "parse_errors" class.
56 // ------------------------------------------------------------------------
57 
58 ATF_TEST_CASE(parse_errors_what);
59 ATF_TEST_CASE_HEAD(parse_errors_what)
60 {
61     set_md_var("descr", "Tests the parse_errors description");
62 }
63 ATF_TEST_CASE_BODY(parse_errors_what)
64 {
65     using tools::parser::parse_error;
66     using tools::parser::parse_errors;
67 
68     parse_errors es;
69     es.push_back(parse_error(2, "Second error"));
70     es.push_back(parse_error(1, "First error"));
71 
72     ATF_REQUIRE_EQ("2: Second error\n1: First error", std::string(es.what()));
73 }
74 
75 // ------------------------------------------------------------------------
76 // Tests for the "token" class.
77 // ------------------------------------------------------------------------
78 
79 ATF_TEST_CASE(token_getters);
80 ATF_TEST_CASE_HEAD(token_getters)
81 {
82     set_md_var("descr", "Tests the token getters");
83 }
84 ATF_TEST_CASE_BODY(token_getters)
85 {
86     using tools::parser::token;
87 
88     {
89         token t(10, 0);
90         ATF_REQUIRE_EQ(t.lineno(), 10);
91         ATF_REQUIRE_EQ(t.type(), 0);
92         ATF_REQUIRE(t.text().empty());
93     }
94 
95     {
96         token t(10, 0, "foo");
97         ATF_REQUIRE_EQ(t.lineno(), 10);
98         ATF_REQUIRE_EQ(t.type(), 0);
99         ATF_REQUIRE_EQ(t.text(), "foo");
100     }
101 
102     {
103         token t(20, 1);
104         ATF_REQUIRE_EQ(t.lineno(), 20);
105         ATF_REQUIRE_EQ(t.type(), 1);
106         ATF_REQUIRE(t.text().empty());
107     }
108 
109     {
110         token t(20, 1, "bar");
111         ATF_REQUIRE_EQ(t.lineno(), 20);
112         ATF_REQUIRE_EQ(t.type(), 1);
113         ATF_REQUIRE_EQ(t.text(), "bar");
114     }
115 }
116 
117 // ------------------------------------------------------------------------
118 // Tests for the "tokenizer" class.
119 // ------------------------------------------------------------------------
120 
121 #define EXPECT(tkz, ttype, ttext) \
122     do { \
123         tools::parser::token t = tkz.next(); \
124         ATF_REQUIRE(t.type() == ttype); \
125         ATF_REQUIRE_EQ(t.text(), ttext); \
126     } while (false);
127 
128 namespace minimal {
129 
130     static const tools::parser::token_type eof_type = 0;
131     static const tools::parser::token_type nl_type = 1;
132     static const tools::parser::token_type word_type = 2;
133 
134     class tokenizer : public tools::parser::tokenizer< std::istream > {
135     public:
136         tokenizer(std::istream& is, bool skipws) :
137             tools::parser::tokenizer< std::istream >
138                 (is, skipws, eof_type, nl_type, word_type)
139         {
140         }
141     };
142 
143 }
144 
145 namespace delims {
146 
147     static const tools::parser::token_type eof_type = 0;
148     static const tools::parser::token_type nl_type = 1;
149     static const tools::parser::token_type word_type = 2;
150     static const tools::parser::token_type plus_type = 3;
151     static const tools::parser::token_type minus_type = 4;
152     static const tools::parser::token_type equal_type = 5;
153 
154     class tokenizer : public tools::parser::tokenizer< std::istream > {
155     public:
156         tokenizer(std::istream& is, bool skipws) :
157             tools::parser::tokenizer< std::istream >
158                 (is, skipws, eof_type, nl_type, word_type)
159         {
160             add_delim('+', plus_type);
161             add_delim('-', minus_type);
162             add_delim('=', equal_type);
163         }
164     };
165 
166 }
167 
168 namespace keywords {
169 
170     static const tools::parser::token_type eof_type = 0;
171     static const tools::parser::token_type nl_type = 1;
172     static const tools::parser::token_type word_type = 2;
173     static const tools::parser::token_type var_type = 3;
174     static const tools::parser::token_type loop_type = 4;
175     static const tools::parser::token_type endloop_type = 5;
176 
177     class tokenizer : public tools::parser::tokenizer< std::istream > {
178     public:
179         tokenizer(std::istream& is, bool skipws) :
180             tools::parser::tokenizer< std::istream >
181                 (is, skipws, eof_type, nl_type, word_type)
182         {
183             add_keyword("var", var_type);
184             add_keyword("loop", loop_type);
185             add_keyword("endloop", endloop_type);
186         }
187     };
188 
189 }
190 
191 namespace quotes {
192 
193     static const tools::parser::token_type eof_type = 0;
194     static const tools::parser::token_type nl_type = 1;
195     static const tools::parser::token_type word_type = 2;
196     static const tools::parser::token_type dblquote_type = 3;
197 
198     class tokenizer : public tools::parser::tokenizer< std::istream > {
199     public:
200         tokenizer(std::istream& is, bool skipws) :
201             tools::parser::tokenizer< std::istream >
202                 (is, skipws, eof_type, nl_type, word_type)
203         {
204             add_quote('"', dblquote_type);
205         }
206     };
207 
208 }
209 
210 ATF_TEST_CASE(tokenizer_minimal_nows);
211 ATF_TEST_CASE_HEAD(tokenizer_minimal_nows)
212 {
213     set_md_var("descr", "Tests the tokenizer class using a minimal parser "
214                "and not skipping whitespace");
215 }
216 ATF_TEST_CASE_BODY(tokenizer_minimal_nows)
217 {
218     using namespace minimal;
219 
220     {
221         std::istringstream iss("");
222         tokenizer mt(iss, false);
223 
224         EXPECT(mt, eof_type, "<<EOF>>");
225         EXPECT(mt, eof_type, "<<EOF>>");
226     }
227 
228     {
229         std::istringstream iss("\n");
230         tokenizer mt(iss, false);
231 
232         EXPECT(mt, nl_type, "<<NEWLINE>>");
233         EXPECT(mt, eof_type, "<<EOF>>");
234         EXPECT(mt, eof_type, "<<EOF>>");
235     }
236 
237     {
238         std::istringstream iss("\n\n\n");
239         tokenizer mt(iss, false);
240 
241         EXPECT(mt, nl_type, "<<NEWLINE>>");
242         EXPECT(mt, nl_type, "<<NEWLINE>>");
243         EXPECT(mt, nl_type, "<<NEWLINE>>");
244         EXPECT(mt, eof_type, "<<EOF>>");
245         EXPECT(mt, eof_type, "<<EOF>>");
246     }
247 
248     {
249         std::istringstream iss("line 1");
250         tokenizer mt(iss, false);
251 
252         EXPECT(mt, word_type, "line 1");
253         EXPECT(mt, eof_type, "<<EOF>>");
254         EXPECT(mt, eof_type, "<<EOF>>");
255     }
256 
257     {
258         std::istringstream iss("line 1\n");
259         tokenizer mt(iss, false);
260 
261         EXPECT(mt, word_type, "line 1");
262         EXPECT(mt, nl_type, "<<NEWLINE>>");
263         EXPECT(mt, eof_type, "<<EOF>>");
264         EXPECT(mt, eof_type, "<<EOF>>");
265     }
266 
267     {
268         std::istringstream iss("line 1\nline 2");
269         tokenizer mt(iss, false);
270 
271         EXPECT(mt, word_type, "line 1");
272         EXPECT(mt, nl_type, "<<NEWLINE>>");
273         EXPECT(mt, word_type, "line 2");
274         EXPECT(mt, eof_type, "<<EOF>>");
275         EXPECT(mt, eof_type, "<<EOF>>");
276     }
277 
278     {
279         std::istringstream iss("line 1\nline 2\nline 3\n");
280         tokenizer mt(iss, false);
281 
282         EXPECT(mt, word_type, "line 1");
283         EXPECT(mt, nl_type, "<<NEWLINE>>");
284         EXPECT(mt, word_type, "line 2");
285         EXPECT(mt, nl_type, "<<NEWLINE>>");
286         EXPECT(mt, word_type, "line 3");
287         EXPECT(mt, nl_type, "<<NEWLINE>>");
288         EXPECT(mt, eof_type, "<<EOF>>");
289         EXPECT(mt, eof_type, "<<EOF>>");
290     }
291 }
292 
293 ATF_TEST_CASE(tokenizer_minimal_ws);
294 ATF_TEST_CASE_HEAD(tokenizer_minimal_ws)
295 {
296     set_md_var("descr", "Tests the tokenizer class using a minimal parser "
297                "and skipping whitespace");
298 }
299 ATF_TEST_CASE_BODY(tokenizer_minimal_ws)
300 {
301     using namespace minimal;
302 
303     {
304         std::istringstream iss("");
305         minimal::tokenizer mt(iss, true);
306 
307         EXPECT(mt, eof_type, "<<EOF>>");
308         EXPECT(mt, eof_type, "<<EOF>>");
309     }
310 
311     {
312         std::istringstream iss(" \t ");
313         tokenizer mt(iss, true);
314 
315         EXPECT(mt, eof_type, "<<EOF>>");
316         EXPECT(mt, eof_type, "<<EOF>>");
317     }
318 
319     {
320         std::istringstream iss("\n");
321         tokenizer mt(iss, true);
322 
323         EXPECT(mt, nl_type, "<<NEWLINE>>");
324         EXPECT(mt, eof_type, "<<EOF>>");
325         EXPECT(mt, eof_type, "<<EOF>>");
326     }
327 
328     {
329         std::istringstream iss(" \t \n \t ");
330         tokenizer mt(iss, true);
331 
332         EXPECT(mt, nl_type, "<<NEWLINE>>");
333         EXPECT(mt, eof_type, "<<EOF>>");
334         EXPECT(mt, eof_type, "<<EOF>>");
335     }
336 
337     {
338         std::istringstream iss("\n\n\n");
339         tokenizer mt(iss, true);
340 
341         EXPECT(mt, nl_type, "<<NEWLINE>>");
342         EXPECT(mt, nl_type, "<<NEWLINE>>");
343         EXPECT(mt, nl_type, "<<NEWLINE>>");
344         EXPECT(mt, eof_type, "<<EOF>>");
345         EXPECT(mt, eof_type, "<<EOF>>");
346     }
347 
348     {
349         std::istringstream iss("line 1");
350         tokenizer mt(iss, true);
351 
352         EXPECT(mt, word_type, "line");
353         EXPECT(mt, word_type, "1");
354         EXPECT(mt, eof_type, "<<EOF>>");
355         EXPECT(mt, eof_type, "<<EOF>>");
356     }
357 
358     {
359         std::istringstream iss("   \tline\t   1\t");
360         tokenizer mt(iss, true);
361 
362         EXPECT(mt, word_type, "line");
363         EXPECT(mt, word_type, "1");
364         EXPECT(mt, eof_type, "<<EOF>>");
365         EXPECT(mt, eof_type, "<<EOF>>");
366     }
367 
368     {
369         std::istringstream iss("line 1\n");
370         tokenizer mt(iss, true);
371 
372         EXPECT(mt, word_type, "line");
373         EXPECT(mt, word_type, "1");
374         EXPECT(mt, nl_type, "<<NEWLINE>>");
375         EXPECT(mt, eof_type, "<<EOF>>");
376         EXPECT(mt, eof_type, "<<EOF>>");
377     }
378 
379     {
380         std::istringstream iss("line 1\nline 2");
381         tokenizer mt(iss, true);
382 
383         EXPECT(mt, word_type, "line");
384         EXPECT(mt, word_type, "1");
385         EXPECT(mt, nl_type, "<<NEWLINE>>");
386         EXPECT(mt, word_type, "line");
387         EXPECT(mt, word_type, "2");
388         EXPECT(mt, eof_type, "<<EOF>>");
389         EXPECT(mt, eof_type, "<<EOF>>");
390     }
391 
392     {
393         std::istringstream iss("line 1\nline 2\nline 3\n");
394         tokenizer mt(iss, true);
395 
396         EXPECT(mt, word_type, "line");
397         EXPECT(mt, word_type, "1");
398         EXPECT(mt, nl_type, "<<NEWLINE>>");
399         EXPECT(mt, word_type, "line");
400         EXPECT(mt, word_type, "2");
401         EXPECT(mt, nl_type, "<<NEWLINE>>");
402         EXPECT(mt, word_type, "line");
403         EXPECT(mt, word_type, "3");
404         EXPECT(mt, nl_type, "<<NEWLINE>>");
405         EXPECT(mt, eof_type, "<<EOF>>");
406         EXPECT(mt, eof_type, "<<EOF>>");
407     }
408 
409     {
410         std::istringstream iss(" \t line \t 1\n\tline\t2\n line 3 \n");
411         tokenizer mt(iss, true);
412 
413         EXPECT(mt, word_type, "line");
414         EXPECT(mt, word_type, "1");
415         EXPECT(mt, nl_type, "<<NEWLINE>>");
416         EXPECT(mt, word_type, "line");
417         EXPECT(mt, word_type, "2");
418         EXPECT(mt, nl_type, "<<NEWLINE>>");
419         EXPECT(mt, word_type, "line");
420         EXPECT(mt, word_type, "3");
421         EXPECT(mt, nl_type, "<<NEWLINE>>");
422         EXPECT(mt, eof_type, "<<EOF>>");
423         EXPECT(mt, eof_type, "<<EOF>>");
424     }
425 }
426 
427 ATF_TEST_CASE(tokenizer_delims_nows);
428 ATF_TEST_CASE_HEAD(tokenizer_delims_nows)
429 {
430     set_md_var("descr", "Tests the tokenizer class using a parser with some "
431                "additional delimiters and not skipping whitespace");
432 }
433 ATF_TEST_CASE_BODY(tokenizer_delims_nows)
434 {
435     using namespace delims;
436 
437     {
438         std::istringstream iss("+-=");
439         tokenizer mt(iss, false);
440 
441         EXPECT(mt, plus_type, "+");
442         EXPECT(mt, minus_type, "-");
443         EXPECT(mt, equal_type, "=");
444         EXPECT(mt, eof_type, "<<EOF>>");
445         EXPECT(mt, eof_type, "<<EOF>>");
446     }
447 
448     {
449         std::istringstream iss("+++");
450         tokenizer mt(iss, false);
451 
452         EXPECT(mt, plus_type, "+");
453         EXPECT(mt, plus_type, "+");
454         EXPECT(mt, plus_type, "+");
455         EXPECT(mt, eof_type, "<<EOF>>");
456         EXPECT(mt, eof_type, "<<EOF>>");
457     }
458 
459     {
460         std::istringstream iss("\n+\n++\n");
461         tokenizer mt(iss, false);
462 
463         EXPECT(mt, nl_type, "<<NEWLINE>>");
464         EXPECT(mt, plus_type, "+");
465         EXPECT(mt, nl_type, "<<NEWLINE>>");
466         EXPECT(mt, plus_type, "+");
467         EXPECT(mt, plus_type, "+");
468         EXPECT(mt, nl_type, "<<NEWLINE>>");
469         EXPECT(mt, eof_type, "<<EOF>>");
470         EXPECT(mt, eof_type, "<<EOF>>");
471     }
472 
473     {
474         std::istringstream iss("foo+bar=baz");
475         tokenizer mt(iss, false);
476 
477         EXPECT(mt, word_type, "foo");
478         EXPECT(mt, plus_type, "+");
479         EXPECT(mt, word_type, "bar");
480         EXPECT(mt, equal_type, "=");
481         EXPECT(mt, word_type, "baz");
482         EXPECT(mt, eof_type, "<<EOF>>");
483         EXPECT(mt, eof_type, "<<EOF>>");
484     }
485 
486     {
487         std::istringstream iss(" foo\t+\tbar = baz ");
488         tokenizer mt(iss, false);
489 
490         EXPECT(mt, word_type, " foo\t");
491         EXPECT(mt, plus_type, "+");
492         EXPECT(mt, word_type, "\tbar ");
493         EXPECT(mt, equal_type, "=");
494         EXPECT(mt, word_type, " baz ");
495         EXPECT(mt, eof_type, "<<EOF>>");
496         EXPECT(mt, eof_type, "<<EOF>>");
497     }
498 }
499 
500 ATF_TEST_CASE(tokenizer_delims_ws);
501 ATF_TEST_CASE_HEAD(tokenizer_delims_ws)
502 {
503     set_md_var("descr", "Tests the tokenizer class using a parser with some "
504                "additional delimiters and skipping whitespace");
505 }
506 ATF_TEST_CASE_BODY(tokenizer_delims_ws)
507 {
508     using namespace delims;
509 
510     {
511         std::istringstream iss(" foo\t+\tbar = baz ");
512         tokenizer mt(iss, true);
513 
514         EXPECT(mt, word_type, "foo");
515         EXPECT(mt, plus_type, "+");
516         EXPECT(mt, word_type, "bar");
517         EXPECT(mt, equal_type, "=");
518         EXPECT(mt, word_type, "baz");
519         EXPECT(mt, eof_type, "<<EOF>>");
520         EXPECT(mt, eof_type, "<<EOF>>");
521     }
522 }
523 
524 ATF_TEST_CASE(tokenizer_keywords_nows);
525 ATF_TEST_CASE_HEAD(tokenizer_keywords_nows)
526 {
527     set_md_var("descr", "Tests the tokenizer class using a parser with some "
528                "additional keywords and not skipping whitespace");
529 }
530 ATF_TEST_CASE_BODY(tokenizer_keywords_nows)
531 {
532     using namespace keywords;
533 
534     {
535         std::istringstream iss("var");
536         tokenizer mt(iss, false);
537 
538         EXPECT(mt, var_type, "var");
539         EXPECT(mt, eof_type, "<<EOF>>");
540         EXPECT(mt, eof_type, "<<EOF>>");
541     }
542 
543     {
544         std::istringstream iss("va");
545         tokenizer mt(iss, false);
546 
547         EXPECT(mt, word_type, "va");
548         EXPECT(mt, eof_type, "<<EOF>>");
549         EXPECT(mt, eof_type, "<<EOF>>");
550     }
551 
552     {
553         std::istringstream iss("vara");
554         tokenizer mt(iss, false);
555 
556         EXPECT(mt, word_type, "vara");
557         EXPECT(mt, eof_type, "<<EOF>>");
558         EXPECT(mt, eof_type, "<<EOF>>");
559     }
560 
561     {
562         std::istringstream iss("var ");
563         tokenizer mt(iss, false);
564 
565         EXPECT(mt, word_type, "var ");
566         EXPECT(mt, eof_type, "<<EOF>>");
567         EXPECT(mt, eof_type, "<<EOF>>");
568     }
569 
570     {
571         std::istringstream iss("var\nloop\nendloop");
572         tokenizer mt(iss, false);
573 
574         EXPECT(mt, var_type, "var");
575         EXPECT(mt, nl_type, "<<NEWLINE>>");
576         EXPECT(mt, loop_type, "loop");
577         EXPECT(mt, nl_type, "<<NEWLINE>>");
578         EXPECT(mt, endloop_type, "endloop");
579         EXPECT(mt, eof_type, "<<EOF>>");
580         EXPECT(mt, eof_type, "<<EOF>>");
581     }
582 }
583 
584 ATF_TEST_CASE(tokenizer_keywords_ws);
585 ATF_TEST_CASE_HEAD(tokenizer_keywords_ws)
586 {
587     set_md_var("descr", "Tests the tokenizer class using a parser with some "
588                "additional keywords and not skipping whitespace");
589 }
590 ATF_TEST_CASE_BODY(tokenizer_keywords_ws)
591 {
592     using namespace keywords;
593 
594     {
595         std::istringstream iss("var ");
596         tokenizer mt(iss, true);
597 
598         EXPECT(mt, var_type, "var");
599         EXPECT(mt, eof_type, "<<EOF>>");
600         EXPECT(mt, eof_type, "<<EOF>>");
601     }
602 
603     {
604         std::istringstream iss(" var \n\tloop\t\n \tendloop \t");
605         tokenizer mt(iss, true);
606 
607         EXPECT(mt, var_type, "var");
608         EXPECT(mt, nl_type, "<<NEWLINE>>");
609         EXPECT(mt, loop_type, "loop");
610         EXPECT(mt, nl_type, "<<NEWLINE>>");
611         EXPECT(mt, endloop_type, "endloop");
612         EXPECT(mt, eof_type, "<<EOF>>");
613         EXPECT(mt, eof_type, "<<EOF>>");
614     }
615 
616     {
617         std::istringstream iss("var loop endloop");
618         tokenizer mt(iss, true);
619 
620         EXPECT(mt, var_type, "var");
621         EXPECT(mt, loop_type, "loop");
622         EXPECT(mt, endloop_type, "endloop");
623         EXPECT(mt, eof_type, "<<EOF>>");
624         EXPECT(mt, eof_type, "<<EOF>>");
625     }
626 }
627 
628 ATF_TEST_CASE(tokenizer_quotes_nows);
629 ATF_TEST_CASE_HEAD(tokenizer_quotes_nows)
630 {
631     set_md_var("descr", "Tests the tokenizer class using a parser with "
632                "quoted strings and not skipping whitespace");
633 }
634 ATF_TEST_CASE_BODY(tokenizer_quotes_nows)
635 {
636     using namespace quotes;
637 
638     {
639         std::istringstream iss("var");
640         tokenizer mt(iss, false);
641 
642         EXPECT(mt, word_type, "var");
643         EXPECT(mt, eof_type, "<<EOF>>");
644         EXPECT(mt, eof_type, "<<EOF>>");
645     }
646 
647     {
648         std::istringstream iss("\"var\"");
649         tokenizer mt(iss, false);
650 
651         EXPECT(mt, word_type, "var");
652         EXPECT(mt, eof_type, "<<EOF>>");
653         EXPECT(mt, eof_type, "<<EOF>>");
654     }
655 
656     {
657         std::istringstream iss("var1\"var2\"");
658         tokenizer mt(iss, false);
659 
660         EXPECT(mt, word_type, "var1");
661         EXPECT(mt, word_type, "var2");
662         EXPECT(mt, eof_type, "<<EOF>>");
663         EXPECT(mt, eof_type, "<<EOF>>");
664     }
665 
666     {
667         std::istringstream iss("var1\"  var2  \"");
668         tokenizer mt(iss, false);
669 
670         EXPECT(mt, word_type, "var1");
671         EXPECT(mt, word_type, "  var2  ");
672         EXPECT(mt, eof_type, "<<EOF>>");
673         EXPECT(mt, eof_type, "<<EOF>>");
674     }
675 }
676 
677 ATF_TEST_CASE(tokenizer_quotes_ws);
678 ATF_TEST_CASE_HEAD(tokenizer_quotes_ws)
679 {
680     set_md_var("descr", "Tests the tokenizer class using a parser with "
681                "quoted strings and skipping whitespace");
682 }
683 ATF_TEST_CASE_BODY(tokenizer_quotes_ws)
684 {
685     using namespace quotes;
686 
687     {
688         std::istringstream iss("  var  ");
689         tokenizer mt(iss, true);
690 
691         EXPECT(mt, word_type, "var");
692         EXPECT(mt, eof_type, "<<EOF>>");
693         EXPECT(mt, eof_type, "<<EOF>>");
694     }
695 
696     {
697         std::istringstream iss("  \"var\"  ");
698         tokenizer mt(iss, true);
699 
700         EXPECT(mt, word_type, "var");
701         EXPECT(mt, eof_type, "<<EOF>>");
702         EXPECT(mt, eof_type, "<<EOF>>");
703     }
704 
705     {
706         std::istringstream iss("  var1  \"var2\"  ");
707         tokenizer mt(iss, true);
708 
709         EXPECT(mt, word_type, "var1");
710         EXPECT(mt, word_type, "var2");
711         EXPECT(mt, eof_type, "<<EOF>>");
712         EXPECT(mt, eof_type, "<<EOF>>");
713     }
714 
715     {
716         std::istringstream iss("  var1  \"  var2  \"  ");
717         tokenizer mt(iss, true);
718 
719         EXPECT(mt, word_type, "var1");
720         EXPECT(mt, word_type, "  var2  ");
721         EXPECT(mt, eof_type, "<<EOF>>");
722         EXPECT(mt, eof_type, "<<EOF>>");
723     }
724 }
725 
726 // ------------------------------------------------------------------------
727 // Tests for the headers parser.
728 // ------------------------------------------------------------------------
729 
730 class header_reader {
731     std::istream& m_is;
732 
733 public:
734     header_reader(std::istream& is) :
735         m_is(is)
736     {
737     }
738 
739     void
740     read(void)
741     {
742         std::pair< size_t, tools::parser::headers_map > hml =
743             tools::parser::read_headers(m_is, 1);
744         tools::parser::validate_content_type(hml.second,
745             "application/X-atf-headers-test", 1234);
746     }
747 
748     std::vector< std::string > m_calls;
749 };
750 
751 ATF_TEST_CASE_WITHOUT_HEAD(headers_1);
752 ATF_TEST_CASE_BODY(headers_1)
753 {
754     const char* input =
755         ""
756     ;
757 
758     const char* exp_calls[] = {
759         NULL
760     };
761 
762     const char* exp_errors[] = {
763         "1: Unexpected token `<<EOF>>'; expected a header name",
764         NULL
765     };
766 
767     do_parser_test< header_reader >(input, exp_calls, exp_errors);
768 }
769 
770 ATF_TEST_CASE_WITHOUT_HEAD(headers_2);
771 ATF_TEST_CASE_BODY(headers_2)
772 {
773     const char* input =
774         "Content-Type\n"
775     ;
776 
777     const char* exp_calls[] = {
778         NULL
779     };
780 
781     const char* exp_errors[] = {
782         "1: Unexpected token `<<NEWLINE>>'; expected `:'",
783         NULL
784     };
785 
786     do_parser_test< header_reader >(input, exp_calls, exp_errors);
787 }
788 
789 ATF_TEST_CASE_WITHOUT_HEAD(headers_3);
790 ATF_TEST_CASE_BODY(headers_3)
791 {
792     const char* input =
793         "Content-Type:\n"
794     ;
795 
796     const char* exp_calls[] = {
797         NULL
798     };
799 
800     const char* exp_errors[] = {
801         "1: Unexpected token `<<NEWLINE>>'; expected a textual value",
802         NULL
803     };
804 
805     do_parser_test< header_reader >(input, exp_calls, exp_errors);
806 }
807 
808 ATF_TEST_CASE_WITHOUT_HEAD(headers_4);
809 ATF_TEST_CASE_BODY(headers_4)
810 {
811     const char* input =
812         "Content-Type: application/X-atf-headers-test\n"
813     ;
814 
815     const char* exp_calls[] = {
816         NULL
817     };
818 
819     const char* exp_errors[] = {
820         "2: Unexpected token `<<EOF>>'; expected a header name",
821         NULL
822     };
823 
824     do_parser_test< header_reader >(input, exp_calls, exp_errors);
825 }
826 
827 ATF_TEST_CASE_WITHOUT_HEAD(headers_5);
828 ATF_TEST_CASE_BODY(headers_5)
829 {
830     const char* input =
831         "Content-Type: application/X-atf-headers-test;\n"
832     ;
833 
834     const char* exp_calls[] = {
835         NULL
836     };
837 
838     const char* exp_errors[] = {
839         "1: Unexpected token `<<NEWLINE>>'; expected an attribute name",
840         NULL
841     };
842 
843     do_parser_test< header_reader >(input, exp_calls, exp_errors);
844 }
845 
846 ATF_TEST_CASE_WITHOUT_HEAD(headers_6);
847 ATF_TEST_CASE_BODY(headers_6)
848 {
849     const char* input =
850         "Content-Type: application/X-atf-headers-test; version\n"
851     ;
852 
853     const char* exp_calls[] = {
854         NULL
855     };
856 
857     const char* exp_errors[] = {
858         "1: Unexpected token `<<NEWLINE>>'; expected `='",
859         NULL
860     };
861 
862     do_parser_test< header_reader >(input, exp_calls, exp_errors);
863 }
864 
865 ATF_TEST_CASE_WITHOUT_HEAD(headers_7);
866 ATF_TEST_CASE_BODY(headers_7)
867 {
868     const char* input =
869         "Content-Type: application/X-atf-headers-test; version=\n"
870     ;
871 
872     const char* exp_calls[] = {
873         NULL
874     };
875 
876     const char* exp_errors[] = {
877         "1: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
878         NULL
879     };
880 
881     do_parser_test< header_reader >(input, exp_calls, exp_errors);
882 }
883 
884 ATF_TEST_CASE_WITHOUT_HEAD(headers_8);
885 ATF_TEST_CASE_BODY(headers_8)
886 {
887     const char* input =
888         "Content-Type: application/X-atf-headers-test; version=\"1234\n"
889     ;
890 
891     const char* exp_calls[] = {
892         NULL
893     };
894 
895     const char* exp_errors[] = {
896         "1: Missing double quotes before end of line",
897         NULL
898     };
899 
900     do_parser_test< header_reader >(input, exp_calls, exp_errors);
901 }
902 
903 ATF_TEST_CASE_WITHOUT_HEAD(headers_9);
904 ATF_TEST_CASE_BODY(headers_9)
905 {
906     const char* input =
907         "Content-Type: application/X-atf-headers-test; version=1234\"\n"
908     ;
909 
910     const char* exp_calls[] = {
911         NULL
912     };
913 
914     const char* exp_errors[] = {
915         "1: Missing double quotes before end of line",
916         NULL
917     };
918 
919     do_parser_test< header_reader >(input, exp_calls, exp_errors);
920 }
921 
922 ATF_TEST_CASE_WITHOUT_HEAD(headers_10);
923 ATF_TEST_CASE_BODY(headers_10)
924 {
925     const char* input =
926         "Content-Type: application/X-atf-headers-test; version=1234\n"
927     ;
928 
929     const char* exp_calls[] = {
930         NULL
931     };
932 
933     const char* exp_errors[] = {
934         "2: Unexpected token `<<EOF>>'; expected a header name",
935         NULL
936     };
937 
938     do_parser_test< header_reader >(input, exp_calls, exp_errors);
939 }
940 
941 ATF_TEST_CASE_WITHOUT_HEAD(headers_11);
942 ATF_TEST_CASE_BODY(headers_11)
943 {
944     const char* input =
945         "Content-Type: application/X-atf-headers-test; version=\"1234\"\n"
946     ;
947 
948     const char* exp_calls[] = {
949         NULL
950     };
951 
952     const char* exp_errors[] = {
953         "2: Unexpected token `<<EOF>>'; expected a header name",
954         NULL
955     };
956 
957     do_parser_test< header_reader >(input, exp_calls, exp_errors);
958 }
959 
960 ATF_TEST_CASE_WITHOUT_HEAD(headers_12);
961 ATF_TEST_CASE_BODY(headers_12)
962 {
963     const char* input =
964         "Content-Type: application/X-atf-headers-test; version=\"1234\"\n"
965         "a b\n"
966         "a-b:\n"
967         "a-b: foo;\n"
968         "a-b: foo; var\n"
969         "a-b: foo; var=\n"
970         "a-b: foo; var=\"a\n"
971         "a-b: foo; var=a\"\n"
972         "a-b: foo; var=\"a\";\n"
973         "a-b: foo; var=\"a\"; second\n"
974         "a-b: foo; var=\"a\"; second=\n"
975         "a-b: foo; var=\"a\"; second=\"b\n"
976         "a-b: foo; var=\"a\"; second=b\"\n"
977         "a-b: foo; var=\"a\"; second=\"b\"\n"
978     ;
979 
980     const char* exp_calls[] = {
981         NULL
982     };
983 
984     const char* exp_errors[] = {
985         "2: Unexpected token `b'; expected `:'",
986         "3: Unexpected token `<<NEWLINE>>'; expected a textual value",
987         "4: Unexpected token `<<NEWLINE>>'; expected an attribute name",
988         "5: Unexpected token `<<NEWLINE>>'; expected `='",
989         "6: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
990         "7: Missing double quotes before end of line",
991         "8: Missing double quotes before end of line",
992         "9: Unexpected token `<<NEWLINE>>'; expected an attribute name",
993         "10: Unexpected token `<<NEWLINE>>'; expected `='",
994         "11: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
995         "12: Missing double quotes before end of line",
996         "13: Missing double quotes before end of line",
997         NULL
998     };
999 
1000     do_parser_test< header_reader >(input, exp_calls, exp_errors);
1001 }
1002 
1003 // ------------------------------------------------------------------------
1004 // Main.
1005 // ------------------------------------------------------------------------
1006 
1007 ATF_INIT_TEST_CASES(tcs)
1008 {
1009     // Add test cases for the "parse_error" class.
1010     ATF_ADD_TEST_CASE(tcs, parse_error_to_string);
1011 
1012     // Add test cases for the "parse_errors" class.
1013     ATF_ADD_TEST_CASE(tcs, parse_errors_what);
1014 
1015     // Add test cases for the "token" class.
1016     ATF_ADD_TEST_CASE(tcs, token_getters);
1017 
1018     // Add test cases for the "tokenizer" class.
1019     ATF_ADD_TEST_CASE(tcs, tokenizer_minimal_nows);
1020     ATF_ADD_TEST_CASE(tcs, tokenizer_minimal_ws);
1021     ATF_ADD_TEST_CASE(tcs, tokenizer_delims_nows);
1022     ATF_ADD_TEST_CASE(tcs, tokenizer_delims_ws);
1023     ATF_ADD_TEST_CASE(tcs, tokenizer_keywords_nows);
1024     ATF_ADD_TEST_CASE(tcs, tokenizer_keywords_ws);
1025     ATF_ADD_TEST_CASE(tcs, tokenizer_quotes_nows);
1026     ATF_ADD_TEST_CASE(tcs, tokenizer_quotes_ws);
1027 
1028     // Add the tests for the headers parser.
1029 
1030     // Add the test cases for the header file.
1031     ATF_ADD_TEST_CASE(tcs, headers_1);
1032     ATF_ADD_TEST_CASE(tcs, headers_2);
1033     ATF_ADD_TEST_CASE(tcs, headers_3);
1034     ATF_ADD_TEST_CASE(tcs, headers_4);
1035     ATF_ADD_TEST_CASE(tcs, headers_5);
1036     ATF_ADD_TEST_CASE(tcs, headers_6);
1037     ATF_ADD_TEST_CASE(tcs, headers_7);
1038     ATF_ADD_TEST_CASE(tcs, headers_8);
1039     ATF_ADD_TEST_CASE(tcs, headers_9);
1040     ATF_ADD_TEST_CASE(tcs, headers_10);
1041     ATF_ADD_TEST_CASE(tcs, headers_11);
1042     ATF_ADD_TEST_CASE(tcs, headers_12);
1043 }
1044