1*6b3a42afSjmmv // Copyright 2010 Google Inc.
2*6b3a42afSjmmv // All rights reserved.
3*6b3a42afSjmmv //
4*6b3a42afSjmmv // Redistribution and use in source and binary forms, with or without
5*6b3a42afSjmmv // modification, are permitted provided that the following conditions are
6*6b3a42afSjmmv // met:
7*6b3a42afSjmmv //
8*6b3a42afSjmmv // * Redistributions of source code must retain the above copyright
9*6b3a42afSjmmv // notice, this list of conditions and the following disclaimer.
10*6b3a42afSjmmv // * Redistributions in binary form must reproduce the above copyright
11*6b3a42afSjmmv // notice, this list of conditions and the following disclaimer in the
12*6b3a42afSjmmv // documentation and/or other materials provided with the distribution.
13*6b3a42afSjmmv // * Neither the name of Google Inc. nor the names of its contributors
14*6b3a42afSjmmv // may be used to endorse or promote products derived from this software
15*6b3a42afSjmmv // without specific prior written permission.
16*6b3a42afSjmmv //
17*6b3a42afSjmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*6b3a42afSjmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*6b3a42afSjmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*6b3a42afSjmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*6b3a42afSjmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*6b3a42afSjmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*6b3a42afSjmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*6b3a42afSjmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*6b3a42afSjmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*6b3a42afSjmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*6b3a42afSjmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*6b3a42afSjmmv
29*6b3a42afSjmmv #include "engine/test_result.hpp"
30*6b3a42afSjmmv
31*6b3a42afSjmmv #include "engine/exceptions.hpp"
32*6b3a42afSjmmv #include "utils/format/macros.hpp"
33*6b3a42afSjmmv #include "utils/sanity.hpp"
34*6b3a42afSjmmv #include "utils/text/operations.ipp"
35*6b3a42afSjmmv
36*6b3a42afSjmmv namespace text = utils::text;
37*6b3a42afSjmmv
38*6b3a42afSjmmv
39*6b3a42afSjmmv /// Constructs a base result.
40*6b3a42afSjmmv ///
41*6b3a42afSjmmv /// \param type_ The type of the result.
42*6b3a42afSjmmv /// \param reason_ The reason explaining the result, if any. It is OK for this
43*6b3a42afSjmmv /// to be empty, which is actually the default.
test_result(const result_type type_,const std::string & reason_)44*6b3a42afSjmmv engine::test_result::test_result(const result_type type_,
45*6b3a42afSjmmv const std::string& reason_) :
46*6b3a42afSjmmv _type(type_),
47*6b3a42afSjmmv _reason(reason_)
48*6b3a42afSjmmv {
49*6b3a42afSjmmv }
50*6b3a42afSjmmv
51*6b3a42afSjmmv
52*6b3a42afSjmmv /// Parses a result from an input stream.
53*6b3a42afSjmmv ///
54*6b3a42afSjmmv /// The parsing of a results file is quite permissive in terms of file syntax
55*6b3a42afSjmmv /// validation. We accept result files with or without trailing new lines, and
56*6b3a42afSjmmv /// with descriptions that may span multiple lines. This is to avoid getting in
57*6b3a42afSjmmv /// trouble when the result is generated from user code, in which case it is
58*6b3a42afSjmmv /// hard to predict how newlines look like. Just swallow them; it's better for
59*6b3a42afSjmmv /// the consumer.
60*6b3a42afSjmmv ///
61*6b3a42afSjmmv /// \param input The stream from which to read the result.
62*6b3a42afSjmmv ///
63*6b3a42afSjmmv /// \return The parsed result. If there is any problem during parsing, the
64*6b3a42afSjmmv /// failure is encoded as a broken result.
65*6b3a42afSjmmv engine::test_result
parse(std::istream & input)66*6b3a42afSjmmv engine::test_result::parse(std::istream& input)
67*6b3a42afSjmmv {
68*6b3a42afSjmmv std::string line;
69*6b3a42afSjmmv if (!std::getline(input, line).good() && line.empty())
70*6b3a42afSjmmv return test_result(broken, "Empty result file");
71*6b3a42afSjmmv
72*6b3a42afSjmmv // Fast-path for the most common case.
73*6b3a42afSjmmv if (line == "passed")
74*6b3a42afSjmmv return test_result(passed);
75*6b3a42afSjmmv
76*6b3a42afSjmmv std::string type, reason;
77*6b3a42afSjmmv const std::string::size_type pos = line.find(": ");
78*6b3a42afSjmmv if (pos == std::string::npos) {
79*6b3a42afSjmmv type = line;
80*6b3a42afSjmmv reason = "";
81*6b3a42afSjmmv } else {
82*6b3a42afSjmmv type = line.substr(0, pos);
83*6b3a42afSjmmv reason = line.substr(pos + 2);
84*6b3a42afSjmmv }
85*6b3a42afSjmmv
86*6b3a42afSjmmv if (input.good()) {
87*6b3a42afSjmmv line.clear();
88*6b3a42afSjmmv while (std::getline(input, line).good() && !line.empty()) {
89*6b3a42afSjmmv reason += "<<NEWLINE>>" + line;
90*6b3a42afSjmmv line.clear();
91*6b3a42afSjmmv }
92*6b3a42afSjmmv if (!line.empty())
93*6b3a42afSjmmv reason += "<<NEWLINE>>" + line;
94*6b3a42afSjmmv }
95*6b3a42afSjmmv
96*6b3a42afSjmmv if (type == "broken") {
97*6b3a42afSjmmv return test_result(broken, reason);
98*6b3a42afSjmmv } else if (type == "expected_failure") {
99*6b3a42afSjmmv return test_result(expected_failure, reason);
100*6b3a42afSjmmv } else if (type == "failed") {
101*6b3a42afSjmmv return test_result(failed, reason);
102*6b3a42afSjmmv } else if (type == "passed") {
103*6b3a42afSjmmv return test_result(passed, reason);
104*6b3a42afSjmmv } else if (type == "skipped") {
105*6b3a42afSjmmv return test_result(skipped, reason);
106*6b3a42afSjmmv } else {
107*6b3a42afSjmmv return test_result(broken, F("Unknown result type '%s'") % type);
108*6b3a42afSjmmv }
109*6b3a42afSjmmv }
110*6b3a42afSjmmv
111*6b3a42afSjmmv
112*6b3a42afSjmmv /// Returns the type of the result.
113*6b3a42afSjmmv ///
114*6b3a42afSjmmv /// \return A result type.
115*6b3a42afSjmmv engine::test_result::result_type
type(void) const116*6b3a42afSjmmv engine::test_result::type(void) const
117*6b3a42afSjmmv {
118*6b3a42afSjmmv return _type;
119*6b3a42afSjmmv }
120*6b3a42afSjmmv
121*6b3a42afSjmmv
122*6b3a42afSjmmv /// Returns the reason explaining the result.
123*6b3a42afSjmmv ///
124*6b3a42afSjmmv /// \return A textual reason, possibly empty.
125*6b3a42afSjmmv const std::string&
reason(void) const126*6b3a42afSjmmv engine::test_result::reason(void) const
127*6b3a42afSjmmv {
128*6b3a42afSjmmv return _reason;
129*6b3a42afSjmmv }
130*6b3a42afSjmmv
131*6b3a42afSjmmv
132*6b3a42afSjmmv /// True if the test case result has a positive connotation.
133*6b3a42afSjmmv ///
134*6b3a42afSjmmv /// \return Whether the test case is good or not.
135*6b3a42afSjmmv bool
good(void) const136*6b3a42afSjmmv engine::test_result::good(void) const
137*6b3a42afSjmmv {
138*6b3a42afSjmmv switch (_type) {
139*6b3a42afSjmmv case expected_failure:
140*6b3a42afSjmmv case passed:
141*6b3a42afSjmmv case skipped:
142*6b3a42afSjmmv return true;
143*6b3a42afSjmmv
144*6b3a42afSjmmv case broken:
145*6b3a42afSjmmv case failed:
146*6b3a42afSjmmv return false;
147*6b3a42afSjmmv }
148*6b3a42afSjmmv UNREACHABLE;
149*6b3a42afSjmmv }
150*6b3a42afSjmmv
151*6b3a42afSjmmv
152*6b3a42afSjmmv /// Equality comparator.
153*6b3a42afSjmmv ///
154*6b3a42afSjmmv /// \param other The test result to compare to.
155*6b3a42afSjmmv ///
156*6b3a42afSjmmv /// \return True if the other object is equal to this one, false otherwise.
157*6b3a42afSjmmv bool
operator ==(const test_result & other) const158*6b3a42afSjmmv engine::test_result::operator==(const test_result& other) const
159*6b3a42afSjmmv {
160*6b3a42afSjmmv return _type == other._type && _reason == other._reason;
161*6b3a42afSjmmv }
162*6b3a42afSjmmv
163*6b3a42afSjmmv
164*6b3a42afSjmmv /// Inequality comparator.
165*6b3a42afSjmmv ///
166*6b3a42afSjmmv /// \param other The test result to compare to.
167*6b3a42afSjmmv ///
168*6b3a42afSjmmv /// \return True if the other object is different from this one, false
169*6b3a42afSjmmv /// otherwise.
170*6b3a42afSjmmv bool
operator !=(const test_result & other) const171*6b3a42afSjmmv engine::test_result::operator!=(const test_result& other) const
172*6b3a42afSjmmv {
173*6b3a42afSjmmv return !(*this == other);
174*6b3a42afSjmmv }
175*6b3a42afSjmmv
176*6b3a42afSjmmv
177*6b3a42afSjmmv /// Injects the object into a stream.
178*6b3a42afSjmmv ///
179*6b3a42afSjmmv /// \param output The stream into which to inject the object.
180*6b3a42afSjmmv /// \param object The object to format.
181*6b3a42afSjmmv ///
182*6b3a42afSjmmv /// \return The output stream.
183*6b3a42afSjmmv std::ostream&
operator <<(std::ostream & output,const test_result & object)184*6b3a42afSjmmv engine::operator<<(std::ostream& output, const test_result& object)
185*6b3a42afSjmmv {
186*6b3a42afSjmmv std::string result_name;
187*6b3a42afSjmmv switch (object.type()) {
188*6b3a42afSjmmv case test_result::broken: result_name = "broken"; break;
189*6b3a42afSjmmv case test_result::expected_failure: result_name = "expected_failure"; break;
190*6b3a42afSjmmv case test_result::failed: result_name = "failed"; break;
191*6b3a42afSjmmv case test_result::passed: result_name = "passed"; break;
192*6b3a42afSjmmv case test_result::skipped: result_name = "skipped"; break;
193*6b3a42afSjmmv }
194*6b3a42afSjmmv const std::string& reason = object.reason();
195*6b3a42afSjmmv if (reason.empty()) {
196*6b3a42afSjmmv output << F("test_result{type=%s}") % text::quote(result_name, '\'');
197*6b3a42afSjmmv } else {
198*6b3a42afSjmmv output << F("test_result{type=%s, reason=%s}")
199*6b3a42afSjmmv % text::quote(result_name, '\'') % text::quote(reason, '\'');
200*6b3a42afSjmmv }
201*6b3a42afSjmmv return output;
202*6b3a42afSjmmv }
203