1 /*
2  * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #include "luaaddon_public.h"
8 #include "testdir.h"
9 #include "testfrontend_public.h"
10 #include "testim_public.h"
11 #include <fcitx-utils/eventdispatcher.h>
12 #include <fcitx-utils/log.h>
13 #include <fcitx-utils/standardpath.h>
14 #include <fcitx-utils/testing.h>
15 #include <fcitx/addonmanager.h>
16 #include <fcitx/inputmethodmanager.h>
17 #include <fcitx/instance.h>
18 #include <iostream>
19 #include <thread>
20 
21 using namespace fcitx;
22 
scheduleEvent(EventDispatcher * dispatcher,Instance * instance)23 void scheduleEvent(EventDispatcher *dispatcher, Instance *instance) {
24     dispatcher->schedule([instance]() {
25         auto luaaddonloader =
26             instance->addonManager().addon("luaaddonloader", true);
27         FCITX_ASSERT(luaaddonloader);
28         auto luaaddon = instance->addonManager().addon("testlua");
29         FCITX_ASSERT(luaaddon);
30         auto imeapi = instance->addonManager().addon("imeapi");
31         FCITX_ASSERT(imeapi);
32     });
33     dispatcher->schedule([dispatcher, instance]() {
34         // Setup the input method group with two input method
35         auto groupName = instance->inputMethodManager().currentGroup();
36         InputMethodGroup group(groupName);
37         group.inputMethodList().push_back(InputMethodGroupItem("keyboard-us"));
38         group.inputMethodList().push_back(InputMethodGroupItem("testim"));
39         group.setDefaultInputMethod("testim");
40         instance->inputMethodManager().setGroup(group);
41 
42         auto testfrontend = instance->addonManager().addon("testfrontend");
43         auto testim = instance->addonManager().addon("testim");
44         auto luaaddon = instance->addonManager().addon("testlua");
45         testim->call<ITestIM::setHandler>(
46             [](const InputMethodEntry &, KeyEvent &keyEvent) {
47                 if (keyEvent.key().states() != KeyState::NoState ||
48                     keyEvent.isRelease()) {
49                     return;
50                 }
51                 auto s = Key::keySymToUTF8(keyEvent.key().sym());
52                 if (!s.empty()) {
53                     keyEvent.inputContext()->commitString(s);
54                     keyEvent.filterAndAccept();
55                 }
56             });
57         auto uuid =
58             testfrontend->call<ITestFrontend::createInputContext>("testapp");
59         auto ic = instance->inputContextManager().findByUUID(uuid);
60         FCITX_ASSERT(ic);
61 
62         // Test with the converter in test.lua
63         testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("a"), false);
64         testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("b"), false);
65         testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("c"), false);
66         testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("d"), false);
67 
68         // Test lua currentInputMethod
69         auto ret = luaaddon->call<ILuaAddon::invokeLuaFunction>(
70             ic, "testInputMethod", RawConfig{});
71         FCITX_INFO() << ret;
72         assert(ret.value() == "keyboard-us");
73 
74         testfrontend->call<ITestFrontend::keyEvent>(uuid, Key("Control+space"),
75                                                     false);
76 
77         // Test lua currentProgram
78         ret = luaaddon->call<ILuaAddon::invokeLuaFunction>(ic, "testProgram",
79                                                            RawConfig{});
80         FCITX_INFO() << ret;
81         assert(ret.value() == "testapp");
82 
83         // Test lua currentInputMethod after ctrl space
84         ret = luaaddon->call<ILuaAddon::invokeLuaFunction>(
85             ic, "testInputMethod", RawConfig{});
86         FCITX_INFO() << ret;
87         assert(ret.value() == "testim");
88 
89         // Test with complex value with invokeLuaFunction
90         FCITX_ASSERT(luaaddon);
91         RawConfig config;
92         config["A"].setValue("5");
93         config["A"]["Q"].setValue("4");
94         FCITX_INFO() << config;
95         ret = luaaddon->call<ILuaAddon::invokeLuaFunction>(ic, "testInvoke",
96                                                            config);
97         FCITX_INFO() << ret;
98         assert(ret["B"]["E"]["F"].value() == "7");
99         RawConfig strConfig;
100         strConfig.setValue("ABC");
101         ret = luaaddon->call<ILuaAddon::invokeLuaFunction>(ic, "testInvoke",
102                                                            strConfig);
103         assert(ret.value() == "DEF");
104         FCITX_INFO() << ret;
105 
106         std::string testString = "ABC测试��DEF";
107         strConfig.setValue(testString);
108         ret = luaaddon->call<ILuaAddon::invokeLuaFunction>(
109             ic, "testUtf16Conversion", strConfig);
110         uint16_t data[] = {0x41,   0x42, 0x43, 0x6d4b, 0x8bd5, 0xd801,
111                            0xdc12, 0x44, 0x45, 0x46,   0x0};
112         FCITX_ASSERT(ret.value().size() == sizeof(data));
113         FCITX_ASSERT(memcmp(ret.value().data(), data, sizeof(data)) == 0);
114 
115         strConfig.setValue(ret.value());
116         ret = luaaddon->call<ILuaAddon::invokeLuaFunction>(
117             ic, "testUtf8Conversion", strConfig);
118         FCITX_ASSERT(ret.value() == testString) << ret;
119 
120         dispatcher->detach();
121         instance->exit();
122     });
123 }
124 
runInstance()125 void runInstance() {}
126 
main()127 int main() {
128     setupTestingEnvironment(
129         TESTING_BINARY_DIR,
130         {"src/addonloader", StandardPath::fcitxPath("addondir")},
131         {"test", TESTING_SOURCE_DIR "/test",
132          StandardPath::fcitxPath("pkgdatadir", "testing")});
133 
134     fcitx::Log::setLogRule("default=5,lua=5");
135     char arg0[] = "testlua";
136     char arg1[] = "--disable=all";
137     char arg2[] = "--enable=testim,testfrontend,luaaddonloader,imeapi,testlua";
138     char *argv[] = {arg0, arg1, arg2};
139     Instance instance(FCITX_ARRAY_SIZE(argv), argv);
140     setenv("FCITX_DATA_HOME", "/Invalid/Path", 1);
141     setenv("FCITX_CONFIG_HOME", "/Invalid/Path", 1);
142     instance.addonManager().registerDefaultLoader(nullptr);
143     EventDispatcher dispatcher;
144     dispatcher.attach(&instance.eventLoop());
145     std::thread thread(scheduleEvent, &dispatcher, &instance);
146     instance.exec();
147     thread.join();
148 
149     return 0;
150 }
151