]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/atf/atf-run/atffile_test.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / atf / atf-run / atffile_test.cpp
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2009 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 extern "C" {
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 }
34
35 #include <algorithm>
36 #include <fstream>
37 #include <memory>
38
39 #include "atf-c++/macros.hpp"
40
41 #include "atf-c++/detail/exceptions.hpp"
42 #include "atf-c++/detail/test_helpers.hpp"
43
44 #include "atffile.hpp"
45
46 namespace detail = atf::atf_run::detail;
47
48 // ------------------------------------------------------------------------
49 // Auxiliary functions.
50 // ------------------------------------------------------------------------
51
52 namespace {
53
54 static
55 std::auto_ptr< std::ofstream >
56 new_atffile(void)
57 {
58     std::auto_ptr< std::ofstream > os(new std::ofstream("Atffile"));
59     ATF_REQUIRE(*os);
60
61     (*os) << "Content-Type: application/X-atf-atffile; version=\"1\"\n\n";
62     return os;
63 }
64
65 static
66 void
67 touch_exec(const char* name)
68 {
69     std::ofstream os(name);
70     ATF_REQUIRE(os);
71     os.close();
72     ATF_REQUIRE(::chmod(name, S_IRWXU) != -1);
73 }
74
75 static inline
76 bool
77 is_in(const std::string& value, const std::vector< std::string >& v)
78 {
79     return std::find(v.begin(), v.end(), value) != v.end();
80 }
81
82 } // anonymous namespace
83
84 // ------------------------------------------------------------------------
85 // Tests cases for the "atffile" parser.
86 // ------------------------------------------------------------------------
87
88 class atffile_reader : protected detail::atf_atffile_reader {
89     void
90     got_conf(const std::string& name, const std::string& val)
91     {
92         m_calls.push_back("got_conf(" + name + ", " + val + ")");
93     }
94
95     void
96     got_prop(const std::string& name, const std::string& val)
97     {
98         m_calls.push_back("got_prop(" + name + ", " + val + ")");
99     }
100
101     void
102     got_tp(const std::string& name, bool isglob)
103     {
104         m_calls.push_back("got_tp(" + name + ", " + (isglob ? "true" : "false")
105                   + ")");
106     }
107
108     void
109     got_eof(void)
110     {
111         m_calls.push_back("got_eof()");
112     }
113
114 public:
115     atffile_reader(std::istream& is) :
116         detail::atf_atffile_reader(is)
117     {
118     }
119
120     void
121     read(void)
122     {
123         atf_atffile_reader::read();
124     }
125
126     std::vector< std::string > m_calls;
127 };
128
129 ATF_TEST_CASE_WITHOUT_HEAD(atffile_1);
130 ATF_TEST_CASE_BODY(atffile_1)
131 {
132     const char* input =
133         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
134         "\n"
135     ;
136
137     const char* exp_calls[] = {
138         "got_eof()",
139         NULL
140     };
141
142     const char* exp_errors[] = {
143         NULL
144     };
145
146     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
147 }
148
149 ATF_TEST_CASE_WITHOUT_HEAD(atffile_2);
150 ATF_TEST_CASE_BODY(atffile_2)
151 {
152     const char* input =
153         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
154         "\n"
155         "# This is a comment on a line of its own.\n"
156         "# And this is another one.\n"
157         "\n"
158         "           # Another after some whitespace.\n"
159         "\n"
160         "# The last one after an empty line.\n"
161     ;
162
163     const char* exp_calls[] = {
164         "got_eof()",
165         NULL
166     };
167
168     const char* exp_errors[] = {
169         NULL
170     };
171
172     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
173 }
174
175 ATF_TEST_CASE_WITHOUT_HEAD(atffile_3);
176 ATF_TEST_CASE_BODY(atffile_3)
177 {
178     const char* input =
179         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
180         "\n"
181         "conf: var1=value1\n"
182         "conf: var2 = value2\n"
183         "conf: var3     =       value3\n"
184         "conf: var4         =       value4\n"
185         "\n"
186         "conf:var5=value5\n"
187         "    conf:var6=value6\n"
188         "\n"
189         "conf: var7 = \"This is a long value.\"\n"
190         "conf: var8 = \"Single-word\"\n"
191         "conf: var9 = \"    Single-word \"\n"
192         "conf: var10 = Single-word\n"
193     ;
194
195     const char* exp_calls[] = {
196         "got_conf(var1, value1)",
197         "got_conf(var2, value2)",
198         "got_conf(var3, value3)",
199         "got_conf(var4, value4)",
200         "got_conf(var5, value5)",
201         "got_conf(var6, value6)",
202         "got_conf(var7, This is a long value.)",
203         "got_conf(var8, Single-word)",
204         "got_conf(var9,     Single-word )",
205         "got_conf(var10, Single-word)",
206         "got_eof()",
207         NULL
208     };
209
210     const char* exp_errors[] = {
211         NULL
212     };
213
214     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
215 }
216
217 ATF_TEST_CASE_WITHOUT_HEAD(atffile_4);
218 ATF_TEST_CASE_BODY(atffile_4)
219 {
220     const char* input =
221         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
222         "\n"
223         "prop: var1=value1\n"
224         "prop: var2 = value2\n"
225         "prop: var3     =       value3\n"
226         "prop: var4         =       value4\n"
227         "\n"
228         "prop:var5=value5\n"
229         "    prop:var6=value6\n"
230         "\n"
231         "prop: var7 = \"This is a long value.\"\n"
232         "prop: var8 = \"Single-word\"\n"
233         "prop: var9 = \"    Single-word \"\n"
234         "prop: var10 = Single-word\n"
235     ;
236
237     const char* exp_calls[] = {
238         "got_prop(var1, value1)",
239         "got_prop(var2, value2)",
240         "got_prop(var3, value3)",
241         "got_prop(var4, value4)",
242         "got_prop(var5, value5)",
243         "got_prop(var6, value6)",
244         "got_prop(var7, This is a long value.)",
245         "got_prop(var8, Single-word)",
246         "got_prop(var9,     Single-word )",
247         "got_prop(var10, Single-word)",
248         "got_eof()",
249         NULL
250     };
251
252     const char* exp_errors[] = {
253         NULL
254     };
255
256     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
257 }
258
259 ATF_TEST_CASE_WITHOUT_HEAD(atffile_5);
260 ATF_TEST_CASE_BODY(atffile_5)
261 {
262     const char* input =
263         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
264         "\n"
265         "tp:foo\n"
266         "tp: foo\n"
267         "tp:  foo\n"
268         "tp:    foo\n"
269         "tp:        foo\n"
270         "tp: \"name with spaces\"\n"
271         "tp: \"single-word\"\n"
272         "tp: single-word\n"
273         "\n"
274         "tp-glob:foo*?bar\n"
275         "tp-glob: foo*?bar\n"
276         "tp-glob:  foo*?bar\n"
277         "tp-glob:       foo*?bar\n"
278         "tp-glob:           foo*?bar\n"
279         "tp-glob: \"glob * with ? spaces\"\n"
280         "tp-glob: \"single-*-word\"\n"
281         "tp-glob: single-*-word\n"
282     ;
283
284     const char* exp_calls[] = {
285         "got_tp(foo, false)",
286         "got_tp(foo, false)",
287         "got_tp(foo, false)",
288         "got_tp(foo, false)",
289         "got_tp(foo, false)",
290         "got_tp(name with spaces, false)",
291         "got_tp(single-word, false)",
292         "got_tp(single-word, false)",
293         "got_tp(foo*?bar, true)",
294         "got_tp(foo*?bar, true)",
295         "got_tp(foo*?bar, true)",
296         "got_tp(foo*?bar, true)",
297         "got_tp(foo*?bar, true)",
298         "got_tp(glob * with ? spaces, true)",
299         "got_tp(single-*-word, true)",
300         "got_tp(single-*-word, true)",
301         "got_eof()",
302         NULL
303     };
304
305     const char* exp_errors[] = {
306         NULL
307     };
308
309     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
310 }
311
312 ATF_TEST_CASE_WITHOUT_HEAD(atffile_6);
313 ATF_TEST_CASE_BODY(atffile_6)
314 {
315     const char* input =
316         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
317         "\n"
318         "prop: foo = bar # A comment.\n"
319         "conf: foo = bar # A comment.\n"
320         "tp: foo # A comment.\n"
321         "tp-glob: foo # A comment.\n"
322     ;
323
324     const char* exp_calls[] = {
325         "got_prop(foo, bar)",
326         "got_conf(foo, bar)",
327         "got_tp(foo, false)",
328         "got_tp(foo, true)",
329         "got_eof()",
330         NULL
331     };
332
333     const char* exp_errors[] = {
334         NULL
335     };
336
337     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
338 }
339
340 ATF_TEST_CASE_WITHOUT_HEAD(atffile_50);
341 ATF_TEST_CASE_BODY(atffile_50)
342 {
343     const char* input =
344         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
345         "\n"
346         "foo\n"
347     ;
348
349     const char* exp_calls[] = {
350         NULL
351     };
352
353     // NO_CHECK_STYLE_BEGIN
354     const char* exp_errors[] = {
355         "3: Unexpected token `foo'; expected conf, #, prop, tp, tp-glob, a new line or eof",
356         NULL
357     };
358     // NO_CHECK_STYLE_END
359
360     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
361 }
362
363 ATF_TEST_CASE_WITHOUT_HEAD(atffile_51);
364 ATF_TEST_CASE_BODY(atffile_51)
365 {
366     const char* input =
367         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
368         "\n"
369         "foo bar\n"
370         "baz\n"
371     ;
372
373     const char* exp_calls[] = {
374         NULL
375     };
376
377     // NO_CHECK_STYLE_BEGIN
378     const char* exp_errors[] = {
379         "3: Unexpected token `foo'; expected conf, #, prop, tp, tp-glob, a new line or eof",
380         "4: Unexpected token `baz'; expected conf, #, prop, tp, tp-glob, a new line or eof",
381         NULL
382     };
383     // NO_CHECK_STYLE_END
384
385     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
386 }
387
388 ATF_TEST_CASE_WITHOUT_HEAD(atffile_52);
389 ATF_TEST_CASE_BODY(atffile_52)
390 {
391     const char* input =
392         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
393         "\n"
394         "conf\n"
395         "conf:\n"
396         "conf: foo =\n"
397         "conf: bar = # A comment.\n"
398         "\n"
399         "prop\n"
400         "prop:\n"
401         "prop: foo =\n"
402         "prop: bar = # A comment.\n"
403         "\n"
404         "tp\n"
405         "tp:\n"
406         "tp: # A comment.\n"
407         "\n"
408         "tp-glob\n"
409         "tp-glob:\n"
410         "tp-glob: # A comment.\n"
411     ;
412
413     const char* exp_calls[] = {
414         NULL
415     };
416
417     const char* exp_errors[] = {
418         "3: Unexpected token `<<NEWLINE>>'; expected `:'",
419         "4: Unexpected token `<<NEWLINE>>'; expected variable name",
420         "5: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
421         "6: Unexpected token `#'; expected word or quoted string",
422         "8: Unexpected token `<<NEWLINE>>'; expected `:'",
423         "9: Unexpected token `<<NEWLINE>>'; expected property name",
424         "10: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
425         "11: Unexpected token `#'; expected word or quoted string",
426         "13: Unexpected token `<<NEWLINE>>'; expected `:'",
427         "14: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
428         "15: Unexpected token `#'; expected word or quoted string",
429         "17: Unexpected token `<<NEWLINE>>'; expected `:'",
430         "18: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
431         "19: Unexpected token `#'; expected word or quoted string",
432         NULL
433     };
434
435     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
436 }
437
438 ATF_TEST_CASE_WITHOUT_HEAD(atffile_53);
439 ATF_TEST_CASE_BODY(atffile_53)
440 {
441     const char* input =
442         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
443         "\n"
444         "prop: foo = \"Correct value\" # With comment.\n"
445         "\n"
446         "prop: bar = # A comment.\n"
447         "\n"
448         "prop: baz = \"Last variable\"\n"
449         "\n"
450         "# End of file.\n"
451     ;
452
453     const char* exp_calls[] = {
454         "got_prop(foo, Correct value)",
455         NULL
456     };
457
458     const char* exp_errors[] = {
459         "5: Unexpected token `#'; expected word or quoted string",
460         NULL
461     };
462
463     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
464 }
465
466 ATF_TEST_CASE_WITHOUT_HEAD(atffile_54);
467 ATF_TEST_CASE_BODY(atffile_54)
468 {
469     const char* input =
470         "Content-Type: application/X-atf-atffile; version=\"1\"\n"
471         "\n"
472         "prop: foo = \"\n"
473         "prop: bar = \"text\n"
474         "prop: baz = \"te\\\"xt\n"
475         "prop: last = \"\\\"\n"
476     ;
477
478     const char* exp_calls[] = {
479         NULL
480     };
481
482     const char* exp_errors[] = {
483         "3: Missing double quotes before end of line",
484         "4: Missing double quotes before end of line",
485         "5: Missing double quotes before end of line",
486         "6: Missing double quotes before end of line",
487         NULL
488     };
489
490     do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
491 }
492
493 // ------------------------------------------------------------------------
494 // Tests cases for the "atffile" class.
495 // ------------------------------------------------------------------------
496
497 ATF_TEST_CASE(atffile_getters);
498 ATF_TEST_CASE_HEAD(atffile_getters) {}
499 ATF_TEST_CASE_BODY(atffile_getters) {
500     atf::tests::vars_map config_vars;
501     config_vars["config-var-1"] = "value 1";
502
503     std::vector< std::string > test_program_names;
504     test_program_names.push_back("test-program-1");
505
506     atf::tests::vars_map properties;
507     properties["test-suite"] = "a test name";
508
509     const atf::atf_run::atffile atffile(config_vars, test_program_names,
510                                         properties);
511     ATF_REQUIRE(config_vars == atffile.conf());
512     ATF_REQUIRE(test_program_names == atffile.tps());
513     ATF_REQUIRE(properties == atffile.props());
514 }
515
516 // ------------------------------------------------------------------------
517 // Tests cases for the free functions.
518 // ------------------------------------------------------------------------
519
520 ATF_TEST_CASE_WITHOUT_HEAD(read_ok_simple);
521 ATF_TEST_CASE_BODY(read_ok_simple) {
522     std::auto_ptr< std::ofstream > os = new_atffile();
523     (*os) << "prop: test-suite = foo\n";
524     (*os) << "tp: tp-1\n";
525     (*os) << "conf: var1 = value1\n";
526     (*os) << "tp: tp-2\n";
527     (*os) << "tp: tp-3\n";
528     (*os) << "prop: prop1 = propvalue1\n";
529     (*os) << "conf: var2 = value2\n";
530     (*os).close();
531
532     touch_exec("tp-1");
533     touch_exec("tp-2");
534     touch_exec("tp-3");
535
536     const atf::atf_run::atffile atffile = atf::atf_run::read_atffile(
537         atf::fs::path("Atffile"));
538     ATF_REQUIRE_EQ(2, atffile.conf().size());
539     ATF_REQUIRE_EQ("value1", atffile.conf().find("var1")->second);
540     ATF_REQUIRE_EQ("value2", atffile.conf().find("var2")->second);
541     ATF_REQUIRE_EQ(3, atffile.tps().size());
542     ATF_REQUIRE(is_in("tp-1", atffile.tps()));
543     ATF_REQUIRE(is_in("tp-2", atffile.tps()));
544     ATF_REQUIRE(is_in("tp-3", atffile.tps()));
545     ATF_REQUIRE_EQ(2, atffile.props().size());
546     ATF_REQUIRE_EQ("foo", atffile.props().find("test-suite")->second);
547     ATF_REQUIRE_EQ("propvalue1", atffile.props().find("prop1")->second);
548 }
549
550 ATF_TEST_CASE_WITHOUT_HEAD(read_ok_some_globs);
551 ATF_TEST_CASE_BODY(read_ok_some_globs) {
552     std::auto_ptr< std::ofstream > os = new_atffile();
553     (*os) << "prop: test-suite = foo\n";
554     (*os) << "tp: foo\n";
555     (*os) << "tp-glob: *K*\n";
556     (*os) << "tp: bar\n";
557     (*os) << "tp-glob: t_*\n";
558     (*os).close();
559
560     touch_exec("foo");
561     touch_exec("bar");
562     touch_exec("aK");
563     touch_exec("KKKKK");
564     touch_exec("t_hello");
565     touch_exec("zzzt_hello");
566
567     const atf::atf_run::atffile atffile = atf::atf_run::read_atffile(
568         atf::fs::path("Atffile"));
569     ATF_REQUIRE_EQ(5, atffile.tps().size());
570     ATF_REQUIRE(is_in("foo", atffile.tps()));
571     ATF_REQUIRE(is_in("bar", atffile.tps()));
572     ATF_REQUIRE(is_in("aK", atffile.tps()));
573     ATF_REQUIRE(is_in("KKKKK", atffile.tps()));
574     ATF_REQUIRE(is_in("t_hello", atffile.tps()));
575 }
576
577 ATF_TEST_CASE_WITHOUT_HEAD(read_missing_test_suite);
578 ATF_TEST_CASE_BODY(read_missing_test_suite) {
579     std::auto_ptr< std::ofstream > os = new_atffile();
580     (*os).close();
581
582     try {
583         (void)atf::atf_run::read_atffile(atf::fs::path("Atffile"));
584         ATF_FAIL("Missing property 'test-suite' did not raise an error");
585     } catch (const atf::not_found_error< std::string >& e) {
586         ATF_REQUIRE_EQ("test-suite", e.get_value());
587     }
588 }
589
590 ATF_TEST_CASE_WITHOUT_HEAD(read_missing_test_program);
591 ATF_TEST_CASE_BODY(read_missing_test_program) {
592     std::auto_ptr< std::ofstream > os = new_atffile();
593     (*os) << "tp: foo\n";
594     (*os) << "tp: bar\n";
595     (*os) << "tp: baz\n";
596     (*os).close();
597
598     touch_exec("foo");
599     touch_exec("baz");
600
601     try {
602         (void)atf::atf_run::read_atffile(atf::fs::path("Atffile"));
603         ATF_FAIL("Missing file 'bar' did not raise an error");
604     } catch (const atf::not_found_error< atf::fs::path >& e) {
605         ATF_REQUIRE_EQ("bar", e.get_value().str());
606     }
607 }
608
609 // ------------------------------------------------------------------------
610 // Main.
611 // ------------------------------------------------------------------------
612
613 ATF_INIT_TEST_CASES(tcs)
614 {
615     // Add the test cases for the parser class.
616     ATF_ADD_TEST_CASE(tcs, atffile_1);
617     ATF_ADD_TEST_CASE(tcs, atffile_2);
618     ATF_ADD_TEST_CASE(tcs, atffile_3);
619     ATF_ADD_TEST_CASE(tcs, atffile_4);
620     ATF_ADD_TEST_CASE(tcs, atffile_5);
621     ATF_ADD_TEST_CASE(tcs, atffile_6);
622     ATF_ADD_TEST_CASE(tcs, atffile_50);
623     ATF_ADD_TEST_CASE(tcs, atffile_51);
624     ATF_ADD_TEST_CASE(tcs, atffile_52);
625     ATF_ADD_TEST_CASE(tcs, atffile_53);
626     ATF_ADD_TEST_CASE(tcs, atffile_54);
627
628     // Add the test cases for the atffile class.
629     ATF_ADD_TEST_CASE(tcs, atffile_getters);
630
631     // Add the test cases for the free functions.
632     ATF_ADD_TEST_CASE(tcs, read_ok_simple);
633     ATF_ADD_TEST_CASE(tcs, read_ok_some_globs);
634     ATF_ADD_TEST_CASE(tcs, read_missing_test_suite);
635     ATF_ADD_TEST_CASE(tcs, read_missing_test_program);
636 }