1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // env_var.cpp |
3 | // |
4 | // Copyright 2012 Eric Niebler. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | #include <cstring> |
9 | #include <sstream> |
10 | #include <boost/config.hpp> |
11 | #include <boost/detail/workaround.hpp> |
12 | #include <boost/proto/proto.hpp> |
13 | #include <boost/test/unit_test.hpp> |
14 | |
15 | namespace proto = boost::proto; |
16 | |
17 | BOOST_PROTO_DEFINE_ENV_VAR(tag0_type, tag0); |
18 | |
19 | struct abstract |
20 | { |
21 | virtual ~abstract() = 0; |
22 | }; |
23 | |
24 | abstract::~abstract() {} |
25 | |
26 | struct concrete : abstract |
27 | { |
28 | ~concrete() {} |
29 | }; |
30 | |
31 | template<typename Tag, typename Env> |
32 | void assert_has_env_var(Env const &) |
33 | { |
34 | BOOST_MPL_ASSERT((proto::result_of::has_env_var<Env, Tag>)); |
35 | } |
36 | |
37 | template<typename Tag, typename Env> |
38 | void assert_has_env_var_not(Env const &) |
39 | { |
40 | BOOST_MPL_ASSERT_NOT((proto::result_of::has_env_var<Env, Tag>)); |
41 | } |
42 | |
43 | void test_is_env() |
44 | { |
45 | BOOST_MPL_ASSERT_NOT((proto::is_env<int>)); |
46 | BOOST_MPL_ASSERT_NOT((proto::is_env<int &>)); |
47 | BOOST_MPL_ASSERT_NOT((proto::is_env<int const &>)); |
48 | |
49 | BOOST_MPL_ASSERT_NOT((proto::is_env<abstract>)); |
50 | BOOST_MPL_ASSERT_NOT((proto::is_env<abstract &>)); |
51 | BOOST_MPL_ASSERT_NOT((proto::is_env<abstract const &>)); |
52 | |
53 | BOOST_MPL_ASSERT((proto::is_env<proto::empty_env>)); |
54 | BOOST_MPL_ASSERT((proto::is_env<proto::empty_env &>)); |
55 | BOOST_MPL_ASSERT((proto::is_env<proto::empty_env const &>)); |
56 | |
57 | BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> >)); |
58 | BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> &>)); |
59 | BOOST_MPL_ASSERT((proto::is_env<proto::env<tag0_type, int> const &>)); |
60 | } |
61 | |
62 | void test_as_env() |
63 | { |
64 | proto::env<proto::data_type, int> e0 = proto::as_env(t: 2); |
65 | BOOST_CHECK_EQUAL(e0[proto::data], 2); |
66 | assert_has_env_var<proto::data_type>(e0); |
67 | assert_has_env_var_not<tag0_type>(e0); |
68 | |
69 | int i = 39; |
70 | proto::env<proto::data_type, int &> e1 = proto::as_env(t: boost::ref(t&: i)); |
71 | assert_has_env_var<proto::data_type>(i); |
72 | assert_has_env_var_not<tag0_type>(i); |
73 | BOOST_CHECK_EQUAL(e1[proto::data], 39); |
74 | BOOST_CHECK_EQUAL(&e1[proto::data], &i); |
75 | |
76 | proto::empty_env e2 = proto::as_env(t: proto::empty_env()); |
77 | proto::env<proto::data_type, int &> e3 = proto::as_env(t&: e1); |
78 | proto::env<proto::data_type, int &> & e4 = proto::as_env(t: boost::ref(t&: e1)); |
79 | BOOST_CHECK_EQUAL(&e4, &e1); |
80 | |
81 | concrete c; |
82 | abstract &a = c; |
83 | std::stringstream sout; |
84 | int rgi[2] = {}; |
85 | proto::env<proto::data_type, abstract &> e5 = proto::as_env(t&: a); |
86 | proto::env<proto::data_type, std::stringstream &> e6 = proto::as_env(t&: sout); |
87 | BOOST_CHECK_EQUAL(&e6[proto::data], &sout); |
88 | proto::env<proto::data_type, int(&)[2]> e7 = proto::as_env(t&: rgi); |
89 | BOOST_CHECK_EQUAL(&e7[proto::data][0], &rgi[0]); |
90 | proto::env<proto::data_type, void(&)()> e8 = proto::as_env(t&: test_as_env); |
91 | BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); |
92 | } |
93 | |
94 | void test_comma() |
95 | { |
96 | proto::env<proto::data_type, int> e0 = (proto::data = 1); |
97 | BOOST_CHECK_EQUAL(e0[proto::data], 1); |
98 | |
99 | int i = 39; |
100 | proto::env<proto::data_type, int &> e1 = (proto::data = boost::ref(t&: i)); |
101 | BOOST_CHECK_EQUAL(e1[proto::data], 39); |
102 | BOOST_CHECK_EQUAL(&e1[proto::data], &i); |
103 | |
104 | concrete c; |
105 | abstract &a = c; |
106 | std::stringstream sout; |
107 | int rgi[2] = {}; |
108 | proto::env<proto::data_type, abstract &> e5 = (proto::data = a); |
109 | proto::env<proto::data_type, std::stringstream &> e6 = (proto::data = sout); |
110 | BOOST_CHECK_EQUAL(&e6[proto::data], &sout); |
111 | proto::env<proto::data_type, int(&)[2]> e7 = (proto::data = rgi); |
112 | BOOST_CHECK_EQUAL(&e7[proto::data][0], &rgi[0]); |
113 | // The test below fails on msvc due to a compiler bug |
114 | // note: <https://connect.microsoft.com/VisualStudio/feedback/details/754684/premature-decay-of-function-types-in-overloaded-assignment-operator> |
115 | #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) |
116 | proto::env<proto::data_type, void(&)()> e8 = (proto::data = boost::ref(test_as_env)); |
117 | BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); |
118 | #else |
119 | proto::env<proto::data_type, void(&)()> e8 = (proto::data = test_as_env); |
120 | BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env); |
121 | #endif |
122 | |
123 | proto::env< |
124 | tag0_type |
125 | , char const (&)[6] |
126 | , proto::env<proto::data_type, int> |
127 | > e9 = (proto::data = 1, tag0 = "hello" ); |
128 | BOOST_CHECK_EQUAL(e9[proto::data], 1); |
129 | BOOST_CHECK_EQUAL(0, std::strcmp(e9[tag0], "hello" )); |
130 | |
131 | proto::env< |
132 | tag0_type |
133 | , int |
134 | , proto::env< |
135 | tag0_type |
136 | , char const (&)[6] |
137 | , proto::env<proto::data_type, int> |
138 | > |
139 | > e10 = (proto::data = 1, tag0 = "hello" , tag0 = 42); |
140 | BOOST_CHECK_EQUAL(e10[proto::data], 1); |
141 | BOOST_CHECK_EQUAL(e10[tag0], 42); |
142 | |
143 | proto::env< |
144 | tag0_type |
145 | , char const (&)[6] |
146 | , proto::env<proto::data_type, abstract &> |
147 | > e11 = (a, tag0 = "hello" ); |
148 | BOOST_CHECK_EQUAL(&e11[proto::data], &a); |
149 | BOOST_CHECK_EQUAL(0, std::strcmp(e11[tag0], "hello" )); |
150 | |
151 | proto::env< |
152 | tag0_type |
153 | , int |
154 | , proto::env< |
155 | tag0_type |
156 | , char const (&)[6] |
157 | , proto::env<proto::data_type, abstract &> |
158 | > |
159 | > e12 = (a, tag0 = "hello" , tag0 = 42); |
160 | BOOST_CHECK_EQUAL(&e12[proto::data], &a); |
161 | BOOST_CHECK_EQUAL(e12[tag0], 42); |
162 | |
163 | proto::env<tag0_type, int> e13 = (proto::empty_env(), tag0 = 42); |
164 | BOOST_CHECK_EQUAL(e13[tag0], 42); |
165 | assert_has_env_var<tag0_type>(e13); |
166 | assert_has_env_var_not<proto::data_type>(e13); |
167 | |
168 | proto::empty_env empty; |
169 | proto::env<tag0_type, int> e14 = (boost::ref(t&: empty), tag0 = 42); |
170 | BOOST_CHECK_EQUAL(e14[tag0], 42); |
171 | |
172 | proto::env< |
173 | proto::data_type |
174 | , char const (&)[6] |
175 | , proto::env<tag0_type, int> |
176 | > e15 = (boost::ref(t&: e14), proto::data = "hello" ); |
177 | BOOST_CHECK_EQUAL(e15[tag0], 42); |
178 | BOOST_CHECK_EQUAL(0, std::strcmp(e15[proto::data], "hello" )); |
179 | |
180 | proto::env< |
181 | proto::data_type |
182 | , char const (&)[6] |
183 | , proto::env<tag0_type, int> |
184 | > e16 = (proto::as_env(t: boost::ref(t&: e14)), proto::data = "hello" ); |
185 | BOOST_CHECK_EQUAL(e16[tag0], 42); |
186 | BOOST_CHECK_EQUAL(0, std::strcmp(e16[proto::data], "hello" )); |
187 | } |
188 | |
189 | void test_result_of_env_var() |
190 | { |
191 | typedef proto::empty_env env0_type; |
192 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type, proto::data_type>::type, proto::key_not_found>)); |
193 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type &, proto::data_type>::type, proto::key_not_found>)); |
194 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env0_type const &, proto::data_type>::type, proto::key_not_found>)); |
195 | |
196 | typedef proto::env<proto::data_type, int> env1_type; |
197 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type, proto::data_type>::type, int>)); |
198 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type &, proto::data_type>::type, int>)); |
199 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env1_type const &, proto::data_type>::type, int>)); |
200 | |
201 | typedef proto::env<proto::data_type, int &> env2_type; |
202 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type, proto::data_type>::type, int &>)); |
203 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type &, proto::data_type>::type, int &>)); |
204 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env2_type const &, proto::data_type>::type, int &>)); |
205 | |
206 | typedef proto::env<proto::data_type, double, proto::env<tag0_type, abstract &> > env3_type; |
207 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type, proto::data_type>::type, double>)); |
208 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type, tag0_type>::type, abstract &>)); |
209 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type &, proto::data_type>::type, double>)); |
210 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type &, tag0_type>::type, abstract &>)); |
211 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type const &, proto::data_type>::type, double>)); |
212 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env3_type const &, tag0_type>::type, abstract &>)); |
213 | |
214 | typedef proto::env<tag0_type, double, proto::env<tag0_type, abstract &> > env4_type; |
215 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type, tag0_type>::type, double>)); |
216 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type &, tag0_type>::type, double>)); |
217 | BOOST_MPL_ASSERT((boost::is_same<proto::result_of::env_var<env4_type const &, tag0_type>::type, double>)); |
218 | } |
219 | |
220 | void test_env_var() |
221 | { |
222 | proto::key_not_found x0 = proto::env_var<proto::data_type>(e: proto::empty_env()); |
223 | proto::key_not_found x1 = proto::env_var<proto::data_type>(e: tag0 = 42); |
224 | int x2 = proto::env_var<tag0_type>(e: tag0 = 42); |
225 | BOOST_CHECK_EQUAL(x2, 42); |
226 | int x3 = proto::functional::env_var<tag0_type>()(tag0 = 42); |
227 | BOOST_CHECK_EQUAL(x3, 42); |
228 | |
229 | int i = 43; |
230 | int & x4 = proto::env_var<tag0_type>(e: tag0 = boost::ref(t&: i)); |
231 | BOOST_CHECK_EQUAL(&x4, &i); |
232 | int & x5 = proto::functional::env_var<tag0_type>()(tag0 = boost::ref(t&: i)); |
233 | BOOST_CHECK_EQUAL(&x5, &i); |
234 | |
235 | concrete c; |
236 | abstract &a = c; |
237 | abstract &x6 = proto::env_var<tag0_type>(e: tag0 = a); |
238 | BOOST_CHECK_EQUAL(&x6, &a); |
239 | abstract &x7 = proto::functional::env_var<tag0_type>()(tag0 = a); |
240 | BOOST_CHECK_EQUAL(&x7, &a); |
241 | |
242 | abstract &x8 = proto::env_var<tag0_type>(e: (42, tag0 = a)); |
243 | BOOST_CHECK_EQUAL(&x8, &a); |
244 | abstract &x9 = proto::functional::env_var<tag0_type>()((42, tag0 = a)); |
245 | BOOST_CHECK_EQUAL(&x9, &a); |
246 | } |
247 | |
248 | void test_env_var_tfx() |
249 | { |
250 | typedef proto::terminal<int>::type int_; |
251 | int_ i = {.child0: 42}; |
252 | |
253 | // tests for _env |
254 | BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &)>::type, proto::empty_env>)); |
255 | BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int)>::type, proto::empty_env>)); |
256 | BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float &)>::type, float &>)); |
257 | |
258 | // Bummer, is there any way around this? |
259 | #ifdef BOOST_RESULT_OF_USE_DECLTYPE |
260 | BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float)>::type, float const &>)); |
261 | BOOST_MPL_ASSERT((boost::is_same<boost::tr1_result_of<proto::_env(int_ &, int &, float)>::type, float>)); |
262 | #else |
263 | BOOST_MPL_ASSERT((boost::is_same<boost::result_of<proto::_env(int_ &, int &, float)>::type, float>)); |
264 | BOOST_MPL_ASSERT((boost::is_same<boost::tr1_result_of<proto::_env(int_ &, int &, float)>::type, float>)); |
265 | #endif |
266 | |
267 | double d = 3.14; |
268 | double & rd = proto::_env()(i, 0, d); |
269 | BOOST_CHECK_EQUAL(&d, &rd); |
270 | |
271 | proto::env<proto::data_type, int> e0 = proto::_env()(i, 0, proto::as_env(t: 42)); |
272 | BOOST_CHECK_EQUAL(e0[proto::data], 42); |
273 | |
274 | proto::env<proto::data_type, int> e1 = proto::_env()(i, 0, proto::functional::as_env()(42)); |
275 | BOOST_CHECK_EQUAL(e1[proto::data], 42); |
276 | |
277 | proto::env<proto::data_type, int> e2 = proto::_env()(i, 0, (proto::data = 42)); |
278 | BOOST_CHECK_EQUAL(e2[proto::data], 42); |
279 | |
280 | proto::env<proto::data_type, int, proto::env<proto::data_type, int> > e3 = proto::_env()(i, 0, (42, proto::data = 43)); |
281 | BOOST_CHECK_EQUAL(e3[proto::data], 43); |
282 | } |
283 | |
284 | using namespace boost::unit_test; |
285 | /////////////////////////////////////////////////////////////////////////////// |
286 | // init_unit_test_suite |
287 | // |
288 | test_suite* init_unit_test_suite( int argc, char* argv[] ) |
289 | { |
290 | test_suite *test = BOOST_TEST_SUITE("test for environment variables" ); |
291 | test->add(BOOST_TEST_CASE(&test_as_env)); |
292 | test->add(BOOST_TEST_CASE(&test_comma)); |
293 | test->add(BOOST_TEST_CASE(&test_result_of_env_var)); |
294 | test->add(BOOST_TEST_CASE(&test_env_var)); |
295 | test->add(BOOST_TEST_CASE(&test_env_var_tfx)); |
296 | return test; |
297 | } |
298 | |