2019-03-01 07:50:42 +00:00
|
|
|
// Copyright 2019 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/torque/ls/json.h"
|
|
|
|
#include "src/torque/ls/message-handler.h"
|
|
|
|
#include "src/torque/ls/message.h"
|
|
|
|
#include "src/torque/server-data.h"
|
|
|
|
#include "src/torque/source-positions.h"
|
2019-03-04 15:24:39 +00:00
|
|
|
#include "test/unittests/test-utils.h"
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace torque {
|
|
|
|
namespace ls {
|
|
|
|
|
2019-03-04 15:24:39 +00:00
|
|
|
TEST(LanguageServerMessage, InitializeRequest) {
|
2019-03-01 07:50:42 +00:00
|
|
|
InitializeRequest request;
|
|
|
|
request.set_id(5);
|
|
|
|
request.set_method("initialize");
|
|
|
|
request.params();
|
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
bool writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
HandleMessage(std::move(request.GetJsonValue()), [&](JsonValue raw_response) {
|
|
|
|
InitializeResponse response(std::move(raw_response));
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
// Check that the response id matches up with the request id, and that
|
|
|
|
// the language server signals its support for definitions.
|
2019-03-04 15:24:39 +00:00
|
|
|
EXPECT_EQ(response.id(), 5);
|
2019-05-07 11:32:31 +00:00
|
|
|
EXPECT_TRUE(response.result().capabilities().definitionProvider());
|
|
|
|
EXPECT_TRUE(response.result().capabilities().documentSymbolProvider());
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-03-01 07:50:42 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-03-01 07:50:42 +00:00
|
|
|
}
|
|
|
|
|
2019-03-04 15:24:39 +00:00
|
|
|
TEST(LanguageServerMessage,
|
|
|
|
RegisterDynamicCapabilitiesAfterInitializedNotification) {
|
2019-03-01 07:50:42 +00:00
|
|
|
Request<bool> notification;
|
|
|
|
notification.set_method("initialized");
|
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
bool writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
HandleMessage(std::move(notification.GetJsonValue()), [&](JsonValue
|
|
|
|
raw_request) {
|
|
|
|
RegistrationRequest request(std::move(raw_request));
|
2019-03-01 07:50:42 +00:00
|
|
|
|
2019-03-04 15:24:39 +00:00
|
|
|
ASSERT_EQ(request.method(), "client/registerCapability");
|
|
|
|
ASSERT_EQ(request.params().registrations_size(), (size_t)1);
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
Registration registration = request.params().registrations(0);
|
2019-03-04 15:24:39 +00:00
|
|
|
ASSERT_EQ(registration.method(), "workspace/didChangeWatchedFiles");
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
auto options =
|
|
|
|
registration
|
|
|
|
.registerOptions<DidChangeWatchedFilesRegistrationOptions>();
|
2019-03-04 15:24:39 +00:00
|
|
|
ASSERT_EQ(options.watchers_size(), (size_t)1);
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-03-01 07:50:42 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-03-01 07:50:42 +00:00
|
|
|
}
|
|
|
|
|
2019-03-04 15:24:39 +00:00
|
|
|
TEST(LanguageServerMessage, GotoDefinitionUnkownFile) {
|
2019-06-05 14:40:29 +00:00
|
|
|
SourceFileMap::Scope source_file_map_scope("");
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
GotoDefinitionRequest request;
|
|
|
|
request.set_id(42);
|
|
|
|
request.set_method("textDocument/definition");
|
|
|
|
request.params().textDocument().set_uri("file:///unknown.tq");
|
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
bool writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
HandleMessage(std::move(request.GetJsonValue()), [&](JsonValue raw_response) {
|
|
|
|
GotoDefinitionResponse response(std::move(raw_response));
|
2019-03-04 15:24:39 +00:00
|
|
|
EXPECT_EQ(response.id(), 42);
|
|
|
|
EXPECT_TRUE(response.IsNull("result"));
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-03-01 07:50:42 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-03-01 07:50:42 +00:00
|
|
|
}
|
|
|
|
|
2019-03-04 15:24:39 +00:00
|
|
|
TEST(LanguageServerMessage, GotoDefinition) {
|
2019-06-05 14:40:29 +00:00
|
|
|
SourceFileMap::Scope source_file_map_scope("");
|
2019-03-05 10:01:53 +00:00
|
|
|
SourceId test_id = SourceFileMap::AddSource("file://test.tq");
|
|
|
|
SourceId definition_id = SourceFileMap::AddSource("file://base.tq");
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
LanguageServerData::Scope server_data_scope;
|
|
|
|
LanguageServerData::AddDefinition({test_id, {1, 0}, {1, 10}},
|
|
|
|
{definition_id, {4, 1}, {4, 5}});
|
|
|
|
|
|
|
|
// First, check a unknown definition. The result must be null.
|
|
|
|
GotoDefinitionRequest request;
|
|
|
|
request.set_id(42);
|
|
|
|
request.set_method("textDocument/definition");
|
|
|
|
request.params().textDocument().set_uri("file://test.tq");
|
|
|
|
request.params().position().set_line(2);
|
|
|
|
request.params().position().set_character(0);
|
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
bool writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
HandleMessage(std::move(request.GetJsonValue()), [&](JsonValue raw_response) {
|
|
|
|
GotoDefinitionResponse response(std::move(raw_response));
|
2019-03-04 15:24:39 +00:00
|
|
|
EXPECT_EQ(response.id(), 42);
|
|
|
|
EXPECT_TRUE(response.IsNull("result"));
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-03-01 07:50:42 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
// Second, check a known defintion.
|
|
|
|
request = GotoDefinitionRequest();
|
|
|
|
request.set_id(43);
|
|
|
|
request.set_method("textDocument/definition");
|
|
|
|
request.params().textDocument().set_uri("file://test.tq");
|
|
|
|
request.params().position().set_line(1);
|
|
|
|
request.params().position().set_character(5);
|
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
HandleMessage(std::move(request.GetJsonValue()), [&](JsonValue raw_response) {
|
|
|
|
GotoDefinitionResponse response(std::move(raw_response));
|
2019-03-04 15:24:39 +00:00
|
|
|
EXPECT_EQ(response.id(), 43);
|
|
|
|
ASSERT_FALSE(response.IsNull("result"));
|
2019-03-01 07:50:42 +00:00
|
|
|
|
|
|
|
Location location = response.result();
|
2019-03-04 15:24:39 +00:00
|
|
|
EXPECT_EQ(location.uri(), "file://base.tq");
|
|
|
|
EXPECT_EQ(location.range().start().line(), 4);
|
|
|
|
EXPECT_EQ(location.range().start().character(), 1);
|
|
|
|
EXPECT_EQ(location.range().end().line(), 4);
|
|
|
|
EXPECT_EQ(location.range().end().character(), 5);
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-03-01 07:50:42 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-03-01 07:50:42 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 08:47:33 +00:00
|
|
|
TEST(LanguageServerMessage, CompilationErrorSendsDiagnostics) {
|
2019-04-25 09:09:19 +00:00
|
|
|
DiagnosticsFiles::Scope diagnostic_files_scope;
|
2019-04-23 08:47:33 +00:00
|
|
|
LanguageServerData::Scope server_data_scope;
|
2019-05-21 12:49:07 +00:00
|
|
|
TorqueMessages::Scope messages_scope;
|
2019-06-05 14:40:29 +00:00
|
|
|
SourceFileMap::Scope source_file_map_scope("");
|
2019-04-23 08:47:33 +00:00
|
|
|
|
|
|
|
TorqueCompilerResult result;
|
2019-05-21 12:49:07 +00:00
|
|
|
{ Error("compilation failed somehow"); }
|
|
|
|
result.messages = std::move(TorqueMessages::Get());
|
2019-04-23 08:47:33 +00:00
|
|
|
result.source_file_map = SourceFileMap::Get();
|
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
bool writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
CompilationFinished(std::move(result), [&](JsonValue raw_response) {
|
|
|
|
PublishDiagnosticsNotification notification(std::move(raw_response));
|
2019-04-23 08:47:33 +00:00
|
|
|
|
|
|
|
EXPECT_EQ(notification.method(), "textDocument/publishDiagnostics");
|
|
|
|
ASSERT_FALSE(notification.IsNull("params"));
|
|
|
|
EXPECT_EQ(notification.params().uri(), "<unknown>");
|
|
|
|
|
|
|
|
ASSERT_GT(notification.params().diagnostics_size(), static_cast<size_t>(0));
|
|
|
|
Diagnostic diagnostic = notification.params().diagnostics(0);
|
|
|
|
EXPECT_EQ(diagnostic.severity(), Diagnostic::kError);
|
|
|
|
EXPECT_EQ(diagnostic.message(), "compilation failed somehow");
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-04-23 08:47:33 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-04-23 08:47:33 +00:00
|
|
|
}
|
|
|
|
|
2019-04-25 09:09:19 +00:00
|
|
|
TEST(LanguageServerMessage, LintErrorSendsDiagnostics) {
|
|
|
|
DiagnosticsFiles::Scope diagnostic_files_scope;
|
2019-05-21 12:49:07 +00:00
|
|
|
TorqueMessages::Scope messages_scope;
|
2019-04-25 09:09:19 +00:00
|
|
|
LanguageServerData::Scope server_data_scope;
|
2019-06-05 14:40:29 +00:00
|
|
|
SourceFileMap::Scope sourc_file_map_scope("");
|
|
|
|
SourceId test_id = SourceFileMap::AddSource("file://test.tq");
|
2019-04-25 09:09:19 +00:00
|
|
|
|
|
|
|
// No compilation errors but two lint warnings.
|
2019-05-21 12:49:07 +00:00
|
|
|
{
|
|
|
|
SourcePosition pos1{test_id, {0, 0}, {0, 1}};
|
|
|
|
SourcePosition pos2{test_id, {1, 0}, {1, 1}};
|
|
|
|
Lint("lint error 1").Position(pos1);
|
|
|
|
Lint("lint error 2").Position(pos2);
|
|
|
|
}
|
|
|
|
|
2019-04-25 09:09:19 +00:00
|
|
|
TorqueCompilerResult result;
|
2019-05-21 12:49:07 +00:00
|
|
|
result.messages = std::move(TorqueMessages::Get());
|
2019-04-25 09:09:19 +00:00
|
|
|
result.source_file_map = SourceFileMap::Get();
|
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
bool writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
CompilationFinished(std::move(result), [&](JsonValue raw_response) {
|
|
|
|
PublishDiagnosticsNotification notification(std::move(raw_response));
|
2019-04-25 09:09:19 +00:00
|
|
|
|
|
|
|
EXPECT_EQ(notification.method(), "textDocument/publishDiagnostics");
|
|
|
|
ASSERT_FALSE(notification.IsNull("params"));
|
2019-06-05 14:40:29 +00:00
|
|
|
EXPECT_EQ(notification.params().uri(), "file://test.tq");
|
2019-04-25 09:09:19 +00:00
|
|
|
|
|
|
|
ASSERT_EQ(notification.params().diagnostics_size(), static_cast<size_t>(2));
|
|
|
|
Diagnostic diagnostic1 = notification.params().diagnostics(0);
|
|
|
|
EXPECT_EQ(diagnostic1.severity(), Diagnostic::kWarning);
|
|
|
|
EXPECT_EQ(diagnostic1.message(), "lint error 1");
|
|
|
|
|
|
|
|
Diagnostic diagnostic2 = notification.params().diagnostics(1);
|
|
|
|
EXPECT_EQ(diagnostic2.severity(), Diagnostic::kWarning);
|
|
|
|
EXPECT_EQ(diagnostic2.message(), "lint error 2");
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-04-25 09:09:19 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-04-25 09:09:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(LanguageServerMessage, CleanCompileSendsNoDiagnostics) {
|
|
|
|
LanguageServerData::Scope server_data_scope;
|
2019-06-05 14:40:29 +00:00
|
|
|
SourceFileMap::Scope sourc_file_map_scope("");
|
2019-04-25 09:09:19 +00:00
|
|
|
|
|
|
|
TorqueCompilerResult result;
|
|
|
|
result.source_file_map = SourceFileMap::Get();
|
|
|
|
|
2019-07-08 13:48:54 +00:00
|
|
|
CompilationFinished(std::move(result), [](JsonValue raw_response) {
|
2019-04-25 09:09:19 +00:00
|
|
|
FAIL() << "Sending unexpected response!";
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-05-07 11:32:31 +00:00
|
|
|
TEST(LanguageServerMessage, NoSymbolsSendsEmptyResponse) {
|
|
|
|
LanguageServerData::Scope server_data_scope;
|
2019-06-05 14:40:29 +00:00
|
|
|
SourceFileMap::Scope sourc_file_map_scope("");
|
2019-05-07 11:32:31 +00:00
|
|
|
|
|
|
|
DocumentSymbolRequest request;
|
|
|
|
request.set_id(42);
|
|
|
|
request.set_method("textDocument/documentSymbol");
|
2019-06-05 14:40:29 +00:00
|
|
|
request.params().textDocument().set_uri("file://test.tq");
|
2019-05-07 11:32:31 +00:00
|
|
|
|
2019-06-03 08:56:54 +00:00
|
|
|
bool writer_called = false;
|
2019-07-08 13:48:54 +00:00
|
|
|
HandleMessage(std::move(request.GetJsonValue()), [&](JsonValue raw_response) {
|
|
|
|
DocumentSymbolResponse response(std::move(raw_response));
|
2019-05-07 11:32:31 +00:00
|
|
|
EXPECT_EQ(response.id(), 42);
|
|
|
|
EXPECT_EQ(response.result_size(), static_cast<size_t>(0));
|
2019-06-03 08:56:54 +00:00
|
|
|
|
|
|
|
writer_called = true;
|
2019-05-07 11:32:31 +00:00
|
|
|
});
|
2019-06-03 08:56:54 +00:00
|
|
|
EXPECT_TRUE(writer_called);
|
2019-05-07 11:32:31 +00:00
|
|
|
}
|
|
|
|
|
2019-03-01 07:50:42 +00:00
|
|
|
} // namespace ls
|
|
|
|
} // namespace torque
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|