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
15namespace proto = boost::proto;
16
17BOOST_PROTO_DEFINE_ENV_VAR(tag0_type, tag0);
18
19struct abstract
20{
21 virtual ~abstract() = 0;
22};
23
24abstract::~abstract() {}
25
26struct concrete : abstract
27{
28 ~concrete() {}
29};
30
31template<typename Tag, typename Env>
32void assert_has_env_var(Env const &)
33{
34 BOOST_MPL_ASSERT((proto::result_of::has_env_var<Env, Tag>));
35}
36
37template<typename Tag, typename Env>
38void assert_has_env_var_not(Env const &)
39{
40 BOOST_MPL_ASSERT_NOT((proto::result_of::has_env_var<Env, Tag>));
41}
42
43void 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
62void 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
94void 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
189void 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
220void 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
248void 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
284using namespace boost::unit_test;
285///////////////////////////////////////////////////////////////////////////////
286// init_unit_test_suite
287//
288test_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

source code of boost/libs/proto/test/env_var.cpp