PageRenderTime 41ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llcommon/tests/lleventcoro_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 799 lines | 627 code | 64 blank | 108 comment | 14 complexity | 6bc23e9cde450b1ca438857f4d18fbbe MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file coroutine_test.cpp
  3. * @author Nat Goodspeed
  4. * @date 2009-04-22
  5. * @brief Test for coroutine.
  6. *
  7. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. /*****************************************************************************/
  29. // test<1>() is cloned from a Boost.Coroutine example program whose copyright
  30. // info is reproduced here:
  31. /*---------------------------------------------------------------------------*/
  32. // Copyright (c) 2006, Giovanni P. Deretta
  33. //
  34. // This code may be used under either of the following two licences:
  35. //
  36. // Permission is hereby granted, free of charge, to any person obtaining a copy
  37. // of this software and associated documentation files (the "Software"), to deal
  38. // in the Software without restriction, including without limitation the rights
  39. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  40. // copies of the Software, and to permit persons to whom the Software is
  41. // furnished to do so, subject to the following conditions:
  42. //
  43. // The above copyright notice and this permission notice shall be included in
  44. // all copies or substantial portions of the Software.
  45. //
  46. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  47. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  48. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  49. // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  50. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  51. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  52. // THE SOFTWARE. OF SUCH DAMAGE.
  53. //
  54. // Or:
  55. //
  56. // Distributed under the Boost Software License, Version 1.0.
  57. // (See accompanying file LICENSE_1_0.txt or copy at
  58. // http://www.boost.org/LICENSE_1_0.txt)
  59. /*****************************************************************************/
  60. // On some platforms, Boost.Coroutine must #define magic symbols before
  61. // #including platform-API headers. Naturally, that's ineffective unless the
  62. // Boost.Coroutine #include is the *first* #include of the platform header.
  63. // That means that client code must generally #include Boost.Coroutine headers
  64. // before anything else.
  65. #include <boost/coroutine/coroutine.hpp>
  66. // Normally, lleventcoro.h obviates future.hpp. We only include this because
  67. // we implement a "by hand" test of future functionality.
  68. #include <boost/coroutine/future.hpp>
  69. #include <boost/bind.hpp>
  70. #include <boost/range.hpp>
  71. #include "linden_common.h"
  72. #include <iostream>
  73. #include <string>
  74. #include "../test/lltut.h"
  75. #include "llsd.h"
  76. #include "llevents.h"
  77. #include "tests/wrapllerrs.h"
  78. #include "stringize.h"
  79. #include "lleventcoro.h"
  80. #include "../test/debug.h"
  81. /*****************************************************************************
  82. * from the banana.cpp example program borrowed for test<1>()
  83. *****************************************************************************/
  84. namespace coroutines = boost::coroutines;
  85. using coroutines::coroutine;
  86. template<typename Iter>
  87. bool match(Iter first, Iter last, std::string match) {
  88. std::string::iterator i = match.begin();
  89. i != match.end();
  90. for(; (first != last) && (i != match.end()); ++i) {
  91. if (*first != *i)
  92. return false;
  93. ++first;
  94. }
  95. return i == match.end();
  96. }
  97. template<typename BidirectionalIterator>
  98. BidirectionalIterator
  99. match_substring(BidirectionalIterator begin,
  100. BidirectionalIterator end,
  101. std::string xmatch,
  102. BOOST_DEDUCED_TYPENAME coroutine<BidirectionalIterator(void)>::self& self) {
  103. BidirectionalIterator begin_ = begin;
  104. for(; begin != end; ++begin)
  105. if(match(begin, end, xmatch)) {
  106. self.yield(begin);
  107. }
  108. return end;
  109. }
  110. typedef coroutine<std::string::iterator(void)> match_coroutine_type;
  111. /*****************************************************************************
  112. * Test helpers
  113. *****************************************************************************/
  114. // I suspect this will be typical of coroutines used in Linden software
  115. typedef boost::coroutines::coroutine<void()> coroutine_type;
  116. /// Simulate an event API whose response is immediate: sent on receipt of the
  117. /// initial request, rather than after some delay. This is the case that
  118. /// distinguishes postAndWait() from calling post(), then calling
  119. /// waitForEventOn().
  120. class ImmediateAPI
  121. {
  122. public:
  123. ImmediateAPI():
  124. mPump("immediate", true)
  125. {
  126. mPump.listen("API", boost::bind(&ImmediateAPI::operator(), this, _1));
  127. }
  128. LLEventPump& getPump() { return mPump; }
  129. // Invoke this with an LLSD map containing:
  130. // ["value"]: Integer value. We will reply with ["value"] + 1.
  131. // ["reply"]: Name of LLEventPump on which to send success response.
  132. // ["error"]: Name of LLEventPump on which to send error response.
  133. // ["fail"]: Presence of this key selects ["error"], else ["success"] as
  134. // the name of the pump on which to send the response.
  135. bool operator()(const LLSD& event) const
  136. {
  137. LLSD::Integer value(event["value"]);
  138. LLSD::String replyPumpName(event.has("fail")? "error" : "reply");
  139. LLEventPumps::instance().obtain(event[replyPumpName]).post(value + 1);
  140. return false;
  141. }
  142. private:
  143. LLEventStream mPump;
  144. };
  145. /*****************************************************************************
  146. * TUT
  147. *****************************************************************************/
  148. namespace tut
  149. {
  150. struct coroutine_data
  151. {
  152. // Define coroutine bodies as methods here so they can use ensure*()
  153. void explicit_wait(coroutine_type::self& self)
  154. {
  155. BEGIN
  156. {
  157. // ... do whatever preliminary stuff must happen ...
  158. // declare the future
  159. boost::coroutines::future<LLSD> future(self);
  160. // tell the future what to wait for
  161. LLTempBoundListener connection(
  162. LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::coroutines::make_callback(future))));
  163. ensure("Not yet", ! future);
  164. // attempting to dereference ("resolve") the future causes the calling
  165. // coroutine to wait for it
  166. debug("about to wait");
  167. result = *future;
  168. ensure("Got it", future);
  169. }
  170. END
  171. }
  172. void waitForEventOn1(coroutine_type::self& self)
  173. {
  174. BEGIN
  175. {
  176. result = waitForEventOn(self, "source");
  177. }
  178. END
  179. }
  180. void waitForEventOn2(coroutine_type::self& self)
  181. {
  182. BEGIN
  183. {
  184. LLEventWithID pair = waitForEventOn(self, "reply", "error");
  185. result = pair.first;
  186. which = pair.second;
  187. debug(STRINGIZE("result = " << result << ", which = " << which));
  188. }
  189. END
  190. }
  191. void postAndWait1(coroutine_type::self& self)
  192. {
  193. BEGIN
  194. {
  195. result = postAndWait(self,
  196. LLSD().insert("value", 17), // request event
  197. immediateAPI.getPump(), // requestPump
  198. "reply1", // replyPump
  199. "reply"); // request["reply"] = name
  200. }
  201. END
  202. }
  203. void postAndWait2(coroutine_type::self& self)
  204. {
  205. BEGIN
  206. {
  207. LLEventWithID pair = ::postAndWait2(self,
  208. LLSD().insert("value", 18),
  209. immediateAPI.getPump(),
  210. "reply2",
  211. "error2",
  212. "reply",
  213. "error");
  214. result = pair.first;
  215. which = pair.second;
  216. debug(STRINGIZE("result = " << result << ", which = " << which));
  217. }
  218. END
  219. }
  220. void postAndWait2_1(coroutine_type::self& self)
  221. {
  222. BEGIN
  223. {
  224. LLEventWithID pair = ::postAndWait2(self,
  225. LLSD().insert("value", 18).insert("fail", LLSD()),
  226. immediateAPI.getPump(),
  227. "reply2",
  228. "error2",
  229. "reply",
  230. "error");
  231. result = pair.first;
  232. which = pair.second;
  233. debug(STRINGIZE("result = " << result << ", which = " << which));
  234. }
  235. END
  236. }
  237. void coroPump(coroutine_type::self& self)
  238. {
  239. BEGIN
  240. {
  241. LLCoroEventPump waiter;
  242. replyName = waiter.getName();
  243. result = waiter.wait(self);
  244. }
  245. END
  246. }
  247. void coroPumpPost(coroutine_type::self& self)
  248. {
  249. BEGIN
  250. {
  251. LLCoroEventPump waiter;
  252. result = waiter.postAndWait(self, LLSD().insert("value", 17),
  253. immediateAPI.getPump(), "reply");
  254. }
  255. END
  256. }
  257. void coroPumps(coroutine_type::self& self)
  258. {
  259. BEGIN
  260. {
  261. LLCoroEventPumps waiter;
  262. replyName = waiter.getName0();
  263. errorName = waiter.getName1();
  264. LLEventWithID pair(waiter.wait(self));
  265. result = pair.first;
  266. which = pair.second;
  267. }
  268. END
  269. }
  270. void coroPumpsNoEx(coroutine_type::self& self)
  271. {
  272. BEGIN
  273. {
  274. LLCoroEventPumps waiter;
  275. replyName = waiter.getName0();
  276. errorName = waiter.getName1();
  277. result = waiter.waitWithException(self);
  278. }
  279. END
  280. }
  281. void coroPumpsEx(coroutine_type::self& self)
  282. {
  283. BEGIN
  284. {
  285. LLCoroEventPumps waiter;
  286. replyName = waiter.getName0();
  287. errorName = waiter.getName1();
  288. try
  289. {
  290. result = waiter.waitWithException(self);
  291. debug("no exception");
  292. }
  293. catch (const LLErrorEvent& e)
  294. {
  295. debug(STRINGIZE("exception " << e.what()));
  296. errordata = e.getData();
  297. }
  298. }
  299. END
  300. }
  301. void coroPumpsNoLog(coroutine_type::self& self)
  302. {
  303. BEGIN
  304. {
  305. LLCoroEventPumps waiter;
  306. replyName = waiter.getName0();
  307. errorName = waiter.getName1();
  308. result = waiter.waitWithLog(self);
  309. }
  310. END
  311. }
  312. void coroPumpsLog(coroutine_type::self& self)
  313. {
  314. BEGIN
  315. {
  316. LLCoroEventPumps waiter;
  317. replyName = waiter.getName0();
  318. errorName = waiter.getName1();
  319. WrapLL_ERRS capture;
  320. try
  321. {
  322. result = waiter.waitWithLog(self);
  323. debug("no exception");
  324. }
  325. catch (const WrapLL_ERRS::FatalException& e)
  326. {
  327. debug(STRINGIZE("exception " << e.what()));
  328. threw = e.what();
  329. }
  330. }
  331. END
  332. }
  333. void coroPumpsPost(coroutine_type::self& self)
  334. {
  335. BEGIN
  336. {
  337. LLCoroEventPumps waiter;
  338. LLEventWithID pair(waiter.postAndWait(self, LLSD().insert("value", 23),
  339. immediateAPI.getPump(), "reply", "error"));
  340. result = pair.first;
  341. which = pair.second;
  342. }
  343. END
  344. }
  345. void coroPumpsPost_1(coroutine_type::self& self)
  346. {
  347. BEGIN
  348. {
  349. LLCoroEventPumps waiter;
  350. LLEventWithID pair(
  351. waiter.postAndWait(self, LLSD().insert("value", 23).insert("fail", LLSD()),
  352. immediateAPI.getPump(), "reply", "error"));
  353. result = pair.first;
  354. which = pair.second;
  355. }
  356. END
  357. }
  358. void coroPumpsPostNoEx(coroutine_type::self& self)
  359. {
  360. BEGIN
  361. {
  362. LLCoroEventPumps waiter;
  363. result = waiter.postAndWaitWithException(self, LLSD().insert("value", 8),
  364. immediateAPI.getPump(), "reply", "error");
  365. }
  366. END
  367. }
  368. void coroPumpsPostEx(coroutine_type::self& self)
  369. {
  370. BEGIN
  371. {
  372. LLCoroEventPumps waiter;
  373. try
  374. {
  375. result = waiter.postAndWaitWithException(self,
  376. LLSD().insert("value", 9).insert("fail", LLSD()),
  377. immediateAPI.getPump(), "reply", "error");
  378. debug("no exception");
  379. }
  380. catch (const LLErrorEvent& e)
  381. {
  382. debug(STRINGIZE("exception " << e.what()));
  383. errordata = e.getData();
  384. }
  385. }
  386. END
  387. }
  388. void coroPumpsPostNoLog(coroutine_type::self& self)
  389. {
  390. BEGIN
  391. {
  392. LLCoroEventPumps waiter;
  393. result = waiter.postAndWaitWithLog(self, LLSD().insert("value", 30),
  394. immediateAPI.getPump(), "reply", "error");
  395. }
  396. END
  397. }
  398. void coroPumpsPostLog(coroutine_type::self& self)
  399. {
  400. BEGIN
  401. {
  402. LLCoroEventPumps waiter;
  403. WrapLL_ERRS capture;
  404. try
  405. {
  406. result = waiter.postAndWaitWithLog(self,
  407. LLSD().insert("value", 31).insert("fail", LLSD()),
  408. immediateAPI.getPump(), "reply", "error");
  409. debug("no exception");
  410. }
  411. catch (const WrapLL_ERRS::FatalException& e)
  412. {
  413. debug(STRINGIZE("exception " << e.what()));
  414. threw = e.what();
  415. }
  416. }
  417. END
  418. }
  419. void ensure_done(coroutine_type& coro)
  420. {
  421. ensure("coroutine complete", ! coro);
  422. }
  423. ImmediateAPI immediateAPI;
  424. std::string replyName, errorName, threw;
  425. LLSD result, errordata;
  426. int which;
  427. };
  428. typedef test_group<coroutine_data> coroutine_group;
  429. typedef coroutine_group::object object;
  430. coroutine_group coroutinegrp("coroutine");
  431. template<> template<>
  432. void object::test<1>()
  433. {
  434. set_test_name("From banana.cpp example program in Boost.Coroutine distro");
  435. std::string buffer = "banananana";
  436. std::string match = "nana";
  437. std::string::iterator begin = buffer.begin();
  438. std::string::iterator end = buffer.end();
  439. #if defined(BOOST_CORO_POSIX_IMPL)
  440. // std::cout << "Using Boost.Coroutine " << BOOST_CORO_POSIX_IMPL << '\n';
  441. #else
  442. // std::cout << "Using non-Posix Boost.Coroutine implementation" << std::endl;
  443. #endif
  444. typedef std::string::iterator signature(std::string::iterator,
  445. std::string::iterator,
  446. std::string,
  447. match_coroutine_type::self&);
  448. coroutine<std::string::iterator(void)> matcher
  449. (boost::bind(static_cast<signature*>(match_substring),
  450. begin,
  451. end,
  452. match,
  453. _1));
  454. std::string::iterator i = matcher();
  455. /*==========================================================================*|
  456. while(matcher && i != buffer.end()) {
  457. std::cout <<"Match at: "<< std::distance(buffer.begin(), i)<<'\n';
  458. i = matcher();
  459. }
  460. |*==========================================================================*/
  461. size_t matches[] = { 2, 4, 6 };
  462. for (size_t *mi(boost::begin(matches)), *mend(boost::end(matches));
  463. mi != mend; ++mi, i = matcher())
  464. {
  465. ensure("more", matcher);
  466. ensure("found", i != buffer.end());
  467. ensure_equals("value", std::distance(buffer.begin(), i), *mi);
  468. }
  469. ensure("done", ! matcher);
  470. }
  471. template<> template<>
  472. void object::test<2>()
  473. {
  474. set_test_name("explicit_wait");
  475. DEBUG;
  476. // Construct the coroutine instance that will run explicit_wait.
  477. // Pass the ctor a callable that accepts the coroutine_type::self
  478. // param passed by the library.
  479. coroutine_type coro(boost::bind(&coroutine_data::explicit_wait, this, _1));
  480. // Start the coroutine
  481. coro(std::nothrow);
  482. // When the coroutine waits for the event pump, it returns here.
  483. debug("about to send");
  484. // Satisfy the wait.
  485. LLEventPumps::instance().obtain("source").post("received");
  486. // Now wait for the coroutine to complete.
  487. ensure_done(coro);
  488. // ensure the coroutine ran and woke up again with the intended result
  489. ensure_equals(result.asString(), "received");
  490. }
  491. template<> template<>
  492. void object::test<3>()
  493. {
  494. set_test_name("waitForEventOn1");
  495. DEBUG;
  496. coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn1, this, _1));
  497. coro(std::nothrow);
  498. debug("about to send");
  499. LLEventPumps::instance().obtain("source").post("received");
  500. debug("back from send");
  501. ensure_done(coro);
  502. ensure_equals(result.asString(), "received");
  503. }
  504. template<> template<>
  505. void object::test<4>()
  506. {
  507. set_test_name("waitForEventOn2 reply");
  508. {
  509. DEBUG;
  510. coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
  511. coro(std::nothrow);
  512. debug("about to send");
  513. LLEventPumps::instance().obtain("reply").post("received");
  514. debug("back from send");
  515. ensure_done(coro);
  516. }
  517. ensure_equals(result.asString(), "received");
  518. ensure_equals("which pump", which, 0);
  519. }
  520. template<> template<>
  521. void object::test<5>()
  522. {
  523. set_test_name("waitForEventOn2 error");
  524. DEBUG;
  525. coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
  526. coro(std::nothrow);
  527. debug("about to send");
  528. LLEventPumps::instance().obtain("error").post("badness");
  529. debug("back from send");
  530. ensure_done(coro);
  531. ensure_equals(result.asString(), "badness");
  532. ensure_equals("which pump", which, 1);
  533. }
  534. template<> template<>
  535. void object::test<6>()
  536. {
  537. set_test_name("coroPump");
  538. DEBUG;
  539. coroutine_type coro(boost::bind(&coroutine_data::coroPump, this, _1));
  540. coro(std::nothrow);
  541. debug("about to send");
  542. LLEventPumps::instance().obtain(replyName).post("received");
  543. debug("back from send");
  544. ensure_done(coro);
  545. ensure_equals(result.asString(), "received");
  546. }
  547. template<> template<>
  548. void object::test<7>()
  549. {
  550. set_test_name("coroPumps reply");
  551. DEBUG;
  552. coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
  553. coro(std::nothrow);
  554. debug("about to send");
  555. LLEventPumps::instance().obtain(replyName).post("received");
  556. debug("back from send");
  557. ensure_done(coro);
  558. ensure_equals(result.asString(), "received");
  559. ensure_equals("which pump", which, 0);
  560. }
  561. template<> template<>
  562. void object::test<8>()
  563. {
  564. set_test_name("coroPumps error");
  565. DEBUG;
  566. coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
  567. coro(std::nothrow);
  568. debug("about to send");
  569. LLEventPumps::instance().obtain(errorName).post("badness");
  570. debug("back from send");
  571. ensure_done(coro);
  572. ensure_equals(result.asString(), "badness");
  573. ensure_equals("which pump", which, 1);
  574. }
  575. template<> template<>
  576. void object::test<9>()
  577. {
  578. set_test_name("coroPumpsNoEx");
  579. DEBUG;
  580. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoEx, this, _1));
  581. coro(std::nothrow);
  582. debug("about to send");
  583. LLEventPumps::instance().obtain(replyName).post("received");
  584. debug("back from send");
  585. ensure_done(coro);
  586. ensure_equals(result.asString(), "received");
  587. }
  588. template<> template<>
  589. void object::test<10>()
  590. {
  591. set_test_name("coroPumpsEx");
  592. DEBUG;
  593. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsEx, this, _1));
  594. coro(std::nothrow);
  595. debug("about to send");
  596. LLEventPumps::instance().obtain(errorName).post("badness");
  597. debug("back from send");
  598. ensure_done(coro);
  599. ensure("no result", result.isUndefined());
  600. ensure_equals("got error", errordata.asString(), "badness");
  601. }
  602. template<> template<>
  603. void object::test<11>()
  604. {
  605. set_test_name("coroPumpsNoLog");
  606. DEBUG;
  607. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoLog, this, _1));
  608. coro(std::nothrow);
  609. debug("about to send");
  610. LLEventPumps::instance().obtain(replyName).post("received");
  611. debug("back from send");
  612. ensure_done(coro);
  613. ensure_equals(result.asString(), "received");
  614. }
  615. template<> template<>
  616. void object::test<12>()
  617. {
  618. set_test_name("coroPumpsLog");
  619. DEBUG;
  620. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsLog, this, _1));
  621. coro(std::nothrow);
  622. debug("about to send");
  623. LLEventPumps::instance().obtain(errorName).post("badness");
  624. debug("back from send");
  625. ensure_done(coro);
  626. ensure("no result", result.isUndefined());
  627. ensure_contains("got error", threw, "badness");
  628. }
  629. template<> template<>
  630. void object::test<13>()
  631. {
  632. set_test_name("postAndWait1");
  633. DEBUG;
  634. coroutine_type coro(boost::bind(&coroutine_data::postAndWait1, this, _1));
  635. coro(std::nothrow);
  636. ensure_done(coro);
  637. ensure_equals(result.asInteger(), 18);
  638. }
  639. template<> template<>
  640. void object::test<14>()
  641. {
  642. set_test_name("postAndWait2");
  643. DEBUG;
  644. coroutine_type coro(boost::bind(&coroutine_data::postAndWait2, this, _1));
  645. coro(std::nothrow);
  646. ensure_done(coro);
  647. ensure_equals(result.asInteger(), 19);
  648. ensure_equals(which, 0);
  649. }
  650. template<> template<>
  651. void object::test<15>()
  652. {
  653. set_test_name("postAndWait2_1");
  654. DEBUG;
  655. coroutine_type coro(boost::bind(&coroutine_data::postAndWait2_1, this, _1));
  656. coro(std::nothrow);
  657. ensure_done(coro);
  658. ensure_equals(result.asInteger(), 19);
  659. ensure_equals(which, 1);
  660. }
  661. template<> template<>
  662. void object::test<16>()
  663. {
  664. set_test_name("coroPumpPost");
  665. DEBUG;
  666. coroutine_type coro(boost::bind(&coroutine_data::coroPumpPost, this, _1));
  667. coro(std::nothrow);
  668. ensure_done(coro);
  669. ensure_equals(result.asInteger(), 18);
  670. }
  671. template<> template<>
  672. void object::test<17>()
  673. {
  674. set_test_name("coroPumpsPost reply");
  675. DEBUG;
  676. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost, this, _1));
  677. coro(std::nothrow);
  678. ensure_done(coro);
  679. ensure_equals(result.asInteger(), 24);
  680. ensure_equals("which pump", which, 0);
  681. }
  682. template<> template<>
  683. void object::test<18>()
  684. {
  685. set_test_name("coroPumpsPost error");
  686. DEBUG;
  687. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost_1, this, _1));
  688. coro(std::nothrow);
  689. ensure_done(coro);
  690. ensure_equals(result.asInteger(), 24);
  691. ensure_equals("which pump", which, 1);
  692. }
  693. template<> template<>
  694. void object::test<19>()
  695. {
  696. set_test_name("coroPumpsPostNoEx");
  697. DEBUG;
  698. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoEx, this, _1));
  699. coro(std::nothrow);
  700. ensure_done(coro);
  701. ensure_equals(result.asInteger(), 9);
  702. }
  703. template<> template<>
  704. void object::test<20>()
  705. {
  706. set_test_name("coroPumpsPostEx");
  707. DEBUG;
  708. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostEx, this, _1));
  709. coro(std::nothrow);
  710. ensure_done(coro);
  711. ensure("no result", result.isUndefined());
  712. ensure_equals("got error", errordata.asInteger(), 10);
  713. }
  714. template<> template<>
  715. void object::test<21>()
  716. {
  717. set_test_name("coroPumpsPostNoLog");
  718. DEBUG;
  719. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoLog, this, _1));
  720. coro(std::nothrow);
  721. ensure_done(coro);
  722. ensure_equals(result.asInteger(), 31);
  723. }
  724. template<> template<>
  725. void object::test<22>()
  726. {
  727. set_test_name("coroPumpsPostLog");
  728. DEBUG;
  729. coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostLog, this, _1));
  730. coro(std::nothrow);
  731. ensure_done(coro);
  732. ensure("no result", result.isUndefined());
  733. ensure_contains("got error", threw, "32");
  734. }
  735. } // namespace tut