1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 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 <atf-c++.hpp>
31 
32 #include "config.hpp"
33 #include "config_file.hpp"
34 #include "env.hpp"
35 #include "test_helpers.hpp"
36 
37 namespace impl = tools::config_file;
38 namespace detail = tools::config_file::detail;
39 
40 namespace {
41 
42 typedef std::map< std::string, std::string > vars_map;
43 
44 } // anonymous namespace
45 
46 namespace atf {
47 namespace config {
48 
49 void __reinit(void);
50 
51 }  // namespace config
52 }  // namespace atf
53 
54 // -------------------------------------------------------------------------
55 // Tests for the "config" parser.
56 // -------------------------------------------------------------------------
57 
58 class config_reader : protected detail::atf_config_reader {
59     void
got_var(const std::string & name,const std::string & val)60     got_var(const std::string& name, const std::string& val)
61     {
62         m_calls.push_back("got_var(" + name + ", " + val + ")");
63     }
64 
65     void
got_eof(void)66     got_eof(void)
67     {
68         m_calls.push_back("got_eof()");
69     }
70 
71 public:
config_reader(std::istream & is)72     config_reader(std::istream& is) :
73         detail::atf_config_reader(is)
74     {
75     }
76 
77     void
read(void)78     read(void)
79     {
80         atf_config_reader::read();
81     }
82 
83     std::vector< std::string > m_calls;
84 };
85 
86 ATF_TEST_CASE_WITHOUT_HEAD(config_1);
ATF_TEST_CASE_BODY(config_1)87 ATF_TEST_CASE_BODY(config_1)
88 {
89     const char* input =
90         "Content-Type: application/X-atf-config; version=\"1\"\n"
91         "\n"
92     ;
93 
94     const char* exp_calls[] = {
95         "got_eof()",
96         NULL
97     };
98 
99     const char* exp_errors[] = {
100         NULL
101     };
102 
103     do_parser_test< config_reader >(input, exp_calls, exp_errors);
104 }
105 
106 ATF_TEST_CASE_WITHOUT_HEAD(config_2);
ATF_TEST_CASE_BODY(config_2)107 ATF_TEST_CASE_BODY(config_2)
108 {
109     const char* input =
110         "Content-Type: application/X-atf-config; version=\"1\"\n"
111         "\n"
112         "# This is a comment on a line of its own.\n"
113         "# And this is another one.\n"
114         "\n"
115         "	    # Another after some whitespace.\n"
116         "\n"
117         "# The last one after an empty line.\n"
118     ;
119 
120     const char* exp_calls[] = {
121         "got_eof()",
122         NULL
123     };
124 
125     const char* exp_errors[] = {
126         NULL
127     };
128 
129     do_parser_test< config_reader >(input, exp_calls, exp_errors);
130 }
131 
132 ATF_TEST_CASE_WITHOUT_HEAD(config_3);
ATF_TEST_CASE_BODY(config_3)133 ATF_TEST_CASE_BODY(config_3)
134 {
135     const char* input =
136         "Content-Type: application/X-atf-config; version=\"1\"\n"
137         "\n"
138         "var1=value1\n"
139         "var2 = value2\n"
140         "var3	=	value3\n"
141         "var4	    =	    value4\n"
142         "\n"
143         "var5=value5\n"
144         "    var6=value6\n"
145         "\n"
146         "var7 = \"This is a long value.\"\n"
147         "var8 = \"Single-word\"\n"
148         "var9 = \"    Single-word	\"\n"
149         "var10 = Single-word\n"
150     ;
151 
152     const char* exp_calls[] = {
153         "got_var(var1, value1)",
154         "got_var(var2, value2)",
155         "got_var(var3, value3)",
156         "got_var(var4, value4)",
157         "got_var(var5, value5)",
158         "got_var(var6, value6)",
159         "got_var(var7, This is a long value.)",
160         "got_var(var8, Single-word)",
161         "got_var(var9,     Single-word	)",
162         "got_var(var10, Single-word)",
163         "got_eof()",
164         NULL
165     };
166 
167     const char* exp_errors[] = {
168         NULL
169     };
170 
171     do_parser_test< config_reader >(input, exp_calls, exp_errors);
172 }
173 
174 ATF_TEST_CASE_WITHOUT_HEAD(config_4);
ATF_TEST_CASE_BODY(config_4)175 ATF_TEST_CASE_BODY(config_4)
176 {
177     const char* input =
178         "Content-Type: application/X-atf-config; version=\"1\"\n"
179         "\n"
180         "foo = bar # A comment.\n"
181     ;
182 
183     const char* exp_calls[] = {
184         "got_var(foo, bar)",
185         "got_eof()",
186         NULL
187     };
188 
189     const char* exp_errors[] = {
190         NULL
191     };
192 
193     do_parser_test< config_reader >(input, exp_calls, exp_errors);
194 }
195 
196 ATF_TEST_CASE_WITHOUT_HEAD(config_50);
ATF_TEST_CASE_BODY(config_50)197 ATF_TEST_CASE_BODY(config_50)
198 {
199     const char* input =
200         "Content-Type: application/X-atf-config; version=\"1\"\n"
201         "\n"
202         "foo\n"
203     ;
204 
205     const char* exp_calls[] = {
206         NULL
207     };
208 
209     const char* exp_errors[] = {
210         "3: Unexpected token `<<NEWLINE>>'; expected equal sign",
211         NULL
212     };
213 
214     do_parser_test< config_reader >(input, exp_calls, exp_errors);
215 }
216 
217 ATF_TEST_CASE_WITHOUT_HEAD(config_51);
ATF_TEST_CASE_BODY(config_51)218 ATF_TEST_CASE_BODY(config_51)
219 {
220     const char* input =
221         "Content-Type: application/X-atf-config; version=\"1\"\n"
222         "\n"
223         "foo bar\n"
224         "baz\n"
225     ;
226 
227     const char* exp_calls[] = {
228         NULL
229     };
230 
231     const char* exp_errors[] = {
232         "3: Unexpected token `bar'; expected equal sign",
233         "4: Unexpected token `<<NEWLINE>>'; expected equal sign",
234         NULL
235     };
236 
237     do_parser_test< config_reader >(input, exp_calls, exp_errors);
238 }
239 
240 ATF_TEST_CASE_WITHOUT_HEAD(config_52);
ATF_TEST_CASE_BODY(config_52)241 ATF_TEST_CASE_BODY(config_52)
242 {
243     const char* input =
244         "Content-Type: application/X-atf-config; version=\"1\"\n"
245         "\n"
246         "foo =\n"
247         "bar = # A comment.\n"
248     ;
249 
250     const char* exp_calls[] = {
251         NULL
252     };
253 
254     const char* exp_errors[] = {
255         "3: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
256         "4: Unexpected token `#'; expected word or quoted string",
257         NULL
258     };
259 
260     do_parser_test< config_reader >(input, exp_calls, exp_errors);
261 }
262 
263 ATF_TEST_CASE_WITHOUT_HEAD(config_53);
ATF_TEST_CASE_BODY(config_53)264 ATF_TEST_CASE_BODY(config_53)
265 {
266     const char* input =
267         "Content-Type: application/X-atf-config; version=\"1\"\n"
268         "\n"
269         "foo = \"Correct value\" # With comment.\n"
270         "\n"
271         "bar = # A comment.\n"
272         "\n"
273         "baz = \"Last variable\"\n"
274         "\n"
275         "# End of file.\n"
276     ;
277 
278     const char* exp_calls[] = {
279         "got_var(foo, Correct value)",
280         NULL
281     };
282 
283     const char* exp_errors[] = {
284         "5: Unexpected token `#'; expected word or quoted string",
285         NULL
286     };
287 
288     do_parser_test< config_reader >(input, exp_calls, exp_errors);
289 }
290 
291 ATF_TEST_CASE_WITHOUT_HEAD(config_54);
ATF_TEST_CASE_BODY(config_54)292 ATF_TEST_CASE_BODY(config_54)
293 {
294     const char* input =
295         "Content-Type: application/X-atf-config; version=\"1\"\n"
296         "\n"
297         "foo = \"\n"
298         "bar = \"text\n"
299         "baz = \"te\\\"xt\n"
300         "last = \"\\\"\n"
301     ;
302 
303     const char* exp_calls[] = {
304         NULL
305     };
306 
307     const char* exp_errors[] = {
308         "3: Missing double quotes before end of line",
309         "4: Missing double quotes before end of line",
310         "5: Missing double quotes before end of line",
311         "6: Missing double quotes before end of line",
312         NULL
313     };
314 
315     do_parser_test< config_reader >(input, exp_calls, exp_errors);
316 }
317 
318 // -------------------------------------------------------------------------
319 // Tests for the free functions.
320 // -------------------------------------------------------------------------
321 
322 ATF_TEST_CASE(merge_configs_both_empty);
ATF_TEST_CASE_HEAD(merge_configs_both_empty)323 ATF_TEST_CASE_HEAD(merge_configs_both_empty) {}
ATF_TEST_CASE_BODY(merge_configs_both_empty)324 ATF_TEST_CASE_BODY(merge_configs_both_empty) {
325     vars_map lower, upper;
326 
327     ATF_REQUIRE(impl::merge_configs(lower, upper).empty());
328 }
329 
330 ATF_TEST_CASE(merge_configs_lower_empty);
ATF_TEST_CASE_HEAD(merge_configs_lower_empty)331 ATF_TEST_CASE_HEAD(merge_configs_lower_empty) {}
ATF_TEST_CASE_BODY(merge_configs_lower_empty)332 ATF_TEST_CASE_BODY(merge_configs_lower_empty) {
333     vars_map lower, upper;
334     upper["var"] = "value";
335 
336     vars_map merged = impl::merge_configs(lower, upper);
337     ATF_REQUIRE_EQ("value", merged["var"]);
338 }
339 
340 ATF_TEST_CASE(merge_configs_upper_empty);
ATF_TEST_CASE_HEAD(merge_configs_upper_empty)341 ATF_TEST_CASE_HEAD(merge_configs_upper_empty) {}
ATF_TEST_CASE_BODY(merge_configs_upper_empty)342 ATF_TEST_CASE_BODY(merge_configs_upper_empty) {
343     vars_map lower, upper;
344     lower["var"] = "value";
345 
346     vars_map merged = impl::merge_configs(lower, upper);
347     ATF_REQUIRE_EQ("value", merged["var"]);
348 }
349 
350 ATF_TEST_CASE(merge_configs_mixed);
ATF_TEST_CASE_HEAD(merge_configs_mixed)351 ATF_TEST_CASE_HEAD(merge_configs_mixed) {}
ATF_TEST_CASE_BODY(merge_configs_mixed)352 ATF_TEST_CASE_BODY(merge_configs_mixed) {
353     vars_map lower, upper;
354     lower["var1"] = "value1";
355     lower["var2"] = "value2-l";
356     upper["var2"] = "value2-u";
357     upper["var3"] = "value3";
358 
359     vars_map merged = impl::merge_configs(lower, upper);
360     ATF_REQUIRE_EQ("value1", merged["var1"]);
361     ATF_REQUIRE_EQ("value2-u", merged["var2"]);
362     ATF_REQUIRE_EQ("value3", merged["var3"]);
363 }
364 
365 ATF_TEST_CASE(read_config_files_none);
ATF_TEST_CASE_HEAD(read_config_files_none)366 ATF_TEST_CASE_HEAD(read_config_files_none) {}
ATF_TEST_CASE_BODY(read_config_files_none)367 ATF_TEST_CASE_BODY(read_config_files_none) {
368     tools::env::set("ATF_CONFDIR", ".");
369     atf::config::__reinit();
370     ATF_REQUIRE(vars_map() == impl::read_config_files("test-suite"));
371 }
372 
373 // -------------------------------------------------------------------------
374 // Main.
375 // -------------------------------------------------------------------------
376 
ATF_INIT_TEST_CASES(tcs)377 ATF_INIT_TEST_CASES(tcs)
378 {
379     ATF_ADD_TEST_CASE(tcs, config_1);
380     ATF_ADD_TEST_CASE(tcs, config_2);
381     ATF_ADD_TEST_CASE(tcs, config_3);
382     ATF_ADD_TEST_CASE(tcs, config_4);
383     ATF_ADD_TEST_CASE(tcs, config_50);
384     ATF_ADD_TEST_CASE(tcs, config_51);
385     ATF_ADD_TEST_CASE(tcs, config_52);
386     ATF_ADD_TEST_CASE(tcs, config_53);
387     ATF_ADD_TEST_CASE(tcs, config_54);
388 
389     ATF_ADD_TEST_CASE(tcs, merge_configs_both_empty);
390     ATF_ADD_TEST_CASE(tcs, merge_configs_lower_empty);
391     ATF_ADD_TEST_CASE(tcs, merge_configs_upper_empty);
392     ATF_ADD_TEST_CASE(tcs, merge_configs_mixed);
393 
394     ATF_ADD_TEST_CASE(tcs, read_config_files_none);
395 }
396