1*b0d29bc4SBrooks Davis // Copyright 2010 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis // documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis // may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis // without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis
29*b0d29bc4SBrooks Davis #include "model/test_program.hpp"
30*b0d29bc4SBrooks Davis
31*b0d29bc4SBrooks Davis #include <map>
32*b0d29bc4SBrooks Davis #include <sstream>
33*b0d29bc4SBrooks Davis
34*b0d29bc4SBrooks Davis #include "model/exceptions.hpp"
35*b0d29bc4SBrooks Davis #include "model/metadata.hpp"
36*b0d29bc4SBrooks Davis #include "model/test_case.hpp"
37*b0d29bc4SBrooks Davis #include "model/test_result.hpp"
38*b0d29bc4SBrooks Davis #include "utils/format/containers.ipp"
39*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
40*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
41*b0d29bc4SBrooks Davis #include "utils/noncopyable.hpp"
42*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
43*b0d29bc4SBrooks Davis #include "utils/text/operations.ipp"
44*b0d29bc4SBrooks Davis
45*b0d29bc4SBrooks Davis namespace fs = utils::fs;
46*b0d29bc4SBrooks Davis namespace text = utils::text;
47*b0d29bc4SBrooks Davis
48*b0d29bc4SBrooks Davis using utils::none;
49*b0d29bc4SBrooks Davis
50*b0d29bc4SBrooks Davis
51*b0d29bc4SBrooks Davis /// Internal implementation of a test_program.
52*b0d29bc4SBrooks Davis struct model::test_program::impl : utils::noncopyable {
53*b0d29bc4SBrooks Davis /// Name of the test program interface.
54*b0d29bc4SBrooks Davis std::string interface_name;
55*b0d29bc4SBrooks Davis
56*b0d29bc4SBrooks Davis /// Name of the test program binary relative to root.
57*b0d29bc4SBrooks Davis fs::path binary;
58*b0d29bc4SBrooks Davis
59*b0d29bc4SBrooks Davis /// Root of the test suite containing the test program.
60*b0d29bc4SBrooks Davis fs::path root;
61*b0d29bc4SBrooks Davis
62*b0d29bc4SBrooks Davis /// Name of the test suite this program belongs to.
63*b0d29bc4SBrooks Davis std::string test_suite_name;
64*b0d29bc4SBrooks Davis
65*b0d29bc4SBrooks Davis /// Metadata of the test program.
66*b0d29bc4SBrooks Davis model::metadata md;
67*b0d29bc4SBrooks Davis
68*b0d29bc4SBrooks Davis /// List of test cases in the test program.
69*b0d29bc4SBrooks Davis ///
70*b0d29bc4SBrooks Davis /// Must be queried via the test_program::test_cases() method.
71*b0d29bc4SBrooks Davis model::test_cases_map test_cases;
72*b0d29bc4SBrooks Davis
73*b0d29bc4SBrooks Davis /// Constructor.
74*b0d29bc4SBrooks Davis ///
75*b0d29bc4SBrooks Davis /// \param interface_name_ Name of the test program interface.
76*b0d29bc4SBrooks Davis /// \param binary_ The name of the test program binary relative to root_.
77*b0d29bc4SBrooks Davis /// \param root_ The root of the test suite containing the test program.
78*b0d29bc4SBrooks Davis /// \param test_suite_name_ The name of the test suite this program
79*b0d29bc4SBrooks Davis /// belongs to.
80*b0d29bc4SBrooks Davis /// \param md_ Metadata of the test program.
81*b0d29bc4SBrooks Davis /// \param test_cases_ The collection of test cases in the test program.
implmodel::test_program::impl82*b0d29bc4SBrooks Davis impl(const std::string& interface_name_, const fs::path& binary_,
83*b0d29bc4SBrooks Davis const fs::path& root_, const std::string& test_suite_name_,
84*b0d29bc4SBrooks Davis const model::metadata& md_, const model::test_cases_map& test_cases_) :
85*b0d29bc4SBrooks Davis interface_name(interface_name_),
86*b0d29bc4SBrooks Davis binary(binary_),
87*b0d29bc4SBrooks Davis root(root_),
88*b0d29bc4SBrooks Davis test_suite_name(test_suite_name_),
89*b0d29bc4SBrooks Davis md(md_)
90*b0d29bc4SBrooks Davis {
91*b0d29bc4SBrooks Davis PRE_MSG(!binary.is_absolute(),
92*b0d29bc4SBrooks Davis F("The program '%s' must be relative to the root of the test "
93*b0d29bc4SBrooks Davis "suite '%s'") % binary % root);
94*b0d29bc4SBrooks Davis
95*b0d29bc4SBrooks Davis set_test_cases(test_cases_);
96*b0d29bc4SBrooks Davis }
97*b0d29bc4SBrooks Davis
98*b0d29bc4SBrooks Davis /// Sets the list of test cases of the test program.
99*b0d29bc4SBrooks Davis ///
100*b0d29bc4SBrooks Davis /// \param test_cases_ The new list of test cases.
101*b0d29bc4SBrooks Davis void
set_test_casesmodel::test_program::impl102*b0d29bc4SBrooks Davis set_test_cases(const model::test_cases_map& test_cases_)
103*b0d29bc4SBrooks Davis {
104*b0d29bc4SBrooks Davis for (model::test_cases_map::const_iterator iter = test_cases_.begin();
105*b0d29bc4SBrooks Davis iter != test_cases_.end(); ++iter) {
106*b0d29bc4SBrooks Davis const std::string& name = (*iter).first;
107*b0d29bc4SBrooks Davis const model::test_case& test_case = (*iter).second;
108*b0d29bc4SBrooks Davis
109*b0d29bc4SBrooks Davis PRE_MSG(name == test_case.name(),
110*b0d29bc4SBrooks Davis F("The test case '%s' has been registered with the "
111*b0d29bc4SBrooks Davis "non-matching name '%s'") % name % test_case.name());
112*b0d29bc4SBrooks Davis
113*b0d29bc4SBrooks Davis test_cases.insert(model::test_cases_map::value_type(
114*b0d29bc4SBrooks Davis name, test_case.apply_metadata_defaults(&md)));
115*b0d29bc4SBrooks Davis }
116*b0d29bc4SBrooks Davis INV(test_cases.size() == test_cases_.size());
117*b0d29bc4SBrooks Davis }
118*b0d29bc4SBrooks Davis };
119*b0d29bc4SBrooks Davis
120*b0d29bc4SBrooks Davis
121*b0d29bc4SBrooks Davis /// Constructs a new test program.
122*b0d29bc4SBrooks Davis ///
123*b0d29bc4SBrooks Davis /// \param interface_name_ Name of the test program interface.
124*b0d29bc4SBrooks Davis /// \param binary_ The name of the test program binary relative to root_.
125*b0d29bc4SBrooks Davis /// \param root_ The root of the test suite containing the test program.
126*b0d29bc4SBrooks Davis /// \param test_suite_name_ The name of the test suite this program belongs to.
127*b0d29bc4SBrooks Davis /// \param md_ Metadata of the test program.
128*b0d29bc4SBrooks Davis /// \param test_cases_ The collection of test cases in the test program.
test_program(const std::string & interface_name_,const fs::path & binary_,const fs::path & root_,const std::string & test_suite_name_,const model::metadata & md_,const model::test_cases_map & test_cases_)129*b0d29bc4SBrooks Davis model::test_program::test_program(const std::string& interface_name_,
130*b0d29bc4SBrooks Davis const fs::path& binary_,
131*b0d29bc4SBrooks Davis const fs::path& root_,
132*b0d29bc4SBrooks Davis const std::string& test_suite_name_,
133*b0d29bc4SBrooks Davis const model::metadata& md_,
134*b0d29bc4SBrooks Davis const model::test_cases_map& test_cases_) :
135*b0d29bc4SBrooks Davis _pimpl(new impl(interface_name_, binary_, root_, test_suite_name_, md_,
136*b0d29bc4SBrooks Davis test_cases_))
137*b0d29bc4SBrooks Davis {
138*b0d29bc4SBrooks Davis }
139*b0d29bc4SBrooks Davis
140*b0d29bc4SBrooks Davis
141*b0d29bc4SBrooks Davis /// Destroys a test program.
~test_program(void)142*b0d29bc4SBrooks Davis model::test_program::~test_program(void)
143*b0d29bc4SBrooks Davis {
144*b0d29bc4SBrooks Davis }
145*b0d29bc4SBrooks Davis
146*b0d29bc4SBrooks Davis
147*b0d29bc4SBrooks Davis /// Gets the name of the test program interface.
148*b0d29bc4SBrooks Davis ///
149*b0d29bc4SBrooks Davis /// \return An interface name.
150*b0d29bc4SBrooks Davis const std::string&
interface_name(void) const151*b0d29bc4SBrooks Davis model::test_program::interface_name(void) const
152*b0d29bc4SBrooks Davis {
153*b0d29bc4SBrooks Davis return _pimpl->interface_name;
154*b0d29bc4SBrooks Davis }
155*b0d29bc4SBrooks Davis
156*b0d29bc4SBrooks Davis
157*b0d29bc4SBrooks Davis /// Gets the path to the test program relative to the root of the test suite.
158*b0d29bc4SBrooks Davis ///
159*b0d29bc4SBrooks Davis /// \return The relative path to the test program binary.
160*b0d29bc4SBrooks Davis const fs::path&
relative_path(void) const161*b0d29bc4SBrooks Davis model::test_program::relative_path(void) const
162*b0d29bc4SBrooks Davis {
163*b0d29bc4SBrooks Davis return _pimpl->binary;
164*b0d29bc4SBrooks Davis }
165*b0d29bc4SBrooks Davis
166*b0d29bc4SBrooks Davis
167*b0d29bc4SBrooks Davis /// Gets the absolute path to the test program.
168*b0d29bc4SBrooks Davis ///
169*b0d29bc4SBrooks Davis /// \return The absolute path to the test program binary.
170*b0d29bc4SBrooks Davis const fs::path
absolute_path(void) const171*b0d29bc4SBrooks Davis model::test_program::absolute_path(void) const
172*b0d29bc4SBrooks Davis {
173*b0d29bc4SBrooks Davis const fs::path full_path = _pimpl->root / _pimpl->binary;
174*b0d29bc4SBrooks Davis return full_path.is_absolute() ? full_path : full_path.to_absolute();
175*b0d29bc4SBrooks Davis }
176*b0d29bc4SBrooks Davis
177*b0d29bc4SBrooks Davis
178*b0d29bc4SBrooks Davis /// Gets the root of the test suite containing this test program.
179*b0d29bc4SBrooks Davis ///
180*b0d29bc4SBrooks Davis /// \return The path to the root of the test suite.
181*b0d29bc4SBrooks Davis const fs::path&
root(void) const182*b0d29bc4SBrooks Davis model::test_program::root(void) const
183*b0d29bc4SBrooks Davis {
184*b0d29bc4SBrooks Davis return _pimpl->root;
185*b0d29bc4SBrooks Davis }
186*b0d29bc4SBrooks Davis
187*b0d29bc4SBrooks Davis
188*b0d29bc4SBrooks Davis /// Gets the name of the test suite containing this test program.
189*b0d29bc4SBrooks Davis ///
190*b0d29bc4SBrooks Davis /// \return The name of the test suite.
191*b0d29bc4SBrooks Davis const std::string&
test_suite_name(void) const192*b0d29bc4SBrooks Davis model::test_program::test_suite_name(void) const
193*b0d29bc4SBrooks Davis {
194*b0d29bc4SBrooks Davis return _pimpl->test_suite_name;
195*b0d29bc4SBrooks Davis }
196*b0d29bc4SBrooks Davis
197*b0d29bc4SBrooks Davis
198*b0d29bc4SBrooks Davis /// Gets the metadata of the test program.
199*b0d29bc4SBrooks Davis ///
200*b0d29bc4SBrooks Davis /// \return The metadata.
201*b0d29bc4SBrooks Davis const model::metadata&
get_metadata(void) const202*b0d29bc4SBrooks Davis model::test_program::get_metadata(void) const
203*b0d29bc4SBrooks Davis {
204*b0d29bc4SBrooks Davis return _pimpl->md;
205*b0d29bc4SBrooks Davis }
206*b0d29bc4SBrooks Davis
207*b0d29bc4SBrooks Davis
208*b0d29bc4SBrooks Davis /// Gets a test case by its name.
209*b0d29bc4SBrooks Davis ///
210*b0d29bc4SBrooks Davis /// \param name The name of the test case to locate.
211*b0d29bc4SBrooks Davis ///
212*b0d29bc4SBrooks Davis /// \return The requested test case.
213*b0d29bc4SBrooks Davis ///
214*b0d29bc4SBrooks Davis /// \throw not_found_error If the specified test case is not in the test
215*b0d29bc4SBrooks Davis /// program.
216*b0d29bc4SBrooks Davis const model::test_case&
find(const std::string & name) const217*b0d29bc4SBrooks Davis model::test_program::find(const std::string& name) const
218*b0d29bc4SBrooks Davis {
219*b0d29bc4SBrooks Davis const test_cases_map& tcs = test_cases();
220*b0d29bc4SBrooks Davis
221*b0d29bc4SBrooks Davis const test_cases_map::const_iterator iter = tcs.find(name);
222*b0d29bc4SBrooks Davis if (iter == tcs.end())
223*b0d29bc4SBrooks Davis throw not_found_error(F("Unknown test case %s in test program %s") %
224*b0d29bc4SBrooks Davis name % relative_path());
225*b0d29bc4SBrooks Davis return (*iter).second;
226*b0d29bc4SBrooks Davis }
227*b0d29bc4SBrooks Davis
228*b0d29bc4SBrooks Davis
229*b0d29bc4SBrooks Davis /// Gets the list of test cases from the test program.
230*b0d29bc4SBrooks Davis ///
231*b0d29bc4SBrooks Davis /// \return The list of test cases provided by the test program.
232*b0d29bc4SBrooks Davis const model::test_cases_map&
test_cases(void) const233*b0d29bc4SBrooks Davis model::test_program::test_cases(void) const
234*b0d29bc4SBrooks Davis {
235*b0d29bc4SBrooks Davis return _pimpl->test_cases;
236*b0d29bc4SBrooks Davis }
237*b0d29bc4SBrooks Davis
238*b0d29bc4SBrooks Davis
239*b0d29bc4SBrooks Davis /// Sets the list of test cases of the test program.
240*b0d29bc4SBrooks Davis ///
241*b0d29bc4SBrooks Davis /// This can only be called once and it may only be called from within
242*b0d29bc4SBrooks Davis /// overridden test_cases() before that method ever returns a value for the
243*b0d29bc4SBrooks Davis /// first time. Any other invocations will result in inconsistent program
244*b0d29bc4SBrooks Davis /// state.
245*b0d29bc4SBrooks Davis ///
246*b0d29bc4SBrooks Davis /// \param test_cases_ The new list of test cases.
247*b0d29bc4SBrooks Davis void
set_test_cases(const model::test_cases_map & test_cases_)248*b0d29bc4SBrooks Davis model::test_program::set_test_cases(const model::test_cases_map& test_cases_)
249*b0d29bc4SBrooks Davis {
250*b0d29bc4SBrooks Davis PRE(_pimpl->test_cases.empty());
251*b0d29bc4SBrooks Davis _pimpl->set_test_cases(test_cases_);
252*b0d29bc4SBrooks Davis }
253*b0d29bc4SBrooks Davis
254*b0d29bc4SBrooks Davis
255*b0d29bc4SBrooks Davis /// Equality comparator.
256*b0d29bc4SBrooks Davis ///
257*b0d29bc4SBrooks Davis /// \param other The other object to compare this one to.
258*b0d29bc4SBrooks Davis ///
259*b0d29bc4SBrooks Davis /// \return True if this object and other are equal; false otherwise.
260*b0d29bc4SBrooks Davis bool
operator ==(const test_program & other) const261*b0d29bc4SBrooks Davis model::test_program::operator==(const test_program& other) const
262*b0d29bc4SBrooks Davis {
263*b0d29bc4SBrooks Davis return _pimpl == other._pimpl || (
264*b0d29bc4SBrooks Davis _pimpl->interface_name == other._pimpl->interface_name &&
265*b0d29bc4SBrooks Davis _pimpl->binary == other._pimpl->binary &&
266*b0d29bc4SBrooks Davis _pimpl->root == other._pimpl->root &&
267*b0d29bc4SBrooks Davis _pimpl->test_suite_name == other._pimpl->test_suite_name &&
268*b0d29bc4SBrooks Davis _pimpl->md == other._pimpl->md &&
269*b0d29bc4SBrooks Davis test_cases() == other.test_cases());
270*b0d29bc4SBrooks Davis }
271*b0d29bc4SBrooks Davis
272*b0d29bc4SBrooks Davis
273*b0d29bc4SBrooks Davis /// Inequality comparator.
274*b0d29bc4SBrooks Davis ///
275*b0d29bc4SBrooks Davis /// \param other The other object to compare this one to.
276*b0d29bc4SBrooks Davis ///
277*b0d29bc4SBrooks Davis /// \return True if this object and other are different; false otherwise.
278*b0d29bc4SBrooks Davis bool
operator !=(const test_program & other) const279*b0d29bc4SBrooks Davis model::test_program::operator!=(const test_program& other) const
280*b0d29bc4SBrooks Davis {
281*b0d29bc4SBrooks Davis return !(*this == other);
282*b0d29bc4SBrooks Davis }
283*b0d29bc4SBrooks Davis
284*b0d29bc4SBrooks Davis
285*b0d29bc4SBrooks Davis /// Less-than comparator.
286*b0d29bc4SBrooks Davis ///
287*b0d29bc4SBrooks Davis /// A test program is considered to be less than another if and only if the
288*b0d29bc4SBrooks Davis /// former's absolute path is less than the absolute path of the latter. In
289*b0d29bc4SBrooks Davis /// other words, the absolute path is used here as the test program's
290*b0d29bc4SBrooks Davis /// identifier.
291*b0d29bc4SBrooks Davis ///
292*b0d29bc4SBrooks Davis /// This simplistic less-than operator overload is provided so that test
293*b0d29bc4SBrooks Davis /// programs can be held in sets and other containers.
294*b0d29bc4SBrooks Davis ///
295*b0d29bc4SBrooks Davis /// \param other The other object to compare this one to.
296*b0d29bc4SBrooks Davis ///
297*b0d29bc4SBrooks Davis /// \return True if this object sorts before the other object; false otherwise.
298*b0d29bc4SBrooks Davis bool
operator <(const test_program & other) const299*b0d29bc4SBrooks Davis model::test_program::operator<(const test_program& other) const
300*b0d29bc4SBrooks Davis {
301*b0d29bc4SBrooks Davis return absolute_path() < other.absolute_path();
302*b0d29bc4SBrooks Davis }
303*b0d29bc4SBrooks Davis
304*b0d29bc4SBrooks Davis
305*b0d29bc4SBrooks Davis /// Injects the object into a stream.
306*b0d29bc4SBrooks Davis ///
307*b0d29bc4SBrooks Davis /// \param output The stream into which to inject the object.
308*b0d29bc4SBrooks Davis /// \param object The object to format.
309*b0d29bc4SBrooks Davis ///
310*b0d29bc4SBrooks Davis /// \return The output stream.
311*b0d29bc4SBrooks Davis std::ostream&
operator <<(std::ostream & output,const test_program & object)312*b0d29bc4SBrooks Davis model::operator<<(std::ostream& output, const test_program& object)
313*b0d29bc4SBrooks Davis {
314*b0d29bc4SBrooks Davis output << F("test_program{interface=%s, binary=%s, root=%s, test_suite=%s, "
315*b0d29bc4SBrooks Davis "metadata=%s, test_cases=%s}")
316*b0d29bc4SBrooks Davis % text::quote(object.interface_name(), '\'')
317*b0d29bc4SBrooks Davis % text::quote(object.relative_path().str(), '\'')
318*b0d29bc4SBrooks Davis % text::quote(object.root().str(), '\'')
319*b0d29bc4SBrooks Davis % text::quote(object.test_suite_name(), '\'')
320*b0d29bc4SBrooks Davis % object.get_metadata()
321*b0d29bc4SBrooks Davis % object.test_cases();
322*b0d29bc4SBrooks Davis return output;
323*b0d29bc4SBrooks Davis }
324*b0d29bc4SBrooks Davis
325*b0d29bc4SBrooks Davis
326*b0d29bc4SBrooks Davis /// Internal implementation of the test_program_builder class.
327*b0d29bc4SBrooks Davis struct model::test_program_builder::impl : utils::noncopyable {
328*b0d29bc4SBrooks Davis /// Partially-constructed program with only the required properties.
329*b0d29bc4SBrooks Davis model::test_program prototype;
330*b0d29bc4SBrooks Davis
331*b0d29bc4SBrooks Davis /// Optional metadata for the test program.
332*b0d29bc4SBrooks Davis model::metadata metadata;
333*b0d29bc4SBrooks Davis
334*b0d29bc4SBrooks Davis /// Collection of test cases.
335*b0d29bc4SBrooks Davis model::test_cases_map test_cases;
336*b0d29bc4SBrooks Davis
337*b0d29bc4SBrooks Davis /// Whether we have created a test_program object or not.
338*b0d29bc4SBrooks Davis bool built;
339*b0d29bc4SBrooks Davis
340*b0d29bc4SBrooks Davis /// Constructor.
341*b0d29bc4SBrooks Davis ///
342*b0d29bc4SBrooks Davis /// \param prototype_ The partially constructed program with only the
343*b0d29bc4SBrooks Davis /// required properties.
implmodel::test_program_builder::impl344*b0d29bc4SBrooks Davis impl(const model::test_program& prototype_) :
345*b0d29bc4SBrooks Davis prototype(prototype_),
346*b0d29bc4SBrooks Davis metadata(model::metadata_builder().build()),
347*b0d29bc4SBrooks Davis built(false)
348*b0d29bc4SBrooks Davis {
349*b0d29bc4SBrooks Davis }
350*b0d29bc4SBrooks Davis };
351*b0d29bc4SBrooks Davis
352*b0d29bc4SBrooks Davis
353*b0d29bc4SBrooks Davis /// Constructs a new builder with non-optional values.
354*b0d29bc4SBrooks Davis ///
355*b0d29bc4SBrooks Davis /// \param interface_name_ Name of the test program interface.
356*b0d29bc4SBrooks Davis /// \param binary_ The name of the test program binary relative to root_.
357*b0d29bc4SBrooks Davis /// \param root_ The root of the test suite containing the test program.
358*b0d29bc4SBrooks Davis /// \param test_suite_name_ The name of the test suite this program belongs to.
test_program_builder(const std::string & interface_name_,const fs::path & binary_,const fs::path & root_,const std::string & test_suite_name_)359*b0d29bc4SBrooks Davis model::test_program_builder::test_program_builder(
360*b0d29bc4SBrooks Davis const std::string& interface_name_, const fs::path& binary_,
361*b0d29bc4SBrooks Davis const fs::path& root_, const std::string& test_suite_name_) :
362*b0d29bc4SBrooks Davis _pimpl(new impl(model::test_program(interface_name_, binary_, root_,
363*b0d29bc4SBrooks Davis test_suite_name_,
364*b0d29bc4SBrooks Davis model::metadata_builder().build(),
365*b0d29bc4SBrooks Davis model::test_cases_map())))
366*b0d29bc4SBrooks Davis {
367*b0d29bc4SBrooks Davis }
368*b0d29bc4SBrooks Davis
369*b0d29bc4SBrooks Davis
370*b0d29bc4SBrooks Davis /// Destructor.
~test_program_builder(void)371*b0d29bc4SBrooks Davis model::test_program_builder::~test_program_builder(void)
372*b0d29bc4SBrooks Davis {
373*b0d29bc4SBrooks Davis }
374*b0d29bc4SBrooks Davis
375*b0d29bc4SBrooks Davis
376*b0d29bc4SBrooks Davis /// Accumulates an additional test case with default metadata.
377*b0d29bc4SBrooks Davis ///
378*b0d29bc4SBrooks Davis /// \param test_case_name The name of the test case.
379*b0d29bc4SBrooks Davis ///
380*b0d29bc4SBrooks Davis /// \return A reference to this builder.
381*b0d29bc4SBrooks Davis model::test_program_builder&
add_test_case(const std::string & test_case_name)382*b0d29bc4SBrooks Davis model::test_program_builder::add_test_case(const std::string& test_case_name)
383*b0d29bc4SBrooks Davis {
384*b0d29bc4SBrooks Davis return add_test_case(test_case_name, model::metadata_builder().build());
385*b0d29bc4SBrooks Davis }
386*b0d29bc4SBrooks Davis
387*b0d29bc4SBrooks Davis
388*b0d29bc4SBrooks Davis /// Accumulates an additional test case.
389*b0d29bc4SBrooks Davis ///
390*b0d29bc4SBrooks Davis /// \param test_case_name The name of the test case.
391*b0d29bc4SBrooks Davis /// \param metadata The test case metadata.
392*b0d29bc4SBrooks Davis ///
393*b0d29bc4SBrooks Davis /// \return A reference to this builder.
394*b0d29bc4SBrooks Davis model::test_program_builder&
add_test_case(const std::string & test_case_name,const model::metadata & metadata)395*b0d29bc4SBrooks Davis model::test_program_builder::add_test_case(const std::string& test_case_name,
396*b0d29bc4SBrooks Davis const model::metadata& metadata)
397*b0d29bc4SBrooks Davis {
398*b0d29bc4SBrooks Davis const model::test_case test_case(test_case_name, metadata);
399*b0d29bc4SBrooks Davis PRE_MSG(_pimpl->test_cases.find(test_case_name) == _pimpl->test_cases.end(),
400*b0d29bc4SBrooks Davis F("Attempted to re-register test case '%s'") % test_case_name);
401*b0d29bc4SBrooks Davis _pimpl->test_cases.insert(model::test_cases_map::value_type(
402*b0d29bc4SBrooks Davis test_case_name, test_case));
403*b0d29bc4SBrooks Davis return *this;
404*b0d29bc4SBrooks Davis }
405*b0d29bc4SBrooks Davis
406*b0d29bc4SBrooks Davis
407*b0d29bc4SBrooks Davis /// Sets the test program metadata.
408*b0d29bc4SBrooks Davis ///
409*b0d29bc4SBrooks Davis /// \return metadata The metadata for the test program.
410*b0d29bc4SBrooks Davis ///
411*b0d29bc4SBrooks Davis /// \return A reference to this builder.
412*b0d29bc4SBrooks Davis model::test_program_builder&
set_metadata(const model::metadata & metadata)413*b0d29bc4SBrooks Davis model::test_program_builder::set_metadata(const model::metadata& metadata)
414*b0d29bc4SBrooks Davis {
415*b0d29bc4SBrooks Davis _pimpl->metadata = metadata;
416*b0d29bc4SBrooks Davis return *this;
417*b0d29bc4SBrooks Davis }
418*b0d29bc4SBrooks Davis
419*b0d29bc4SBrooks Davis
420*b0d29bc4SBrooks Davis /// Creates a new test_program object.
421*b0d29bc4SBrooks Davis ///
422*b0d29bc4SBrooks Davis /// \pre This has not yet been called. We only support calling this function
423*b0d29bc4SBrooks Davis /// once.
424*b0d29bc4SBrooks Davis ///
425*b0d29bc4SBrooks Davis /// \return The constructed test_program object.
426*b0d29bc4SBrooks Davis model::test_program
build(void) const427*b0d29bc4SBrooks Davis model::test_program_builder::build(void) const
428*b0d29bc4SBrooks Davis {
429*b0d29bc4SBrooks Davis PRE(!_pimpl->built);
430*b0d29bc4SBrooks Davis _pimpl->built = true;
431*b0d29bc4SBrooks Davis
432*b0d29bc4SBrooks Davis return test_program(_pimpl->prototype.interface_name(),
433*b0d29bc4SBrooks Davis _pimpl->prototype.relative_path(),
434*b0d29bc4SBrooks Davis _pimpl->prototype.root(),
435*b0d29bc4SBrooks Davis _pimpl->prototype.test_suite_name(),
436*b0d29bc4SBrooks Davis _pimpl->metadata,
437*b0d29bc4SBrooks Davis _pimpl->test_cases);
438*b0d29bc4SBrooks Davis }
439*b0d29bc4SBrooks Davis
440*b0d29bc4SBrooks Davis
441*b0d29bc4SBrooks Davis /// Creates a new dynamically-allocated test_program object.
442*b0d29bc4SBrooks Davis ///
443*b0d29bc4SBrooks Davis /// \pre This has not yet been called. We only support calling this function
444*b0d29bc4SBrooks Davis /// once.
445*b0d29bc4SBrooks Davis ///
446*b0d29bc4SBrooks Davis /// \return The constructed test_program object.
447*b0d29bc4SBrooks Davis model::test_program_ptr
build_ptr(void) const448*b0d29bc4SBrooks Davis model::test_program_builder::build_ptr(void) const
449*b0d29bc4SBrooks Davis {
450*b0d29bc4SBrooks Davis const test_program result = build();
451*b0d29bc4SBrooks Davis return test_program_ptr(new test_program(result));
452*b0d29bc4SBrooks Davis }
453