Skip to content
Snippets Groups Projects
json_test.cc 8.26 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <catch2/catch.hpp>
    
    #include <google/protobuf/util/json_util.h>
    #include <testpb/messages.pb.h>
    
    TEST_CASE("simple struct", "[protobuf]") {
      auto json = R"(
    {
    
      "int_value": 9223372036854775807,
    
      "string_value": "foo bar",
      "int_arr": [4, 2],
      "string_arr": ["foo", "bar", "baz"],
      "int_map": {
    
        "42": 4,
        "72": 2,
    
      },
      "string_map": {
        "foo": "foo_value",
        "bar": "bar_value"
    
    }
    )";
    
      testproto::SimpleStruct msg;
    
      google::protobuf::util::JsonParseOptions options;
      auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
    
      CHECK(status.error_message() == "");
      REQUIRE(status.ok());
      CHECK(msg.string_value() == "foo bar");
    
      CHECK(msg.int_value() == 9223372036854775807);
    
      CHECK(msg.int_arr().size() == 2);
      CHECK(msg.int_arr().Get(0) == 4);
      CHECK(msg.int_arr().Get(1) == 2);
    
      CHECK(msg.string_arr().size() == 3);
      std::vector<std::string> expected{"foo", "bar", "baz"};
      CHECK(
        std::equal(
          msg.string_arr().begin(), msg.string_arr().end(),
          expected.begin(), expected.end()
        )
      );
    
      CHECK(msg.int_map_size() == 2);
    
      CHECK(msg.int_map().at(42) == 4);
      CHECK(msg.int_map().at(72) == 2);
    
    
      CHECK(msg.string_map_size() == 2);
      CHECK(msg.string_map().at("foo") == "foo_value");
      CHECK(msg.string_map().at("bar") == "bar_value");
    
      CHECK(msg.double_value() == 42);
    }
    
    
    TEST_CASE("unmarshal bytes", "[protobuf]") {
      auto json = R"(
    {
      "bytes_value": "AEJmb29iYXI=",
    }
    )";
    
      testproto::BytesType msg;
    
      google::protobuf::util::JsonParseOptions options;
      auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
    
      CHECK(status.error_message() == "");
      REQUIRE(status.ok());
      using namespace std::string_literals;
      CHECK(msg.bytes_value() == "\x00\x42"s "foobar");
    }
    
    
    TEST_CASE("two dimensional array", "[protobuf]") {
      auto json = R"(
    {
      arr: [
        {
          str_arr: ["foo", "bar"]
        }
      ]
    }
    )";
    
      testproto::TwoDimensionalArray msg;
    
      google::protobuf::util::JsonParseOptions options;
      auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
    
      CHECK(status.error_message() == "");
      REQUIRE(status.ok());
      REQUIRE(msg.arr().size() == 1);
      REQUIRE(msg.arr().at(0).str_arr().size() == 2);
      REQUIRE(msg.arr().at(0).str_arr().at(0) == "foo");
      REQUIRE(msg.arr().at(0).str_arr().at(1) == "bar");
    
    }
    
    TEST_CASE("invalid json", "[protobuf]") {
      auto json = R"(
    {
      "string_value": invalid,
    }
    )";
    
      testproto::SimpleStruct msg;
    
      google::protobuf::util::JsonParseOptions options;
      auto status = JsonStringToMessage(json, &msg, options);
    
      REQUIRE_FALSE(status.ok());
    }
    
    TEST_CASE("null/missing integer value", "[protobuf]") {
      auto json = R"(
    {
      "int_value": null,
      "string_value": "foo bar",
    }
    )";
    
      google::protobuf::util::JsonParseOptions options;
    
      testproto::SimpleStruct msg;
      auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
    
      REQUIRE(status.ok());
      REQUIRE(msg.string_value() == "foo bar");
      REQUIRE(msg.int_value() == 0);
    
      json = R"(
    {
      "string_value": "foo bar",
    }
    )";
    
      msg = testproto::SimpleStruct{};
      status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
    
      REQUIRE(status.ok());
      REQUIRE(msg.string_value() == "foo bar");
      REQUIRE(msg.int_value() == 0);
    }
    
    
    TEST_CASE("json marshal double", "[protobuf]") {
      testproto::SimpleStruct msg;
      msg.set_double_value(42);
    
      std::string json;
      google::protobuf::util::JsonOptions options;
      options.add_whitespace = true;
      options.preserve_proto_field_names = true;
      options.always_print_enums_as_ints = true;
      auto status = google::protobuf::util::MessageToJsonString(msg, &json, options);
      auto expected = R"({
     "double_value": 42
    }
    )";
    
      REQUIRE(json == expected);
    }
    
    TEST_CASE("json marshal uint64", "[protobuf]") {
      testproto::SimpleStruct msg;
      msg.set_uint64_value(42);
    
      std::string json;
      google::protobuf::util::JsonOptions options;
      options.add_whitespace = true;
      options.preserve_proto_field_names = true;
      options.always_print_enums_as_ints = true;
      auto status = google::protobuf::util::MessageToJsonString(msg, &json, options);
      auto expected = R"({
     "uint64_value": "42"
    }
    )";
    
      REQUIRE(json == expected);
    }
    
    
    TEST_CASE("json marshal naming", "[protobuf]") {
      testproto::JsonNaming msg;
      msg.set_foo_value(1);
      msg.set_barvalue(2);
      msg.set_bazvalue(3);
      msg.set_qux_value(4);
    
      std::string json;
      google::protobuf::util::JsonOptions options;
      options.add_whitespace = true;
      options.preserve_proto_field_names = true;
      options.always_print_primitive_fields = true;
      options.always_print_enums_as_ints = true;
      auto status = google::protobuf::util::MessageToJsonString(msg, &json, options);
      auto expected = R"({
     "foo_value": 1,
     "barValue": 2,
     "BazValue": 3,
     "quX_Value": 4
    }
    )";
    
      REQUIRE(json == expected);
    }
    
    TEST_CASE("json unmarshal naming", "[protobuf]") {
      SECTION("accept snake case") {
        auto json = R"(
    {
      "quX_Value": 42,
    }
    )";
    
        testproto::JsonNaming msg;
        google::protobuf::util::JsonParseOptions options;
        auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
        CHECK(status.error_message() == "");
        REQUIRE(status.ok());
        CHECK(msg.qux_value() == 42);
      }
    
      SECTION("accept camelCase case") {
        auto json = R"(
    {
      "barValue": 42,
    }
    )";
    
        testproto::JsonNaming msg;
        google::protobuf::util::JsonParseOptions options;
        auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
        CHECK(status.error_message() == "");
        REQUIRE(status.ok());
        CHECK(msg.barvalue() == 42);
      }
    
      SECTION("accept CamelCase case") {
        auto json = R"(
    {
      "BazValue": 42,
    }
    )";
    
        testproto::JsonNaming msg;
        google::protobuf::util::JsonParseOptions options;
        auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
        CHECK(status.error_message() == "");
        REQUIRE(status.ok());
        CHECK(msg.bazvalue() == 42);
      }
    }
    
    TEST_CASE("oneof unmarshal", "[protobuf]") {
      SECTION("accept string value") {
        auto json = R"(
    {
      "string_value": "foo bar",
    }
      )";
    
        testproto::OneofValue msg;
        google::protobuf::util::JsonParseOptions options;
        auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
    
        CHECK(status.error_message() == "");
        REQUIRE(status.ok());
        CHECK(msg.data_case() == testproto::OneofValue::kStringValue);
        CHECK_FALSE(msg.has_struct_value());
        CHECK(msg.string_value() == "foo bar");
      }
    
      SECTION("accept struct value") {
        auto json = R"(
    {
      "struct_value": {
        "int_value": 42
      }
    }
      )";
    
        testproto::OneofValue msg;
        google::protobuf::util::JsonParseOptions options;
        auto status = google::protobuf::util::JsonStringToMessage(json, &msg, options);
    
        CHECK(status.error_message() == "");
        REQUIRE(status.ok());
        CHECK(msg.data_case() == testproto::OneofValue::kStructValue);
        CHECK(msg.has_struct_value());
        CHECK(msg.struct_value().int_value() == 42);
      }
    }
    
    TEST_CASE("oneof marshal", "[protobuf]") {
      SECTION("marshal string value") {
        testproto::OneofValue msg;
        msg.set_string_value("foo bar");
        google::protobuf::util::JsonPrintOptions options;
        options.preserve_proto_field_names = true;
        std::string json;
        auto status = google::protobuf::util::MessageToJsonString(msg, &json, options);
    
        auto expected = R"({"string_value":"foo bar"})";
    
        CHECK(status.error_message() == "");
        REQUIRE(status.ok());
        CHECK(json == expected);
      }
    
      SECTION("marshal struct value") {
        testproto::OneofValue msg;
        msg.mutable_struct_value()->set_int_value(42);
        google::protobuf::util::JsonPrintOptions options;
        options.preserve_proto_field_names = true;
        std::string json;
        auto status = google::protobuf::util::MessageToJsonString(msg, &json, options);
    
        auto expected = R"({"struct_value":{"int_value":"42"}})";
    
        CHECK(status.error_message() == "");
        REQUIRE(status.ok());
        CHECK(json == expected);
      }
    
    }
    
    
    TEST_CASE("empty messages with OmitEmpty", "[protobuf]") {
      testproto::MessageType msg;
      msg.add_foo_arr();
    
      google::protobuf::util::JsonPrintOptions options;
      options.preserve_proto_field_names = true;
    
      options.always_print_primitive_fields = false;
    
      std::string json;
      auto status = google::protobuf::util::MessageToJsonString(msg, &json, options);
    
      auto expected = R"({"foo_arr":[{}]})";
    
      CHECK(json == expected);
    }