summaryrefslogtreecommitdiff
path: root/indra/llcommon/tests/lazyeventapi_test.cpp
blob: f3fcf84e4957045efc4850c821345316fd5593e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
 * @file   lazyeventapi_test.cpp
 * @author Nat Goodspeed
 * @date   2022-06-18
 * @brief  Test for lazyeventapi.
 *
 * $LicenseInfo:firstyear=2022&license=viewerlgpl$
 * Copyright (c) 2022, Linden Research, Inc.
 * $/LicenseInfo$
 */

// Precompiled header
#include "linden_common.h"
// associated header
#include "lazyeventapi.h"
// STL headers
// std headers
// external library headers
// other Linden headers
#include "../test/lltut.h"
#include "llevents.h"
#include "llsdutil.h"

// observable side effect, solely for testing
static LLSD data;

// LLEventAPI listener subclass
class MyListener: public LLEventAPI
{
public:
    // need this trivial forwarding constructor
    // (of course do any other initialization your subclass requires)
    MyListener(const LL::LazyEventAPIParams& params):
        LLEventAPI(params)
    {}

    // example operation, registered by LazyEventAPI subclass below
    void set_data(const LLSD& event)
    {
        data = event["data"];
    }
};

// LazyEventAPI registrar subclass
class MyRegistrar: public LL::LazyEventAPI<MyListener>
{
    using super = LL::LazyEventAPI<MyListener>;
    using super::listener;
public:
    // LazyEventAPI subclass initializes like a classic LLEventAPI subclass
    // constructor, with API name and desc plus add() calls for the defined
    // operations
    MyRegistrar():
        super("Test", "This is a test LLEventAPI")
    {
        add("set", "This is a set operation", &listener::set_data);
    }
};
// Normally we'd declare a static instance of MyRegistrar -- but because we
// want to test both with and without, defer declaration to individual test
// methods.

/*****************************************************************************
*   TUT
*****************************************************************************/
namespace tut
{
    struct lazyeventapi_data
    {
        lazyeventapi_data()
        {
            // before every test, reset 'data'
            data.clear();
        }
        ~lazyeventapi_data()
        {
            // after every test, reset LLEventPumps
            LLEventPumps::deleteSingleton();
        }
    };
    typedef test_group<lazyeventapi_data> lazyeventapi_group;
    typedef lazyeventapi_group::object object;
    lazyeventapi_group lazyeventapigrp("lazyeventapi");

    template<> template<>
    void object::test<1>()
    {
        set_test_name("LazyEventAPI");
        // this is where the magic (should) happen
        // 'register' still a keyword until C++17
        MyRegistrar regster;
        LLEventPumps::instance().obtain("Test").post(llsd::map("op", "set", "data", "hey"));
        ensure_equals("failed to set data", data.asString(), "hey");
    }

    template<> template<>
    void object::test<2>()
    {
        set_test_name("No LazyEventAPI");
        // Because the MyRegistrar declaration in test<1>() is local, because
        // it has been destroyed, we fully expect NOT to reach a MyListener
        // instance with this post.
        LLEventPumps::instance().obtain("Test").post(llsd::map("op", "set", "data", "moot"));
        ensure("accidentally set data", ! data.isDefined());
    }

    template<> template<>
    void object::test<3>()
    {
        set_test_name("LazyEventAPI metadata");
        MyRegistrar regster;
        // Of course we have 'regster' in hand; we don't need to search for
        // it. But this next test verifies that we can find (all) LazyEventAPI
        // instances using LazyEventAPIBase::instance_snapshot. Normally we
        // wouldn't search; normally we'd just look at each instance in the
        // loop body.
        const MyRegistrar* found = nullptr;
        for (const auto& registrar : LL::LazyEventAPIBase::instance_snapshot())
            if ((found = dynamic_cast<const MyRegistrar*>(&registrar)))
                break;
        ensure("Failed to find MyRegistrar via LLInstanceTracker", found);

        ensure_equals("wrong API name", found->getName(), "Test");
        ensure_contains("wrong API desc", found->getDesc(), "test LLEventAPI");
        ensure_equals("wrong API field", found->getDispatchKey(), "op");
        // Normally we'd just iterate over *found. But for test purposes,
        // actually capture the range of NameDesc pairs in a vector.
        std::vector<LL::LazyEventAPIBase::NameDesc> ops{ found->begin(), found->end() };
        ensure_equals("failed to find operations", ops.size(), 1);
        ensure_equals("wrong operation name", ops[0].first, "set");
        ensure_contains("wrong operation desc", ops[0].second, "set operation");
        LLSD metadata{ found->getMetadata(ops[0].first) };
        ensure_equals("bad metadata name", metadata["name"].asString(), ops[0].first);
        ensure_equals("bad metadata desc", metadata["desc"].asString(), ops[0].second);
    }
} // namespace tut