text: /*************************************************************************
   * libjson-rpc-cpp
   *************************************************************************
   * @file    test_common.cpp
   * @date    28.09.2013
   * @author  Peter Spiess-Knafl <dev@spiessknafl.at>
   * @license See attached LICENSE.txt
   ************************************************************************/
  
  #include "checkexception.h"
  #include <catch2/catch.hpp>
  #include <jsonrpccpp/common/exception.h>
  #include <jsonrpccpp/common/procedure.h>
  #include <jsonrpccpp/common/specificationparser.h>
  #include <jsonrpccpp/common/specificationwriter.h>
  
  #define TEST_MODULE "[common]"
  
  using namespace jsonrpc;
  using namespace std;
  
  namespace testcommon {
  bool check_exception1(JsonRpcException const &ex) {
    return ex.GetCode() == Errors::ERROR_RPC_JSON_PARSE_ERROR;
  }
  
  bool check_exception2(JsonRpcException const &ex) {
    return ex.GetCode() == Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX;
  }
  } // namespace testcommon
  
  using namespace testcommon;
  
  TEST_CASE("test_procedure_parametervalidation", TEST_MODULE) {
    Procedure proc1("someprocedure", PARAMS_BY_NAME, JSON_BOOLEAN, "name",
                    JSON_STRING, "ssnr", JSON_INTEGER, NULL);
  
    // Expected to pass validation
    Json::Value param1;
    param1["name"] = "Peter";
    param1["ssnr"] = 4711;
    CHECK(proc1.ValidateNamedParameters(param1) == true);
  
    // Expected to fail validation
    Json::Value param2;
    param2.append("Peter");
    param2.append(4711);
    CHECK(proc1.ValidateNamedParameters(param2) == false);
  
    // Expected to fail validation
    Json::Value param3;
    param3.append(4711);
    param3.append("Peter");
    CHECK(proc1.ValidateNamedParameters(param3) == false);
  
    Procedure proc2("someprocedure", PARAMS_BY_NAME, JSON_BOOLEAN, "bool",
                    JSON_BOOLEAN, "object", JSON_OBJECT, "array", JSON_ARRAY,
                    "real", JSON_REAL, "int", JSON_INTEGER, "numeric",
                    JSON_NUMERIC, NULL);
    Json::Value param4;
    Json::Value array;
    array.append(0);
    param4["bool"] = true;
    param4["object"] = param1;
    param4["array"] = array;
    param4["real"] = 0.332;
    param4["int"] = 3;
    param4["numeric"] = 7;
  
    CHECK(proc2.ValidateNamedParameters(param4) == true);
  
    param4["bool"] = "String";
    CHECK(proc2.ValidateNamedParameters(param4) == false);
    param4["bool"] = true;
  
    param4["object"] = "String";
    CHECK(proc2.ValidateNamedParameters(param4) == false);
    param4["object"] = param1;
  
    param4["real"] = "String";
    CHECK(proc2.ValidateNamedParameters(param4) == false);
    param4["real"] = 0.322;
  
    param4["array"] = "String";
    CHECK(proc2.ValidateNamedParameters(param4) == false);
    param4["array"] = array;
  
    param4["int"] = "String";
    CHECK(proc2.ValidateNamedParameters(param4) == false);
    param4["int"] = 3;
  
    param4["numeric"] = "String";
    CHECK(proc2.ValidateNamedParameters(param4) == false);
  
    param4["numeric"] = 8.657;
    CHECK(proc2.ValidateNamedParameters(param4) == true);
  }
  
  TEST_CASE("test_exception", TEST_MODULE) {
    JsonRpcException ex(Errors::ERROR_CLIENT_CONNECTOR);
    CHECK(string(ex.what()) == "Exception -32003 : Client connector error");
    CHECK(string(ex.GetMessage()) == "Client connector error");
    CHECK(ex.GetCode() == -32003);
  
    JsonRpcException ex2(Errors::ERROR_CLIENT_CONNECTOR, "addInfo");
    CHECK(string(ex2.what()) ==
          "Exception -32003 : Client connector error: addInfo");
  
    JsonRpcException ex3("addInfo");
    CHECK(string(ex3.what()) == "addInfo");
    CHECK(ex3.GetMessage() == "addInfo");
    CHECK(ex3.GetCode() == 0);
  
    Json::Value data;
    data.append(13);
    data.append(41);
    JsonRpcException ex4(Errors::ERROR_RPC_INTERNAL_ERROR, "internal error",
                         data);
    CHECK(ex4.GetData().size() == 2);
    CHECK(ex4.GetData()[0].asInt() == 13);
    CHECK(ex4.GetData()[1].asInt() == 41);
  }
  
  TEST_CASE("test_specificationparser_errors", TEST_MODULE) {
    CHECK_EXCEPTION_TYPE(
        SpecificationParser::GetProceduresFromFile("testspec1.json"),
        JsonRpcException, check_exception1);
    CHECK_EXCEPTION_TYPE(
        SpecificationParser::GetProceduresFromFile("testspec2.json"),
        JsonRpcException, check_exception2);
    CHECK_EXCEPTION_TYPE(
        SpecificationParser::GetProceduresFromFile("testspec3.json"),
        JsonRpcException, check_exception2);
    CHECK_EXCEPTION_TYPE(
        SpecificationParser::GetProceduresFromFile("testspec4.json"),
        JsonRpcException, check_exception2);
    CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromString("{}"),
                         JsonRpcException, check_exception2);
  
    CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromString(
                             "[{\"name\":\"proc1\"},{\"name\":\"proc1\"}]"),
                         JsonRpcException, check_exception2);
    CHECK_EXCEPTION_TYPE(
        SpecificationParser::GetProceduresFromString(
            "[{\"name\":\"proc1\", \"params\": {\"param1\": null}}]"),
        JsonRpcException, check_exception2);
    CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromString(
                             "[{\"name\":\"proc1\", \"params\": 23}]"),
                         JsonRpcException, check_exception2);
  }
  
  TEST_CASE("test_specificationparser_success", TEST_MODULE) {
    std::vector<Procedure> procs =
        SpecificationParser::GetProceduresFromFile("testspec5.json");
    REQUIRE(procs.size() == 4);
  
    CHECK(procs[0].GetProcedureName() == "testmethod");
    CHECK(procs[0].GetReturnType() == JSON_STRING);
    CHECK(procs[0].GetProcedureType() == RPC_METHOD);
    CHECK(procs[0].GetParameterDeclarationType() == PARAMS_BY_NAME);
  
    CHECK(procs[2].GetProcedureName() == "testmethod2");
    CHECK(procs[2].GetReturnType() == JSON_REAL);
    CHECK(procs[2].GetProcedureType() == RPC_METHOD);
    CHECK(procs[2].GetParameterDeclarationType() == PARAMS_BY_NAME);
  
    CHECK(procs[1].GetProcedureName() == "testnotification");
    CHECK(procs[1].GetProcedureType() == RPC_NOTIFICATION);
    CHECK(procs[1].GetParameterDeclarationType() == PARAMS_BY_NAME);
  
    CHECK(procs[3].GetProcedureName() == "testnotification2");
    CHECK(procs[3].GetProcedureType() == RPC_NOTIFICATION);
    CHECK(procs[3].GetParameterDeclarationType() == PARAMS_BY_NAME);
  }
  
  TEST_CASE("test_specificationwriter", TEST_MODULE) {
    vector<Procedure> procedures;
  
    procedures.push_back(Procedure("testmethod1", PARAMS_BY_NAME, JSON_INTEGER,
                                   "param1", JSON_INTEGER, "param2", JSON_REAL,
                                   NULL));
    procedures.push_back(Procedure("testmethod2", PARAMS_BY_POSITION,
                                   JSON_INTEGER, "param1", JSON_OBJECT, "param2",
                                   JSON_ARRAY, NULL));
  
    procedures.push_back(Procedure("testnotification1", PARAMS_BY_NAME, "param1",
                                   JSON_BOOLEAN, "param2", JSON_STRING, NULL));
    procedures.push_back(Procedure("testnotification2", PARAMS_BY_POSITION,
                                   "param1", JSON_INTEGER, "param2", JSON_STRING,
                                   NULL));
  
    procedures.push_back(
        Procedure("testnotification3", PARAMS_BY_POSITION, NULL));
  
    Json::Value result = SpecificationWriter::toJsonValue(procedures);
  
    REQUIRE(result.isArray() == true);
    REQUIRE(result.size() == procedures.size());
  
    CHECK(result[0]["name"].asString() == "testmethod1");
    CHECK(result[1]["name"].asString() == "testmethod2");
    CHECK(result[2]["name"].asString() == "testnotification1");
    CHECK(result[3]["name"].asString() == "testnotification2");
    CHECK(result[4]["name"].asString() == "testnotification3");
  
    REQUIRE(result[0]["params"].isObject() == true);
    CHECK(result[0]["params"]["param1"].isIntegral() == true);
    CHECK(result[0]["params"]["param2"].isDouble() == true);
  
    REQUIRE(result[1]["params"].isArray() == true);
    CHECK(result[1]["params"][0].isObject() == true);
    CHECK(result[1]["params"][1].isArray() == true);
  
    REQUIRE(result[2]["params"].isObject() == true);
    CHECK(result[2]["params"]["param1"].isBool() == true);
    CHECK(result[2]["params"]["param2"].isString() == true);
  
    REQUIRE(result[3]["params"].isArray() == true);
    CHECK(result[3]["params"][0].isIntegral() == true);
    CHECK(result[3]["params"][1].isString() == true);
  
    CHECK(result[4].isMember("params") == false);
  
    CHECK(result[0]["returns"].isIntegral() == true);
    CHECK(result[1]["returns"].isIntegral() == true);
  
    CHECK(SpecificationWriter::toFile("testspec.json", procedures) == true);
    CHECK(SpecificationWriter::toFile("/a/b/c/testspec.json", procedures) ==
          false);
  }
  