lleventcoro_test.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:27k
源码类别:

游戏引擎

开发平台:

C++ Builder

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