Repository: envoyproxy/envoy
File: test/common/formatter/substitution_formatter_test.cc (C++)

Code before:
  (*struct_inner.mutable_fields())["inner_key"] = ValueUtil::stringValue("inner_value");
  Protobuf::Value obj_value;
  *obj_value.mutable_struct_value() = struct_inner;
  fields_map["test_obj"] = obj_value;
  Protobuf::ListValue list_inner;
  *list_inner.add_values() = ValueUtil::stringValue("item0");
  *list_inner.add_values() = ValueUtil::numberValue(4.2);
  Protobuf::Value list_value;
  *list_value.mutable_list_value() = list_inner;
  fields_map["test_lst"] = list_value;
  (*metadata.mutable_filter_metadata())["com.test"] = struct_obj;
}

TEST(SubstitutionFormatterTest, DynamicMetadataFieldExtractor) {
  envoy::config::core::v3::Metadata metadata;
  populateMetadataTestData(metadata);
  NiceMock<StreamInfo::MockStreamInfo> stream_info;
  EXPECT_CALL(stream_info, dynamicMetadata()).WillRepeatedly(ReturnRef(metadata));
  EXPECT_CALL(Const(stream_info), dynamicMetadata()).WillRepeatedly(ReturnRef(metadata));

  {
    DynamicMetadataFormatter formatter("com.test", {}, absl::optional<size_t>());
    std::string val = formatter.format(stream_info).value();
    EXPECT_TRUE(val.find("\"test_key\":\"test_value\"") != std::string::npos);
    EXPECT_TRUE(val.find("\"test_obj\":{\"inner_key\":\"inner_value\"}") != std::string::npos);
    EXPECT_TRUE(val.find("\"test_lst\":[\"item0\",4.2]") != std::string::npos);

    Protobuf::Value expected_val;
    expected_val.mutable_struct_value()->CopyFrom(metadata.filter_metadata().at("com.test"));
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(expected_val));
  }
  {
    DynamicMetadataFormatter formatter("com.test", {"test_key"}, absl::optional<size_t>());
    EXPECT_EQ("test_value", formatter.format(stream_info));
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(ValueUtil::stringValue("test_value")));
  }
  {
    DynamicMetadataFormatter formatter("com.test", {"test_obj"}, absl::optional<size_t>());
    EXPECT_EQ("{\"inner_key\":\"inner_value\"}", formatter.format(stream_info));

    Protobuf::Value expected_val;
    (*expected_val.mutable_struct_value()->mutable_fields())["inner_key"] =
        ValueUtil::stringValue("inner_value");
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(expected_val));
  }
  {
    DynamicMetadataFormatter formatter("com.test", {"test_obj", "inner_key"},
                                       absl::optional<size_t>());
    EXPECT_EQ("inner_value", formatter.format(stream_info));
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(ValueUtil::stringValue("inner_value")));
  }

Review comment (bug):
Frustrating because you're copying the structure of nearby existing code but the nearby existing code is yuck: could you instead do
```
EXPECT_THAT(val, HasSubstr(R"("test_lst":["item0",4.2]")"));
```
(this is more readable and, in the case that the test fails, would show the string and expectation, vs. the existing code on test failure would just say something useless along the lines of "expected true but was false")

Fixing the adjacent ones in the same way optional.

Code after:
  (*struct_inner.mutable_fields())["inner_key"] = ValueUtil::stringValue("inner_value");
  Protobuf::Value obj_value;
  *obj_value.mutable_struct_value() = struct_inner;
  fields_map["test_obj"] = obj_value;
  Protobuf::ListValue list_inner;
  *list_inner.add_values() = ValueUtil::stringValue("item0");
  *list_inner.add_values() = ValueUtil::numberValue(4.2);
  Protobuf::Value list_value;
  *list_value.mutable_list_value() = list_inner;
  fields_map["test_list"] = list_value;
  (*metadata.mutable_filter_metadata())["com.test"] = struct_obj;
}

TEST(SubstitutionFormatterTest, DynamicMetadataFieldExtractor) {
  envoy::config::core::v3::Metadata metadata;
  populateMetadataTestData(metadata);
  NiceMock<StreamInfo::MockStreamInfo> stream_info;
  EXPECT_CALL(stream_info, dynamicMetadata()).WillRepeatedly(ReturnRef(metadata));
  EXPECT_CALL(Const(stream_info), dynamicMetadata()).WillRepeatedly(ReturnRef(metadata));

  {
    DynamicMetadataFormatter formatter("com.test", {}, absl::optional<size_t>());
    std::string val = formatter.format(stream_info).value();
    EXPECT_THAT(val, HasSubstr(R"("test_key":"test_value")"));
    EXPECT_THAT(val, HasSubstr(R"("test_obj":{"inner_key":"inner_value"})"));
    EXPECT_THAT(val, HasSubstr(R"("test_list":["item0",4.2])"));

    Protobuf::Value expected_val;
    expected_val.mutable_struct_value()->CopyFrom(metadata.filter_metadata().at("com.test"));
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(expected_val));
  }
  {
    DynamicMetadataFormatter formatter("com.test", {"test_key"}, absl::optional<size_t>());
    EXPECT_EQ("test_value", formatter.format(stream_info));
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(ValueUtil::stringValue("test_value")));
  }
  {
    DynamicMetadataFormatter formatter("com.test", {"test_obj"}, absl::optional<size_t>());
    EXPECT_EQ("{\"inner_key\":\"inner_value\"}", formatter.format(stream_info));

    Protobuf::Value expected_val;
    (*expected_val.mutable_struct_value()->mutable_fields())["inner_key"] =
        ValueUtil::stringValue("inner_value");
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(expected_val));
  }
  {
    DynamicMetadataFormatter formatter("com.test", {"test_obj", "inner_key"},
                                       absl::optional<size_t>());
    EXPECT_EQ("inner_value", formatter.format(stream_info));
    EXPECT_THAT(formatter.formatValue(stream_info), ProtoEq(ValueUtil::stringValue("inner_value")));
  }