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