1// Copyright 2010 The Kyua Authors. 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 "model/test_case.hpp" 30 31#include "model/metadata.hpp" 32#include "model/test_result.hpp" 33#include "utils/format/macros.hpp" 34#include "utils/noncopyable.hpp" 35#include "utils/optional.ipp" 36#include "utils/text/operations.ipp" 37 38namespace text = utils::text; 39 40using utils::none; 41using utils::optional; 42 43 44/// Internal implementation for a test_case. 45struct model::test_case::impl : utils::noncopyable { 46 /// Name of the test case; must be unique within the test program. 47 std::string name; 48 49 /// Metadata of the container test program. 50 /// 51 /// Yes, this is a pointer. Yes, we do not own the object pointed to. 52 /// However, because this is only intended to point to the metadata object 53 /// of test programs _containing_ this test case, we can assume that the 54 /// referenced object will be alive for the lifetime of this test case. 55 const model::metadata* md_defaults; 56 57 /// Test case metadata. 58 model::metadata md; 59 60 /// Fake result to return instead of running the test case. 61 optional< model::test_result > fake_result; 62 63 /// Constructor. 64 /// 65 /// \param name_ The name of the test case within the test program. 66 /// \param md_defaults_ Metadata of the container test program. 67 /// \param md_ Metadata of the test case. 68 /// \param fake_result_ Fake result to return instead of running the test 69 /// case. 70 impl(const std::string& name_, 71 const model::metadata* md_defaults_, 72 const model::metadata& md_, 73 const optional< model::test_result >& fake_result_) : 74 name(name_), 75 md_defaults(md_defaults_), 76 md(md_), 77 fake_result(fake_result_) 78 { 79 } 80 81 /// Gets the test case metadata. 82 /// 83 /// This combines the test case's metadata with any possible test program 84 /// metadata, using the latter as defaults. 85 /// 86 /// \return The test case metadata. 87 model::metadata 88 get_metadata(void) const 89 { 90 if (md_defaults != NULL) { 91 return md_defaults->apply_overrides(md); 92 } else { 93 return md; 94 } 95 } 96 97 /// Equality comparator. 98 /// 99 /// \param other The other object to compare this one to. 100 /// 101 /// \return True if this object and other are equal; false otherwise. 102 bool 103 operator==(const impl& other) const 104 { 105 return (name == other.name && 106 get_metadata() == other.get_metadata() && 107 fake_result == other.fake_result); 108 } 109}; 110 111 112/// Constructs a new test case from an already-built impl oject. 113/// 114/// \param pimpl_ The internal representation of the test case. 115model::test_case::test_case(std::shared_ptr< impl > pimpl_) : 116 _pimpl(pimpl_) 117{ 118} 119 120 121/// Constructs a new test case. 122/// 123/// \param name_ The name of the test case within the test program. 124/// \param md_ Metadata of the test case. 125model::test_case::test_case(const std::string& name_, 126 const model::metadata& md_) : 127 _pimpl(new impl(name_, NULL, md_, none)) 128{ 129} 130 131 132 133/// Constructs a new fake test case. 134/// 135/// A fake test case is a test case that is not really defined by the test 136/// program. Such test cases have a name surrounded by '__' and, when executed, 137/// they return a fixed, pre-recorded result. 138/// 139/// This is necessary for the cases where listing the test cases of a test 140/// program fails. In this scenario, we generate a single test case within 141/// the test program that unconditionally returns a failure. 142/// 143/// TODO(jmmv): Need to get rid of this. We should be able to report the 144/// status of test programs independently of test cases, as some interfaces 145/// don't know about the latter at all. 146/// 147/// \param name_ The name to give to this fake test case. This name has to be 148/// prefixed and suffixed by '__' to clearly denote that this is internal. 149/// \param description_ The description of the test case, if any. 150/// \param test_result_ The fake result to return when this test case is run. 151model::test_case::test_case( 152 const std::string& name_, 153 const std::string& description_, 154 const model::test_result& test_result_) : 155 _pimpl(new impl( 156 name_, 157 NULL, 158 model::metadata_builder().set_description(description_).build(), 159 utils::make_optional(test_result_))) 160{ 161 PRE_MSG(name_.length() > 4 && name_.substr(0, 2) == "__" && 162 name_.substr(name_.length() - 2) == "__", 163 "Invalid fake name provided to fake test case"); 164} 165 166 167/// Destroys a test case. 168model::test_case::~test_case(void) 169{ 170} 171 172 173/// Constructs a new test case applying metadata defaults. 174/// 175/// This method is intended to be used by the container test program when 176/// ownership of the test is given to it. At that point, the test case receives 177/// the default metadata properties of the test program, not the global 178/// defaults. 179/// 180/// \param defaults The metadata properties to use as defaults. The provided 181/// object's lifetime MUST extend the lifetime of the test case. Because 182/// this is only intended to point at the metadata of the test program 183/// containing this test case, this assumption should hold. 184/// 185/// \return A new test case. 186model::test_case 187model::test_case::apply_metadata_defaults(const metadata* defaults) const 188{ 189 return test_case(std::shared_ptr< impl >(new impl( 190 _pimpl->name, 191 defaults, 192 _pimpl->md, 193 _pimpl->fake_result))); 194} 195 196 197/// Gets the test case name. 198/// 199/// \return The test case name, relative to the test program. 200const std::string& 201model::test_case::name(void) const 202{ 203 return _pimpl->name; 204} 205 206 207/// Gets the test case metadata. 208/// 209/// This combines the test case's metadata with any possible test program 210/// metadata, using the latter as defaults. You should use this method in 211/// generaland not get_raw_metadata(). 212/// 213/// \return The test case metadata. 214model::metadata 215model::test_case::get_metadata(void) const 216{ 217 return _pimpl->get_metadata(); 218} 219 220 221/// Gets the original test case metadata without test program overrides. 222/// 223/// This method should be used for storage purposes as serialized test cases 224/// should record exactly whatever the test case reported and not what the test 225/// program may have provided. The final values will be reconstructed at load 226/// time. 227/// 228/// \return The test case metadata. 229const model::metadata& 230model::test_case::get_raw_metadata(void) const 231{ 232 return _pimpl->md; 233} 234 235 236/// Gets the fake result pre-stored for this test case. 237/// 238/// \return A fake result, or none if not defined. 239optional< model::test_result > 240model::test_case::fake_result(void) const 241{ 242 return _pimpl->fake_result; 243} 244 245 246/// Equality comparator. 247/// 248/// \warning Because test cases reference their container test programs, and 249/// test programs include test cases, we cannot perform a full comparison here: 250/// otherwise, we'd enter an inifinte loop. Therefore, out of necessity, this 251/// does NOT compare whether the container test programs of the affected test 252/// cases are the same. 253/// 254/// \param other The other object to compare this one to. 255/// 256/// \return True if this object and other are equal; false otherwise. 257bool 258model::test_case::operator==(const test_case& other) const 259{ 260 return _pimpl == other._pimpl || *_pimpl == *other._pimpl; 261} 262 263 264/// Inequality comparator. 265/// 266/// \param other The other object to compare this one to. 267/// 268/// \return True if this object and other are different; false otherwise. 269bool 270model::test_case::operator!=(const test_case& other) const 271{ 272 return !(*this == other); 273} 274 275 276/// Injects the object into a stream. 277/// 278/// \param output The stream into which to inject the object. 279/// \param object The object to format. 280/// 281/// \return The output stream. 282std::ostream& 283model::operator<<(std::ostream& output, const test_case& object) 284{ 285 output << F("test_case{name=%s, metadata=%s}") 286 % text::quote(object.name(), '\'') 287 % object.get_metadata(); 288 return output; 289} 290 291 292/// Adds an already-constructed test case. 293/// 294/// \param test_case The test case to add. 295/// 296/// \return A reference to this builder. 297model::test_cases_map_builder& 298model::test_cases_map_builder::add(const test_case& test_case) 299{ 300 _test_cases.insert( 301 test_cases_map::value_type(test_case.name(), test_case)); 302 return *this; 303} 304 305 306/// Constructs and adds a new test case with default metadata. 307/// 308/// \param test_case_name The name of the test case to add. 309/// 310/// \return A reference to this builder. 311model::test_cases_map_builder& 312model::test_cases_map_builder::add(const std::string& test_case_name) 313{ 314 return add(test_case(test_case_name, metadata_builder().build())); 315} 316 317 318/// Constructs and adds a new test case with explicit metadata. 319/// 320/// \param test_case_name The name of the test case to add. 321/// \param metadata The metadata of the test case. 322/// 323/// \return A reference to this builder. 324model::test_cases_map_builder& 325model::test_cases_map_builder::add(const std::string& test_case_name, 326 const metadata& metadata) 327{ 328 return add(test_case(test_case_name, metadata)); 329} 330 331 332/// Creates a new test_cases_map. 333/// 334/// \return The constructed test_cases_map. 335model::test_cases_map 336model::test_cases_map_builder::build(void) const 337{ 338 return _test_cases; 339} 340