1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2007, 2008, 2009, 2010 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 "../macros.hpp"
33
34#include "parser.hpp"
35#include "test_helpers.hpp"
36
37// ------------------------------------------------------------------------
38// Tests for the "parse_error" class.
39// ------------------------------------------------------------------------
40
41ATF_TEST_CASE(parse_error_to_string);
42ATF_TEST_CASE_HEAD(parse_error_to_string)
43{
44    set_md_var("descr", "Tests the parse_error conversion to strings");
45}
46ATF_TEST_CASE_BODY(parse_error_to_string)
47{
48    using atf::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
58ATF_TEST_CASE(parse_errors_what);
59ATF_TEST_CASE_HEAD(parse_errors_what)
60{
61    set_md_var("descr", "Tests the parse_errors description");
62}
63ATF_TEST_CASE_BODY(parse_errors_what)
64{
65    using atf::parser::parse_error;
66    using atf::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
79ATF_TEST_CASE(token_getters);
80ATF_TEST_CASE_HEAD(token_getters)
81{
82    set_md_var("descr", "Tests the token getters");
83}
84ATF_TEST_CASE_BODY(token_getters)
85{
86    using atf::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        atf::parser::token t = tkz.next(); \
124        ATF_REQUIRE(t.type() == ttype); \
125        ATF_REQUIRE_EQ(t.text(), ttext); \
126    } while (false);
127
128namespace minimal {
129
130    static const atf::parser::token_type eof_type = 0;
131    static const atf::parser::token_type nl_type = 1;
132    static const atf::parser::token_type word_type = 2;
133
134    class tokenizer : public atf::parser::tokenizer< std::istream > {
135    public:
136        tokenizer(std::istream& is, bool skipws) :
137            atf::parser::tokenizer< std::istream >
138                (is, skipws, eof_type, nl_type, word_type)
139        {
140        }
141    };
142
143}
144
145namespace delims {
146
147    static const atf::parser::token_type eof_type = 0;
148    static const atf::parser::token_type nl_type = 1;
149    static const atf::parser::token_type word_type = 2;
150    static const atf::parser::token_type plus_type = 3;
151    static const atf::parser::token_type minus_type = 4;
152    static const atf::parser::token_type equal_type = 5;
153
154    class tokenizer : public atf::parser::tokenizer< std::istream > {
155    public:
156        tokenizer(std::istream& is, bool skipws) :
157            atf::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
168namespace keywords {
169
170    static const atf::parser::token_type eof_type = 0;
171    static const atf::parser::token_type nl_type = 1;
172    static const atf::parser::token_type word_type = 2;
173    static const atf::parser::token_type var_type = 3;
174    static const atf::parser::token_type loop_type = 4;
175    static const atf::parser::token_type endloop_type = 5;
176
177    class tokenizer : public atf::parser::tokenizer< std::istream > {
178    public:
179        tokenizer(std::istream& is, bool skipws) :
180            atf::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
191namespace quotes {
192
193    static const atf::parser::token_type eof_type = 0;
194    static const atf::parser::token_type nl_type = 1;
195    static const atf::parser::token_type word_type = 2;
196    static const atf::parser::token_type dblquote_type = 3;
197
198    class tokenizer : public atf::parser::tokenizer< std::istream > {
199    public:
200        tokenizer(std::istream& is, bool skipws) :
201            atf::parser::tokenizer< std::istream >
202                (is, skipws, eof_type, nl_type, word_type)
203        {
204            add_quote('"', dblquote_type);
205        }
206    };
207
208}
209
210ATF_TEST_CASE(tokenizer_minimal_nows);
211ATF_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}
216ATF_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
293ATF_TEST_CASE(tokenizer_minimal_ws);
294ATF_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}
299ATF_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
427ATF_TEST_CASE(tokenizer_delims_nows);
428ATF_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}
433ATF_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
500ATF_TEST_CASE(tokenizer_delims_ws);
501ATF_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}
506ATF_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
524ATF_TEST_CASE(tokenizer_keywords_nows);
525ATF_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}
530ATF_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
584ATF_TEST_CASE(tokenizer_keywords_ws);
585ATF_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}
590ATF_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
628ATF_TEST_CASE(tokenizer_quotes_nows);
629ATF_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}
634ATF_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
677ATF_TEST_CASE(tokenizer_quotes_ws);
678ATF_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}
683ATF_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
730class header_reader {
731    std::istream& m_is;
732
733public:
734    header_reader(std::istream& is) :
735        m_is(is)
736    {
737    }
738
739    void
740    read(void)
741    {
742        std::pair< size_t, atf::parser::headers_map > hml =
743            atf::parser::read_headers(m_is, 1);
744        atf::parser::validate_content_type(hml.second,
745            "application/X-atf-headers-test", 1234);
746    }
747
748    std::vector< std::string > m_calls;
749};
750
751ATF_TEST_CASE_WITHOUT_HEAD(headers_1);
752ATF_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
770ATF_TEST_CASE_WITHOUT_HEAD(headers_2);
771ATF_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
789ATF_TEST_CASE_WITHOUT_HEAD(headers_3);
790ATF_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
808ATF_TEST_CASE_WITHOUT_HEAD(headers_4);
809ATF_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
827ATF_TEST_CASE_WITHOUT_HEAD(headers_5);
828ATF_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
846ATF_TEST_CASE_WITHOUT_HEAD(headers_6);
847ATF_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
865ATF_TEST_CASE_WITHOUT_HEAD(headers_7);
866ATF_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
884ATF_TEST_CASE_WITHOUT_HEAD(headers_8);
885ATF_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
903ATF_TEST_CASE_WITHOUT_HEAD(headers_9);
904ATF_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
922ATF_TEST_CASE_WITHOUT_HEAD(headers_10);
923ATF_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
941ATF_TEST_CASE_WITHOUT_HEAD(headers_11);
942ATF_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
960ATF_TEST_CASE_WITHOUT_HEAD(headers_12);
961ATF_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
1007ATF_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