diff --git a/CMakeLists.txt b/CMakeLists.txt index 62eb240..9feebad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,15 @@ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) add_library(coverage_config INTERFACE) +# Warning options for the compiler +string( + APPEND _warning_opts + "$<$,$,$>:-Wall;-Wextra;-Weffc++;-Werror;>" + "$<$,$>:-Wthread-safety;-Wpedantic;>" + "$<$:-pedantic;-pedantic-errors;>" + ) + + if (COMPILE_TESTS) if (CODE_COVERAGE) message("Enabled coverage flags") @@ -22,6 +31,7 @@ if (COMPILE_TESTS) target_link_libraries(coverage_config INTERFACE --coverage) endif () add_executable(jsonrpccpp-test test/main.cpp test/client.cpp test/typemapper.cpp test/dispatcher.cpp test/server.cpp test/batchclient.cpp test/testclientconnector.hpp examples/warehouse/warehouseapp.cpp test/warehouseapp.cpp) + target_compile_options(jsonrpccpp-test PUBLIC "${_warning_opts}") target_include_directories(jsonrpccpp-test PRIVATE vendor examples) target_link_libraries(jsonrpccpp-test coverage_config json-rpc-cxx) enable_testing() @@ -31,8 +41,10 @@ endif () if (COMPILE_EXAMPLES) find_package(Threads) add_executable(example-warehouse examples/warehouse/main.cpp examples/warehouse/warehouseapp.cpp examples/warehouse/types.h examples/inmemoryconnector.hpp) + target_compile_options(example-warehouse PUBLIC "${_warning_opts}") target_link_libraries(example-warehouse json-rpc-cxx Threads::Threads) - target_include_directories(example-warehouse PRIVATE vendor examples) + target_include_directories(example-warehouse SYSTEM PRIVATE vendor) + target_include_directories(example-warehouse PRIVATE examples) add_test(NAME example COMMAND example-warehouse) endif () diff --git a/examples/cpphttplibconnector.hpp b/examples/cpphttplibconnector.hpp index 5eca318..1c05541 100644 --- a/examples/cpphttplibconnector.hpp +++ b/examples/cpphttplibconnector.hpp @@ -22,12 +22,17 @@ class CppHttpLibClientConnector : public jsonrpccxx::IClientConnector { class CppHttpLibServerConnector { public: - explicit CppHttpLibServerConnector(jsonrpccxx::JsonRpcServer &server, int port) : server(server), port(port) { - httpServer.Post("/jsonrpc", [&](const httplib::Request &req, httplib::Response &res) { - res.status = 200; - res.set_content(server.HandleRequest(req.body), "application/json"); - }); + explicit CppHttpLibServerConnector(jsonrpccxx::JsonRpcServer &server, int port) : + thread(), + server(server), + httpServer(), + port(port) { + httpServer.Post("/jsonrpc", + [this](const httplib::Request &req, httplib::Response &res) { + this->PostAction(req, res); + }); } + virtual ~CppHttpLibServerConnector() { StopListening(); } bool StartListening() { @@ -49,4 +54,10 @@ class CppHttpLibServerConnector { jsonrpccxx::JsonRpcServer &server; httplib::Server httpServer; int port; -}; \ No newline at end of file + + void PostAction(const httplib::Request &req, + httplib::Response &res) { + res.status = 200; + res.set_content(this->server.HandleRequest(req.body), "application/json"); + } +}; diff --git a/examples/warehouse/main.cpp b/examples/warehouse/main.cpp index 2a06ab7..454f66d 100644 --- a/examples/warehouse/main.cpp +++ b/examples/warehouse/main.cpp @@ -22,7 +22,11 @@ class WareHouseClient { void doWarehouseStuff(IClientConnector &clientConnector) { JsonRpcClient client(clientConnector, version::v2); WareHouseClient appClient(client); - Product p = {"0xff", 22.4, "Product 1", category::cash_carry}; + Product p; + p.id = "0xff"; + p.price = 22.4; + p.name = "Product 1"; + p.cat = category::cash_carry; cout << "Adding product: " << std::boolalpha << appClient.AddProduct(p) << "\n"; Product p2 = appClient.GetProduct("0xff"); @@ -54,4 +58,4 @@ int main() { doWarehouseStuff(httpClient); return 0; -} \ No newline at end of file +} diff --git a/examples/warehouse/types.h b/examples/warehouse/types.h index 82cd737..1395f40 100644 --- a/examples/warehouse/types.h +++ b/examples/warehouse/types.h @@ -2,18 +2,28 @@ #include enum class category { order, cash_carry }; + struct Product { +public: + Product() : id(), price(), name(), cat() {} std::string id; double price; std::string name; category cat; }; -NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::order, "order"}, {category::cash_carry, "cc"}}); -inline void to_json(nlohmann::json &j, const Product &p) { j = nlohmann::json{{"id", p.id}, {"price", p.price}, {"name", p.name}, {"category", p.cat}}; } +NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::order, "order"}, {category::cash_carry, "cc"}}) + +inline void to_json(nlohmann::json &j, const Product &p) { + j = nlohmann::json{{"id", p.id}, + {"price", p.price}, + {"name", p.name}, + {"category", p.cat}}; + } + inline void from_json(const nlohmann::json &j, Product &p) { j.at("name").get_to(p.name); j.at("id").get_to(p.id); j.at("price").get_to(p.price); j.at("category").get_to(p.cat); -} \ No newline at end of file +} diff --git a/examples/warehouse/warehouseapp.hpp b/examples/warehouse/warehouseapp.hpp index b282654..8936ad5 100644 --- a/examples/warehouse/warehouseapp.hpp +++ b/examples/warehouse/warehouseapp.hpp @@ -5,6 +5,9 @@ class WarehouseServer { public: + WarehouseServer() : + products() {} + bool AddProduct(const Product &p); const Product& GetProduct(const std::string& id); diff --git a/include/jsonrpccxx/batchclient.hpp b/include/jsonrpccxx/batchclient.hpp index 96fb781..c2084de 100644 --- a/include/jsonrpccxx/batchclient.hpp +++ b/include/jsonrpccxx/batchclient.hpp @@ -46,7 +46,7 @@ namespace jsonrpccxx { class BatchResponse { public: - explicit BatchResponse(json &&response) : response(response) { + explicit BatchResponse(json &&response) : response(response), results(), errors(), nullIds() { for (auto &[key, value] : response.items()) { if (value.is_object() && valid_id_not_null(value) && has_key(value, "result")) { results[value["id"]] = std::stoi(key); @@ -98,4 +98,4 @@ namespace jsonrpccxx { } } }; -} \ No newline at end of file +} diff --git a/include/jsonrpccxx/dispatcher.hpp b/include/jsonrpccxx/dispatcher.hpp index 2e335c5..572d55f 100644 --- a/include/jsonrpccxx/dispatcher.hpp +++ b/include/jsonrpccxx/dispatcher.hpp @@ -12,6 +12,11 @@ namespace jsonrpccxx { class Dispatcher { public: + Dispatcher() : + methods(), + notifications(), + mapping() {} + bool Add(const std::string &name, MethodHandle callback, const NamedParamMapping &mapping = NAMED_PARAM_MAPPING) { if (contains(name)) return false; @@ -98,4 +103,4 @@ namespace jsonrpccxx { throw JsonRpcException(-32600, "invalid request: params field must be an array, object"); } }; -} // namespace jsonrpccxx \ No newline at end of file +} // namespace jsonrpccxx diff --git a/include/jsonrpccxx/server.hpp b/include/jsonrpccxx/server.hpp index 753a1ca..03e9567 100644 --- a/include/jsonrpccxx/server.hpp +++ b/include/jsonrpccxx/server.hpp @@ -7,6 +7,7 @@ namespace jsonrpccxx { class JsonRpcServer { public: + JsonRpcServer() : dispatcher() {} virtual ~JsonRpcServer() = default; virtual std::string HandleRequest(const std::string &request) = 0; @@ -106,4 +107,4 @@ namespace jsonrpccxx { } } }; -} \ No newline at end of file +} diff --git a/test/client.cpp b/test/client.cpp index 033af0e..c7fc877 100644 --- a/test/client.cpp +++ b/test/client.cpp @@ -13,7 +13,7 @@ struct F { TestClientConnector c; JsonRpcClient clientV1; JsonRpcClient clientV2; - F() : clientV1(c, version::v1), clientV2(c, version::v2) {} + F() : c(), clientV1(c, version::v1), clientV2(c, version::v2) {} }; TEST_CASE_METHOD(F, "v2_method_noparams", TEST_MODULE) { @@ -256,4 +256,4 @@ TEST_CASE_METHOD(F, "v1_notification_call_params_byposition", TEST_MODULE) { CHECK(c.request["params"][2] == true); } -// TODO: test cases with return type mapping and param mapping for v1/v2 method and notification \ No newline at end of file +// TODO: test cases with return type mapping and param mapping for v1/v2 method and notification diff --git a/test/integrationtest.hpp b/test/integrationtest.hpp index 3a38ec7..672457f 100644 --- a/test/integrationtest.hpp +++ b/test/integrationtest.hpp @@ -8,8 +8,8 @@ using namespace jsonrpccxx; struct IntegrationTest { - IntegrationTest() : connector(rpcServer), client(connector, version::v2) {} + IntegrationTest() : rpcServer(), connector(rpcServer), client(connector, version::v2) {} JsonRpc2Server rpcServer; InMemoryConnector connector; JsonRpcClient client; -}; \ No newline at end of file +}; diff --git a/test/server.cpp b/test/server.cpp index c8c7e50..18412fe 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -13,7 +13,7 @@ struct Server2 { JsonRpc2Server server; TestServerConnector connector; - Server2() : connector(server) {} + Server2() : server(), connector(server) {} }; TEST_CASE_METHOD(Server2, "v2_method_not_found", TEST_MODULE) { @@ -61,9 +61,10 @@ TEST_CASE_METHOD(Server2, "v2_malformed_requests", TEST_MODULE) { enum class category { ord, cc }; -NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::ord, "order"}, {category::cc, "cc"}}); +NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::ord, "order"}, {category::cc, "cc"}}) struct product { + product() : id(), price(), name(), cat() {} int id; double price; string name; @@ -75,6 +76,8 @@ void from_json(const json &j, product &p); class TestServer { public: + TestServer() : param_proc(), param_a(), param_b(), catalog() {} + unsigned int add_function(unsigned int a, unsigned int b) { this->param_a = a; this->param_b = b; @@ -95,8 +98,8 @@ class TestServer { }; void dirty_notification() { throw std::exception(); } - int dirty_method(int a, int b) { throw std::exception(); } - int dirty_method2(int a, int b) { throw - 7; } + int dirty_method(int a, int b) { to_string(a+b); throw std::exception(); } + int dirty_method2(int a, int b) { throw (a+b); } string param_proc; int param_a; diff --git a/test/testclientconnector.hpp b/test/testclientconnector.hpp index ad1f94c..a3fb21f 100644 --- a/test/testclientconnector.hpp +++ b/test/testclientconnector.hpp @@ -11,6 +11,8 @@ using namespace std; class TestClientConnector : public IClientConnector { public: + TestClientConnector() : request(), raw_response() {} + json request; string raw_response; @@ -64,4 +66,4 @@ class TestClientConnector : public IClientConnector { CHECK(has_key(request, "params")); } } -}; \ No newline at end of file +}; diff --git a/test/testserverconnector.hpp b/test/testserverconnector.hpp index f548602..e9cd354 100644 --- a/test/testserverconnector.hpp +++ b/test/testserverconnector.hpp @@ -8,7 +8,7 @@ using namespace Catch::Matchers; class TestServerConnector { public: - explicit TestServerConnector(JsonRpcServer &handler) : handler(handler) {} + explicit TestServerConnector(JsonRpcServer &handler) : handler(handler), raw_response() {} void SendRawRequest(const string &request) { this->raw_response = handler.HandleRequest(request); } void SendRequest(const json &request) { SendRawRequest(request.dump()); } @@ -60,4 +60,4 @@ class TestServerConnector { private: JsonRpcServer &handler; string raw_response; -}; \ No newline at end of file +}; diff --git a/test/typemapper.cpp b/test/typemapper.cpp index 4abbe7e..4b6e02f 100644 --- a/test/typemapper.cpp +++ b/test/typemapper.cpp @@ -85,21 +85,34 @@ TEST_CASE("test incorrect params", TEST_MODULE) { enum class category { order, cash_carry }; struct product { + product() : id(), price(), name(), cat() {} int id; double price; string name; category cat; }; -NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::order, "order"}, {category::cash_carry, "cc"}}); +NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::order, "order"}, {category::cash_carry, "cc"}}) void to_json(json &j, const product &p) { j = json{{"id", p.id}, {"price", p.price}, {"name", p.name}, {"category", p.cat}}; } product get_product(int id) { - if (id == 1) - return product{1, 22.50, "some product", category::order}; - else if (id == 2) - return product{2, 55.50, "some product 2", category::cash_carry}; + if (id == 1) { + product p; + p.id = 1; + p.price = 22.50; + p.name = "some product"; + p.cat = category::order; + return p; + } + else if (id == 2) { + product p; + p.id = 2; + p.price = 55.50; + p.name = "some product 2"; + p.cat = category::cash_carry; + return p; + } throw JsonRpcException(-50000, "product not found"); } @@ -131,7 +144,7 @@ static vector catalog; bool add_products(const vector &products) { std::copy(products.begin(), products.end(), std::back_inserter(catalog)); return true; -}; +} TEST_CASE("test with custom params", TEST_MODULE) { MethodHandle mh = GetHandle(&add_products); @@ -175,4 +188,4 @@ TEST_CASE("test number range checking", TEST_MODULE) { unsigned short max_ss = numeric_limits::max(); CHECK(mh2({max_su, max_ss}) == max_su + max_ss); REQUIRE_THROWS_WITH(mh2({max_su, max_su}), Contains("invalid parameter: exceeds value range of integer")); -} \ No newline at end of file +} diff --git a/test/warehouseapp.cpp b/test/warehouseapp.cpp index 2f811e9..ef92e7a 100644 --- a/test/warehouseapp.cpp +++ b/test/warehouseapp.cpp @@ -9,9 +9,13 @@ TEST_CASE_METHOD(IntegrationTest, "warehouse_test", TEST_MODULE) { rpcServer.Add("GetProduct", GetHandle(&WarehouseServer::GetProduct, app)); rpcServer.Add("AddProduct", GetHandle(&WarehouseServer::AddProduct, app)); - Product p = {"0xff", 22.4, "Product 1", category::cash_carry}; + Product p; + p.id = "0xff"; + p.price = 22.4; + p.name = "Product 1"; + p.cat = category::cash_carry; CHECK(client.CallMethod(1, "AddProduct", {p})); Product p2 = client.CallMethod(1, "GetProduct", {"0xff"}); CHECK((p2.id == p.id && p2.name == p.name && p2.price == p.price && p2.cat == p.cat)); -} \ No newline at end of file +}