Serenity Operating System
1/*
2 * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "Tests.h"
8#include "../FileDB.h"
9#include "CppComprehensionEngine.h"
10#include <AK/LexicalPath.h>
11#include <LibCore/DeprecatedFile.h>
12#include <LibMain/Main.h>
13
14static bool s_some_test_failed = false;
15
16#define I_TEST(name) \
17 { \
18 printf("Testing " #name "... "); \
19 fflush(stdout); \
20 }
21
22#define PASS \
23 do { \
24 printf("PASS\n"); \
25 fflush(stdout); \
26 return; \
27 } while (0)
28
29#define FAIL(reason) \
30 do { \
31 printf("FAIL: " #reason "\n"); \
32 s_some_test_failed = true; \
33 return; \
34 } while (0)
35
36constexpr auto TESTS_ROOT_DIR = "/home/anon/Tests/cpp-tests/comprehension"sv;
37
38class FileDB : public CodeComprehension::FileDB {
39public:
40 FileDB() = default;
41
42 void add(DeprecatedString filename, DeprecatedString content)
43 {
44 m_map.set(filename, content);
45 }
46
47 virtual Optional<DeprecatedString> get_or_read_from_filesystem(StringView filename) const override
48 {
49 DeprecatedString target_filename = filename;
50 if (!project_root().is_null() && filename.starts_with(project_root())) {
51 target_filename = LexicalPath::relative_path(filename, project_root());
52 }
53 return m_map.get(target_filename);
54 }
55
56private:
57 HashMap<DeprecatedString, DeprecatedString> m_map;
58};
59
60static void test_complete_local_args();
61static void test_complete_local_vars();
62static void test_complete_type();
63static void test_find_variable_definition();
64static void test_complete_includes();
65static void test_parameters_hint();
66
67int run_tests()
68{
69 test_complete_local_args();
70 test_complete_local_vars();
71 test_complete_type();
72 test_find_variable_definition();
73 test_complete_includes();
74 test_parameters_hint();
75 return s_some_test_failed ? 1 : 0;
76}
77
78static void add_file(FileDB& filedb, DeprecatedString const& name)
79{
80 auto file = Core::DeprecatedFile::open(LexicalPath::join(TESTS_ROOT_DIR, name).string(), Core::OpenMode::ReadOnly);
81 VERIFY(!file.is_error());
82 filedb.add(name, DeprecatedString::copy(file.value()->read_all()));
83}
84
85void test_complete_local_args()
86{
87 I_TEST(Complete Local Args)
88 FileDB filedb;
89 add_file(filedb, "complete_local_args.cpp");
90 CodeComprehension::Cpp::CppComprehensionEngine engine(filedb);
91 auto suggestions = engine.get_suggestions("complete_local_args.cpp", { 2, 6 });
92 if (suggestions.size() != 2)
93 FAIL(bad size);
94
95 if (suggestions[0].completion == "argc" && suggestions[1].completion == "argv")
96 PASS;
97
98 FAIL("wrong results");
99}
100
101void test_complete_local_vars()
102{
103 I_TEST(Complete Local Vars)
104 FileDB filedb;
105 add_file(filedb, "complete_local_vars.cpp");
106 CodeComprehension::Cpp::CppComprehensionEngine autocomplete(filedb);
107 auto suggestions = autocomplete.get_suggestions("complete_local_vars.cpp", { 3, 7 });
108 if (suggestions.size() != 1)
109 FAIL(bad size);
110
111 if (suggestions[0].completion == "myvar1")
112 PASS;
113
114 FAIL("wrong results");
115}
116
117void test_complete_type()
118{
119 I_TEST(Complete Type)
120 FileDB filedb;
121 add_file(filedb, "complete_type.cpp");
122 CodeComprehension::Cpp::CppComprehensionEngine autocomplete(filedb);
123 auto suggestions = autocomplete.get_suggestions("complete_type.cpp", { 5, 7 });
124 if (suggestions.size() != 1)
125 FAIL(bad size);
126
127 if (suggestions[0].completion == "MyStruct")
128 PASS;
129
130 FAIL("wrong results");
131}
132
133void test_find_variable_definition()
134{
135 I_TEST(Find Variable Declaration)
136 FileDB filedb;
137 add_file(filedb, "find_variable_declaration.cpp");
138 CodeComprehension::Cpp::CppComprehensionEngine engine(filedb);
139 auto position = engine.find_declaration_of("find_variable_declaration.cpp", { 2, 5 });
140 if (!position.has_value())
141 FAIL("declaration not found");
142
143 if (position.value().file == "find_variable_declaration.cpp" && position.value().line == 0 && position.value().column >= 19)
144 PASS;
145 FAIL("wrong declaration location");
146}
147
148void test_complete_includes()
149{
150 I_TEST(Complete include statements)
151 FileDB filedb;
152 filedb.set_project_root(TESTS_ROOT_DIR);
153 add_file(filedb, "complete_includes.cpp");
154 add_file(filedb, "sample_header.h");
155 CodeComprehension::Cpp::CppComprehensionEngine autocomplete(filedb);
156
157 auto suggestions = autocomplete.get_suggestions("complete_includes.cpp", { 0, 22 });
158 if (suggestions.size() != 1)
159 FAIL(project include - bad size);
160
161 if (suggestions[0].completion != "\"sample_header.h\"")
162 FAIL("project include - wrong results");
163
164 suggestions = autocomplete.get_suggestions("complete_includes.cpp", { 1, 18 });
165 if (suggestions.size() != 1)
166 FAIL(global include - bad size);
167
168 if (suggestions[0].completion != "<sys/cdefs.h>")
169 FAIL("global include - wrong results");
170
171 PASS;
172}
173
174void test_parameters_hint()
175{
176 I_TEST(Function Parameters hint)
177 FileDB filedb;
178 filedb.set_project_root(TESTS_ROOT_DIR);
179 add_file(filedb, "parameters_hint1.cpp");
180 CodeComprehension::Cpp::CppComprehensionEngine engine(filedb);
181
182 auto result = engine.get_function_params_hint("parameters_hint1.cpp", { 4, 9 });
183 if (!result.has_value())
184 FAIL("failed to get parameters hint (1)");
185 if (result->params != Vector<DeprecatedString> { "int x", "char y" } || result->current_index != 0)
186 FAIL("bad result (1)");
187
188 result = engine.get_function_params_hint("parameters_hint1.cpp", { 5, 15 });
189 if (!result.has_value())
190 FAIL("failed to get parameters hint (2)");
191 if (result->params != Vector<DeprecatedString> { "int x", "char y" } || result->current_index != 1)
192 FAIL("bad result (2)");
193
194 result = engine.get_function_params_hint("parameters_hint1.cpp", { 6, 8 });
195 if (!result.has_value())
196 FAIL("failed to get parameters hint (3)");
197 if (result->params != Vector<DeprecatedString> { "int x", "char y" } || result->current_index != 0)
198 FAIL("bad result (3)");
199
200 PASS;
201}
202
203ErrorOr<int> serenity_main(Main::Arguments)
204{
205 return run_tests();
206}