Browse Source

Added language protocol tests

merge-requests/404/merge
eidheim 5 years ago
parent
commit
aa91e38bfa
  1. 3
      src/source_language_protocol.cpp
  2. 2
      src/source_language_protocol.hpp
  3. 6
      tests/CMakeLists.txt
  4. 55
      tests/language_protocol_client_test.cpp
  5. 359
      tests/language_protocol_server_test.cpp
  6. 0
      tests/language_protocol_test_files/.rustfmt.toml
  7. 3
      tests/language_protocol_test_files/main.rs
  8. 4
      tests/stubs/notebook.cpp

3
src/source_language_protocol.cpp

@ -119,6 +119,9 @@ LanguageProtocol::Client::~Client() {
process->kill();
exit_status = process->get_exit_status();
}
if(on_exit_status)
on_exit_status(exit_status);
if(Config::get().log.language_server)
std::cout << "Language server exit status: " << exit_status << std::endl;
}

2
src/source_language_protocol.hpp

@ -155,6 +155,8 @@ namespace LanguageProtocol {
void write_notification(const std::string &method, const std::string &params);
void handle_server_notification(const std::string &method, const boost::property_tree::ptree &params);
void handle_server_request(size_t id, const std::string &method, const boost::property_tree::ptree &params);
std::function<void(int exit_status)> on_exit_status;
};
} // namespace LanguageProtocol

6
tests/CMakeLists.txt

@ -84,6 +84,12 @@ if(BUILD_TESTING)
add_executable(utility_test utility_test.cpp $<TARGET_OBJECTS:test_stubs>)
target_link_libraries(utility_test juci_shared)
add_test(utility_test utility_test)
add_executable(language_protocol_client_test language_protocol_client_test.cpp $<TARGET_OBJECTS:test_stubs>)
target_link_libraries(language_protocol_client_test juci_shared)
add_test(language_protocol_client_test language_protocol_client_test)
add_executable(language_protocol_server_test language_protocol_server_test.cpp)
endif()
if(BUILD_FUZZING)

55
tests/language_protocol_client_test.cpp

@ -0,0 +1,55 @@
#include "config.hpp"
#include "source_language_protocol.hpp"
#include <glib.h>
//Requires display server to work
//However, it is possible to use the Broadway backend if the test is run in a pure terminal environment:
//broadwayd&
//make test
void flush_events() {
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
}
int main() {
auto app = Gtk::Application::create();
Gsv::init();
auto tests_path = boost::filesystem::canonical(JUCI_TESTS_PATH);
auto build_path = boost::filesystem::canonical(JUCI_BUILD_PATH);
auto view = new Source::LanguageProtocolView(boost::filesystem::canonical(tests_path / "language_protocol_test_files" / "main.rs"),
Source::LanguageManager::get_default()->get_language("rust"),
"rust",
(build_path / "tests" / "language_protocol_server_test").string());
while(!view->initialized)
flush_events();
g_assert(view->capabilities.document_formatting);
view->get_buffer()->insert_at_cursor(" ");
g_assert(view->get_buffer()->get_text() == R"( fn main() {
println!("Hello, world!");
}
)");
view->format_style(false);
g_assert(view->get_buffer()->get_text() == R"(fn main() {
println!("Hello, world!");
}
)");
std::atomic<int> exit_status(-1);
view->client->on_exit_status = [&exit_status](int exit_status_) {
exit_status = exit_status_;
};
delete view;
while(exit_status == -1)
flush_events();
g_assert_cmpint(exit_status, ==, 0);
}

359
tests/language_protocol_server_test.cpp

@ -0,0 +1,359 @@
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
int main() {
std::string line;
try {
// Read initialize and respond
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "initialize")
return 1;
std::string result = R"({
"jsonrpc": "2.0",
"id": "0",
"result": {
"capabilities": {
"textDocumentSync": {
"openClose": "true",
"change": "2",
"save": ""
},
"selectionRangeProvider": "true",
"hoverProvider": "true",
"completionProvider": {
"triggerCharacters": [
":",
".",
"'"
]
},
"signatureHelpProvider": {
"triggerCharacters": [
"(",
","
]
},
"definitionProvider": "true",
"typeDefinitionProvider": "true",
"implementationProvider": "true",
"referencesProvider": "true",
"documentHighlightProvider": "true",
"documentSymbolProvider": "true",
"workspaceSymbolProvider": "true",
"codeActionProvider": {
"codeActionKinds": [
"",
"quickfix",
"refactor",
"refactor.extract",
"refactor.inline",
"refactor.rewrite"
],
"resolveProvider": "true"
},
"codeLensProvider": {
"resolveProvider": "true"
},
"documentFormattingProvider": "true",
"documentOnTypeFormattingProvider": {
"firstTriggerCharacter": "=",
"moreTriggerCharacter": [
".",
">",
"{"
]
},
"renameProvider": {
"prepareProvider": "true"
},
"foldingRangeProvider": "true",
"workspace": {
"fileOperations": {
"willRename": {
"filters": [
{
"scheme": "file",
"pattern": {
"glob": "**\/*.rs",
"matches": "file"
}
},
{
"scheme": "file",
"pattern": {
"glob": "**",
"matches": "folder"
}
}
]
}
}
},
"callHierarchyProvider": "true",
"semanticTokensProvider": {
"legend": {
"tokenTypes": [
"comment",
"keyword",
"string",
"number",
"regexp",
"operator",
"namespace",
"type",
"struct",
"class",
"interface",
"enum",
"enumMember",
"typeParameter",
"function",
"method",
"property",
"macro",
"variable",
"parameter",
"angle",
"arithmetic",
"attribute",
"bitwise",
"boolean",
"brace",
"bracket",
"builtinType",
"characterLiteral",
"colon",
"comma",
"comparison",
"constParameter",
"dot",
"escapeSequence",
"formatSpecifier",
"generic",
"label",
"lifetime",
"logical",
"operator",
"parenthesis",
"punctuation",
"selfKeyword",
"semicolon",
"typeAlias",
"union",
"unresolvedReference"
],
"tokenModifiers": [
"documentation",
"declaration",
"definition",
"static",
"abstract",
"deprecated",
"readonly",
"constant",
"controlFlow",
"injected",
"mutable",
"consuming",
"async",
"unsafe",
"attribute",
"trait",
"callable",
"intraDocLink"
]
},
"range": "true",
"full": {
"delta": "true"
}
},
"experimental": {
"joinLines": "true",
"ssr": "true",
"onEnter": "true",
"parentModule": "true",
"runnables": {
"kinds": [
"cargo"
]
},
"workspaceSymbolScopeKindFiltering": "true"
}
},
"serverInfo": {
"name": "rust-analyzer",
"version": "3022a2c3a 2021-05-25 dev"
},
"offsetEncoding": "utf-8"
}
})";
std::cout << "Content-Length: " << result.size() << "\r\n\r\n"
<< result;
}
// Read initialized
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "initialized")
return 2;
}
// Read textDocument/didOpen
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "textDocument/didOpen")
return 3;
}
// Read textDocument/didChange
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "textDocument/didChange")
return 4;
}
// Read and write textDocument/formatting
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "textDocument/formatting")
return 5;
std::string result = R"({
"jsonrpc": "2.0",
"id": "1",
"result": [
{
"range": {
"start": {
"line": "0",
"character": "0"
},
"end": {
"line": "0",
"character": "1"
}
},
"newText": ""
}
]
})";
std::cout << "Content-Length: " << result.size() << "\r\n\r\n"
<< result;
}
// Read textDocument/didChange
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "textDocument/didChange")
return 6;
}
// Read textDocument/didClose
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "textDocument/didClose")
return 7;
}
// Read shutdown and respond
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "shutdown")
return 8;
std::string result = R"({
"jsonrpc": "2.0",
"id": "2",
"result": {}
})";
std::cout << "Content-Length: " << result.size() << "\r\n\r\n"
<< result;
}
// Read exit
{
std::getline(std::cin, line);
auto size = std::atoi(line.substr(16).c_str());
std::getline(std::cin, line);
std::string buffer;
buffer.resize(size);
std::cin.read(&buffer[0], size);
std::stringstream ss(buffer);
boost::property_tree::ptree pt;
boost::property_tree::json_parser::read_json(ss, pt);
if(pt.get<std::string>("method") != "exit")
return 9;
}
}
catch(const std::exception &e) {
std::cerr << e.what() << std::endl;
return 100;
}
}

0
tests/language_protocol_test_files/.rustfmt.toml

3
tests/language_protocol_test_files/main.rs

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

4
tests/stubs/notebook.cpp

@ -8,4 +8,8 @@ Source::View *Notebook::get_current_view() {
bool Notebook::open(const boost::filesystem::path &file_path, Position position) { return true; }
bool Notebook::open(Source::View *view) { return true; }
void Notebook::open_uri(const std::string &uri) {}
bool Notebook::close(Source::View *view) { return true; }

Loading…
Cancel
Save