1 // (C) Copyright Dave Abrahams and Thomas Becker 2003. Distributed
2 // under the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 //
6
7 // File:
8 // =====
9 // zip_iterator_test_main.cpp
10
11 // Author:
12 // =======
13 // Thomas Becker
14
15 // Created:
16 // ========
17 // Jul 15, 2003
18
19 // Purpose:
20 // ========
21 // Test driver for zip_iterator.hpp
22
23 // Compilers Tested:
24 // =================
25 // Metrowerks Codewarrior Pro 7.2, 8.3
26 // gcc 2.95.3
27 // gcc 3.2
28 // Microsoft VC 6sp5 (test fails due to some compiler bug)
29 // Microsoft VC 7 (works)
30 // Microsoft VC 7.1
31 // Intel 5
32 // Intel 6
33 // Intel 7.1
34 // Intel 8
35 // Borland 5.5.1 (broken due to lack of support from Boost.Tuples)
36
37 /////////////////////////////////////////////////////////////////////////////
38 //
39 // Includes
40 //
41 /////////////////////////////////////////////////////////////////////////////
42
43 #include <boost/iterator/zip_iterator.hpp>
44 #include <boost/iterator/zip_iterator.hpp> // 2nd #include tests #include guard.
45 #include <iostream>
46 #include <vector>
47 #include <list>
48 #include <set>
49 #include <string>
50 #include <functional>
51 #include <boost/tuple/tuple.hpp>
52 #include <boost/iterator/transform_iterator.hpp>
53 #include <boost/iterator/is_readable_iterator.hpp>
54 #include <boost/type_traits/is_same.hpp>
55 #include <boost/detail/workaround.hpp>
56 #include <stddef.h>
57
58
59 /// Tests for https://svn.boost.org/trac/boost/ticket/1517
to_value(int const & v)60 int to_value(int const &v)
61 {
62 return v;
63 }
64
category_test()65 void category_test()
66 {
67 std::list<int> rng1;
68 std::string rng2;
69
70 boost::make_zip_iterator(
71 boost::make_tuple(
72 boost::make_transform_iterator(rng1.begin(), &to_value), // BidirectionalInput
73 rng2.begin() // RandomAccess
74 )
75 );
76 }
77 ///
78
79 /////////////////////////////////////////////////////////////////////////////
80 //
81 // Das Main Funktion
82 //
83 /////////////////////////////////////////////////////////////////////////////
84
main(void)85 int main( void )
86 {
87
88 category_test();
89
90 std::cout << "\n"
91 << "***********************************************\n"
92 << "* *\n"
93 << "* Test driver for boost::zip_iterator *\n"
94 << "* Copyright Thomas Becker 2003 *\n"
95 << "* *\n"
96 << "***********************************************\n\n"
97 << std::flush;
98
99 size_t num_successful_tests = 0;
100 size_t num_failed_tests = 0;
101
102 /////////////////////////////////////////////////////////////////////////////
103 //
104 // Zip iterator construction and dereferencing
105 //
106 /////////////////////////////////////////////////////////////////////////////
107
108 std::cout << "Zip iterator construction and dereferencing: "
109 << std::flush;
110
111 std::vector<double> vect1(3);
112 vect1[0] = 42.;
113 vect1[1] = 43.;
114 vect1[2] = 44.;
115
116 std::set<int> intset;
117 intset.insert(52);
118 intset.insert(53);
119 intset.insert(54);
120 //
121
122 typedef
123 boost::zip_iterator<
124 boost::tuples::tuple<
125 std::set<int>::iterator
126 , std::vector<double>::iterator
127 >
128 > zit_mixed;
129
130 zit_mixed zip_it_mixed = zit_mixed(
131 boost::make_tuple(
132 intset.begin()
133 , vect1.begin()
134 )
135 );
136
137 boost::tuples::tuple<int, double> val_tuple(
138 *zip_it_mixed);
139
140 boost::tuples::tuple<const int&, double&> ref_tuple(
141 *zip_it_mixed);
142
143 double dblOldVal = boost::tuples::get<1>(ref_tuple);
144 boost::tuples::get<1>(ref_tuple) -= 41.;
145
146 if( 52 == boost::tuples::get<0>(val_tuple) &&
147 42. == boost::tuples::get<1>(val_tuple) &&
148 52 == boost::tuples::get<0>(ref_tuple) &&
149 1. == boost::tuples::get<1>(ref_tuple) &&
150 1. == *vect1.begin()
151 )
152 {
153 ++num_successful_tests;
154 std::cout << "OK" << std::endl;
155 }
156 else
157 {
158 ++num_failed_tests = 0;
159 std::cout << "not OK" << std::endl;
160 }
161
162 // Undo change to vect1
163 boost::tuples::get<1>(ref_tuple) = dblOldVal;
164
165 /////////////////////////////////////////////////////////////////////////////
166 //
167 // Zip iterator with 12 components
168 //
169 /////////////////////////////////////////////////////////////////////////////
170
171 std::cout << "Zip iterators with 12 components: "
172 << std::flush;
173
174 // Declare 12 containers
175 //
176 std::list<int> li1;
177 li1.push_back(1);
178 std::set<int> se1;
179 se1.insert(2);
180 std::vector<int> ve1;
181 ve1.push_back(3);
182 //
183 std::list<int> li2;
184 li2.push_back(4);
185 std::set<int> se2;
186 se2.insert(5);
187 std::vector<int> ve2;
188 ve2.push_back(6);
189 //
190 std::list<int> li3;
191 li3.push_back(7);
192 std::set<int> se3;
193 se3.insert(8);
194 std::vector<int> ve3;
195 ve3.push_back(9);
196 //
197 std::list<int> li4;
198 li4.push_back(10);
199 std::set<int> se4;
200 se4.insert(11);
201 std::vector<int> ve4;
202 ve4.push_back(12);
203
204 // typedefs for cons lists of iterators.
205 typedef boost::tuples::cons<
206 std::set<int>::iterator,
207 boost::tuples::tuple<
208 std::vector<int>::iterator,
209 std::list<int>::iterator,
210 std::set<int>::iterator,
211 std::vector<int>::iterator,
212 std::list<int>::iterator,
213 std::set<int>::iterator,
214 std::vector<int>::iterator,
215 std::list<int>::iterator,
216 std::set<int>::iterator,
217 std::vector<int>::const_iterator
218 >::inherited
219 > cons_11_its_type;
220 //
221 typedef boost::tuples::cons<
222 std::list<int>::const_iterator,
223 cons_11_its_type
224 > cons_12_its_type;
225
226 // typedefs for cons lists for dereferencing the zip iterator
227 // made from the cons list above.
228 typedef boost::tuples::cons<
229 const int&,
230 boost::tuples::tuple<
231 int&,
232 int&,
233 const int&,
234 int&,
235 int&,
236 const int&,
237 int&,
238 int&,
239 const int&,
240 const int&
241 >::inherited
242 > cons_11_refs_type;
243 //
244 typedef boost::tuples::cons<
245 const int&,
246 cons_11_refs_type
247 > cons_12_refs_type;
248
249 // typedef for zip iterator with 12 elements
250 typedef boost::zip_iterator<cons_12_its_type> zip_it_12_type;
251
252 // Declare a 12-element zip iterator.
253 zip_it_12_type zip_it_12(
254 cons_12_its_type(
255 li1.begin(),
256 cons_11_its_type(
257 se1.begin(),
258 boost::make_tuple(
259 ve1.begin(),
260 li2.begin(),
261 se2.begin(),
262 ve2.begin(),
263 li3.begin(),
264 se3.begin(),
265 ve3.begin(),
266 li4.begin(),
267 se4.begin(),
268 ve4.begin()
269 )
270 )
271 )
272 );
273
274 // Dereference, mess with the result a little.
275 cons_12_refs_type zip_it_12_dereferenced(*zip_it_12);
276 boost::tuples::get<9>(zip_it_12_dereferenced) = 42;
277
278 // Make a copy and move it a little to force some instantiations.
279 zip_it_12_type zip_it_12_copy(zip_it_12);
280 ++zip_it_12_copy;
281
282 if( boost::tuples::get<11>(zip_it_12.get_iterator_tuple()) == ve4.begin() &&
283 boost::tuples::get<11>(zip_it_12_copy.get_iterator_tuple()) == ve4.end() &&
284 1 == boost::tuples::get<0>(zip_it_12_dereferenced) &&
285 12 == boost::tuples::get<11>(zip_it_12_dereferenced) &&
286 42 == *(li4.begin())
287 )
288 {
289 ++num_successful_tests;
290 std::cout << "OK" << std::endl;
291 }
292 else
293 {
294 ++num_failed_tests = 0;
295 std::cout << "not OK" << std::endl;
296 }
297
298 /////////////////////////////////////////////////////////////////////////////
299 //
300 // Zip iterator incrementing and dereferencing
301 //
302 /////////////////////////////////////////////////////////////////////////////
303
304 std::cout << "Zip iterator ++ and *: "
305 << std::flush;
306
307 std::vector<double> vect2(3);
308 vect2[0] = 2.2;
309 vect2[1] = 3.3;
310 vect2[2] = 4.4;
311
312 boost::zip_iterator<
313 boost::tuples::tuple<
314 std::vector<double>::const_iterator,
315 std::vector<double>::const_iterator
316 >
317 >
318 zip_it_begin(
319 boost::make_tuple(
320 vect1.begin(),
321 vect2.begin()
322 )
323 );
324
325 boost::zip_iterator<
326 boost::tuples::tuple<
327 std::vector<double>::const_iterator,
328 std::vector<double>::const_iterator
329 >
330 >
331 zip_it_run(
332 boost::make_tuple(
333 vect1.begin(),
334 vect2.begin()
335 )
336 );
337
338 boost::zip_iterator<
339 boost::tuples::tuple<
340 std::vector<double>::const_iterator,
341 std::vector<double>::const_iterator
342 >
343 >
344 zip_it_end(
345 boost::make_tuple(
346 vect1.end(),
347 vect2.end()
348 )
349 );
350
351 if( zip_it_run == zip_it_begin &&
352 42. == boost::tuples::get<0>(*zip_it_run) &&
353 2.2 == boost::tuples::get<1>(*zip_it_run) &&
354 43. == boost::tuples::get<0>(*(++zip_it_run)) &&
355 3.3 == boost::tuples::get<1>(*zip_it_run) &&
356 44. == boost::tuples::get<0>(*(++zip_it_run)) &&
357 4.4 == boost::tuples::get<1>(*zip_it_run) &&
358 zip_it_end == ++zip_it_run
359 )
360 {
361 ++num_successful_tests;
362 std::cout << "OK" << std::endl;
363 }
364 else
365 {
366 ++num_failed_tests = 0;
367 std::cout << "not OK" << std::endl;
368 }
369
370 /////////////////////////////////////////////////////////////////////////////
371 //
372 // Zip iterator decrementing and dereferencing
373 //
374 /////////////////////////////////////////////////////////////////////////////
375
376 std::cout << "Zip iterator -- and *: "
377 << std::flush;
378
379 if( zip_it_run == zip_it_end &&
380 zip_it_end == zip_it_run-- &&
381 44. == boost::tuples::get<0>(*zip_it_run) &&
382 4.4 == boost::tuples::get<1>(*zip_it_run) &&
383 43. == boost::tuples::get<0>(*(--zip_it_run)) &&
384 3.3 == boost::tuples::get<1>(*zip_it_run) &&
385 42. == boost::tuples::get<0>(*(--zip_it_run)) &&
386 2.2 == boost::tuples::get<1>(*zip_it_run) &&
387 zip_it_begin == zip_it_run
388 )
389 {
390 ++num_successful_tests;
391 std::cout << "OK" << std::endl;
392 }
393 else
394 {
395 ++num_failed_tests = 0;
396 std::cout << "not OK" << std::endl;
397 }
398
399 /////////////////////////////////////////////////////////////////////////////
400 //
401 // Zip iterator copy construction and equality
402 //
403 /////////////////////////////////////////////////////////////////////////////
404
405 std::cout << "Zip iterator copy construction and equality: "
406 << std::flush;
407
408 boost::zip_iterator<
409 boost::tuples::tuple<
410 std::vector<double>::const_iterator,
411 std::vector<double>::const_iterator
412 >
413 > zip_it_run_copy(zip_it_run);
414
415 if(zip_it_run == zip_it_run && zip_it_run == zip_it_run_copy)
416 {
417 ++num_successful_tests;
418 std::cout << "OK" << std::endl;
419 }
420 else
421 {
422 ++num_failed_tests = 0;
423 std::cout << "not OK" << std::endl;
424 }
425
426 /////////////////////////////////////////////////////////////////////////////
427 //
428 // Zip iterator inequality
429 //
430 /////////////////////////////////////////////////////////////////////////////
431
432 std::cout << "Zip iterator inequality: "
433 << std::flush;
434
435 if(!(zip_it_run != zip_it_run_copy) && zip_it_run != ++zip_it_run_copy)
436 {
437 ++num_successful_tests;
438 std::cout << "OK" << std::endl;
439 }
440 else
441 {
442 ++num_failed_tests = 0;
443 std::cout << "not OK" << std::endl;
444 }
445
446 /////////////////////////////////////////////////////////////////////////////
447 //
448 // Zip iterator less than
449 //
450 /////////////////////////////////////////////////////////////////////////////
451
452 std::cout << "Zip iterator less than: "
453 << std::flush;
454
455 // Note: zip_it_run_copy == zip_it_run + 1
456 //
457 if( zip_it_run < zip_it_run_copy &&
458 !( zip_it_run < --zip_it_run_copy) &&
459 zip_it_run == zip_it_run_copy
460 )
461 {
462 ++num_successful_tests;
463 std::cout << "OK" << std::endl;
464 }
465 else
466 {
467 ++num_failed_tests = 0;
468 std::cout << "not OK" << std::endl;
469 }
470
471 /////////////////////////////////////////////////////////////////////////////
472 //
473 // Zip iterator less than or equal
474 //
475 /////////////////////////////////////////////////////////////////////////////
476
477 std::cout << "zip iterator less than or equal: "
478 << std::flush;
479
480 // Note: zip_it_run_copy == zip_it_run
481 //
482 ++zip_it_run;
483 zip_it_run_copy += 2;
484
485 if( zip_it_run <= zip_it_run_copy &&
486 zip_it_run <= --zip_it_run_copy &&
487 !( zip_it_run <= --zip_it_run_copy) &&
488 zip_it_run <= zip_it_run
489 )
490 {
491 ++num_successful_tests;
492 std::cout << "OK" << std::endl;
493 }
494 else
495 {
496 ++num_failed_tests = 0;
497 std::cout << "not OK" << std::endl;
498 }
499
500 /////////////////////////////////////////////////////////////////////////////
501 //
502 // Zip iterator greater than
503 //
504 /////////////////////////////////////////////////////////////////////////////
505
506 std::cout << "Zip iterator greater than: "
507 << std::flush;
508
509 // Note: zip_it_run_copy == zip_it_run - 1
510 //
511 if( zip_it_run > zip_it_run_copy &&
512 !( zip_it_run > ++zip_it_run_copy) &&
513 zip_it_run == zip_it_run_copy
514 )
515 {
516 ++num_successful_tests;
517 std::cout << "OK" << std::endl;
518 }
519 else
520 {
521 ++num_failed_tests = 0;
522 std::cout << "not OK" << std::endl;
523 }
524
525 /////////////////////////////////////////////////////////////////////////////
526 //
527 // Zip iterator greater than or equal
528 //
529 /////////////////////////////////////////////////////////////////////////////
530
531 std::cout << "Zip iterator greater than or equal: "
532 << std::flush;
533
534 ++zip_it_run;
535
536 // Note: zip_it_run == zip_it_run_copy + 1
537 //
538 if( zip_it_run >= zip_it_run_copy &&
539 --zip_it_run >= zip_it_run_copy &&
540 ! (zip_it_run >= ++zip_it_run_copy)
541 )
542 {
543 ++num_successful_tests;
544 std::cout << "OK" << std::endl;
545 }
546 else
547 {
548 ++num_failed_tests = 0;
549 std::cout << "not OK" << std::endl;
550 }
551
552 /////////////////////////////////////////////////////////////////////////////
553 //
554 // Zip iterator + int
555 //
556 /////////////////////////////////////////////////////////////////////////////
557
558 std::cout << "Zip iterator + int: "
559 << std::flush;
560
561 // Note: zip_it_run == zip_it_run_copy - 1
562 //
563 zip_it_run = zip_it_run + 2;
564 ++zip_it_run_copy;
565
566 if( zip_it_run == zip_it_run_copy && zip_it_run == zip_it_begin + 3 )
567 {
568 ++num_successful_tests;
569 std::cout << "OK" << std::endl;
570 }
571 else
572 {
573 ++num_failed_tests = 0;
574 std::cout << "not OK" << std::endl;
575 }
576
577 /////////////////////////////////////////////////////////////////////////////
578 //
579 // Zip iterator - int
580 //
581 /////////////////////////////////////////////////////////////////////////////
582
583 std::cout << "Zip iterator - int: "
584 << std::flush;
585
586 // Note: zip_it_run == zip_it_run_copy, and both are at end position
587 //
588 zip_it_run = zip_it_run - 2;
589 --zip_it_run_copy;
590 --zip_it_run_copy;
591
592 if( zip_it_run == zip_it_run_copy && (zip_it_run - 1) == zip_it_begin )
593 {
594 ++num_successful_tests;
595 std::cout << "OK" << std::endl;
596 }
597 else
598 {
599 ++num_failed_tests = 0;
600 std::cout << "not OK" << std::endl;
601 }
602
603 /////////////////////////////////////////////////////////////////////////////
604 //
605 // Zip iterator +=
606 //
607 /////////////////////////////////////////////////////////////////////////////
608
609 std::cout << "Zip iterator +=: "
610 << std::flush;
611
612 // Note: zip_it_run == zip_it_run_copy, and both are at begin + 1
613 //
614 zip_it_run += 2;
615 if( zip_it_run == zip_it_begin + 3 )
616 {
617 ++num_successful_tests;
618 std::cout << "OK" << std::endl;
619 }
620 else
621 {
622 ++num_failed_tests = 0;
623 std::cout << "not OK" << std::endl;
624 }
625
626 /////////////////////////////////////////////////////////////////////////////
627 //
628 // Zip iterator -=
629 //
630 /////////////////////////////////////////////////////////////////////////////
631
632 std::cout << "Zip iterator -=: "
633 << std::flush;
634
635 // Note: zip_it_run is at end position, zip_it_run_copy is at
636 // begin plus one.
637 //
638 zip_it_run -= 2;
639 if( zip_it_run == zip_it_run_copy )
640 {
641 ++num_successful_tests;
642 std::cout << "OK" << std::endl;
643 }
644 else
645 {
646 ++num_failed_tests = 0;
647 std::cout << "not OK" << std::endl;
648 }
649
650 /////////////////////////////////////////////////////////////////////////////
651 //
652 // Zip iterator getting member iterators
653 //
654 /////////////////////////////////////////////////////////////////////////////
655
656 std::cout << "Zip iterator member iterators: "
657 << std::flush;
658
659 // Note: zip_it_run and zip_it_run_copy are both at
660 // begin plus one.
661 //
662 if( boost::tuples::get<0>(zip_it_run.get_iterator_tuple()) == vect1.begin() + 1 &&
663 boost::tuples::get<1>(zip_it_run.get_iterator_tuple()) == vect2.begin() + 1
664 )
665 {
666 ++num_successful_tests;
667 std::cout << "OK" << std::endl;
668 }
669 else
670 {
671 ++num_failed_tests = 0;
672 std::cout << "not OK" << std::endl;
673 }
674
675 /////////////////////////////////////////////////////////////////////////////
676 //
677 // Making zip iterators
678 //
679 /////////////////////////////////////////////////////////////////////////////
680
681 std::cout << "Making zip iterators: "
682 << std::flush;
683
684 std::vector<boost::tuples::tuple<double, double> >
685 vect_of_tuples(3);
686
687 std::copy(
688 boost::make_zip_iterator(
689 boost::make_tuple(
690 vect1.begin(),
691 vect2.begin()
692 )
693 ),
694 boost::make_zip_iterator(
695 boost::make_tuple(
696 vect1.end(),
697 vect2.end()
698 )
699 ),
700 vect_of_tuples.begin()
701 );
702
703 if( 42. == boost::tuples::get<0>(*vect_of_tuples.begin()) &&
704 2.2 == boost::tuples::get<1>(*vect_of_tuples.begin()) &&
705 43. == boost::tuples::get<0>(*(vect_of_tuples.begin() + 1)) &&
706 3.3 == boost::tuples::get<1>(*(vect_of_tuples.begin() + 1)) &&
707 44. == boost::tuples::get<0>(*(vect_of_tuples.begin() + 2)) &&
708 4.4 == boost::tuples::get<1>(*(vect_of_tuples.begin() + 2))
709 )
710 {
711 ++num_successful_tests;
712 std::cout << "OK" << std::endl;
713 }
714 else
715 {
716 ++num_failed_tests = 0;
717 std::cout << "not OK" << std::endl;
718 }
719
720 /////////////////////////////////////////////////////////////////////////////
721 //
722 // Zip iterator non-const --> const conversion
723 //
724 /////////////////////////////////////////////////////////////////////////////
725
726 std::cout << "Zip iterator non-const to const conversion: "
727 << std::flush;
728
729 boost::zip_iterator<
730 boost::tuples::tuple<
731 std::set<int>::const_iterator,
732 std::vector<double>::const_iterator
733 >
734 >
735 zip_it_const(
736 boost::make_tuple(
737 intset.begin(),
738 vect2.begin()
739 )
740 );
741 //
742 boost::zip_iterator<
743 boost::tuples::tuple<
744 std::set<int>::iterator,
745 std::vector<double>::const_iterator
746 >
747 >
748 zip_it_half_const(
749 boost::make_tuple(
750 intset.begin(),
751 vect2.begin()
752 )
753 );
754 //
755 boost::zip_iterator<
756 boost::tuples::tuple<
757 std::set<int>::iterator,
758 std::vector<double>::iterator
759 >
760 >
761 zip_it_non_const(
762 boost::make_tuple(
763 intset.begin(),
764 vect2.begin()
765 )
766 );
767
768 zip_it_half_const = ++zip_it_non_const;
769 zip_it_const = zip_it_half_const;
770 ++zip_it_const;
771 // zip_it_non_const = ++zip_it_const; // Error: can't convert from const to non-const
772
773 if( 54 == boost::tuples::get<0>(*zip_it_const) &&
774 4.4 == boost::tuples::get<1>(*zip_it_const) &&
775 53 == boost::tuples::get<0>(*zip_it_half_const) &&
776 3.3 == boost::tuples::get<1>(*zip_it_half_const)
777 )
778 {
779 ++num_successful_tests;
780 std::cout << "OK" << std::endl;
781 }
782 else
783 {
784 ++num_failed_tests = 0;
785 std::cout << "not OK" << std::endl;
786 }
787
788
789 /////////////////////////////////////////////////////////////////////////////
790 //
791 // Zip iterator categories
792 //
793 /////////////////////////////////////////////////////////////////////////////
794
795 std::cout << "Zip iterator categories: "
796 << std::flush;
797
798 // The big iterator of the previous test has vector, list, and set iterators.
799 // Therefore, it must be bidirectional, but not random access.
800 bool bBigItIsBidirectionalIterator = boost::is_convertible<
801 boost::iterator_traversal<zip_it_12_type>::type
802 , boost::bidirectional_traversal_tag
803 >::value;
804
805 bool bBigItIsRandomAccessIterator = boost::is_convertible<
806 boost::iterator_traversal<zip_it_12_type>::type
807 , boost::random_access_traversal_tag
808 >::value;
809
810 // A combining iterator with all vector iterators must have random access
811 // traversal.
812 //
813 typedef boost::zip_iterator<
814 boost::tuples::tuple<
815 std::vector<double>::const_iterator,
816 std::vector<double>::const_iterator
817 >
818 > all_vects_type;
819
820 bool bAllVectsIsRandomAccessIterator = boost::is_convertible<
821 boost::iterator_traversal<all_vects_type>::type
822 , boost::random_access_traversal_tag
823 >::value;
824
825 // The big test.
826 if( bBigItIsBidirectionalIterator &&
827 ! bBigItIsRandomAccessIterator &&
828 bAllVectsIsRandomAccessIterator
829 )
830 {
831 ++num_successful_tests;
832 std::cout << "OK" << std::endl;
833 }
834 else
835 {
836 ++num_failed_tests = 0;
837 std::cout << "not OK" << std::endl;
838 }
839
840 // Done
841 //
842 std::cout << "\nTest Result:"
843 << "\n============"
844 << "\nNumber of successful tests: " << static_cast<unsigned int>(num_successful_tests)
845 << "\nNumber of failed tests: " << static_cast<unsigned int>(num_failed_tests)
846 << std::endl;
847
848 return num_failed_tests;
849 }
850
851