mixed_optional.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // no #include guard
  2. // Copyright (C) 2008-2018 Lorenzo Caminiti
  3. // Distributed under the Boost Software License, Version 1.0 (see accompanying
  4. // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
  5. // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
  6. // Test base and derived classes mixing boost::optional and non- result types.
  7. #include "../detail/oteststream.hpp"
  8. #include "../detail/counter.hpp"
  9. #include <boost/contract/base_types.hpp>
  10. #include <boost/contract/public_function.hpp>
  11. #include <boost/contract/override.hpp>
  12. #include <boost/contract/check.hpp>
  13. #include <boost/contract/assert.hpp>
  14. #include <boost/optional.hpp>
  15. #include <boost/detail/lightweight_test.hpp>
  16. #include <boost/config.hpp>
  17. #include <sstream>
  18. #include <cassert>
  19. boost::contract::test::detail::oteststream out;
  20. struct ch_tag;
  21. typedef boost::contract::test::detail::counter<ch_tag, char> ch_type;
  22. #ifdef BOOST_CONTRACT_TEST_REF // Test with result types by reference.
  23. #define BOOST_CONTRACT_TEST_CH_TYPE ch_type&
  24. #define BOOST_CONTRACT_TEST_CH_INIT = ch_init
  25. ch_type ch_init;
  26. unsigned const ch_extras = 2; // 1 local and 1 global var.
  27. #else // Test with result types by value.
  28. #define BOOST_CONTRACT_TEST_CH_TYPE ch_type
  29. #define BOOST_CONTRACT_TEST_CH_INIT /* nothing */
  30. unsigned const ch_extras = 1; // 1 for local var (no global var).
  31. #endif
  32. bool tested_d_copies = false;
  33. struct d {
  34. static void static_invariant() { out << "d::static_inv" << std::endl; }
  35. void invariant() const { out << "d::inv" << std::endl; }
  36. virtual BOOST_CONTRACT_TEST_CH_TYPE f(
  37. ch_type& ch, boost::contract::virtual_* v = 0) {
  38. unsigned const old_ch_copies = ch_type::copies();
  39. boost::optional<BOOST_CONTRACT_TEST_CH_TYPE> result;
  40. boost::contract::check c = boost::contract::public_function(
  41. v, result, this)
  42. .precondition([&] {
  43. out << "d::f::pre" << std::endl;
  44. BOOST_CONTRACT_ASSERT(ch.value == 'd');
  45. })
  46. .old([] { out << "d::f::old" << std::endl; })
  47. .postcondition([&] (boost::optional<ch_type const&> const& result) {
  48. out << "d::f::post" << std::endl;
  49. BOOST_CONTRACT_ASSERT(result->value == ch.value);
  50. })
  51. ;
  52. BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
  53. tested_d_copies = true;
  54. out << "d::f::body" << std::endl;
  55. return *(result = ch);
  56. }
  57. };
  58. bool tested_c_copies = false;
  59. struct c
  60. #define BASES public d
  61. : BASES
  62. {
  63. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
  64. #undef BASES
  65. static void static_invariant() { out << "c::static_inv" << std::endl; }
  66. void invariant() const { out << "c::inv" << std::endl; }
  67. virtual BOOST_CONTRACT_TEST_CH_TYPE f(
  68. ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
  69. unsigned const old_ch_copies = ch_type::copies();
  70. boost::optional<BOOST_CONTRACT_TEST_CH_TYPE> result;
  71. boost::contract::check c = boost::contract::public_function<override_f>(
  72. v, result, &c::f, this, ch)
  73. .precondition([&] {
  74. out << "c::f::pre" << std::endl;
  75. BOOST_CONTRACT_ASSERT(ch.value == 'c');
  76. })
  77. .old([] { out << "c::f::old" << std::endl; })
  78. .postcondition([&] (boost::optional<ch_type const&> const& result) {
  79. out << "c::f::post" << std::endl;
  80. BOOST_CONTRACT_ASSERT(result->value == ch.value);
  81. })
  82. ;
  83. BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
  84. tested_c_copies = true;
  85. out << "c::f::body" << std::endl;
  86. return *(result = ch);
  87. }
  88. BOOST_CONTRACT_OVERRIDE(f)
  89. };
  90. bool tested_b_copies = false;
  91. struct b
  92. #define BASES public c
  93. : BASES
  94. {
  95. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
  96. #undef BASES
  97. static void static_invariant() { out << "b::static_inv" << std::endl; }
  98. void invariant() const { out << "b::inv" << std::endl; }
  99. virtual BOOST_CONTRACT_TEST_CH_TYPE f(
  100. ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
  101. unsigned const old_ch_copies = ch_type::copies();
  102. BOOST_CONTRACT_TEST_CH_TYPE result BOOST_CONTRACT_TEST_CH_INIT;
  103. boost::contract::check c = boost::contract::public_function<override_f>(
  104. v, result, &b::f, this, ch)
  105. .precondition([&] {
  106. out << "b::f::pre" << std::endl;
  107. BOOST_CONTRACT_ASSERT(ch.value == 'b');
  108. })
  109. .old([] { out << "b::f::old" << std::endl; })
  110. .postcondition([&] (ch_type const& result) {
  111. out << "b::f::post" << std::endl;
  112. BOOST_CONTRACT_ASSERT(result.value == ch.value);
  113. })
  114. ;
  115. BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
  116. tested_b_copies = true;
  117. out << "b::f::body" << std::endl;
  118. return result = ch;
  119. }
  120. BOOST_CONTRACT_OVERRIDE(f)
  121. };
  122. bool tested_a_copies = false;
  123. struct a
  124. #define BASES public b
  125. : BASES
  126. {
  127. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
  128. #undef BASES
  129. static void static_invariant() { out << "a::static_inv" << std::endl; }
  130. void invariant() const { out << "a::inv" << std::endl; }
  131. virtual BOOST_CONTRACT_TEST_CH_TYPE f(
  132. ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
  133. unsigned const old_ch_copies = ch_type::copies();
  134. boost::optional<BOOST_CONTRACT_TEST_CH_TYPE> result;
  135. boost::contract::check c = boost::contract::public_function<override_f>(
  136. v, result, &a::f, this, ch)
  137. .precondition([&] {
  138. out << "a::f::pre" << std::endl;
  139. BOOST_CONTRACT_ASSERT(ch.value == 'a');
  140. })
  141. .old([] { out << "a::f::old" << std::endl; })
  142. .postcondition([&] (boost::optional<ch_type const&> const& result) {
  143. out << "a::f::post" << std::endl;
  144. BOOST_CONTRACT_ASSERT(result->value == ch.value);
  145. })
  146. ;
  147. BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
  148. tested_a_copies = true;
  149. out << "a::f::body" << std::endl;
  150. return *(result = ch);
  151. }
  152. BOOST_CONTRACT_OVERRIDE(f)
  153. };
  154. bool tested_e_copies = false;
  155. struct e
  156. #define BASES public b
  157. : BASES
  158. {
  159. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
  160. #undef BASES
  161. static void static_invariant() { out << "e::static_inv" << std::endl; }
  162. void invariant() const { out << "e::inv" << std::endl; }
  163. virtual BOOST_CONTRACT_TEST_CH_TYPE f(
  164. ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
  165. unsigned const old_ch_copies = ch_type::copies();
  166. BOOST_CONTRACT_TEST_CH_TYPE result BOOST_CONTRACT_TEST_CH_INIT;
  167. boost::contract::check c = boost::contract::public_function<override_f>(
  168. v, result, &e::f, this, ch)
  169. .precondition([&] {
  170. out << "e::f::pre" << std::endl;
  171. BOOST_CONTRACT_ASSERT(ch.value == 'e');
  172. })
  173. .old([] { out << "e::f::old" << std::endl; })
  174. .postcondition([&] (ch_type const& result) {
  175. out << "e::f::post" << std::endl;
  176. BOOST_CONTRACT_ASSERT(result.value == ch.value);
  177. })
  178. ;
  179. BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
  180. tested_e_copies = true;
  181. out << "e::f::body" << std::endl;
  182. return result = ch;
  183. }
  184. BOOST_CONTRACT_OVERRIDE(f)
  185. };
  186. int main() {
  187. std::ostringstream ok;
  188. ch_type ch;
  189. #ifdef BOOST_CONTRACT_TEST_REF
  190. ch_init.value = '\0';
  191. #endif
  192. // Test optional in overriding a::f and non-optional in overridden b::f.
  193. a aa;
  194. ch.value = 'a';
  195. out.str("");
  196. aa.f(ch);
  197. ok.str(""); ok
  198. #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
  199. << "d::static_inv" << std::endl
  200. << "d::inv" << std::endl
  201. << "c::static_inv" << std::endl
  202. << "c::inv" << std::endl
  203. << "b::static_inv" << std::endl
  204. << "b::inv" << std::endl
  205. << "a::static_inv" << std::endl
  206. << "a::inv" << std::endl
  207. #endif
  208. #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
  209. << "d::f::pre" << std::endl
  210. << "c::f::pre" << std::endl
  211. << "b::f::pre" << std::endl
  212. << "a::f::pre" << std::endl
  213. #endif
  214. #ifndef BOOST_CONTRACT_NO_OLDS
  215. << "d::f::old" << std::endl
  216. << "c::f::old" << std::endl
  217. << "b::f::old" << std::endl
  218. << "a::f::old" << std::endl
  219. #endif
  220. << "a::f::body" << std::endl
  221. #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
  222. << "d::static_inv" << std::endl
  223. << "d::inv" << std::endl
  224. << "c::static_inv" << std::endl
  225. << "c::inv" << std::endl
  226. << "b::static_inv" << std::endl
  227. << "b::inv" << std::endl
  228. << "a::static_inv" << std::endl
  229. << "a::inv" << std::endl
  230. #endif
  231. #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
  232. << "d::f::old" << std::endl
  233. << "d::f::post" << std::endl
  234. << "c::f::old" << std::endl
  235. << "c::f::post" << std::endl
  236. << "b::f::old" << std::endl
  237. << "b::f::post" << std::endl
  238. << "a::f::post" << std::endl
  239. #endif
  240. ;
  241. BOOST_TEST(out.eq(ok.str()));
  242. BOOST_TEST(tested_a_copies);
  243. BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
  244. // Test non-optional in overriding b::f and optional in overridden c::f.
  245. b bb;
  246. ch.value = 'b';
  247. out.str("");
  248. bb.f(ch);
  249. ok.str(""); ok
  250. #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
  251. << "d::static_inv" << std::endl
  252. << "d::inv" << std::endl
  253. << "c::static_inv" << std::endl
  254. << "c::inv" << std::endl
  255. << "b::static_inv" << std::endl
  256. << "b::inv" << std::endl
  257. #endif
  258. #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
  259. << "d::f::pre" << std::endl
  260. << "c::f::pre" << std::endl
  261. << "b::f::pre" << std::endl
  262. #endif
  263. #ifndef BOOST_CONTRACT_NO_OLDS
  264. << "d::f::old" << std::endl
  265. << "c::f::old" << std::endl
  266. << "b::f::old" << std::endl
  267. #endif
  268. << "b::f::body" << std::endl
  269. #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
  270. << "d::static_inv" << std::endl
  271. << "d::inv" << std::endl
  272. << "c::static_inv" << std::endl
  273. << "c::inv" << std::endl
  274. << "b::static_inv" << std::endl
  275. << "b::inv" << std::endl
  276. #endif
  277. #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
  278. << "d::f::old" << std::endl
  279. << "d::f::post" << std::endl
  280. << "c::f::old" << std::endl
  281. << "c::f::post" << std::endl
  282. << "b::f::post" << std::endl
  283. #endif
  284. ;
  285. BOOST_TEST(out.eq(ok.str()));
  286. BOOST_TEST(tested_b_copies);
  287. BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
  288. // Test optional in both overriding c::f and overridden d::f.
  289. c cc;
  290. ch.value = 'c';
  291. out.str("");
  292. cc.f(ch);
  293. ok.str(""); ok
  294. #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
  295. << "d::static_inv" << std::endl
  296. << "d::inv" << std::endl
  297. << "c::static_inv" << std::endl
  298. << "c::inv" << std::endl
  299. #endif
  300. #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
  301. << "d::f::pre" << std::endl
  302. << "c::f::pre" << std::endl
  303. #endif
  304. #ifndef BOOST_CONTRACT_NO_OLDS
  305. << "d::f::old" << std::endl
  306. << "c::f::old" << std::endl
  307. #endif
  308. << "c::f::body" << std::endl
  309. #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
  310. << "d::static_inv" << std::endl
  311. << "d::inv" << std::endl
  312. << "c::static_inv" << std::endl
  313. << "c::inv" << std::endl
  314. #endif
  315. #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
  316. << "d::f::old" << std::endl
  317. << "d::f::post" << std::endl
  318. << "c::f::post" << std::endl
  319. #endif
  320. ;
  321. BOOST_TEST(out.eq(ok.str()));
  322. BOOST_TEST(tested_c_copies);
  323. BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
  324. // Test non-optional in both overriding c::f and overridden d::f.
  325. e ee;
  326. ch.value = 'e';
  327. out.str("");
  328. ee.f(ch);
  329. ok.str(""); ok
  330. #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
  331. << "d::static_inv" << std::endl
  332. << "d::inv" << std::endl
  333. << "c::static_inv" << std::endl
  334. << "c::inv" << std::endl
  335. << "b::static_inv" << std::endl
  336. << "b::inv" << std::endl
  337. << "e::static_inv" << std::endl
  338. << "e::inv" << std::endl
  339. #endif
  340. #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
  341. << "d::f::pre" << std::endl
  342. << "c::f::pre" << std::endl
  343. << "b::f::pre" << std::endl
  344. << "e::f::pre" << std::endl
  345. #endif
  346. #ifndef BOOST_CONTRACT_NO_OLDS
  347. << "d::f::old" << std::endl
  348. << "c::f::old" << std::endl
  349. << "b::f::old" << std::endl
  350. << "e::f::old" << std::endl
  351. #endif
  352. << "e::f::body" << std::endl
  353. #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
  354. << "d::static_inv" << std::endl
  355. << "d::inv" << std::endl
  356. << "c::static_inv" << std::endl
  357. << "c::inv" << std::endl
  358. << "b::static_inv" << std::endl
  359. << "b::inv" << std::endl
  360. << "e::static_inv" << std::endl
  361. << "e::inv" << std::endl
  362. #endif
  363. #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
  364. << "d::f::old" << std::endl
  365. << "d::f::post" << std::endl
  366. << "c::f::old" << std::endl
  367. << "c::f::post" << std::endl
  368. << "b::f::old" << std::endl
  369. << "b::f::post" << std::endl
  370. << "e::f::post" << std::endl
  371. #endif
  372. ;
  373. BOOST_TEST(out.eq(ok.str()));
  374. BOOST_TEST(tested_e_copies);
  375. BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
  376. return boost::report_errors();
  377. }