env_var.cpp 12 KB

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