1*b0d29bc4SBrooks Davis // Copyright 2012 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis // documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis // may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis // without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis
29*b0d29bc4SBrooks Davis #include "utils/config/parser.hpp"
30*b0d29bc4SBrooks Davis
31*b0d29bc4SBrooks Davis #include <stdexcept>
32*b0d29bc4SBrooks Davis
33*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
34*b0d29bc4SBrooks Davis
35*b0d29bc4SBrooks Davis #include "utils/config/exceptions.hpp"
36*b0d29bc4SBrooks Davis #include "utils/config/parser.hpp"
37*b0d29bc4SBrooks Davis #include "utils/config/tree.ipp"
38*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
39*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
40*b0d29bc4SBrooks Davis
41*b0d29bc4SBrooks Davis namespace config = utils::config;
42*b0d29bc4SBrooks Davis namespace fs = utils::fs;
43*b0d29bc4SBrooks Davis
44*b0d29bc4SBrooks Davis
45*b0d29bc4SBrooks Davis namespace {
46*b0d29bc4SBrooks Davis
47*b0d29bc4SBrooks Davis
48*b0d29bc4SBrooks Davis /// Implementation of a parser for testing purposes.
49*b0d29bc4SBrooks Davis class mock_parser : public config::parser {
50*b0d29bc4SBrooks Davis /// Initializes the tree keys before reading the file.
51*b0d29bc4SBrooks Davis ///
52*b0d29bc4SBrooks Davis /// \param [in,out] tree The tree in which to define the key structure.
53*b0d29bc4SBrooks Davis /// \param syntax_version The version of the file format as specified in the
54*b0d29bc4SBrooks Davis /// configuration file.
55*b0d29bc4SBrooks Davis void
setup(config::tree & tree,const int syntax_version)56*b0d29bc4SBrooks Davis setup(config::tree& tree, const int syntax_version)
57*b0d29bc4SBrooks Davis {
58*b0d29bc4SBrooks Davis if (syntax_version == 1) {
59*b0d29bc4SBrooks Davis // Do nothing on config_tree.
60*b0d29bc4SBrooks Davis } else if (syntax_version == 2) {
61*b0d29bc4SBrooks Davis tree.define< config::string_node >("top_string");
62*b0d29bc4SBrooks Davis tree.define< config::int_node >("inner.int");
63*b0d29bc4SBrooks Davis tree.define_dynamic("inner.dynamic");
64*b0d29bc4SBrooks Davis } else {
65*b0d29bc4SBrooks Davis throw std::runtime_error(F("Unknown syntax version %s") %
66*b0d29bc4SBrooks Davis syntax_version);
67*b0d29bc4SBrooks Davis }
68*b0d29bc4SBrooks Davis }
69*b0d29bc4SBrooks Davis
70*b0d29bc4SBrooks Davis public:
71*b0d29bc4SBrooks Davis /// Initializes a parser.
72*b0d29bc4SBrooks Davis ///
73*b0d29bc4SBrooks Davis /// \param tree The mock config tree to parse.
mock_parser(config::tree & tree)74*b0d29bc4SBrooks Davis mock_parser(config::tree& tree) :
75*b0d29bc4SBrooks Davis config::parser(tree)
76*b0d29bc4SBrooks Davis {
77*b0d29bc4SBrooks Davis }
78*b0d29bc4SBrooks Davis };
79*b0d29bc4SBrooks Davis
80*b0d29bc4SBrooks Davis
81*b0d29bc4SBrooks Davis } // anonymous namespace
82*b0d29bc4SBrooks Davis
83*b0d29bc4SBrooks Davis
84*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(no_keys__ok);
ATF_TEST_CASE_BODY(no_keys__ok)85*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(no_keys__ok)
86*b0d29bc4SBrooks Davis {
87*b0d29bc4SBrooks Davis atf::utils::create_file(
88*b0d29bc4SBrooks Davis "output.lua",
89*b0d29bc4SBrooks Davis "syntax(2)\n"
90*b0d29bc4SBrooks Davis "local foo = 'value'\n");
91*b0d29bc4SBrooks Davis
92*b0d29bc4SBrooks Davis config::tree tree;
93*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua"));
94*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW(config::unknown_key_error,
95*b0d29bc4SBrooks Davis tree.lookup< config::string_node >("foo"));
96*b0d29bc4SBrooks Davis }
97*b0d29bc4SBrooks Davis
98*b0d29bc4SBrooks Davis
99*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(no_keys__unknown_key);
ATF_TEST_CASE_BODY(no_keys__unknown_key)100*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(no_keys__unknown_key)
101*b0d29bc4SBrooks Davis {
102*b0d29bc4SBrooks Davis atf::utils::create_file(
103*b0d29bc4SBrooks Davis "output.lua",
104*b0d29bc4SBrooks Davis "syntax(2)\n"
105*b0d29bc4SBrooks Davis "foo = 'value'\n");
106*b0d29bc4SBrooks Davis
107*b0d29bc4SBrooks Davis config::tree tree;
108*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error, "foo",
109*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua")));
110*b0d29bc4SBrooks Davis }
111*b0d29bc4SBrooks Davis
112*b0d29bc4SBrooks Davis
113*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(some_keys__ok);
ATF_TEST_CASE_BODY(some_keys__ok)114*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(some_keys__ok)
115*b0d29bc4SBrooks Davis {
116*b0d29bc4SBrooks Davis atf::utils::create_file(
117*b0d29bc4SBrooks Davis "output.lua",
118*b0d29bc4SBrooks Davis "syntax(2)\n"
119*b0d29bc4SBrooks Davis "top_string = 'foo'\n"
120*b0d29bc4SBrooks Davis "inner.int = 12345\n"
121*b0d29bc4SBrooks Davis "inner.dynamic.foo = 78\n"
122*b0d29bc4SBrooks Davis "inner.dynamic.bar = 'some text'\n");
123*b0d29bc4SBrooks Davis
124*b0d29bc4SBrooks Davis config::tree tree;
125*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua"));
126*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("foo", tree.lookup< config::string_node >("top_string"));
127*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(12345, tree.lookup< config::int_node >("inner.int"));
128*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("78",
129*b0d29bc4SBrooks Davis tree.lookup< config::string_node >("inner.dynamic.foo"));
130*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("some text",
131*b0d29bc4SBrooks Davis tree.lookup< config::string_node >("inner.dynamic.bar"));
132*b0d29bc4SBrooks Davis }
133*b0d29bc4SBrooks Davis
134*b0d29bc4SBrooks Davis
135*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(some_keys__not_strict);
ATF_TEST_CASE_BODY(some_keys__not_strict)136*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(some_keys__not_strict)
137*b0d29bc4SBrooks Davis {
138*b0d29bc4SBrooks Davis atf::utils::create_file(
139*b0d29bc4SBrooks Davis "output.lua",
140*b0d29bc4SBrooks Davis "syntax(2)\n"
141*b0d29bc4SBrooks Davis "top_string = 'foo'\n"
142*b0d29bc4SBrooks Davis "unknown_string = 'bar'\n"
143*b0d29bc4SBrooks Davis "top_string = 'baz'\n");
144*b0d29bc4SBrooks Davis
145*b0d29bc4SBrooks Davis config::tree tree(false);
146*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua"));
147*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("baz", tree.lookup< config::string_node >("top_string"));
148*b0d29bc4SBrooks Davis ATF_REQUIRE(!tree.is_set("unknown_string"));
149*b0d29bc4SBrooks Davis }
150*b0d29bc4SBrooks Davis
151*b0d29bc4SBrooks Davis
152*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(some_keys__unknown_key);
ATF_TEST_CASE_BODY(some_keys__unknown_key)153*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(some_keys__unknown_key)
154*b0d29bc4SBrooks Davis {
155*b0d29bc4SBrooks Davis atf::utils::create_file(
156*b0d29bc4SBrooks Davis "output.lua",
157*b0d29bc4SBrooks Davis "syntax(2)\n"
158*b0d29bc4SBrooks Davis "top_string2 = 'foo'\n");
159*b0d29bc4SBrooks Davis config::tree tree1;
160*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error,
161*b0d29bc4SBrooks Davis "Unknown configuration property 'top_string2'",
162*b0d29bc4SBrooks Davis mock_parser(tree1).parse(fs::path("output.lua")));
163*b0d29bc4SBrooks Davis
164*b0d29bc4SBrooks Davis atf::utils::create_file(
165*b0d29bc4SBrooks Davis "output.lua",
166*b0d29bc4SBrooks Davis "syntax(2)\n"
167*b0d29bc4SBrooks Davis "inner.int2 = 12345\n");
168*b0d29bc4SBrooks Davis config::tree tree2;
169*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error,
170*b0d29bc4SBrooks Davis "Unknown configuration property 'inner.int2'",
171*b0d29bc4SBrooks Davis mock_parser(tree2).parse(fs::path("output.lua")));
172*b0d29bc4SBrooks Davis }
173*b0d29bc4SBrooks Davis
174*b0d29bc4SBrooks Davis
175*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(invalid_syntax);
ATF_TEST_CASE_BODY(invalid_syntax)176*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(invalid_syntax)
177*b0d29bc4SBrooks Davis {
178*b0d29bc4SBrooks Davis config::tree tree;
179*b0d29bc4SBrooks Davis
180*b0d29bc4SBrooks Davis atf::utils::create_file("output.lua", "syntax(56)\n");
181*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error,
182*b0d29bc4SBrooks Davis "Unknown syntax version 56",
183*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua")));
184*b0d29bc4SBrooks Davis }
185*b0d29bc4SBrooks Davis
186*b0d29bc4SBrooks Davis
187*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(syntax_deprecated_format);
ATF_TEST_CASE_BODY(syntax_deprecated_format)188*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(syntax_deprecated_format)
189*b0d29bc4SBrooks Davis {
190*b0d29bc4SBrooks Davis config::tree tree;
191*b0d29bc4SBrooks Davis
192*b0d29bc4SBrooks Davis atf::utils::create_file("output.lua", "syntax('config', 1)\n");
193*b0d29bc4SBrooks Davis (void)mock_parser(tree).parse(fs::path("output.lua"));
194*b0d29bc4SBrooks Davis
195*b0d29bc4SBrooks Davis atf::utils::create_file("output.lua", "syntax('foo', 1)\n");
196*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error, "must be 'config'",
197*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua")));
198*b0d29bc4SBrooks Davis
199*b0d29bc4SBrooks Davis atf::utils::create_file("output.lua", "syntax('config', 2)\n");
200*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error, "only takes one argument",
201*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua")));
202*b0d29bc4SBrooks Davis }
203*b0d29bc4SBrooks Davis
204*b0d29bc4SBrooks Davis
205*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(syntax_not_called);
ATF_TEST_CASE_BODY(syntax_not_called)206*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(syntax_not_called)
207*b0d29bc4SBrooks Davis {
208*b0d29bc4SBrooks Davis config::tree tree;
209*b0d29bc4SBrooks Davis tree.define< config::int_node >("var");
210*b0d29bc4SBrooks Davis
211*b0d29bc4SBrooks Davis atf::utils::create_file("output.lua", "var = 3\n");
212*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error, "No syntax defined",
213*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua")));
214*b0d29bc4SBrooks Davis
215*b0d29bc4SBrooks Davis ATF_REQUIRE(!tree.is_set("var"));
216*b0d29bc4SBrooks Davis }
217*b0d29bc4SBrooks Davis
218*b0d29bc4SBrooks Davis
219*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(syntax_called_more_than_once);
ATF_TEST_CASE_BODY(syntax_called_more_than_once)220*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(syntax_called_more_than_once)
221*b0d29bc4SBrooks Davis {
222*b0d29bc4SBrooks Davis config::tree tree;
223*b0d29bc4SBrooks Davis tree.define< config::int_node >("var");
224*b0d29bc4SBrooks Davis
225*b0d29bc4SBrooks Davis atf::utils::create_file(
226*b0d29bc4SBrooks Davis "output.lua",
227*b0d29bc4SBrooks Davis "syntax(2)\n"
228*b0d29bc4SBrooks Davis "var = 3\n"
229*b0d29bc4SBrooks Davis "syntax(2)\n"
230*b0d29bc4SBrooks Davis "var = 5\n");
231*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(config::syntax_error,
232*b0d29bc4SBrooks Davis "syntax\\(\\) can only be called once",
233*b0d29bc4SBrooks Davis mock_parser(tree).parse(fs::path("output.lua")));
234*b0d29bc4SBrooks Davis
235*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(3, tree.lookup< config::int_node >("var"));
236*b0d29bc4SBrooks Davis }
237*b0d29bc4SBrooks Davis
238*b0d29bc4SBrooks Davis
ATF_INIT_TEST_CASES(tcs)239*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
240*b0d29bc4SBrooks Davis {
241*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, no_keys__ok);
242*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, no_keys__unknown_key);
243*b0d29bc4SBrooks Davis
244*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, some_keys__ok);
245*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, some_keys__not_strict);
246*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, some_keys__unknown_key);
247*b0d29bc4SBrooks Davis
248*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, invalid_syntax);
249*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, syntax_deprecated_format);
250*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, syntax_not_called);
251*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, syntax_called_more_than_once);
252*b0d29bc4SBrooks Davis }
253