lleventcoro_test.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:27k
- /**
- * @file coroutine_test.cpp
- * @author Nat Goodspeed
- * @date 2009-04-22
- * @brief Test for coroutine.
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 2009-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- /*****************************************************************************/
- // test<1>() is cloned from a Boost.Coroutine example program whose copyright
- // info is reproduced here:
- /*---------------------------------------------------------------------------*/
- // Copyright (c) 2006, Giovanni P. Deretta
- //
- // This code may be used under either of the following two licences:
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE. OF SUCH DAMAGE.
- //
- // Or:
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- /*****************************************************************************/
- // On some platforms, Boost.Coroutine must #define magic symbols before
- // #including platform-API headers. Naturally, that's ineffective unless the
- // Boost.Coroutine #include is the *first* #include of the platform header.
- // That means that client code must generally #include Boost.Coroutine headers
- // before anything else.
- #include <boost/coroutine/coroutine.hpp>
- // Normally, lleventcoro.h obviates future.hpp. We only include this because
- // we implement a "by hand" test of future functionality.
- #include <boost/coroutine/future.hpp>
- #include <boost/bind.hpp>
- #include <boost/range.hpp>
- #include "linden_common.h"
- #include <iostream>
- #include <string>
- #include "../test/lltut.h"
- #include "llsd.h"
- #include "llevents.h"
- #include "tests/wrapllerrs.h"
- #include "stringize.h"
- #include "lleventcoro.h"
- #include "../test/debug.h"
- /*****************************************************************************
- * from the banana.cpp example program borrowed for test<1>()
- *****************************************************************************/
- namespace coroutines = boost::coroutines;
- using coroutines::coroutine;
- template<typename Iter>
- bool match(Iter first, Iter last, std::string match) {
- std::string::iterator i = match.begin();
- i != match.end();
- for(; (first != last) && (i != match.end()); ++i) {
- if (*first != *i)
- return false;
- ++first;
- }
- return i == match.end();
- }
- template<typename BidirectionalIterator>
- BidirectionalIterator
- match_substring(BidirectionalIterator begin,
- BidirectionalIterator end,
- std::string xmatch,
- BOOST_DEDUCED_TYPENAME coroutine<BidirectionalIterator(void)>::self& self) {
- BidirectionalIterator begin_ = begin;
- for(; begin != end; ++begin)
- if(match(begin, end, xmatch)) {
- self.yield(begin);
- }
- return end;
- }
- typedef coroutine<std::string::iterator(void)> match_coroutine_type;
- /*****************************************************************************
- * Test helpers
- *****************************************************************************/
- // I suspect this will be typical of coroutines used in Linden software
- typedef boost::coroutines::coroutine<void()> coroutine_type;
- /// Simulate an event API whose response is immediate: sent on receipt of the
- /// initial request, rather than after some delay. This is the case that
- /// distinguishes postAndWait() from calling post(), then calling
- /// waitForEventOn().
- class ImmediateAPI
- {
- public:
- ImmediateAPI():
- mPump("immediate", true)
- {
- mPump.listen("API", boost::bind(&ImmediateAPI::operator(), this, _1));
- }
- LLEventPump& getPump() { return mPump; }
- // Invoke this with an LLSD map containing:
- // ["value"]: Integer value. We will reply with ["value"] + 1.
- // ["reply"]: Name of LLEventPump on which to send success response.
- // ["error"]: Name of LLEventPump on which to send error response.
- // ["fail"]: Presence of this key selects ["error"], else ["success"] as
- // the name of the pump on which to send the response.
- bool operator()(const LLSD& event) const
- {
- LLSD::Integer value(event["value"]);
- LLSD::String replyPumpName(event.has("fail")? "error" : "reply");
- LLEventPumps::instance().obtain(event[replyPumpName]).post(value + 1);
- return false;
- }
- private:
- LLEventStream mPump;
- };
- /*****************************************************************************
- * TUT
- *****************************************************************************/
- namespace tut
- {
- struct coroutine_data
- {
- // Define coroutine bodies as methods here so they can use ensure*()
- void explicit_wait(coroutine_type::self& self)
- {
- BEGIN
- {
- // ... do whatever preliminary stuff must happen ...
- // declare the future
- boost::coroutines::future<LLSD> future(self);
- // tell the future what to wait for
- LLTempBoundListener connection(
- LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::coroutines::make_callback(future))));
- ensure("Not yet", ! future);
- // attempting to dereference ("resolve") the future causes the calling
- // coroutine to wait for it
- debug("about to wait");
- result = *future;
- ensure("Got it", future);
- }
- END
- }
- void waitForEventOn1(coroutine_type::self& self)
- {
- BEGIN
- {
- result = waitForEventOn(self, "source");
- }
- END
- }
- void waitForEventOn2(coroutine_type::self& self)
- {
- BEGIN
- {
- LLEventWithID pair = waitForEventOn(self, "reply", "error");
- result = pair.first;
- which = pair.second;
- debug(STRINGIZE("result = " << result << ", which = " << which));
- }
- END
- }
- void postAndWait1(coroutine_type::self& self)
- {
- BEGIN
- {
- result = postAndWait(self,
- LLSD().insert("value", 17), // request event
- immediateAPI.getPump(), // requestPump
- "reply1", // replyPump
- "reply"); // request["reply"] = name
- }
- END
- }
- void postAndWait2(coroutine_type::self& self)
- {
- BEGIN
- {
- LLEventWithID pair = ::postAndWait2(self,
- LLSD().insert("value", 18),
- immediateAPI.getPump(),
- "reply2",
- "error2",
- "reply",
- "error");
- result = pair.first;
- which = pair.second;
- debug(STRINGIZE("result = " << result << ", which = " << which));
- }
- END
- }
- void postAndWait2_1(coroutine_type::self& self)
- {
- BEGIN
- {
- LLEventWithID pair = ::postAndWait2(self,
- LLSD().insert("value", 18).insert("fail", LLSD()),
- immediateAPI.getPump(),
- "reply2",
- "error2",
- "reply",
- "error");
- result = pair.first;
- which = pair.second;
- debug(STRINGIZE("result = " << result << ", which = " << which));
- }
- END
- }
- void coroPump(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPump waiter;
- replyName = waiter.getName();
- result = waiter.wait(self);
- }
- END
- }
- void coroPumpPost(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPump waiter;
- result = waiter.postAndWait(self, LLSD().insert("value", 17),
- immediateAPI.getPump(), "reply");
- }
- END
- }
- void coroPumps(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- LLEventWithID pair(waiter.wait(self));
- result = pair.first;
- which = pair.second;
- }
- END
- }
- void coroPumpsNoEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- result = waiter.waitWithException(self);
- }
- END
- }
- void coroPumpsEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- try
- {
- result = waiter.waitWithException(self);
- debug("no exception");
- }
- catch (const LLErrorEvent& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- errordata = e.getData();
- }
- }
- END
- }
- void coroPumpsNoLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- result = waiter.waitWithLog(self);
- }
- END
- }
- void coroPumpsLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- WrapLL_ERRS capture;
- try
- {
- result = waiter.waitWithLog(self);
- debug("no exception");
- }
- catch (const WrapLL_ERRS::FatalException& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- threw = e.what();
- }
- }
- END
- }
- void coroPumpsPost(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- LLEventWithID pair(waiter.postAndWait(self, LLSD().insert("value", 23),
- immediateAPI.getPump(), "reply", "error"));
- result = pair.first;
- which = pair.second;
- }
- END
- }
- void coroPumpsPost_1(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- LLEventWithID pair(
- waiter.postAndWait(self, LLSD().insert("value", 23).insert("fail", LLSD()),
- immediateAPI.getPump(), "reply", "error"));
- result = pair.first;
- which = pair.second;
- }
- END
- }
- void coroPumpsPostNoEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- result = waiter.postAndWaitWithException(self, LLSD().insert("value", 8),
- immediateAPI.getPump(), "reply", "error");
- }
- END
- }
- void coroPumpsPostEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- try
- {
- result = waiter.postAndWaitWithException(self,
- LLSD().insert("value", 9).insert("fail", LLSD()),
- immediateAPI.getPump(), "reply", "error");
- debug("no exception");
- }
- catch (const LLErrorEvent& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- errordata = e.getData();
- }
- }
- END
- }
- void coroPumpsPostNoLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- result = waiter.postAndWaitWithLog(self, LLSD().insert("value", 30),
- immediateAPI.getPump(), "reply", "error");
- }
- END
- }
- void coroPumpsPostLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- WrapLL_ERRS capture;
- try
- {
- result = waiter.postAndWaitWithLog(self,
- LLSD().insert("value", 31).insert("fail", LLSD()),
- immediateAPI.getPump(), "reply", "error");
- debug("no exception");
- }
- catch (const WrapLL_ERRS::FatalException& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- threw = e.what();
- }
- }
- END
- }
- void ensure_done(coroutine_type& coro)
- {
- ensure("coroutine complete", ! coro);
- }
- ImmediateAPI immediateAPI;
- std::string replyName, errorName, threw;
- LLSD result, errordata;
- int which;
- };
- typedef test_group<coroutine_data> coroutine_group;
- typedef coroutine_group::object object;
- coroutine_group coroutinegrp("coroutine");
- template<> template<>
- void object::test<1>()
- {
- set_test_name("From banana.cpp example program in Boost.Coroutine distro");
- std::string buffer = "banananana";
- std::string match = "nana";
- std::string::iterator begin = buffer.begin();
- std::string::iterator end = buffer.end();
- #if defined(BOOST_CORO_POSIX_IMPL)
- // std::cout << "Using Boost.Coroutine " << BOOST_CORO_POSIX_IMPL << 'n';
- #else
- // std::cout << "Using non-Posix Boost.Coroutine implementation" << std::endl;
- #endif
- typedef std::string::iterator signature(std::string::iterator,
- std::string::iterator,
- std::string,
- match_coroutine_type::self&);
- coroutine<std::string::iterator(void)> matcher
- (boost::bind(static_cast<signature*>(match_substring),
- begin,
- end,
- match,
- _1));
- std::string::iterator i = matcher();
- /*==========================================================================*|
- while(matcher && i != buffer.end()) {
- std::cout <<"Match at: "<< std::distance(buffer.begin(), i)<<'n';
- i = matcher();
- }
- |*==========================================================================*/
- size_t matches[] = { 2, 4, 6 };
- for (size_t *mi(boost::begin(matches)), *mend(boost::end(matches));
- mi != mend; ++mi, i = matcher())
- {
- ensure("more", matcher);
- ensure("found", i != buffer.end());
- ensure_equals("value", std::distance(buffer.begin(), i), *mi);
- }
- ensure("done", ! matcher);
- }
- template<> template<>
- void object::test<2>()
- {
- set_test_name("explicit_wait");
- DEBUG;
- // Construct the coroutine instance that will run explicit_wait.
- // Pass the ctor a callable that accepts the coroutine_type::self
- // param passed by the library.
- coroutine_type coro(boost::bind(&coroutine_data::explicit_wait, this, _1));
- // Start the coroutine
- coro(std::nothrow);
- // When the coroutine waits for the event pump, it returns here.
- debug("about to send");
- // Satisfy the wait.
- LLEventPumps::instance().obtain("source").post("received");
- // Now wait for the coroutine to complete.
- ensure_done(coro);
- // ensure the coroutine ran and woke up again with the intended result
- ensure_equals(result.asString(), "received");
- }
- template<> template<>
- void object::test<3>()
- {
- set_test_name("waitForEventOn1");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn1, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain("source").post("received");
- debug("back from send");
- ensure_done(coro);
- ensure_equals(result.asString(), "received");
- }
- template<> template<>
- void object::test<4>()
- {
- set_test_name("waitForEventOn2 reply");
- {
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain("reply").post("received");
- debug("back from send");
- ensure_done(coro);
- }
- ensure_equals(result.asString(), "received");
- ensure_equals("which pump", which, 0);
- }
- template<> template<>
- void object::test<5>()
- {
- set_test_name("waitForEventOn2 error");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain("error").post("badness");
- debug("back from send");
- ensure_done(coro);
- ensure_equals(result.asString(), "badness");
- ensure_equals("which pump", which, 1);
- }
- template<> template<>
- void object::test<6>()
- {
- set_test_name("coroPump");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPump, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain(replyName).post("received");
- debug("back from send");
- ensure_done(coro);
- ensure_equals(result.asString(), "received");
- }
- template<> template<>
- void object::test<7>()
- {
- set_test_name("coroPumps reply");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain(replyName).post("received");
- debug("back from send");
- ensure_done(coro);
- ensure_equals(result.asString(), "received");
- ensure_equals("which pump", which, 0);
- }
- template<> template<>
- void object::test<8>()
- {
- set_test_name("coroPumps error");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain(errorName).post("badness");
- debug("back from send");
- ensure_done(coro);
- ensure_equals(result.asString(), "badness");
- ensure_equals("which pump", which, 1);
- }
- template<> template<>
- void object::test<9>()
- {
- set_test_name("coroPumpsNoEx");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoEx, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain(replyName).post("received");
- debug("back from send");
- ensure_done(coro);
- ensure_equals(result.asString(), "received");
- }
- template<> template<>
- void object::test<10>()
- {
- set_test_name("coroPumpsEx");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsEx, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain(errorName).post("badness");
- debug("back from send");
- ensure_done(coro);
- ensure("no result", result.isUndefined());
- ensure_equals("got error", errordata.asString(), "badness");
- }
- template<> template<>
- void object::test<11>()
- {
- set_test_name("coroPumpsNoLog");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoLog, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain(replyName).post("received");
- debug("back from send");
- ensure_done(coro);
- ensure_equals(result.asString(), "received");
- }
- template<> template<>
- void object::test<12>()
- {
- set_test_name("coroPumpsLog");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsLog, this, _1));
- coro(std::nothrow);
- debug("about to send");
- LLEventPumps::instance().obtain(errorName).post("badness");
- debug("back from send");
- ensure_done(coro);
- ensure("no result", result.isUndefined());
- ensure_contains("got error", threw, "badness");
- }
- template<> template<>
- void object::test<13>()
- {
- set_test_name("postAndWait1");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::postAndWait1, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 18);
- }
- template<> template<>
- void object::test<14>()
- {
- set_test_name("postAndWait2");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::postAndWait2, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 19);
- ensure_equals(which, 0);
- }
- template<> template<>
- void object::test<15>()
- {
- set_test_name("postAndWait2_1");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::postAndWait2_1, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 19);
- ensure_equals(which, 1);
- }
- template<> template<>
- void object::test<16>()
- {
- set_test_name("coroPumpPost");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpPost, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 18);
- }
- template<> template<>
- void object::test<17>()
- {
- set_test_name("coroPumpsPost reply");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 24);
- ensure_equals("which pump", which, 0);
- }
- template<> template<>
- void object::test<18>()
- {
- set_test_name("coroPumpsPost error");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost_1, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 24);
- ensure_equals("which pump", which, 1);
- }
- template<> template<>
- void object::test<19>()
- {
- set_test_name("coroPumpsPostNoEx");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoEx, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 9);
- }
- template<> template<>
- void object::test<20>()
- {
- set_test_name("coroPumpsPostEx");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostEx, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure("no result", result.isUndefined());
- ensure_equals("got error", errordata.asInteger(), 10);
- }
- template<> template<>
- void object::test<21>()
- {
- set_test_name("coroPumpsPostNoLog");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoLog, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure_equals(result.asInteger(), 31);
- }
- template<> template<>
- void object::test<22>()
- {
- set_test_name("coroPumpsPostLog");
- DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostLog, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
- ensure("no result", result.isUndefined());
- ensure_contains("got error", threw, "32");
- }
- } // namespace tut