xref: /freebsd/contrib/kyua/model/test_program_test.cpp (revision 257e70f1d5ee61037c8c59b116538d3b6b1427a2)
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_program.hpp"
30 
31 extern "C" {
32 #include <sys/stat.h>
33 
34 #include <signal.h>
35 }
36 
37 #include <set>
38 #include <sstream>
39 
40 #include <atf-c++.hpp>
41 
42 #include "model/exceptions.hpp"
43 #include "model/metadata.hpp"
44 #include "model/test_case.hpp"
45 #include "model/test_result.hpp"
46 #include "utils/env.hpp"
47 #include "utils/format/containers.ipp"
48 #include "utils/format/macros.hpp"
49 #include "utils/fs/operations.hpp"
50 #include "utils/fs/path.hpp"
51 #include "utils/optional.ipp"
52 
53 namespace fs = utils::fs;
54 
55 
56 namespace {
57 
58 
59 /// Test program that sets its test cases lazily.
60 ///
61 /// This test class exists to test the behavior of a test_program object when
62 /// the class is extended to offer lazy loading of test cases.  We simulate such
63 /// lazy loading here by storing the list of test cases aside at construction
64 /// time and later setting it lazily the first time test_cases() is called.
65 class lazy_test_program : public model::test_program {
66     /// Whether set_test_cases() has yet been called or not.
67     mutable bool _set_test_cases_called;
68 
69     /// The list of test cases for this test program.
70     ///
71     /// Only use this in the call to set_test_cases().  All other reads of the
72     /// test cases list should happen via the parent class' test_cases() method.
73     model::test_cases_map _lazy_test_cases;
74 
75 public:
76     /// Constructs a new test program.
77     ///
78     /// \param interface_name_ Name of the test program interface.
79     /// \param binary_ The name of the test program binary relative to root_.
80     /// \param root_ The root of the test suite containing the test program.
81     /// \param test_suite_name_ The name of the test suite.
82     /// \param metadata_ Metadata of the test program.
83     /// \param test_cases_ The collection of test cases in the test program.
lazy_test_program(const std::string & interface_name_,const utils::fs::path & binary_,const utils::fs::path & root_,const std::string & test_suite_name_,const model::metadata & metadata_,const model::test_cases_map & test_cases_)84     lazy_test_program(const std::string& interface_name_,
85                       const utils::fs::path& binary_,
86                       const utils::fs::path& root_,
87                       const std::string& test_suite_name_,
88                       const model::metadata& metadata_,
89                       const model::test_cases_map& test_cases_) :
90         test_program(interface_name_, binary_, root_, test_suite_name_,
91                      metadata_, model::test_cases_map()),
92         _set_test_cases_called(false),
93         _lazy_test_cases(test_cases_)
94     {
95     }
96 
97     /// Lazily sets the test cases on the parent and returns them.
98     ///
99     /// \return The list of test cases.
100     const model::test_cases_map&
test_cases(void) const101     test_cases(void) const
102     {
103         if (!_set_test_cases_called) {
104             const_cast< lazy_test_program* >(this)->set_test_cases(
105                 _lazy_test_cases);
106             _set_test_cases_called = true;
107         }
108         return test_program::test_cases();
109     }
110 };
111 
112 
113 }  // anonymous namespace
114 
115 
116 /// Runs a ctor_and_getters test.
117 ///
118 /// \tparam TestProgram Either model::test_program or lazy_test_program.
119 template< class TestProgram >
120 static void
check_ctor_and_getters(void)121 check_ctor_and_getters(void)
122 {
123     const model::metadata tp_md = model::metadata_builder()
124         .add_custom("first", "foo")
125         .add_custom("second", "bar")
126         .build();
127     const model::metadata tc_md = model::metadata_builder()
128         .add_custom("first", "baz")
129         .build();
130 
131     const TestProgram test_program(
132         "mock", fs::path("binary"), fs::path("root"), "suite-name", tp_md,
133         model::test_cases_map_builder().add("foo", tc_md).build());
134 
135 
136     ATF_REQUIRE_EQ("mock", test_program.interface_name());
137     ATF_REQUIRE_EQ(fs::path("binary"), test_program.relative_path());
138     ATF_REQUIRE_EQ(fs::current_path() / "root/binary",
139                    test_program.absolute_path());
140     ATF_REQUIRE_EQ(fs::path("root"), test_program.root());
141     ATF_REQUIRE_EQ("suite-name", test_program.test_suite_name());
142     ATF_REQUIRE_EQ(tp_md, test_program.get_metadata());
143 
144     const model::metadata exp_tc_md = model::metadata_builder()
145         .add_custom("first", "baz")
146         .add_custom("second", "bar")
147         .build();
148     const model::test_cases_map exp_tcs = model::test_cases_map_builder()
149         .add("foo", exp_tc_md)
150         .build();
151     ATF_REQUIRE_EQ(exp_tcs, test_program.test_cases());
152 }
153 
154 
155 ATF_TEST_CASE_WITHOUT_HEAD(ctor_and_getters);
ATF_TEST_CASE_BODY(ctor_and_getters)156 ATF_TEST_CASE_BODY(ctor_and_getters)
157 {
158     check_ctor_and_getters< model::test_program >();
159 }
160 
161 
162 ATF_TEST_CASE_WITHOUT_HEAD(derived__ctor_and_getters);
ATF_TEST_CASE_BODY(derived__ctor_and_getters)163 ATF_TEST_CASE_BODY(derived__ctor_and_getters)
164 {
165     check_ctor_and_getters< lazy_test_program >();
166 }
167 
168 
169 /// Runs a find_ok test.
170 ///
171 /// \tparam TestProgram Either model::test_program or lazy_test_program.
172 template< class TestProgram >
173 static void
check_find_ok(void)174 check_find_ok(void)
175 {
176     const model::test_case test_case("main", model::metadata_builder().build());
177 
178     const TestProgram test_program(
179         "mock", fs::path("non-existent"), fs::path("."), "suite-name",
180         model::metadata_builder().build(),
181         model::test_cases_map_builder().add(test_case).build());
182 
183     const model::test_case& found_test_case = test_program.find("main");
184     ATF_REQUIRE_EQ(test_case, found_test_case);
185 }
186 
187 
188 ATF_TEST_CASE_WITHOUT_HEAD(find__ok);
ATF_TEST_CASE_BODY(find__ok)189 ATF_TEST_CASE_BODY(find__ok)
190 {
191     check_find_ok< model::test_program >();
192 }
193 
194 
195 ATF_TEST_CASE_WITHOUT_HEAD(derived__find__ok);
ATF_TEST_CASE_BODY(derived__find__ok)196 ATF_TEST_CASE_BODY(derived__find__ok)
197 {
198     check_find_ok< lazy_test_program >();
199 }
200 
201 
202 /// Runs a find_missing test.
203 ///
204 /// \tparam TestProgram Either model::test_program or lazy_test_program.
205 template< class TestProgram >
206 static void
check_find_missing(void)207 check_find_missing(void)
208 {
209     const TestProgram test_program(
210         "mock", fs::path("non-existent"), fs::path("."), "suite-name",
211         model::metadata_builder().build(),
212         model::test_cases_map_builder().add("main").build());
213 
214     ATF_REQUIRE_THROW_RE(model::not_found_error,
215                          "case.*abc.*program.*non-existent",
216                          test_program.find("abc"));
217 }
218 
219 
220 ATF_TEST_CASE_WITHOUT_HEAD(find__missing);
ATF_TEST_CASE_BODY(find__missing)221 ATF_TEST_CASE_BODY(find__missing)
222 {
223     check_find_missing< model::test_program >();
224 }
225 
226 
227 ATF_TEST_CASE_WITHOUT_HEAD(derived__find__missing);
ATF_TEST_CASE_BODY(derived__find__missing)228 ATF_TEST_CASE_BODY(derived__find__missing)
229 {
230     check_find_missing< lazy_test_program >();
231 }
232 
233 
234 /// Runs a metadata_inheritance test.
235 ///
236 /// \tparam TestProgram Either model::test_program or lazy_test_program.
237 template< class TestProgram >
238 static void
check_metadata_inheritance(void)239 check_metadata_inheritance(void)
240 {
241     const model::test_cases_map test_cases = model::test_cases_map_builder()
242         .add("inherit-all")
243         .add("inherit-some",
244              model::metadata_builder()
245              .set_description("Overriden description")
246              .build())
247         .add("inherit-none",
248              model::metadata_builder()
249              .add_allowed_architecture("overriden-arch")
250              .add_allowed_platform("overriden-platform")
251              .set_description("Overriden description")
252              .build())
253         .build();
254 
255     const model::metadata metadata = model::metadata_builder()
256         .add_allowed_architecture("base-arch")
257         .set_description("Base description")
258         .build();
259     const TestProgram test_program(
260         "plain", fs::path("non-existent"), fs::path("."), "suite-name",
261         metadata, test_cases);
262 
263     {
264         const model::metadata exp_metadata = model::metadata_builder()
265             .add_allowed_architecture("base-arch")
266             .set_description("Base description")
267             .build();
268         ATF_REQUIRE_EQ(exp_metadata,
269                        test_program.find("inherit-all").get_metadata());
270     }
271 
272     {
273         const model::metadata exp_metadata = model::metadata_builder()
274             .add_allowed_architecture("base-arch")
275             .set_description("Overriden description")
276             .build();
277         ATF_REQUIRE_EQ(exp_metadata,
278                        test_program.find("inherit-some").get_metadata());
279     }
280 
281     {
282         const model::metadata exp_metadata = model::metadata_builder()
283             .add_allowed_architecture("overriden-arch")
284             .add_allowed_platform("overriden-platform")
285             .set_description("Overriden description")
286             .build();
287         ATF_REQUIRE_EQ(exp_metadata,
288                        test_program.find("inherit-none").get_metadata());
289     }
290 }
291 
292 
293 ATF_TEST_CASE_WITHOUT_HEAD(metadata_inheritance);
ATF_TEST_CASE_BODY(metadata_inheritance)294 ATF_TEST_CASE_BODY(metadata_inheritance)
295 {
296     check_metadata_inheritance< model::test_program >();
297 }
298 
299 
300 ATF_TEST_CASE_WITHOUT_HEAD(derived__metadata_inheritance);
ATF_TEST_CASE_BODY(derived__metadata_inheritance)301 ATF_TEST_CASE_BODY(derived__metadata_inheritance)
302 {
303     check_metadata_inheritance< lazy_test_program >();
304 }
305 
306 
307 /// Runs a operators_eq_and_ne__copy test.
308 ///
309 /// \tparam TestProgram Either model::test_program or lazy_test_program.
310 template< class TestProgram >
311 static void
check_operators_eq_and_ne__copy(void)312 check_operators_eq_and_ne__copy(void)
313 {
314     const TestProgram tp1(
315         "plain", fs::path("non-existent"), fs::path("."), "suite-name",
316         model::metadata_builder().build(),
317         model::test_cases_map());
318     const TestProgram tp2 = tp1;
319     ATF_REQUIRE(  tp1 == tp2);
320     ATF_REQUIRE(!(tp1 != tp2));
321 }
322 
323 
324 ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__copy);
ATF_TEST_CASE_BODY(operators_eq_and_ne__copy)325 ATF_TEST_CASE_BODY(operators_eq_and_ne__copy)
326 {
327     check_operators_eq_and_ne__copy< model::test_program >();
328 }
329 
330 
331 ATF_TEST_CASE_WITHOUT_HEAD(derived__operators_eq_and_ne__copy);
ATF_TEST_CASE_BODY(derived__operators_eq_and_ne__copy)332 ATF_TEST_CASE_BODY(derived__operators_eq_and_ne__copy)
333 {
334     check_operators_eq_and_ne__copy< lazy_test_program >();
335 }
336 
337 
338 /// Runs a operators_eq_and_ne__not_copy test.
339 ///
340 /// \tparam TestProgram Either model::test_program or lazy_test_program.
341 template< class TestProgram >
342 static void
check_operators_eq_and_ne__not_copy(void)343 check_operators_eq_and_ne__not_copy(void)
344 {
345     const std::string base_interface("plain");
346     const fs::path base_relative_path("the/test/program");
347     const fs::path base_root("/the/root");
348     const std::string base_test_suite("suite-name");
349     const model::metadata base_metadata = model::metadata_builder()
350         .add_custom("foo", "bar")
351         .build();
352 
353     const model::test_cases_map base_tcs = model::test_cases_map_builder()
354         .add("main", model::metadata_builder()
355              .add_custom("second", "baz")
356              .build())
357         .build();
358 
359     const TestProgram base_tp(
360         base_interface, base_relative_path, base_root, base_test_suite,
361         base_metadata, base_tcs);
362 
363     // Construct with all same values.
364     {
365         const model::test_cases_map other_tcs = model::test_cases_map_builder()
366             .add("main", model::metadata_builder()
367                  .add_custom("second", "baz")
368                  .build())
369             .build();
370 
371         const TestProgram other_tp(
372             base_interface, base_relative_path, base_root, base_test_suite,
373             base_metadata, other_tcs);
374 
375         ATF_REQUIRE(  base_tp == other_tp);
376         ATF_REQUIRE(!(base_tp != other_tp));
377     }
378 
379     // Construct with same final metadata values but using a different
380     // intermediate representation.  The original test program has one property
381     // in the base test program definition and another in the test case; here,
382     // we put both definitions explicitly in the test case.
383     {
384         const model::test_cases_map other_tcs = model::test_cases_map_builder()
385             .add("main", model::metadata_builder()
386                  .add_custom("foo", "bar")
387                  .add_custom("second", "baz")
388                  .build())
389             .build();
390 
391         const TestProgram other_tp(
392             base_interface, base_relative_path, base_root, base_test_suite,
393             base_metadata, other_tcs);
394 
395         ATF_REQUIRE(  base_tp == other_tp);
396         ATF_REQUIRE(!(base_tp != other_tp));
397     }
398 
399     // Different interface.
400     {
401         const TestProgram other_tp(
402             "atf", base_relative_path, base_root, base_test_suite,
403             base_metadata, base_tcs);
404 
405         ATF_REQUIRE(!(base_tp == other_tp));
406         ATF_REQUIRE(  base_tp != other_tp);
407     }
408 
409     // Different relative path.
410     {
411         const TestProgram other_tp(
412             base_interface, fs::path("a/b/c"), base_root, base_test_suite,
413             base_metadata, base_tcs);
414 
415         ATF_REQUIRE(!(base_tp == other_tp));
416         ATF_REQUIRE(  base_tp != other_tp);
417     }
418 
419     // Different root.
420     {
421         const TestProgram other_tp(
422             base_interface, base_relative_path, fs::path("."), base_test_suite,
423             base_metadata, base_tcs);
424 
425         ATF_REQUIRE(!(base_tp == other_tp));
426         ATF_REQUIRE(  base_tp != other_tp);
427     }
428 
429     // Different test suite.
430     {
431         const TestProgram other_tp(
432             base_interface, base_relative_path, base_root, "different-suite",
433             base_metadata, base_tcs);
434 
435         ATF_REQUIRE(!(base_tp == other_tp));
436         ATF_REQUIRE(  base_tp != other_tp);
437     }
438 
439     // Different metadata.
440     {
441         const TestProgram other_tp(
442             base_interface, base_relative_path, base_root, base_test_suite,
443             model::metadata_builder().build(), base_tcs);
444 
445         ATF_REQUIRE(!(base_tp == other_tp));
446         ATF_REQUIRE(  base_tp != other_tp);
447     }
448 
449     // Different test cases.
450     {
451         const model::test_cases_map other_tcs = model::test_cases_map_builder()
452             .add("foo").build();
453 
454         const TestProgram other_tp(
455             base_interface, base_relative_path, base_root, base_test_suite,
456             base_metadata, other_tcs);
457 
458         ATF_REQUIRE(!(base_tp == other_tp));
459         ATF_REQUIRE(  base_tp != other_tp);
460     }
461 }
462 
463 
464 ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__not_copy);
ATF_TEST_CASE_BODY(operators_eq_and_ne__not_copy)465 ATF_TEST_CASE_BODY(operators_eq_and_ne__not_copy)
466 {
467     check_operators_eq_and_ne__not_copy< model::test_program >();
468 }
469 
470 
471 ATF_TEST_CASE_WITHOUT_HEAD(derived__operators_eq_and_ne__not_copy);
ATF_TEST_CASE_BODY(derived__operators_eq_and_ne__not_copy)472 ATF_TEST_CASE_BODY(derived__operators_eq_and_ne__not_copy)
473 {
474     check_operators_eq_and_ne__not_copy< lazy_test_program >();
475 }
476 
477 
478 /// Runs a operator_lt test.
479 ///
480 /// \tparam TestProgram Either model::test_program or lazy_test_program.
481 template< class TestProgram >
482 static void
check_operator_lt(void)483 check_operator_lt(void)
484 {
485     const TestProgram tp1(
486         "plain", fs::path("a/b/c"), fs::path("/foo/bar"), "suite-name",
487         model::metadata_builder().build(),
488         model::test_cases_map());
489     const TestProgram tp2(
490         "atf", fs::path("c"), fs::path("/foo/bar"), "suite-name",
491         model::metadata_builder().build(),
492         model::test_cases_map());
493     const TestProgram tp3(
494         "plain", fs::path("a/b/c"), fs::path("/abc"), "suite-name",
495         model::metadata_builder().build(),
496         model::test_cases_map());
497 
498     ATF_REQUIRE(!(tp1 < tp1));
499 
500     ATF_REQUIRE(  tp1 < tp2);
501     ATF_REQUIRE(!(tp2 < tp1));
502 
503     ATF_REQUIRE(!(tp1 < tp3));
504     ATF_REQUIRE(  tp3 < tp1);
505 
506     // And now, test the actual reason why we want to have an < overload by
507     // attempting to put the various programs in a set.
508     std::set< TestProgram > programs;
509     programs.insert(tp1);
510     programs.insert(tp2);
511     programs.insert(tp3);
512 }
513 
514 
515 ATF_TEST_CASE_WITHOUT_HEAD(operator_lt);
ATF_TEST_CASE_BODY(operator_lt)516 ATF_TEST_CASE_BODY(operator_lt)
517 {
518     check_operator_lt< model::test_program >();
519 }
520 
521 
522 ATF_TEST_CASE_WITHOUT_HEAD(derived__operator_lt);
ATF_TEST_CASE_BODY(derived__operator_lt)523 ATF_TEST_CASE_BODY(derived__operator_lt)
524 {
525     check_operator_lt< lazy_test_program >();
526 }
527 
528 
529 /// Runs a output__no_test_cases test.
530 ///
531 /// \tparam TestProgram Either model::test_program or lazy_test_program.
532 template< class TestProgram >
533 static void
check_output__no_test_cases(void)534 check_output__no_test_cases(void)
535 {
536     TestProgram tp(
537         "plain", fs::path("binary/path"), fs::path("/the/root"), "suite-name",
538         model::metadata_builder().add_allowed_architecture("a").build(),
539         model::test_cases_map());
540 
541     std::ostringstream str;
542     str << tp;
543     ATF_REQUIRE_EQ(
544         "test_program{interface='plain', binary='binary/path', "
545         "root='/the/root', test_suite='suite-name', "
546         "metadata=metadata{allowed_architectures='a', allowed_platforms='', "
547         "description='', execenv='', execenv_jail_params='', "
548         "has_cleanup='false', is_exclusive='false', "
549         "required_configs='', required_disk_space='0', required_files='', "
550         "required_memory='0', "
551         "required_programs='', required_user='', timeout='300'}, "
552         "test_cases=map()}",
553         str.str());
554 }
555 
556 
557 ATF_TEST_CASE_WITHOUT_HEAD(output__no_test_cases);
ATF_TEST_CASE_BODY(output__no_test_cases)558 ATF_TEST_CASE_BODY(output__no_test_cases)
559 {
560     check_output__no_test_cases< model::test_program >();
561 }
562 
563 
564 ATF_TEST_CASE_WITHOUT_HEAD(derived__output__no_test_cases);
ATF_TEST_CASE_BODY(derived__output__no_test_cases)565 ATF_TEST_CASE_BODY(derived__output__no_test_cases)
566 {
567     check_output__no_test_cases< lazy_test_program >();
568 }
569 
570 
571 /// Runs a output__some_test_cases test.
572 ///
573 /// \tparam TestProgram Either model::test_program or lazy_test_program.
574 template< class TestProgram >
575 static void
check_output__some_test_cases(void)576 check_output__some_test_cases(void)
577 {
578     const model::test_cases_map test_cases = model::test_cases_map_builder()
579         .add("the-name", model::metadata_builder()
580              .add_allowed_platform("foo")
581              .add_custom("bar", "baz")
582              .build())
583         .add("another-name")
584         .build();
585 
586     const TestProgram tp = TestProgram(
587         "plain", fs::path("binary/path"), fs::path("/the/root"), "suite-name",
588         model::metadata_builder().add_allowed_architecture("a").build(),
589         test_cases);
590 
591     std::ostringstream str;
592     str << tp;
593     ATF_REQUIRE_EQ(
594         "test_program{interface='plain', binary='binary/path', "
595         "root='/the/root', test_suite='suite-name', "
596         "metadata=metadata{allowed_architectures='a', allowed_platforms='', "
597         "description='', execenv='', execenv_jail_params='', "
598         "has_cleanup='false', is_exclusive='false', "
599         "required_configs='', required_disk_space='0', required_files='', "
600         "required_memory='0', "
601         "required_programs='', required_user='', timeout='300'}, "
602         "test_cases=map("
603         "another-name=test_case{name='another-name', "
604         "metadata=metadata{allowed_architectures='a', allowed_platforms='', "
605         "description='', execenv='', execenv_jail_params='', "
606         "has_cleanup='false', is_exclusive='false', "
607         "required_configs='', required_disk_space='0', required_files='', "
608         "required_memory='0', "
609         "required_programs='', required_user='', timeout='300'}}, "
610         "the-name=test_case{name='the-name', "
611         "metadata=metadata{allowed_architectures='a', allowed_platforms='foo', "
612         "custom.bar='baz', description='', execenv='', execenv_jail_params='', "
613         "has_cleanup='false', is_exclusive='false', "
614         "required_configs='', required_disk_space='0', required_files='', "
615         "required_memory='0', "
616         "required_programs='', required_user='', timeout='300'}})}",
617         str.str());
618 }
619 
620 
621 ATF_TEST_CASE_WITHOUT_HEAD(output__some_test_cases);
ATF_TEST_CASE_BODY(output__some_test_cases)622 ATF_TEST_CASE_BODY(output__some_test_cases)
623 {
624     check_output__some_test_cases< model::test_program >();
625 }
626 
627 
628 ATF_TEST_CASE_WITHOUT_HEAD(derived__output__some_test_cases);
ATF_TEST_CASE_BODY(derived__output__some_test_cases)629 ATF_TEST_CASE_BODY(derived__output__some_test_cases)
630 {
631     check_output__some_test_cases< lazy_test_program >();
632 }
633 
634 
635 ATF_TEST_CASE_WITHOUT_HEAD(builder__defaults);
ATF_TEST_CASE_BODY(builder__defaults)636 ATF_TEST_CASE_BODY(builder__defaults)
637 {
638     const model::test_program expected(
639         "mock", fs::path("non-existent"), fs::path("."), "suite-name",
640         model::metadata_builder().build(), model::test_cases_map());
641 
642     const model::test_program built = model::test_program_builder(
643         "mock", fs::path("non-existent"), fs::path("."), "suite-name")
644         .build();
645 
646     ATF_REQUIRE_EQ(built, expected);
647 }
648 
649 
650 ATF_TEST_CASE_WITHOUT_HEAD(builder__overrides);
ATF_TEST_CASE_BODY(builder__overrides)651 ATF_TEST_CASE_BODY(builder__overrides)
652 {
653     const model::metadata md = model::metadata_builder()
654         .add_custom("foo", "bar")
655         .build();
656     const model::test_cases_map tcs = model::test_cases_map_builder()
657         .add("first")
658         .add("second", md)
659         .build();
660     const model::test_program expected(
661         "mock", fs::path("binary"), fs::path("root"), "suite-name", md, tcs);
662 
663     const model::test_program built = model::test_program_builder(
664         "mock", fs::path("binary"), fs::path("root"), "suite-name")
665         .add_test_case("first")
666         .add_test_case("second", md)
667         .set_metadata(md)
668         .build();
669 
670     ATF_REQUIRE_EQ(built, expected);
671 }
672 
673 
674 ATF_TEST_CASE_WITHOUT_HEAD(builder__ptr);
ATF_TEST_CASE_BODY(builder__ptr)675 ATF_TEST_CASE_BODY(builder__ptr)
676 {
677     const model::test_program expected(
678         "mock", fs::path("non-existent"), fs::path("."), "suite-name",
679         model::metadata_builder().build(), model::test_cases_map());
680 
681     const model::test_program_ptr built = model::test_program_builder(
682         "mock", fs::path("non-existent"), fs::path("."), "suite-name")
683         .build_ptr();
684 
685     ATF_REQUIRE_EQ(*built, expected);
686 }
687 
688 
ATF_INIT_TEST_CASES(tcs)689 ATF_INIT_TEST_CASES(tcs)
690 {
691     ATF_ADD_TEST_CASE(tcs, ctor_and_getters);
692     ATF_ADD_TEST_CASE(tcs, find__ok);
693     ATF_ADD_TEST_CASE(tcs, find__missing);
694     ATF_ADD_TEST_CASE(tcs, metadata_inheritance);
695     ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__copy);
696     ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__not_copy);
697     ATF_ADD_TEST_CASE(tcs, operator_lt);
698     ATF_ADD_TEST_CASE(tcs, output__no_test_cases);
699     ATF_ADD_TEST_CASE(tcs, output__some_test_cases);
700 
701     ATF_ADD_TEST_CASE(tcs, derived__ctor_and_getters);
702     ATF_ADD_TEST_CASE(tcs, derived__find__ok);
703     ATF_ADD_TEST_CASE(tcs, derived__find__missing);
704     ATF_ADD_TEST_CASE(tcs, derived__metadata_inheritance);
705     ATF_ADD_TEST_CASE(tcs, derived__operators_eq_and_ne__copy);
706     ATF_ADD_TEST_CASE(tcs, derived__operators_eq_and_ne__not_copy);
707     ATF_ADD_TEST_CASE(tcs, derived__operator_lt);
708     ATF_ADD_TEST_CASE(tcs, derived__output__no_test_cases);
709     ATF_ADD_TEST_CASE(tcs, derived__output__some_test_cases);
710 
711     ATF_ADD_TEST_CASE(tcs, builder__defaults);
712     ATF_ADD_TEST_CASE(tcs, builder__overrides);
713     ATF_ADD_TEST_CASE(tcs, builder__ptr);
714 }
715