685 lines
28 KiB
C++
685 lines
28 KiB
C++
module;
|
|
|
|
export module lsp.test.provider.completion;
|
|
|
|
import std;
|
|
|
|
import lsp.test.framework;
|
|
import lsp.provider.text_document.completion;
|
|
import lsp.provider.completion_item.resolve;
|
|
import lsp.core.dispacther;
|
|
import lsp.manager.manager_hub;
|
|
import lsp.scheduler.async_executor;
|
|
import lsp.protocol;
|
|
import lsp.codec.facade;
|
|
import lsp.test.provider.fixtures;
|
|
|
|
export namespace lsp::test::provider
|
|
{
|
|
class CompletionTests
|
|
{
|
|
public:
|
|
static void Register(TestRunner& runner);
|
|
|
|
private:
|
|
static TestResult TestClassMethodCompletion();
|
|
static TestResult TestClassMethodEmptyPrefixCompletion();
|
|
static TestResult TestNewCompletion();
|
|
static TestResult TestNewEmptyPrefixCompletion();
|
|
static TestResult TestUnitScopedNewCompletion();
|
|
static TestResult TestCreateObjectCompletion();
|
|
static TestResult TestCreateObjectEmptyPrefixCompletion();
|
|
static TestResult TestCreateObjectQuotedCompletion();
|
|
static TestResult TestCreateObjectQuotedEmptyPrefixCompletion();
|
|
static TestResult TestCreateObjectSingleQuoteCompletion();
|
|
static TestResult TestCreateObjectQualifiedCompletion();
|
|
static TestResult TestCreateObjectQuotedQualifiedCompletion();
|
|
static TestResult TestCreateObjectUnitCallQualifiedCompletion();
|
|
static TestResult TestUnitContextCompletion();
|
|
static TestResult TestUnitContextEmptyPrefixCompletion();
|
|
static TestResult TestUnitMemberCompletion();
|
|
static TestResult TestUnitMemberDotCompletion();
|
|
static TestResult TestObjectMemberCompletion();
|
|
static TestResult TestObjectMemberQualifiedSelfUnitCompletion();
|
|
static TestResult TestObjectMemberQualifiedTypeCompletion();
|
|
static TestResult TestFunctionCompletion();
|
|
static TestResult TestKeywordCompletion();
|
|
static TestResult TestClassContextCompletion();
|
|
static TestResult TestClassContextEmptyPrefixCompletion();
|
|
static TestResult TestUnitScopedNewAliasCompletion();
|
|
static TestResult TestCompletionResolveNewSnippet();
|
|
static TestResult TestCompletionResolveCreateObjectSnippet();
|
|
static TestResult TestCompletionResolveCreateObjectUnquotedSnippet();
|
|
static TestResult TestCompletionResolveCreateObjectSingleQuoteSnippet();
|
|
};
|
|
}
|
|
|
|
namespace lsp::test::provider
|
|
{
|
|
namespace
|
|
{
|
|
struct ProviderEnv
|
|
{
|
|
scheduler::AsyncExecutor scheduler{ 1 };
|
|
manager::ManagerHub hub{};
|
|
core::ExecutionContext context;
|
|
|
|
ProviderEnv()
|
|
: context([](core::ServerLifecycleEvent) {}, scheduler, hub)
|
|
{
|
|
hub.Initialize();
|
|
}
|
|
};
|
|
|
|
protocol::ResponseMessage ParseResponse(const std::string& json)
|
|
{
|
|
auto parsed = codec::Deserialize<protocol::ResponseMessage>(json);
|
|
if (!parsed)
|
|
{
|
|
throw std::runtime_error("Failed to deserialize response");
|
|
}
|
|
return *parsed;
|
|
}
|
|
|
|
protocol::Position FindPosition(const std::string& content, const std::string& marker)
|
|
{
|
|
auto pos = content.find(marker);
|
|
assertTrue(pos != std::string::npos, "Marker not found in fixture");
|
|
protocol::Position result{};
|
|
result.line = 0;
|
|
result.character = 0;
|
|
for (std::size_t i = 0; i < pos; ++i)
|
|
{
|
|
if (content[i] == '\n')
|
|
{
|
|
result.line++;
|
|
result.character = 0;
|
|
}
|
|
else
|
|
{
|
|
result.character++;
|
|
}
|
|
}
|
|
result.character += static_cast<std::uint32_t>(marker.size());
|
|
return result;
|
|
}
|
|
|
|
void OpenDocument(manager::ManagerHub& hub, const std::string& uri, const std::string& text, int version)
|
|
{
|
|
protocol::DidOpenTextDocumentParams open_params;
|
|
open_params.textDocument.uri = uri;
|
|
open_params.textDocument.languageId = "tsl";
|
|
open_params.textDocument.version = version;
|
|
open_params.textDocument.text = text;
|
|
hub.documents().OpenDocument(open_params);
|
|
}
|
|
|
|
std::vector<protocol::CompletionItem> RequestCompletion(ProviderEnv& env,
|
|
const std::string& uri,
|
|
const std::string& content,
|
|
const std::string& marker)
|
|
{
|
|
protocol::CompletionParams params;
|
|
params.textDocument.uri = uri;
|
|
params.position = FindPosition(content, marker);
|
|
|
|
protocol::RequestMessage request;
|
|
request.id = "c1";
|
|
request.method = "textDocument/completion";
|
|
request.params = codec::ToLSPAny(params);
|
|
|
|
::lsp::provider::text_document::Completion handler;
|
|
auto json = handler.ProvideResponse(request, env.context);
|
|
auto response = ParseResponse(json);
|
|
if (!response.result.has_value())
|
|
{
|
|
return {};
|
|
}
|
|
auto list = codec::FromLSPAny.template operator()<protocol::CompletionList>(response.result.value());
|
|
return list.items;
|
|
}
|
|
|
|
bool HasLabel(const std::vector<protocol::CompletionItem>& items, const std::string& label)
|
|
{
|
|
return std::any_of(items.begin(), items.end(), [&](const auto& item) {
|
|
return item.label == label;
|
|
});
|
|
}
|
|
|
|
std::optional<protocol::CompletionItem> FindItem(const std::vector<protocol::CompletionItem>& items,
|
|
const std::string& label)
|
|
{
|
|
auto it = std::find_if(items.begin(), items.end(), [&](const auto& item) {
|
|
return item.label == label;
|
|
});
|
|
if (it == items.end())
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
return *it;
|
|
}
|
|
}
|
|
|
|
void CompletionTests::Register(TestRunner& runner)
|
|
{
|
|
runner.addTest("completion class(Widget).", TestClassMethodCompletion);
|
|
runner.addTest("completion class(Widget).<empty>", TestClassMethodEmptyPrefixCompletion);
|
|
runner.addTest("completion new Widget", TestNewCompletion);
|
|
runner.addTest("completion new <empty>", TestNewEmptyPrefixCompletion);
|
|
runner.addTest("completion new unit(MainUnit).Widget", TestUnitScopedNewCompletion);
|
|
runner.addTest("completion createobject", TestCreateObjectCompletion);
|
|
runner.addTest("completion createobject <empty>", TestCreateObjectEmptyPrefixCompletion);
|
|
runner.addTest("completion createobject quoted", TestCreateObjectQuotedCompletion);
|
|
runner.addTest("completion createobject quoted <empty>", TestCreateObjectQuotedEmptyPrefixCompletion);
|
|
runner.addTest("completion createobject single quote", TestCreateObjectSingleQuoteCompletion);
|
|
runner.addTest("completion createobject qualified", TestCreateObjectQualifiedCompletion);
|
|
runner.addTest("completion createobject qualified quoted", TestCreateObjectQuotedQualifiedCompletion);
|
|
runner.addTest("completion createobject qualified unit()", TestCreateObjectUnitCallQualifiedCompletion);
|
|
runner.addTest("completion unit(", TestUnitContextCompletion);
|
|
runner.addTest("completion unit(<empty>)", TestUnitContextEmptyPrefixCompletion);
|
|
runner.addTest("completion unit member", TestUnitMemberCompletion);
|
|
runner.addTest("completion unit member dot", TestUnitMemberDotCompletion);
|
|
runner.addTest("completion object member", TestObjectMemberCompletion);
|
|
runner.addTest("completion object member qualified self unit", TestObjectMemberQualifiedSelfUnitCompletion);
|
|
runner.addTest("completion object member qualified type", TestObjectMemberQualifiedTypeCompletion);
|
|
runner.addTest("completion function prefix", TestFunctionCompletion);
|
|
runner.addTest("completion keyword prefix", TestKeywordCompletion);
|
|
runner.addTest("completion class(", TestClassContextCompletion);
|
|
runner.addTest("completion class(<empty>)", TestClassContextEmptyPrefixCompletion);
|
|
runner.addTest("completion new alias", TestUnitScopedNewAliasCompletion);
|
|
runner.addTest("completion resolve new snippet", TestCompletionResolveNewSnippet);
|
|
runner.addTest("completion resolve createobject snippet", TestCompletionResolveCreateObjectSnippet);
|
|
runner.addTest("completion resolve createobject unquoted snippet", TestCompletionResolveCreateObjectUnquotedSnippet);
|
|
runner.addTest("completion resolve createobject single quote snippet", TestCompletionResolveCreateObjectSingleQuoteSnippet);
|
|
}
|
|
|
|
TestResult CompletionTests::TestClassMethodCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "class(Widget).Sta");
|
|
assertTrue(HasLabel(items, "StaticFoo"), "class() should suggest static methods");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestClassMethodEmptyPrefixCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "class(Widget).");
|
|
assertTrue(HasLabel(items, "StaticFoo"), "class() should suggest static methods with empty prefix");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestNewCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "new Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "new context should suggest classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestNewEmptyPrefixCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "obj := new ");
|
|
assertTrue(HasLabel(items, "Widget"), "new context should suggest classes with empty prefix");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestUnitScopedNewCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "new unit(MainUnit).Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "unit scoped new should suggest unit classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject(Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "createobject should suggest classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectEmptyPrefixCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "aliased := createobject(");
|
|
assertTrue(HasLabel(items, "Widget"), "createobject should suggest classes with empty prefix");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectQuotedCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject(\"Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "quoted createobject should suggest classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectQuotedEmptyPrefixCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "aliased := createobject(\"");
|
|
assertTrue(HasLabel(items, "Widget"), "quoted createobject should suggest classes with empty prefix");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectSingleQuoteCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
|
|
auto replacement_pos = content.find("createobject(\"Wid\");");
|
|
assertTrue(replacement_pos != std::string::npos, "Fixture should include createobject(\"Wid\");");
|
|
content.replace(replacement_pos, std::string_view("createobject(\"Wid\");").size(), "createobject('Wid');");
|
|
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject('Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "single-quote createobject should suggest classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectQualifiedCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject(MainUnit.Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "qualified createobject should suggest classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectQuotedQualifiedCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject(\"MainUnit.");
|
|
assertTrue(HasLabel(items, "Widget"), "qualified quoted createobject should suggest unit classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCreateObjectUnitCallQualifiedCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
|
|
auto replacement_pos = content.find("createobject(MainUnit.Wid);");
|
|
assertTrue(replacement_pos != std::string::npos, "Fixture should include createobject(MainUnit.Wid);");
|
|
content.replace(replacement_pos,
|
|
std::string_view("createobject(MainUnit.Wid);").size(),
|
|
"createobject(unit(MainUnit).Wid);");
|
|
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject(unit(MainUnit).Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "unit() qualified createobject should suggest unit classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestUnitContextCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "unit(Main");
|
|
assertTrue(HasLabel(items, "MainUnit"), "unit context should list visible units");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestUnitContextEmptyPrefixCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, " unit(");
|
|
assertTrue(HasLabel(items, "MainUnit"), "unit context should list visible units with empty prefix");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestUnitMemberCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "unit(MainUnit).Uni");
|
|
assertTrue(HasLabel(items, "UnitFunc"), "unit member completion should list functions");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestUnitMemberDotCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "MainUnit.Uni");
|
|
assertTrue(HasLabel(items, "UnitFunc"), "unit member dot completion should list functions");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestObjectMemberCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "obj.Fo");
|
|
assertTrue(HasLabel(items, "Foo"), "object member completion should list instance methods");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestObjectMemberQualifiedSelfUnitCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "aliased.Fo");
|
|
assertTrue(HasLabel(items, "Foo"), "qualified self unit type should resolve instance members");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestObjectMemberQualifiedTypeCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
env.hub.symbols().LoadWorkspace(ToUri(FixturePath("workspace")));
|
|
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "unit_inst.Wor");
|
|
assertTrue(HasLabel(items, "Work"), "qualified type should resolve workspace class members");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestFunctionCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "UnitF");
|
|
assertTrue(HasLabel(items, "UnitFunc"), "function prefix should return UnitFunc");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestKeywordCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "fun");
|
|
assertTrue(HasLabel(items, "function"), "keyword completion should include 'function'");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestClassContextCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "class(Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "class context should suggest classes with static methods");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestClassContextEmptyPrefixCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "class(");
|
|
assertTrue(HasLabel(items, "Widget"), "class context should suggest classes with static methods");
|
|
assertFalse(HasLabel(items, "Plain"), "class context should not suggest classes without static methods");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestUnitScopedNewAliasCompletion()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "new MainUnit.Wid");
|
|
assertTrue(HasLabel(items, "Widget"), "alias scoped new should suggest classes");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCompletionResolveNewSnippet()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "new Wid");
|
|
auto item = FindItem(items, "Widget");
|
|
assertTrue(item.has_value(), "Expected Widget completion");
|
|
|
|
protocol::RequestMessage request;
|
|
request.id = "r1";
|
|
request.method = "completionItem/resolve";
|
|
request.params = codec::ToLSPAny(*item);
|
|
|
|
::lsp::provider::completion_item::Resolve resolver;
|
|
auto json = resolver.ProvideResponse(request, env.context);
|
|
auto response = ParseResponse(json);
|
|
auto resolved = codec::FromLSPAny.template operator()<protocol::CompletionItem>(response.result.value());
|
|
|
|
assertTrue(resolved.insertText.has_value(), "Resolved item should have insertText");
|
|
assertTrue(resolved.insertText.value().find("Widget(") == 0, "Resolved new snippet should start with Widget(");
|
|
assertTrue(resolved.insertText.value().contains("${1:a}"), "Resolved new snippet should include param placeholders");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCompletionResolveCreateObjectSnippet()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject(\"Wid");
|
|
auto item = FindItem(items, "Widget");
|
|
assertTrue(item.has_value(), "Expected Widget completion");
|
|
|
|
protocol::RequestMessage request;
|
|
request.id = "r2";
|
|
request.method = "completionItem/resolve";
|
|
request.params = codec::ToLSPAny(*item);
|
|
|
|
::lsp::provider::completion_item::Resolve resolver;
|
|
auto json = resolver.ProvideResponse(request, env.context);
|
|
auto response = ParseResponse(json);
|
|
auto resolved = codec::FromLSPAny.template operator()<protocol::CompletionItem>(response.result.value());
|
|
|
|
assertTrue(resolved.insertText.has_value(), "Resolved item should have insertText");
|
|
auto snippet = resolved.insertText.value();
|
|
assertTrue(snippet.starts_with("Widget\""), "Resolved createobject snippet should close quote but not add opening quote");
|
|
assertTrue(snippet.contains("${1:a}"), "Resolved createobject snippet should include param placeholders");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCompletionResolveCreateObjectUnquotedSnippet()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject(Wid");
|
|
auto item = FindItem(items, "Widget");
|
|
assertTrue(item.has_value(), "Expected Widget completion");
|
|
|
|
protocol::RequestMessage request;
|
|
request.id = "r3";
|
|
request.method = "completionItem/resolve";
|
|
request.params = codec::ToLSPAny(*item);
|
|
|
|
::lsp::provider::completion_item::Resolve resolver;
|
|
auto json = resolver.ProvideResponse(request, env.context);
|
|
auto response = ParseResponse(json);
|
|
auto resolved = codec::FromLSPAny.template operator()<protocol::CompletionItem>(response.result.value());
|
|
|
|
assertTrue(resolved.insertText.has_value(), "Resolved item should have insertText");
|
|
auto snippet = resolved.insertText.value();
|
|
assertTrue(snippet.starts_with("\"Widget\""), "Resolved createobject snippet should add opening quote for unquoted call");
|
|
assertTrue(snippet.contains("${1:a}"), "Resolved createobject snippet should include param placeholders");
|
|
return result;
|
|
}
|
|
|
|
TestResult CompletionTests::TestCompletionResolveCreateObjectSingleQuoteSnippet()
|
|
{
|
|
TestResult result{ "", true, "ok" };
|
|
ProviderEnv env;
|
|
auto path = FixturePath("main_unit.tsf");
|
|
auto content = ReadTextFile(path);
|
|
|
|
auto replacement_pos = content.find("createobject(\"Wid\");");
|
|
assertTrue(replacement_pos != std::string::npos, "Fixture should include createobject(\"Wid\");");
|
|
content.replace(replacement_pos, std::string_view("createobject(\"Wid\");").size(), "createobject('Wid');");
|
|
|
|
auto uri = ToUri(path);
|
|
OpenDocument(env.hub, uri, content, 1);
|
|
|
|
auto items = RequestCompletion(env, uri, content, "createobject('Wid");
|
|
auto item = FindItem(items, "Widget");
|
|
assertTrue(item.has_value(), "Expected Widget completion");
|
|
|
|
protocol::RequestMessage request;
|
|
request.id = "r4";
|
|
request.method = "completionItem/resolve";
|
|
request.params = codec::ToLSPAny(*item);
|
|
|
|
::lsp::provider::completion_item::Resolve resolver;
|
|
auto json = resolver.ProvideResponse(request, env.context);
|
|
auto response = ParseResponse(json);
|
|
auto resolved = codec::FromLSPAny.template operator()<protocol::CompletionItem>(response.result.value());
|
|
|
|
assertTrue(resolved.insertText.has_value(), "Resolved item should have insertText");
|
|
auto snippet = resolved.insertText.value();
|
|
assertTrue(snippet.starts_with("Widget'"), "Resolved createobject snippet should close single quote but not add opening quote");
|
|
assertTrue(snippet.contains("${1:a}"), "Resolved createobject snippet should include param placeholders");
|
|
return result;
|
|
}
|
|
}
|