2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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.
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.
34 #include "atffile.hpp"
35 #include "exceptions.hpp"
39 namespace impl
= tools
;
40 namespace detail
= tools::detail
;
44 typedef std::map
< std::string
, std::string
> vars_map
;
46 } // anonymous namespace
48 // ------------------------------------------------------------------------
49 // The "atf_atffile" auxiliary parser.
50 // ------------------------------------------------------------------------
52 namespace atf_atffile
{
54 static const tools::parser::token_type eof_type
= 0;
55 static const tools::parser::token_type nl_type
= 1;
56 static const tools::parser::token_type text_type
= 2;
57 static const tools::parser::token_type colon_type
= 3;
58 static const tools::parser::token_type conf_type
= 4;
59 static const tools::parser::token_type dblquote_type
= 5;
60 static const tools::parser::token_type equal_type
= 6;
61 static const tools::parser::token_type hash_type
= 7;
62 static const tools::parser::token_type prop_type
= 8;
63 static const tools::parser::token_type tp_type
= 9;
64 static const tools::parser::token_type tp_glob_type
= 10;
66 class tokenizer
: public tools::parser::tokenizer
< std::istream
> {
68 tokenizer(std::istream
& is
, size_t curline
) :
69 tools::parser::tokenizer
< std::istream
>
70 (is
, true, eof_type
, nl_type
, text_type
, curline
)
72 add_delim(':', colon_type
);
73 add_delim('=', equal_type
);
74 add_delim('#', hash_type
);
75 add_quote('"', dblquote_type
);
76 add_keyword("conf", conf_type
);
77 add_keyword("prop", prop_type
);
78 add_keyword("tp", tp_type
);
79 add_keyword("tp-glob", tp_glob_type
);
83 } // namespace atf_atffile
85 // ------------------------------------------------------------------------
86 // The "atf_atffile_reader" class.
87 // ------------------------------------------------------------------------
89 detail::atf_atffile_reader::atf_atffile_reader(std::istream
& is
) :
94 detail::atf_atffile_reader::~atf_atffile_reader(void)
99 detail::atf_atffile_reader::got_conf(
100 const std::string
& name
__attribute__((__unused__
)),
101 const std::string
& val
__attribute__((__unused__
)))
106 detail::atf_atffile_reader::got_prop(
107 const std::string
& name
__attribute__((__unused__
)),
108 const std::string
& val
__attribute__((__unused__
)))
113 detail::atf_atffile_reader::got_tp(
114 const std::string
& name
__attribute__((__unused__
)),
115 bool isglob
__attribute__((__unused__
)))
120 detail::atf_atffile_reader::got_eof(void)
125 detail::atf_atffile_reader::read(void)
127 using tools::parser::parse_error
;
128 using namespace atf_atffile
;
130 std::pair
< size_t, tools::parser::headers_map
> hml
=
131 tools::parser::read_headers(m_is
, 1);
132 tools::parser::validate_content_type(hml
.second
,
133 "application/X-atf-atffile", 1);
135 tokenizer
tkz(m_is
, hml
.first
);
136 tools::parser::parser
< tokenizer
> p(tkz
);
140 tools::parser::token t
=
141 p
.expect(conf_type
, hash_type
, prop_type
, tp_type
,
142 tp_glob_type
, nl_type
, eof_type
,
143 "conf, #, prop, tp, tp-glob, a new line or eof");
144 if (t
.type() == eof_type
)
147 if (t
.type() == conf_type
) {
148 t
= p
.expect(colon_type
, "`:'");
150 t
= p
.expect(text_type
, "variable name");
151 std::string var
= t
.text();
153 t
= p
.expect(equal_type
, "equal sign");
155 t
= p
.expect(text_type
, "word or quoted string");
156 ATF_PARSER_CALLBACK(p
, got_conf(var
, t
.text()));
157 } else if (t
.type() == hash_type
) {
158 (void)p
.rest_of_line();
159 } else if (t
.type() == prop_type
) {
160 t
= p
.expect(colon_type
, "`:'");
162 t
= p
.expect(text_type
, "property name");
163 std::string name
= t
.text();
165 t
= p
.expect(equal_type
, "equale sign");
167 t
= p
.expect(text_type
, "word or quoted string");
168 ATF_PARSER_CALLBACK(p
, got_prop(name
, t
.text()));
169 } else if (t
.type() == tp_type
) {
170 t
= p
.expect(colon_type
, "`:'");
172 t
= p
.expect(text_type
, "word or quoted string");
173 ATF_PARSER_CALLBACK(p
, got_tp(t
.text(), false));
174 } else if (t
.type() == tp_glob_type
) {
175 t
= p
.expect(colon_type
, "`:'");
177 t
= p
.expect(text_type
, "word or quoted string");
178 ATF_PARSER_CALLBACK(p
, got_tp(t
.text(), true));
179 } else if (t
.type() == nl_type
) {
184 t
= p
.expect(nl_type
, hash_type
, eof_type
,
185 "new line or comment");
186 if (t
.type() == hash_type
) {
187 (void)p
.rest_of_line();
189 } else if (t
.type() == eof_type
)
191 } catch (const parse_error
& pe
) {
197 ATF_PARSER_CALLBACK(p
, got_eof());
200 // ------------------------------------------------------------------------
201 // The "reader" helper class.
202 // ------------------------------------------------------------------------
204 class reader
: public detail::atf_atffile_reader
{
205 const tools::fs::directory
& m_dir
;
206 vars_map m_conf
, m_props
;
207 std::vector
< std::string
> m_tps
;
210 got_tp(const std::string
& name
, bool isglob
)
213 std::vector
< std::string
> ms
=
214 tools::expand::expand_glob(name
, m_dir
.names());
215 // Cannot use m_tps.insert(iterator, begin, end) here because it
216 // does not work under Solaris.
217 for (std::vector
< std::string
>::const_iterator iter
= ms
.begin();
218 iter
!= ms
.end(); iter
++)
219 m_tps
.push_back(*iter
);
221 if (m_dir
.find(name
) == m_dir
.end())
222 throw tools::not_found_error
< tools::fs::path
>
223 ("Cannot locate the " + name
+ " file",
224 tools::fs::path(name
));
225 m_tps
.push_back(name
);
230 got_prop(const std::string
& name
, const std::string
& val
)
236 got_conf(const std::string
& var
, const std::string
& val
)
242 reader(std::istream
& is
, const tools::fs::directory
& dir
) :
243 detail::atf_atffile_reader(is
),
262 const std::vector
< std::string
>&
270 // ------------------------------------------------------------------------
271 // The "atffile" class.
272 // ------------------------------------------------------------------------
274 impl::atffile::atffile(const vars_map
& config_vars
,
275 const std::vector
< std::string
>& test_program_names
,
276 const vars_map
& properties
) :
278 m_tps(test_program_names
),
281 assert(properties
.find("test-suite") != properties
.end());
284 const std::vector
< std::string
>&
285 impl::atffile::tps(void)
292 impl::atffile::conf(void)
299 impl::atffile::props(void)
305 // ------------------------------------------------------------------------
307 // ------------------------------------------------------------------------
309 // XXX Glob expansion and file existance checks certainly do not belong in
310 // a *parser*. This needs to be taken out...
312 impl::read_atffile(const tools::fs::path
& filename
)
314 // Scan the directory where the atffile lives in to gather a list of
315 // all possible test programs in it.
316 tools::fs::directory
dir(filename
.branch_path());
317 dir
.erase(filename
.leaf_name());
318 tools::fs::directory::iterator iter
= dir
.begin();
319 while (iter
!= dir
.end()) {
320 const std::string
& name
= (*iter
).first
;
321 const tools::fs::file_info
& fi
= (*iter
).second
;
323 // Discard hidden files and non-executable ones so that they are
324 // not candidates for glob matching.
325 if (name
[0] == '.' || (!fi
.is_owner_executable() &&
326 !fi
.is_group_executable()))
332 // Parse the atffile.
333 std::ifstream
is(filename
.c_str());
335 throw tools::not_found_error
< tools::fs::path
>
336 ("Cannot open Atffile", filename
);
342 if (r
.props().find("test-suite") == r
.props().end())
343 throw tools::not_found_error
< std::string
>
344 ("Undefined property `test-suite'", "test-suite");
346 return atffile(r
.conf(), r
.tps(), r
.props());