1 /*
2 * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
6 */
7
8 #include <vector>
9 #include "fcitx-utils/log.h"
10 #include "fcitx/focusgroup.h"
11 #include "fcitx/inputcontext.h"
12 #include "fcitx/inputcontextmanager.h"
13 #include "fcitx/inputcontextproperty.h"
14
15 #define TEST_FOCUS(ARGS...) \
16 do { \
17 bool focus_result[] = {ARGS}; \
18 for (size_t i = 0; i < FCITX_ARRAY_SIZE(focus_result); i++) { \
19 FCITX_ASSERT(ic[i]->hasFocus() == focus_result[i]); \
20 } \
21 } while (0)
22
23 using namespace fcitx;
24
25 class TestInputContext : public InputContext {
26 public:
TestInputContext(InputContextManager & manager,const std::string & program={})27 TestInputContext(InputContextManager &manager,
28 const std::string &program = {})
29 : InputContext(manager, program) {}
30
~TestInputContext()31 ~TestInputContext() { destroy(); }
32
frontend() const33 const char *frontend() const override { return "test"; }
34
commitStringImpl(const std::string &)35 void commitStringImpl(const std::string &) override {}
deleteSurroundingTextImpl(int,unsigned int)36 void deleteSurroundingTextImpl(int, unsigned int) override {}
forwardKeyImpl(const ForwardKeyEvent &)37 void forwardKeyImpl(const ForwardKeyEvent &) override {}
updatePreeditImpl()38 void updatePreeditImpl() override {}
39 };
40
41 class TestProperty : public InputContextProperty {
42 public:
num() const43 int num() const { return num_; }
setNum(int n)44 void setNum(int n) { num_ = n; }
45
46 protected:
47 int num_ = 0;
48 };
49
50 class TestSharedProperty : public TestProperty {
51 public:
needCopy() const52 bool needCopy() const override { return true; }
copyTo(InputContextProperty * other_)53 void copyTo(InputContextProperty *other_) override {
54 auto *other = static_cast<TestSharedProperty *>(other_);
55 other->num_ = num_;
56 }
57 };
58
test_simple()59 void test_simple() {
60 InputContextManager manager;
61
62 {
63 std::vector<std::unique_ptr<InputContext>> ic;
64 ic.reserve(8);
65 for (int i = 0; i < 8; i++) {
66 ic.emplace_back(std::make_unique<TestInputContext>(manager));
67 }
68
69 ic.pop_back();
70 ic.emplace_back(new TestInputContext(manager));
71
72 FocusGroup group("", manager), group2("", manager);
73 ic[2]->setFocusGroup(&group);
74 ic[3]->setFocusGroup(&group);
75 ic[4]->setFocusGroup(&group2);
76 ic[5]->setFocusGroup(&group2);
77
78 TEST_FOCUS(false, false, false, false, false, false, false, false);
79 ic[0]->focusIn();
80 TEST_FOCUS(true, false, false, false, false, false, false, false);
81 ic[0]->focusOut();
82 TEST_FOCUS(false, false, false, false, false, false, false, false);
83 ic[2]->focusIn();
84 TEST_FOCUS(false, false, true, false, false, false, false, false);
85 ic[3]->focusIn();
86 TEST_FOCUS(false, false, false, true, false, false, false, false);
87 ic[4]->focusIn();
88 TEST_FOCUS(false, false, false, true, true, false, false, false);
89 ic[6]->focusIn();
90 TEST_FOCUS(false, false, false, true, true, false, true, false);
91 ic[7]->focusIn();
92 TEST_FOCUS(false, false, false, true, true, false, true, true);
93 ic[1]->focusIn();
94 TEST_FOCUS(false, true, false, true, true, false, true, true);
95 ic[5]->focusIn();
96 TEST_FOCUS(false, true, false, true, false, true, true, true);
97
98 ic[1]->setCapabilityFlags(CapabilityFlag::Digit);
99 FCITX_ASSERT(ic[1]->capabilityFlags() == CapabilityFlag::Digit);
100 }
101
102 {
103 std::vector<std::unique_ptr<InputContext>> ic;
104 ic.emplace_back(new TestInputContext(manager, "Firefox"));
105 ic.emplace_back(new TestInputContext(manager, "Firefox"));
106 ic.emplace_back(new TestInputContext(manager, "Chrome"));
107
108 SimpleInputContextPropertyFactory<TestSharedProperty> testsharedFactory;
109 FactoryFor<TestProperty> testFactory(
110 [](InputContext &) { return new TestProperty; });
111 FCITX_ASSERT(manager.registerProperty("shared", &testsharedFactory));
112 FCITX_ASSERT(manager.registerProperty("property", &testFactory));
113
114 ic.emplace_back(new TestInputContext(manager, "Chrome"));
115
116 std::array<const char *, 2> slot{{"shared", "property"}};
117 auto check = [&ic, &slot](auto expect) {
118 int idx = 0;
119 for (const auto *s : slot) {
120 int idx2 = 0;
121 for (auto &context : ic) {
122 FCITX_ASSERT(context->propertyAs<TestProperty>(s)->num() ==
123 expect[idx][idx2]);
124 idx2++;
125 }
126 idx++;
127 }
128 };
129
130 {
131 int expect[][4] = {
132 {0, 0, 0, 0},
133 {0, 0, 0, 0},
134 };
135 check(expect);
136 }
137
138 ic[0]->propertyAs<TestProperty>(slot[0])->setNum(1);
139 ic[0]->propertyAs<TestProperty>(slot[1])->setNum(2);
140 ic[0]->updateProperty(slot[0]);
141 ic[0]->updateProperty(slot[1]);
142 {
143 int expect[][4] = {
144 {1, 0, 0, 0},
145 {2, 0, 0, 0},
146 };
147 check(expect);
148 }
149 manager.setPropertyPropagatePolicy(PropertyPropagatePolicy::Program);
150 ic[0]->updateProperty(slot[0]);
151 ic[0]->updateProperty(slot[1]);
152 {
153 int expect[][4] = {
154 {1, 1, 0, 0},
155 {2, 0, 0, 0},
156 };
157 check(expect);
158 }
159 manager.setPropertyPropagatePolicy(PropertyPropagatePolicy::All);
160 ic[0]->updateProperty(slot[0]);
161 ic[0]->updateProperty(slot[1]);
162 {
163 int expect[][4] = {
164 {1, 1, 1, 1},
165 {2, 0, 0, 0},
166 };
167 check(expect);
168 }
169 ic.emplace_back(new TestInputContext(manager, "Firefox"));
170 FCITX_ASSERT(ic.back()->propertyAs<TestProperty>(slot[0])->num() == 1);
171 FCITX_ASSERT(ic.back()->propertyAs<TestProperty>(slot[1])->num() == 0);
172 manager.setPropertyPropagatePolicy(PropertyPropagatePolicy::Program);
173 {
174 ic[3]->propertyAs<TestProperty>(slot[0])->setNum(3);
175 ic[3]->updateProperty(slot[0]);
176 int expect[][5] = {
177 {1, 1, 3, 3, 1},
178 {2, 0, 0, 0, 0},
179 };
180 check(expect);
181 }
182 }
183 }
184
test_property()185 void test_property() {
186 InputContextManager manager;
187 FactoryFor<TestProperty> testFactory(
188 [](InputContext &) { return new TestProperty; });
189 manager.registerProperty("test", &testFactory);
190 std::vector<std::unique_ptr<InputContext>> ic;
191 ic.emplace_back(new TestInputContext(manager, "Firefox"));
192 auto *testProperty = ic[0]->propertyFor(&testFactory);
193 FCITX_ASSERT(testProperty->num() == 0);
194 FCITX_ASSERT(testFactory.registered());
195 testFactory.unregister();
196 FCITX_ASSERT(!testFactory.registered());
197
198 manager.registerProperty("test", &testFactory);
199 auto *testProperty2 = ic[0]->propertyFor(&testFactory);
200 FCITX_ASSERT(testProperty2->num() == 0);
201 }
202
test_preedit_override()203 void test_preedit_override() {
204 InputContextManager manager;
205 auto ic = std::make_unique<TestInputContext>(manager, "Firefox");
206 ic->setCapabilityFlags(CapabilityFlag::Preedit);
207 FCITX_ASSERT(ic->capabilityFlags().test(CapabilityFlag::Preedit));
208 ic->setEnablePreedit(false);
209 FCITX_ASSERT(!ic->capabilityFlags().test(CapabilityFlag::Preedit));
210 manager.setPreeditEnabledByDefault(false);
211 ic = std::make_unique<TestInputContext>(manager, "Firefox");
212 FCITX_ASSERT(!ic->capabilityFlags().test(CapabilityFlag::Preedit));
213 ic->setCapabilityFlags(CapabilityFlag::Preedit);
214 FCITX_ASSERT(!ic->capabilityFlags().test(CapabilityFlag::Preedit));
215 ic->setEnablePreedit(true);
216 FCITX_ASSERT(ic->capabilityFlags().test(CapabilityFlag::Preedit));
217 }
218
main()219 int main() {
220 test_simple();
221 test_property();
222 test_preedit_override();
223
224 return 0;
225 }
226