• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~abstract()24 abstract::~abstract() {}
25 
26 struct concrete : abstract
27 {
~concreteconcrete28     ~concrete() {}
29 };
30 
31 template<typename Tag, typename Env>
assert_has_env_var(Env const &)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>
assert_has_env_var_not(Env const &)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 
test_is_env()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 
test_as_env()62 void test_as_env()
63 {
64     proto::env<proto::data_type, int> e0 = proto::as_env(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(boost::ref(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(proto::empty_env());
77     proto::env<proto::data_type, int &> e3 = proto::as_env(e1);
78     proto::env<proto::data_type, int &> & e4 = proto::as_env(boost::ref(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(a);
86     proto::env<proto::data_type, std::stringstream &> e6 = proto::as_env(sout);
87     BOOST_CHECK_EQUAL(&e6[proto::data], &sout);
88     proto::env<proto::data_type, int(&)[2]> e7 = proto::as_env(rgi);
89     BOOST_CHECK_EQUAL(&e7[proto::data][0], &rgi[0]);
90     proto::env<proto::data_type, void(&)()> e8 = proto::as_env(test_as_env);
91     BOOST_CHECK_EQUAL(&e8[proto::data], &test_as_env);
92 }
93 
test_comma()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(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(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(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(boost::ref(e14)), proto::data = "hello");
185     BOOST_CHECK_EQUAL(e16[tag0], 42);
186     BOOST_CHECK_EQUAL(0, std::strcmp(e16[proto::data], "hello"));
187 }
188 
test_result_of_env_var()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 
test_env_var()220 void test_env_var()
221 {
222     proto::key_not_found x0 = proto::env_var<proto::data_type>(proto::empty_env());
223     proto::key_not_found x1 = proto::env_var<proto::data_type>(tag0 = 42);
224     int x2 = proto::env_var<tag0_type>(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>(tag0 = boost::ref(i));
231     BOOST_CHECK_EQUAL(&x4, &i);
232     int & x5 = proto::functional::env_var<tag0_type>()(tag0 = boost::ref(i));
233     BOOST_CHECK_EQUAL(&x5, &i);
234 
235     concrete c;
236     abstract &a = c;
237     abstract &x6 = proto::env_var<tag0_type>(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>((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 
test_env_var_tfx()248 void test_env_var_tfx()
249 {
250     typedef proto::terminal<int>::type int_;
251     int_ i = {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(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 //
init_unit_test_suite(int argc,char * argv[])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