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