1*0a6a1f1dSLionel Sambuc //
2*0a6a1f1dSLionel Sambuc // Automated Testing Framework (atf)
3*0a6a1f1dSLionel Sambuc //
4*0a6a1f1dSLionel Sambuc // Copyright (c) 2007 The NetBSD Foundation, Inc.
5*0a6a1f1dSLionel Sambuc // All rights reserved.
6*0a6a1f1dSLionel Sambuc //
7*0a6a1f1dSLionel Sambuc // Redistribution and use in source and binary forms, with or without
8*0a6a1f1dSLionel Sambuc // modification, are permitted provided that the following conditions
9*0a6a1f1dSLionel Sambuc // are met:
10*0a6a1f1dSLionel Sambuc // 1. Redistributions of source code must retain the above copyright
11*0a6a1f1dSLionel Sambuc // notice, this list of conditions and the following disclaimer.
12*0a6a1f1dSLionel Sambuc // 2. Redistributions in binary form must reproduce the above copyright
13*0a6a1f1dSLionel Sambuc // notice, this list of conditions and the following disclaimer in the
14*0a6a1f1dSLionel Sambuc // documentation and/or other materials provided with the distribution.
15*0a6a1f1dSLionel Sambuc //
16*0a6a1f1dSLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17*0a6a1f1dSLionel Sambuc // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18*0a6a1f1dSLionel Sambuc // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*0a6a1f1dSLionel Sambuc // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*0a6a1f1dSLionel Sambuc // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21*0a6a1f1dSLionel Sambuc // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*0a6a1f1dSLionel Sambuc // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*0a6a1f1dSLionel Sambuc // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*0a6a1f1dSLionel Sambuc // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*0a6a1f1dSLionel Sambuc // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*0a6a1f1dSLionel Sambuc // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*0a6a1f1dSLionel Sambuc // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*0a6a1f1dSLionel Sambuc //
29*0a6a1f1dSLionel Sambuc
30*0a6a1f1dSLionel Sambuc extern "C" {
31*0a6a1f1dSLionel Sambuc #include <sys/time.h>
32*0a6a1f1dSLionel Sambuc }
33*0a6a1f1dSLionel Sambuc
34*0a6a1f1dSLionel Sambuc #include <cassert>
35*0a6a1f1dSLionel Sambuc #include <cstdlib>
36*0a6a1f1dSLionel Sambuc #include <map>
37*0a6a1f1dSLionel Sambuc #include <sstream>
38*0a6a1f1dSLionel Sambuc #include <utility>
39*0a6a1f1dSLionel Sambuc
40*0a6a1f1dSLionel Sambuc #include "parser.hpp"
41*0a6a1f1dSLionel Sambuc #include "reader.hpp"
42*0a6a1f1dSLionel Sambuc #include "text.hpp"
43*0a6a1f1dSLionel Sambuc
44*0a6a1f1dSLionel Sambuc namespace impl = tools::atf_report;
45*0a6a1f1dSLionel Sambuc #define IMPL_NAME "tools::atf_report"
46*0a6a1f1dSLionel Sambuc
47*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
48*0a6a1f1dSLionel Sambuc // Auxiliary functions.
49*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
50*0a6a1f1dSLionel Sambuc
51*0a6a1f1dSLionel Sambuc template< typename Type >
52*0a6a1f1dSLionel Sambuc Type
string_to_int(const std::string & str)53*0a6a1f1dSLionel Sambuc string_to_int(const std::string& str)
54*0a6a1f1dSLionel Sambuc {
55*0a6a1f1dSLionel Sambuc std::istringstream ss(str);
56*0a6a1f1dSLionel Sambuc Type s;
57*0a6a1f1dSLionel Sambuc ss >> s;
58*0a6a1f1dSLionel Sambuc
59*0a6a1f1dSLionel Sambuc return s;
60*0a6a1f1dSLionel Sambuc }
61*0a6a1f1dSLionel Sambuc
62*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
63*0a6a1f1dSLionel Sambuc // The "atf_tps" auxiliary parser.
64*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
65*0a6a1f1dSLionel Sambuc
66*0a6a1f1dSLionel Sambuc namespace atf_tps {
67*0a6a1f1dSLionel Sambuc
68*0a6a1f1dSLionel Sambuc static const tools::parser::token_type eof_type = 0;
69*0a6a1f1dSLionel Sambuc static const tools::parser::token_type nl_type = 1;
70*0a6a1f1dSLionel Sambuc static const tools::parser::token_type text_type = 2;
71*0a6a1f1dSLionel Sambuc static const tools::parser::token_type colon_type = 3;
72*0a6a1f1dSLionel Sambuc static const tools::parser::token_type comma_type = 4;
73*0a6a1f1dSLionel Sambuc static const tools::parser::token_type tps_count_type = 5;
74*0a6a1f1dSLionel Sambuc static const tools::parser::token_type tp_start_type = 6;
75*0a6a1f1dSLionel Sambuc static const tools::parser::token_type tp_end_type = 7;
76*0a6a1f1dSLionel Sambuc static const tools::parser::token_type tc_start_type = 8;
77*0a6a1f1dSLionel Sambuc static const tools::parser::token_type tc_so_type = 9;
78*0a6a1f1dSLionel Sambuc static const tools::parser::token_type tc_se_type = 10;
79*0a6a1f1dSLionel Sambuc static const tools::parser::token_type tc_end_type = 11;
80*0a6a1f1dSLionel Sambuc static const tools::parser::token_type passed_type = 12;
81*0a6a1f1dSLionel Sambuc static const tools::parser::token_type failed_type = 13;
82*0a6a1f1dSLionel Sambuc static const tools::parser::token_type skipped_type = 14;
83*0a6a1f1dSLionel Sambuc static const tools::parser::token_type info_type = 16;
84*0a6a1f1dSLionel Sambuc static const tools::parser::token_type expected_death_type = 17;
85*0a6a1f1dSLionel Sambuc static const tools::parser::token_type expected_exit_type = 18;
86*0a6a1f1dSLionel Sambuc static const tools::parser::token_type expected_failure_type = 19;
87*0a6a1f1dSLionel Sambuc static const tools::parser::token_type expected_signal_type = 20;
88*0a6a1f1dSLionel Sambuc static const tools::parser::token_type expected_timeout_type = 21;
89*0a6a1f1dSLionel Sambuc
90*0a6a1f1dSLionel Sambuc class tokenizer : public tools::parser::tokenizer< std::istream > {
91*0a6a1f1dSLionel Sambuc public:
tokenizer(std::istream & is,size_t curline)92*0a6a1f1dSLionel Sambuc tokenizer(std::istream& is, size_t curline) :
93*0a6a1f1dSLionel Sambuc tools::parser::tokenizer< std::istream >
94*0a6a1f1dSLionel Sambuc (is, true, eof_type, nl_type, text_type, curline)
95*0a6a1f1dSLionel Sambuc {
96*0a6a1f1dSLionel Sambuc add_delim(':', colon_type);
97*0a6a1f1dSLionel Sambuc add_delim(',', comma_type);
98*0a6a1f1dSLionel Sambuc add_keyword("tps-count", tps_count_type);
99*0a6a1f1dSLionel Sambuc add_keyword("tp-start", tp_start_type);
100*0a6a1f1dSLionel Sambuc add_keyword("tp-end", tp_end_type);
101*0a6a1f1dSLionel Sambuc add_keyword("tc-start", tc_start_type);
102*0a6a1f1dSLionel Sambuc add_keyword("tc-so", tc_so_type);
103*0a6a1f1dSLionel Sambuc add_keyword("tc-se", tc_se_type);
104*0a6a1f1dSLionel Sambuc add_keyword("tc-end", tc_end_type);
105*0a6a1f1dSLionel Sambuc add_keyword("passed", passed_type);
106*0a6a1f1dSLionel Sambuc add_keyword("failed", failed_type);
107*0a6a1f1dSLionel Sambuc add_keyword("skipped", skipped_type);
108*0a6a1f1dSLionel Sambuc add_keyword("info", info_type);
109*0a6a1f1dSLionel Sambuc add_keyword("expected_death", expected_death_type);
110*0a6a1f1dSLionel Sambuc add_keyword("expected_exit", expected_exit_type);
111*0a6a1f1dSLionel Sambuc add_keyword("expected_failure", expected_failure_type);
112*0a6a1f1dSLionel Sambuc add_keyword("expected_signal", expected_signal_type);
113*0a6a1f1dSLionel Sambuc add_keyword("expected_timeout", expected_timeout_type);
114*0a6a1f1dSLionel Sambuc }
115*0a6a1f1dSLionel Sambuc };
116*0a6a1f1dSLionel Sambuc
117*0a6a1f1dSLionel Sambuc } // namespace atf_tps
118*0a6a1f1dSLionel Sambuc
119*0a6a1f1dSLionel Sambuc struct timeval
read_timeval(tools::parser::parser<atf_tps::tokenizer> & parser)120*0a6a1f1dSLionel Sambuc read_timeval(tools::parser::parser< atf_tps::tokenizer >& parser)
121*0a6a1f1dSLionel Sambuc {
122*0a6a1f1dSLionel Sambuc using namespace atf_tps;
123*0a6a1f1dSLionel Sambuc
124*0a6a1f1dSLionel Sambuc tools::parser::token t = parser.expect(text_type, "timestamp");
125*0a6a1f1dSLionel Sambuc const std::string::size_type divider = t.text().find('.');
126*0a6a1f1dSLionel Sambuc if (divider == std::string::npos || divider == 0 ||
127*0a6a1f1dSLionel Sambuc divider == t.text().length() - 1)
128*0a6a1f1dSLionel Sambuc throw tools::parser::parse_error(t.lineno(),
129*0a6a1f1dSLionel Sambuc "Malformed timestamp value " + t.text());
130*0a6a1f1dSLionel Sambuc
131*0a6a1f1dSLionel Sambuc struct timeval tv;
132*0a6a1f1dSLionel Sambuc tv.tv_sec = string_to_int< long >(t.text().substr(0, divider));
133*0a6a1f1dSLionel Sambuc tv.tv_usec = string_to_int< long >(t.text().substr(divider + 1));
134*0a6a1f1dSLionel Sambuc return tv;
135*0a6a1f1dSLionel Sambuc }
136*0a6a1f1dSLionel Sambuc
137*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
138*0a6a1f1dSLionel Sambuc // The "atf_tps_reader" class.
139*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
140*0a6a1f1dSLionel Sambuc
atf_tps_reader(std::istream & is)141*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::atf_tps_reader(std::istream& is) :
142*0a6a1f1dSLionel Sambuc m_is(is)
143*0a6a1f1dSLionel Sambuc {
144*0a6a1f1dSLionel Sambuc }
145*0a6a1f1dSLionel Sambuc
~atf_tps_reader(void)146*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::~atf_tps_reader(void)
147*0a6a1f1dSLionel Sambuc {
148*0a6a1f1dSLionel Sambuc }
149*0a6a1f1dSLionel Sambuc
150*0a6a1f1dSLionel Sambuc void
got_info(const std::string & what,const std::string & val)151*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_info(
152*0a6a1f1dSLionel Sambuc const std::string& what __attribute__((__unused__)),
153*0a6a1f1dSLionel Sambuc const std::string& val __attribute__((__unused__)))
154*0a6a1f1dSLionel Sambuc {
155*0a6a1f1dSLionel Sambuc }
156*0a6a1f1dSLionel Sambuc
157*0a6a1f1dSLionel Sambuc void
got_ntps(size_t ntps)158*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_ntps(size_t ntps __attribute__((__unused__)))
159*0a6a1f1dSLionel Sambuc {
160*0a6a1f1dSLionel Sambuc }
161*0a6a1f1dSLionel Sambuc
162*0a6a1f1dSLionel Sambuc void
got_tp_start(const std::string & tp,size_t ntcs)163*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_tp_start(
164*0a6a1f1dSLionel Sambuc const std::string& tp __attribute__((__unused__)),
165*0a6a1f1dSLionel Sambuc size_t ntcs __attribute__((__unused__)))
166*0a6a1f1dSLionel Sambuc {
167*0a6a1f1dSLionel Sambuc }
168*0a6a1f1dSLionel Sambuc
169*0a6a1f1dSLionel Sambuc void
got_tp_end(struct timeval * tv,const std::string & reason)170*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_tp_end(
171*0a6a1f1dSLionel Sambuc struct timeval* tv __attribute__((__unused__)),
172*0a6a1f1dSLionel Sambuc const std::string& reason __attribute__((__unused__)))
173*0a6a1f1dSLionel Sambuc {
174*0a6a1f1dSLionel Sambuc }
175*0a6a1f1dSLionel Sambuc
176*0a6a1f1dSLionel Sambuc void
got_tc_start(const std::string & tcname)177*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_tc_start(
178*0a6a1f1dSLionel Sambuc const std::string& tcname __attribute__((__unused__)))
179*0a6a1f1dSLionel Sambuc {
180*0a6a1f1dSLionel Sambuc }
181*0a6a1f1dSLionel Sambuc
182*0a6a1f1dSLionel Sambuc void
got_tc_stdout_line(const std::string & line)183*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_tc_stdout_line(
184*0a6a1f1dSLionel Sambuc const std::string& line __attribute__((__unused__)))
185*0a6a1f1dSLionel Sambuc {
186*0a6a1f1dSLionel Sambuc }
187*0a6a1f1dSLionel Sambuc
188*0a6a1f1dSLionel Sambuc void
got_tc_stderr_line(const std::string & line)189*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_tc_stderr_line(
190*0a6a1f1dSLionel Sambuc const std::string& line __attribute__((__unused__)))
191*0a6a1f1dSLionel Sambuc {
192*0a6a1f1dSLionel Sambuc }
193*0a6a1f1dSLionel Sambuc
194*0a6a1f1dSLionel Sambuc void
got_tc_end(const std::string & state,struct timeval * tv,const std::string & reason)195*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_tc_end(
196*0a6a1f1dSLionel Sambuc const std::string& state __attribute__((__unused__)),
197*0a6a1f1dSLionel Sambuc struct timeval* tv __attribute__((__unused__)),
198*0a6a1f1dSLionel Sambuc const std::string& reason __attribute__((__unused__)))
199*0a6a1f1dSLionel Sambuc {
200*0a6a1f1dSLionel Sambuc }
201*0a6a1f1dSLionel Sambuc
202*0a6a1f1dSLionel Sambuc void
got_eof(void)203*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::got_eof(void)
204*0a6a1f1dSLionel Sambuc {
205*0a6a1f1dSLionel Sambuc }
206*0a6a1f1dSLionel Sambuc
207*0a6a1f1dSLionel Sambuc void
read_info(void * pptr)208*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::read_info(void* pptr)
209*0a6a1f1dSLionel Sambuc {
210*0a6a1f1dSLionel Sambuc using tools::parser::parse_error;
211*0a6a1f1dSLionel Sambuc using namespace atf_tps;
212*0a6a1f1dSLionel Sambuc
213*0a6a1f1dSLionel Sambuc tools::parser::parser< tokenizer >& p =
214*0a6a1f1dSLionel Sambuc *reinterpret_cast< tools::parser::parser< tokenizer >* >
215*0a6a1f1dSLionel Sambuc (pptr);
216*0a6a1f1dSLionel Sambuc
217*0a6a1f1dSLionel Sambuc (void)p.expect(colon_type, "`:'");
218*0a6a1f1dSLionel Sambuc
219*0a6a1f1dSLionel Sambuc tools::parser::token t = p.expect(text_type, "info property name");
220*0a6a1f1dSLionel Sambuc (void)p.expect(comma_type, "`,'");
221*0a6a1f1dSLionel Sambuc got_info(t.text(), tools::text::trim(p.rest_of_line()));
222*0a6a1f1dSLionel Sambuc
223*0a6a1f1dSLionel Sambuc (void)p.expect(nl_type, "new line");
224*0a6a1f1dSLionel Sambuc }
225*0a6a1f1dSLionel Sambuc
226*0a6a1f1dSLionel Sambuc void
read_tp(void * pptr)227*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::read_tp(void* pptr)
228*0a6a1f1dSLionel Sambuc {
229*0a6a1f1dSLionel Sambuc using tools::parser::parse_error;
230*0a6a1f1dSLionel Sambuc using namespace atf_tps;
231*0a6a1f1dSLionel Sambuc
232*0a6a1f1dSLionel Sambuc tools::parser::parser< tokenizer >& p =
233*0a6a1f1dSLionel Sambuc *reinterpret_cast< tools::parser::parser< tokenizer >* >
234*0a6a1f1dSLionel Sambuc (pptr);
235*0a6a1f1dSLionel Sambuc
236*0a6a1f1dSLionel Sambuc tools::parser::token t = p.expect(tp_start_type,
237*0a6a1f1dSLionel Sambuc "start of test program");
238*0a6a1f1dSLionel Sambuc
239*0a6a1f1dSLionel Sambuc t = p.expect(colon_type, "`:'");
240*0a6a1f1dSLionel Sambuc
241*0a6a1f1dSLionel Sambuc struct timeval s1 = read_timeval(p);
242*0a6a1f1dSLionel Sambuc
243*0a6a1f1dSLionel Sambuc t = p.expect(comma_type, "`,'");
244*0a6a1f1dSLionel Sambuc
245*0a6a1f1dSLionel Sambuc t = p.expect(text_type, "test program name");
246*0a6a1f1dSLionel Sambuc std::string tpname = t.text();
247*0a6a1f1dSLionel Sambuc
248*0a6a1f1dSLionel Sambuc t = p.expect(comma_type, "`,'");
249*0a6a1f1dSLionel Sambuc
250*0a6a1f1dSLionel Sambuc t = p.expect(text_type, "number of test programs");
251*0a6a1f1dSLionel Sambuc size_t ntcs = string_to_int< std::size_t >(t.text());
252*0a6a1f1dSLionel Sambuc
253*0a6a1f1dSLionel Sambuc t = p.expect(nl_type, "new line");
254*0a6a1f1dSLionel Sambuc
255*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_tp_start(tpname, ntcs));
256*0a6a1f1dSLionel Sambuc
257*0a6a1f1dSLionel Sambuc size_t i = 0;
258*0a6a1f1dSLionel Sambuc while (p.good() && i < ntcs) {
259*0a6a1f1dSLionel Sambuc try {
260*0a6a1f1dSLionel Sambuc read_tc(&p);
261*0a6a1f1dSLionel Sambuc i++;
262*0a6a1f1dSLionel Sambuc } catch (const parse_error& pe) {
263*0a6a1f1dSLionel Sambuc p.add_error(pe);
264*0a6a1f1dSLionel Sambuc p.reset(nl_type);
265*0a6a1f1dSLionel Sambuc }
266*0a6a1f1dSLionel Sambuc }
267*0a6a1f1dSLionel Sambuc t = p.expect(tp_end_type, "end of test program");
268*0a6a1f1dSLionel Sambuc
269*0a6a1f1dSLionel Sambuc t = p.expect(colon_type, "`:'");
270*0a6a1f1dSLionel Sambuc
271*0a6a1f1dSLionel Sambuc struct timeval s2 = read_timeval(p);
272*0a6a1f1dSLionel Sambuc
273*0a6a1f1dSLionel Sambuc struct timeval s3;
274*0a6a1f1dSLionel Sambuc timersub(&s2, &s1, &s3);
275*0a6a1f1dSLionel Sambuc
276*0a6a1f1dSLionel Sambuc t = p.expect(comma_type, "`,'");
277*0a6a1f1dSLionel Sambuc
278*0a6a1f1dSLionel Sambuc t = p.expect(text_type, "test program name");
279*0a6a1f1dSLionel Sambuc if (t.text() != tpname)
280*0a6a1f1dSLionel Sambuc throw parse_error(t.lineno(), "Test program name used in "
281*0a6a1f1dSLionel Sambuc "terminator does not match "
282*0a6a1f1dSLionel Sambuc "opening");
283*0a6a1f1dSLionel Sambuc
284*0a6a1f1dSLionel Sambuc t = p.expect(nl_type, comma_type,
285*0a6a1f1dSLionel Sambuc "new line or comma_type");
286*0a6a1f1dSLionel Sambuc std::string reason;
287*0a6a1f1dSLionel Sambuc if (t.type() == comma_type) {
288*0a6a1f1dSLionel Sambuc reason = tools::text::trim(p.rest_of_line());
289*0a6a1f1dSLionel Sambuc if (reason.empty())
290*0a6a1f1dSLionel Sambuc throw parse_error(t.lineno(),
291*0a6a1f1dSLionel Sambuc "Empty reason for failed test program");
292*0a6a1f1dSLionel Sambuc t = p.next();
293*0a6a1f1dSLionel Sambuc }
294*0a6a1f1dSLionel Sambuc
295*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_tp_end(&s3, reason));
296*0a6a1f1dSLionel Sambuc }
297*0a6a1f1dSLionel Sambuc
298*0a6a1f1dSLionel Sambuc void
read_tc(void * pptr)299*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::read_tc(void* pptr)
300*0a6a1f1dSLionel Sambuc {
301*0a6a1f1dSLionel Sambuc using tools::parser::parse_error;
302*0a6a1f1dSLionel Sambuc using namespace atf_tps;
303*0a6a1f1dSLionel Sambuc
304*0a6a1f1dSLionel Sambuc tools::parser::parser< tokenizer >& p =
305*0a6a1f1dSLionel Sambuc *reinterpret_cast< tools::parser::parser< tokenizer >* >
306*0a6a1f1dSLionel Sambuc (pptr);
307*0a6a1f1dSLionel Sambuc
308*0a6a1f1dSLionel Sambuc tools::parser::token t = p.expect(tc_start_type, "start of test case");
309*0a6a1f1dSLionel Sambuc
310*0a6a1f1dSLionel Sambuc t = p.expect(colon_type, "`:'");
311*0a6a1f1dSLionel Sambuc
312*0a6a1f1dSLionel Sambuc struct timeval s1 = read_timeval(p);
313*0a6a1f1dSLionel Sambuc
314*0a6a1f1dSLionel Sambuc t = p.expect(comma_type, "`,'");
315*0a6a1f1dSLionel Sambuc
316*0a6a1f1dSLionel Sambuc t = p.expect(text_type, "test case name");
317*0a6a1f1dSLionel Sambuc std::string tcname = t.text();
318*0a6a1f1dSLionel Sambuc
319*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_tc_start(tcname));
320*0a6a1f1dSLionel Sambuc
321*0a6a1f1dSLionel Sambuc t = p.expect(nl_type, "new line");
322*0a6a1f1dSLionel Sambuc
323*0a6a1f1dSLionel Sambuc t = p.expect(tc_end_type, tc_so_type, tc_se_type,
324*0a6a1f1dSLionel Sambuc "end of test case or test case's stdout/stderr line");
325*0a6a1f1dSLionel Sambuc while (t.type() != tc_end_type &&
326*0a6a1f1dSLionel Sambuc (t.type() == tc_so_type || t.type() == tc_se_type)) {
327*0a6a1f1dSLionel Sambuc tools::parser::token t2 = t;
328*0a6a1f1dSLionel Sambuc
329*0a6a1f1dSLionel Sambuc t = p.expect(colon_type, "`:'");
330*0a6a1f1dSLionel Sambuc
331*0a6a1f1dSLionel Sambuc std::string line = p.rest_of_line();
332*0a6a1f1dSLionel Sambuc
333*0a6a1f1dSLionel Sambuc if (t2.type() == tc_so_type) {
334*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_tc_stdout_line(line));
335*0a6a1f1dSLionel Sambuc } else {
336*0a6a1f1dSLionel Sambuc assert(t2.type() == tc_se_type);
337*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_tc_stderr_line(line));
338*0a6a1f1dSLionel Sambuc }
339*0a6a1f1dSLionel Sambuc
340*0a6a1f1dSLionel Sambuc t = p.expect(nl_type, "new line");
341*0a6a1f1dSLionel Sambuc
342*0a6a1f1dSLionel Sambuc t = p.expect(tc_end_type, tc_so_type, tc_se_type,
343*0a6a1f1dSLionel Sambuc "end of test case or test case's stdout/stderr line");
344*0a6a1f1dSLionel Sambuc }
345*0a6a1f1dSLionel Sambuc
346*0a6a1f1dSLionel Sambuc t = p.expect(colon_type, "`:'");
347*0a6a1f1dSLionel Sambuc
348*0a6a1f1dSLionel Sambuc struct timeval s2 = read_timeval(p);
349*0a6a1f1dSLionel Sambuc
350*0a6a1f1dSLionel Sambuc struct timeval s3;
351*0a6a1f1dSLionel Sambuc timersub(&s2, &s1, &s3);
352*0a6a1f1dSLionel Sambuc
353*0a6a1f1dSLionel Sambuc t = p.expect(comma_type, "`,'");
354*0a6a1f1dSLionel Sambuc
355*0a6a1f1dSLionel Sambuc t = p.expect(text_type, "test case name");
356*0a6a1f1dSLionel Sambuc if (t.text() != tcname)
357*0a6a1f1dSLionel Sambuc throw parse_error(t.lineno(),
358*0a6a1f1dSLionel Sambuc "Test case name used in terminator does not "
359*0a6a1f1dSLionel Sambuc "match opening");
360*0a6a1f1dSLionel Sambuc
361*0a6a1f1dSLionel Sambuc t = p.expect(comma_type, "`,'");
362*0a6a1f1dSLionel Sambuc
363*0a6a1f1dSLionel Sambuc t = p.expect(expected_death_type, expected_exit_type, expected_failure_type,
364*0a6a1f1dSLionel Sambuc expected_signal_type, expected_timeout_type, passed_type, failed_type,
365*0a6a1f1dSLionel Sambuc skipped_type, "expected_{death,exit,failure,signal,timeout}, failed, "
366*0a6a1f1dSLionel Sambuc "passed or skipped");
367*0a6a1f1dSLionel Sambuc if (t.type() == passed_type) {
368*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_tc_end("passed", &s3, ""));
369*0a6a1f1dSLionel Sambuc } else {
370*0a6a1f1dSLionel Sambuc std::string state;
371*0a6a1f1dSLionel Sambuc if (t.type() == expected_death_type) state = "expected_death";
372*0a6a1f1dSLionel Sambuc else if (t.type() == expected_exit_type) state = "expected_exit";
373*0a6a1f1dSLionel Sambuc else if (t.type() == expected_failure_type) state = "expected_failure";
374*0a6a1f1dSLionel Sambuc else if (t.type() == expected_signal_type) state = "expected_signal";
375*0a6a1f1dSLionel Sambuc else if (t.type() == expected_timeout_type) state = "expected_timeout";
376*0a6a1f1dSLionel Sambuc else if (t.type() == failed_type) state = "failed";
377*0a6a1f1dSLionel Sambuc else if (t.type() == skipped_type) state = "skipped";
378*0a6a1f1dSLionel Sambuc else std::abort();
379*0a6a1f1dSLionel Sambuc
380*0a6a1f1dSLionel Sambuc t = p.expect(comma_type, "`,'");
381*0a6a1f1dSLionel Sambuc std::string reason = tools::text::trim(p.rest_of_line());
382*0a6a1f1dSLionel Sambuc if (reason.empty())
383*0a6a1f1dSLionel Sambuc throw parse_error(t.lineno(), "Empty reason for " + state +
384*0a6a1f1dSLionel Sambuc " test case result");
385*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_tc_end(state, &s3, reason));
386*0a6a1f1dSLionel Sambuc }
387*0a6a1f1dSLionel Sambuc
388*0a6a1f1dSLionel Sambuc t = p.expect(nl_type, "new line");
389*0a6a1f1dSLionel Sambuc }
390*0a6a1f1dSLionel Sambuc
391*0a6a1f1dSLionel Sambuc void
read(void)392*0a6a1f1dSLionel Sambuc impl::atf_tps_reader::read(void)
393*0a6a1f1dSLionel Sambuc {
394*0a6a1f1dSLionel Sambuc using tools::parser::parse_error;
395*0a6a1f1dSLionel Sambuc using namespace atf_tps;
396*0a6a1f1dSLionel Sambuc
397*0a6a1f1dSLionel Sambuc std::pair< size_t, tools::parser::headers_map > hml =
398*0a6a1f1dSLionel Sambuc tools::parser::read_headers(m_is, 1);
399*0a6a1f1dSLionel Sambuc tools::parser::validate_content_type(hml.second,
400*0a6a1f1dSLionel Sambuc "application/X-atf-tps", 3);
401*0a6a1f1dSLionel Sambuc
402*0a6a1f1dSLionel Sambuc tokenizer tkz(m_is, hml.first);
403*0a6a1f1dSLionel Sambuc tools::parser::parser< tokenizer > p(tkz);
404*0a6a1f1dSLionel Sambuc
405*0a6a1f1dSLionel Sambuc try {
406*0a6a1f1dSLionel Sambuc tools::parser::token t;
407*0a6a1f1dSLionel Sambuc
408*0a6a1f1dSLionel Sambuc while ((t = p.expect(tps_count_type, info_type, "tps-count or info "
409*0a6a1f1dSLionel Sambuc "field")).type() == info_type)
410*0a6a1f1dSLionel Sambuc read_info(&p);
411*0a6a1f1dSLionel Sambuc
412*0a6a1f1dSLionel Sambuc t = p.expect(colon_type, "`:'");
413*0a6a1f1dSLionel Sambuc
414*0a6a1f1dSLionel Sambuc t = p.expect(text_type, "number of test programs");
415*0a6a1f1dSLionel Sambuc size_t ntps = string_to_int< std::size_t >(t.text());
416*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_ntps(ntps));
417*0a6a1f1dSLionel Sambuc
418*0a6a1f1dSLionel Sambuc t = p.expect(nl_type, "new line");
419*0a6a1f1dSLionel Sambuc
420*0a6a1f1dSLionel Sambuc size_t i = 0;
421*0a6a1f1dSLionel Sambuc while (p.good() && i < ntps) {
422*0a6a1f1dSLionel Sambuc try {
423*0a6a1f1dSLionel Sambuc read_tp(&p);
424*0a6a1f1dSLionel Sambuc i++;
425*0a6a1f1dSLionel Sambuc } catch (const parse_error& pe) {
426*0a6a1f1dSLionel Sambuc p.add_error(pe);
427*0a6a1f1dSLionel Sambuc p.reset(nl_type);
428*0a6a1f1dSLionel Sambuc }
429*0a6a1f1dSLionel Sambuc }
430*0a6a1f1dSLionel Sambuc
431*0a6a1f1dSLionel Sambuc while ((t = p.expect(eof_type, info_type, "end of stream or info "
432*0a6a1f1dSLionel Sambuc "field")).type() == info_type)
433*0a6a1f1dSLionel Sambuc read_info(&p);
434*0a6a1f1dSLionel Sambuc ATF_PARSER_CALLBACK(p, got_eof());
435*0a6a1f1dSLionel Sambuc } catch (const parse_error& pe) {
436*0a6a1f1dSLionel Sambuc p.add_error(pe);
437*0a6a1f1dSLionel Sambuc p.reset(nl_type);
438*0a6a1f1dSLionel Sambuc }
439*0a6a1f1dSLionel Sambuc }
440