PageRenderTime 60ms CodeModel.GetById 6ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llcommon/tests/lleventfilter_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 293 lines | 173 code | 12 blank | 108 comment | 0 complexity | 98a1cd0488c74986569438bf84d4b70d MD5 | raw file
  1/**
  2 * @file   lleventfilter_test.cpp
  3 * @author Nat Goodspeed
  4 * @date   2009-03-06
  5 * @brief  Test for lleventfilter.
  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// Precompiled header
 30#include "linden_common.h"
 31// associated header
 32#include "lleventfilter.h"
 33// STL headers
 34// std headers
 35// external library headers
 36// other Linden headers
 37#include "../test/lltut.h"
 38#include "stringize.h"
 39#include "listener.h"
 40#include "tests/wrapllerrs.h"
 41
 42/*****************************************************************************
 43*   Test classes
 44*****************************************************************************/
 45// Strictly speaking, we're testing LLEventTimeoutBase rather than the
 46// production LLEventTimeout (using LLTimer) because we don't want every test
 47// run to pause for some number of seconds until we reach a real timeout. But
 48// as we've carefully put all functionality except actual LLTimer calls into
 49// LLEventTimeoutBase, that should suffice. We're not not not trying to test
 50// LLTimer here.
 51class TestEventTimeout: public LLEventTimeoutBase
 52{
 53public:
 54    TestEventTimeout():
 55        mElapsed(true)
 56    {}
 57    TestEventTimeout(LLEventPump& source):
 58        LLEventTimeoutBase(source),
 59        mElapsed(true)
 60    {}
 61
 62    // test hook
 63    void forceTimeout(bool timeout=true) { mElapsed = timeout; }
 64
 65protected:
 66    virtual void setCountdown(F32 seconds) { mElapsed = false; }
 67    virtual bool countdownElapsed() const { return mElapsed; }
 68
 69private:
 70    bool mElapsed;
 71};
 72
 73/*****************************************************************************
 74*   TUT
 75*****************************************************************************/
 76namespace tut
 77{
 78    struct filter_data
 79    {
 80        // The resemblance between this test data and that in llevents_tut.cpp
 81        // is not coincidental.
 82        filter_data():
 83            pumps(LLEventPumps::instance()),
 84            mainloop(pumps.obtain("mainloop")),
 85            listener0("first"),
 86            listener1("second")
 87        {}
 88        LLEventPumps& pumps;
 89        LLEventPump& mainloop;
 90        Listener listener0;
 91        Listener listener1;
 92
 93        void check_listener(const std::string& desc, const Listener& listener, const LLSD& got)
 94        {
 95            ensure_equals(STRINGIZE(listener << ' ' << desc),
 96                          listener.getLastEvent(), got);
 97        }
 98    };
 99    typedef test_group<filter_data> filter_group;
100    typedef filter_group::object filter_object;
101    filter_group filtergrp("lleventfilter");
102
103    template<> template<>
104    void filter_object::test<1>()
105    {
106        set_test_name("LLEventMatching");
107        LLEventPump& driver(pumps.obtain("driver"));
108        listener0.reset(0);
109        // Listener isn't derived from LLEventTrackable specifically to test
110        // various connection-management mechanisms. But that means we have a
111        // couple of transient Listener objects, one of which is listening to
112        // a persistent LLEventPump. Capture those connections in local
113        // LLTempBoundListener instances so they'll disconnect
114        // on destruction.
115        LLTempBoundListener temp1(
116            listener0.listenTo(driver));
117        // Construct a pattern LLSD: desired Event must have a key "foo"
118        // containing string "bar"
119        LLEventMatching filter(driver, LLSD().insert("foo", "bar"));
120        listener1.reset(0);
121        LLTempBoundListener temp2(
122            listener1.listenTo(filter));
123        driver.post(1);
124        check_listener("direct", listener0, LLSD(1));
125        check_listener("filtered", listener1, LLSD(0));
126        // Okay, construct an LLSD map matching the pattern
127        LLSD data;
128        data["foo"] = "bar";
129        data["random"] = 17;
130        driver.post(data);
131        check_listener("direct", listener0, data);
132        check_listener("filtered", listener1, data);
133    }
134
135    template<> template<>
136    void filter_object::test<2>()
137    {
138        set_test_name("LLEventTimeout::actionAfter()");
139        LLEventPump& driver(pumps.obtain("driver"));
140        TestEventTimeout filter(driver);
141        listener0.reset(0);
142        LLTempBoundListener temp1(
143            listener0.listenTo(filter));
144        // Use listener1.call() as the Action for actionAfter(), since it
145        // already provides a way to sense the call
146        listener1.reset(0);
147        // driver --> filter --> listener0
148        filter.actionAfter(20,
149                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
150        // Okay, (fake) timer is ticking. 'filter' can only sense the timer
151        // when we pump mainloop. Do that right now to take the logic path
152        // before either the anticipated event arrives or the timer expires.
153        mainloop.post(17);
154        check_listener("no timeout 1", listener1, LLSD(0));
155        // Expected event arrives...
156        driver.post(1);
157        check_listener("event passed thru", listener0, LLSD(1));
158        // Should have canceled the timer. Verify that by asserting that the
159        // time has expired, then pumping mainloop again.
160        filter.forceTimeout();
161        mainloop.post(17);
162        check_listener("no timeout 2", listener1, LLSD(0));
163        // Verify chained actionAfter() calls, that is, that a second
164        // actionAfter() resets the timer established by the first
165        // actionAfter().
166        filter.actionAfter(20,
167                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
168        // Since our TestEventTimeout class isn't actually manipulating time
169        // (quantities of seconds), only a bool "elapsed" flag, sense that by
170        // forcing the flag between actionAfter() calls.
171        filter.forceTimeout();
172        // Pumping mainloop here would result in a timeout (as we'll verify
173        // below). This state simulates a ticking timer that has not yet timed
174        // out. But now, before a mainloop event lets 'filter' recognize
175        // timeout on the previous actionAfter() call, pretend we're pushing
176        // that timeout farther into the future.
177        filter.actionAfter(20,
178                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
179        // Look ma, no timeout!
180        mainloop.post(17);
181        check_listener("no timeout 3", listener1, LLSD(0));
182        // Now let the updated actionAfter() timer expire.
183        filter.forceTimeout();
184        // Notice the timeout.
185        mainloop.post(17);
186        check_listener("timeout", listener1, LLSD("timeout"));
187        // Timing out cancels the timer. Verify that.
188        listener1.reset(0);
189        filter.forceTimeout();
190        mainloop.post(17);
191        check_listener("no timeout 4", listener1, LLSD(0));
192        // Reset the timer and then cancel() it.
193        filter.actionAfter(20,
194                           boost::bind(&Listener::call, boost::ref(listener1), LLSD("timeout")));
195        // neither expired nor satisified
196        mainloop.post(17);
197        check_listener("no timeout 5", listener1, LLSD(0));
198        // cancel
199        filter.cancel();
200        // timeout!
201        filter.forceTimeout();
202        mainloop.post(17);
203        check_listener("no timeout 6", listener1, LLSD(0));
204    }
205
206    template<> template<>
207    void filter_object::test<3>()
208    {
209        set_test_name("LLEventTimeout::eventAfter()");
210        LLEventPump& driver(pumps.obtain("driver"));
211        TestEventTimeout filter(driver);
212        listener0.reset(0);
213        LLTempBoundListener temp1(
214            listener0.listenTo(filter));
215        filter.eventAfter(20, LLSD("timeout"));
216        // Okay, (fake) timer is ticking. 'filter' can only sense the timer
217        // when we pump mainloop. Do that right now to take the logic path
218        // before either the anticipated event arrives or the timer expires.
219        mainloop.post(17);
220        check_listener("no timeout 1", listener0, LLSD(0));
221        // Expected event arrives...
222        driver.post(1);
223        check_listener("event passed thru", listener0, LLSD(1));
224        // Should have canceled the timer. Verify that by asserting that the
225        // time has expired, then pumping mainloop again.
226        filter.forceTimeout();
227        mainloop.post(17);
228        check_listener("no timeout 2", listener0, LLSD(1));
229        // Set timer again.
230        filter.eventAfter(20, LLSD("timeout"));
231        // Now let the timer expire.
232        filter.forceTimeout();
233        // Notice the timeout.
234        mainloop.post(17);
235        check_listener("timeout", listener0, LLSD("timeout"));
236        // Timing out cancels the timer. Verify that.
237        listener0.reset(0);
238        filter.forceTimeout();
239        mainloop.post(17);
240        check_listener("no timeout 3", listener0, LLSD(0));
241    }
242
243    template<> template<>
244    void filter_object::test<4>()
245    {
246        set_test_name("LLEventTimeout::errorAfter()");
247        WrapLL_ERRS capture;
248        LLEventPump& driver(pumps.obtain("driver"));
249        TestEventTimeout filter(driver);
250        listener0.reset(0);
251        LLTempBoundListener temp1(
252            listener0.listenTo(filter));
253        filter.errorAfter(20, "timeout");
254        // Okay, (fake) timer is ticking. 'filter' can only sense the timer
255        // when we pump mainloop. Do that right now to take the logic path
256        // before either the anticipated event arrives or the timer expires.
257        mainloop.post(17);
258        check_listener("no timeout 1", listener0, LLSD(0));
259        // Expected event arrives...
260        driver.post(1);
261        check_listener("event passed thru", listener0, LLSD(1));
262        // Should have canceled the timer. Verify that by asserting that the
263        // time has expired, then pumping mainloop again.
264        filter.forceTimeout();
265        mainloop.post(17);
266        check_listener("no timeout 2", listener0, LLSD(1));
267        // Set timer again.
268        filter.errorAfter(20, "timeout");
269        // Now let the timer expire.
270        filter.forceTimeout();
271        // Notice the timeout.
272        std::string threw;
273        try
274        {
275            mainloop.post(17);
276        }
277        catch (const WrapLL_ERRS::FatalException& e)
278        {
279            threw = e.what();
280        }
281        ensure_contains("errorAfter() timeout exception", threw, "timeout");
282        // Timing out cancels the timer. Verify that.
283        listener0.reset(0);
284        filter.forceTimeout();
285        mainloop.post(17);
286        check_listener("no timeout 3", listener0, LLSD(0));
287    }
288} // namespace tut
289
290/*****************************************************************************
291*   Link dependencies
292*****************************************************************************/
293#include "llsdutil.cpp"