1 // Boost.Range library
2 //
3 //  Copyright Neil Groves 2014. Use, modification and
4 //  distribution is subject to the Boost Software License, Version
5 //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 //
9 // For more information, see http://www.boost.org/libs/range/
10 //
11 // Credits:
12 //  Jurgen Hunold provided a test case that demonstrated that the range adaptors
13 //  were producing iterators that were not default constructible. This became
14 //  symptomatic after enabling concept checking assertions. This test is a
15 //  lightly modified version of his supplied code to ensure that his use case
16 //  never breaks again. (hopefully!)
17 //
18 
19 #include <boost/range/adaptor/transformed.hpp>
20 #include <boost/range/adaptor/filtered.hpp>
21 #include <boost/range/algorithm/copy.hpp>
22 #include <boost/bind/bind.hpp>
23 
24 #include <boost/test/test_tools.hpp>
25 #include <boost/test/unit_test.hpp>
26 
27 #include <vector>
28 #include <set>
29 
30 namespace boost_range_test
31 {
32     namespace
33     {
34 
35 class foo
36 {
37 public:
from_string(const std::string & source)38     static foo from_string(const std::string& source)
39     {
40         foo f;
41         f.m_valid = true;
42         f.m_value = 0u;
43         for (std::string::const_iterator it = source.begin();
44              it != source.end(); ++it)
45         {
46             f.m_value += *it;
47             if ((*it < 'a') || (*it > 'z'))
48                 f.m_valid = false;
49         }
50         return f;
51     }
is_valid() const52     bool is_valid() const
53     {
54         return m_valid;
55     }
operator <(const foo & other) const56     bool operator<(const foo& other) const
57     {
58         return m_value < other.m_value;
59     }
operator ==(const foo & other) const60     bool operator==(const foo& other) const
61     {
62         return m_value == other.m_value && m_valid == other.m_valid;
63     }
operator !=(const foo & other) const64     bool operator!=(const foo& other) const
65     {
66         return !operator==(other);
67     }
68 
operator <<(std::ostream & out,const foo & obj)69     friend inline std::ostream& operator<<(std::ostream& out, const foo& obj)
70     {
71         out << "{value=" << obj.m_value
72             << ", valid=" << std::boolalpha << obj.m_valid << "}\n";
73         return out;
74     }
75 
76 private:
77     boost::uint64_t m_value;
78     bool m_valid;
79 };
80 
chained_adaptors_test()81 void chained_adaptors_test()
82 {
83     std::vector<std::string> sep;
84 
85     sep.push_back("AB");
86     sep.push_back("ab");
87     sep.push_back("aghj");
88 
89     std::set<foo> foos;
90 
91     using namespace boost::placeholders;
92 
93     boost::copy(sep
94         | boost::adaptors::transformed(boost::bind(&foo::from_string, _1))
95         | boost::adaptors::filtered(boost::bind(&foo::is_valid, _1)),
96         std::inserter(foos, foos.end()));
97 
98     std::vector<foo> reference;
99     reference.push_back(foo::from_string("ab"));
100     reference.push_back(foo::from_string("aghj"));
101 
102     BOOST_CHECK_EQUAL_COLLECTIONS(
103                 reference.begin(), reference.end(),
104                 foos.begin(), foos.end());
105 }
106 
107     } // anonymous namespace
108 } // namespace boost_range_test
109 
110 boost::unit_test::test_suite*
init_unit_test_suite(int argc,char * argv[])111 init_unit_test_suite(int argc, char* argv[])
112 {
113     boost::unit_test::test_suite* test
114         = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.chained adaptors" );
115 
116     test->add(BOOST_TEST_CASE( boost_range_test::chained_adaptors_test));
117 
118     return test;
119 }
120