blob: bc9471217d52b95fc494ce304f45f9f8ffe6adbb [file] [edit]
// Protocol Buffers - Google's data interchange format
// Copyright 2026 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
// JSON conformance tests for repeated fields: JSON arrays of primitives,
// enums, strings, bytes and messages round-trip, array elements of the wrong
// type are rejected, a single value where an array was expected is rejected,
// and so is a trailing comma in an array. This replaces the legacy
// BinaryAndJsonConformanceSuiteImpl<M>::RunJsonTestsForRepeatedTypes(); the
// test names and the requests sent to the testee are identical to the legacy
// ones.
//
// Like the legacy RunValidJsonTest(), each valid input is sent twice: once to
// be serialized as binary ("<name>.ProtobufOutput") and once as JSON
// ("<name>.JsonOutput"). ExpectParseFailureForJson() asked for JSON output
// under a name without an output suffix.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/strings/string_view.h"
#include "conformance/binary_test_util.h"
#include "conformance/matchers.h"
#include "conformance/message_type_fixtures.h"
#include "conformance/testee.h"
namespace google {
namespace protobuf {
namespace conformance {
namespace {
using ::testing::ValuesIn;
using JsonRepeatedTest = MessageTypeConformanceTest;
// ---------------------------------------------------------------------------
// Repeated fields of each kind round-trip.
// ---------------------------------------------------------------------------
TEST_P(JsonRepeatedTest, PrimitiveRepeatedField) {
constexpr absl::string_view kInput =
R"json({"repeatedInt32": [1, 2, 3, 4]})json";
constexpr absl::string_view kExpected =
R"pb(repeated_int32: [ 1, 2, 3, 4 ])pb";
EXPECT_THAT(Testee("PrimitiveRepeatedField")
.ParseJson(message(), kInput)
.SerializeBinary(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
EXPECT_THAT(Testee("PrimitiveRepeatedField")
.ParseJson(message(), kInput)
.SerializeJson(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
}
TEST_P(JsonRepeatedTest, EnumRepeatedField) {
constexpr absl::string_view kInput =
R"json({"repeatedNestedEnum": ["FOO", "BAR", "BAZ"]})json";
constexpr absl::string_view kExpected =
R"pb(repeated_nested_enum: [ FOO, BAR, BAZ ])pb";
EXPECT_THAT(Testee("EnumRepeatedField")
.ParseJson(message(), kInput)
.SerializeBinary(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
EXPECT_THAT(
Testee("EnumRepeatedField").ParseJson(message(), kInput).SerializeJson(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
}
TEST_P(JsonRepeatedTest, StringRepeatedField) {
constexpr absl::string_view kInput =
R"json({"repeatedString": ["Hello", "world"]})json";
constexpr absl::string_view kExpected =
R"pb(repeated_string: [ "Hello", "world" ])pb";
EXPECT_THAT(Testee("StringRepeatedField")
.ParseJson(message(), kInput)
.SerializeBinary(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
EXPECT_THAT(Testee("StringRepeatedField")
.ParseJson(message(), kInput)
.SerializeJson(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
}
TEST_P(JsonRepeatedTest, BytesRepeatedField) {
constexpr absl::string_view kInput =
R"json({"repeatedBytes": ["AAEC", "AQI="]})json";
constexpr absl::string_view kExpected =
R"pb(repeated_bytes: [ "\x00\x01\x02", "\x01\x02" ])pb";
EXPECT_THAT(Testee("BytesRepeatedField")
.ParseJson(message(), kInput)
.SerializeBinary(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
EXPECT_THAT(
Testee("BytesRepeatedField").ParseJson(message(), kInput).SerializeJson(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
}
TEST_P(JsonRepeatedTest, MessageRepeatedField) {
constexpr absl::string_view kInput =
R"json({"repeatedNestedMessage": [{"a": 1234}, {"a": 5678}]})json";
constexpr absl::string_view kExpected = R"pb(
repeated_nested_message: { a: 1234 }
repeated_nested_message: { a: 5678 }
)pb";
EXPECT_THAT(Testee("MessageRepeatedField")
.ParseJson(message(), kInput)
.SerializeBinary(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
EXPECT_THAT(Testee("MessageRepeatedField")
.ParseJson(message(), kInput)
.SerializeJson(),
Yields(WhenParsed(EqualsTextProto(kExpected))));
}
// ---------------------------------------------------------------------------
// Repeated field elements of the wrong type are rejected.
// ---------------------------------------------------------------------------
TEST_P(JsonRepeatedTest,
RepeatedFieldWrongElementTypeExpectingIntegersGotBool) {
EXPECT_THAT(Testee("RepeatedFieldWrongElementTypeExpectingIntegersGotBool")
.ParseJson(message(),
R"json({"repeatedInt32": [1, false, 3, 4]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest,
RepeatedFieldWrongElementTypeExpectingIntegersGotString) {
EXPECT_THAT(Testee("RepeatedFieldWrongElementTypeExpectingIntegersGotString")
.ParseJson(message(),
R"json({"repeatedInt32": [1, 2, "name", 4]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest,
RepeatedFieldWrongElementTypeExpectingIntegersGotMessage) {
EXPECT_THAT(
Testee("RepeatedFieldWrongElementTypeExpectingIntegersGotMessage")
.ParseJson(message(),
R"json({"repeatedInt32": [1, 2, 3, {"a": 4}]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest, RepeatedFieldWrongElementTypeExpectingStringsGotInt) {
EXPECT_THAT(
Testee("RepeatedFieldWrongElementTypeExpectingStringsGotInt")
.ParseJson(message(),
R"json({"repeatedString": ["1", 2, "3", "4"]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest, RepeatedFieldWrongElementTypeExpectingStringsGotBool) {
EXPECT_THAT(
Testee("RepeatedFieldWrongElementTypeExpectingStringsGotBool")
.ParseJson(message(),
R"json({"repeatedString": ["1", "2", false, "4"]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest,
RepeatedFieldWrongElementTypeExpectingStringsGotMessage) {
EXPECT_THAT(
Testee("RepeatedFieldWrongElementTypeExpectingStringsGotMessage")
.ParseJson(message(),
R"json({"repeatedString": ["1", 2, "3", {"a": 4}]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest, RepeatedFieldWrongElementTypeExpectingMessagesGotInt) {
EXPECT_THAT(
Testee("RepeatedFieldWrongElementTypeExpectingMessagesGotInt")
.ParseJson(message(),
R"json({"repeatedNestedMessage": [{"a": 1}, 2]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest,
RepeatedFieldWrongElementTypeExpectingMessagesGotBool) {
EXPECT_THAT(
Testee("RepeatedFieldWrongElementTypeExpectingMessagesGotBool")
.ParseJson(message(),
R"json({"repeatedNestedMessage": [{"a": 1}, false]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest,
RepeatedFieldWrongElementTypeExpectingMessagesGotString) {
EXPECT_THAT(
Testee("RepeatedFieldWrongElementTypeExpectingMessagesGotString")
.ParseJson(message(),
R"json({"repeatedNestedMessage": [{"a": 1}, "2"]})json")
.ParseOnly(),
Yields(IsParseError()));
}
// ---------------------------------------------------------------------------
// A single value where a repeated field was expected is rejected, even if it
// is of the right type.
// ---------------------------------------------------------------------------
TEST_P(JsonRepeatedTest, SingleValueForRepeatedFieldInt32) {
EXPECT_THAT(Testee("SingleValueForRepeatedFieldInt32")
.ParseJson(message(), R"json({"repeatedInt32": 1})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest, SingleValueForRepeatedFieldMessage) {
EXPECT_THAT(Testee("SingleValueForRepeatedFieldMessage")
.ParseJson(message(),
R"json({"repeatedNestedMessage": {"a": 1}})json")
.ParseOnly(),
Yields(IsParseError()));
}
// ---------------------------------------------------------------------------
// A trailing comma in a repeated field is rejected.
// ---------------------------------------------------------------------------
TEST_P(JsonRepeatedTest, RepeatedFieldTrailingComma) {
EXPECT_THAT(
Testee(kP1, "RepeatedFieldTrailingComma")
.ParseJson(message(), R"json({"repeatedInt32": [1, 2, 3, 4,]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest, RepeatedFieldTrailingCommaWithSpace) {
EXPECT_THAT(
Testee(kP1, "RepeatedFieldTrailingCommaWithSpace")
.ParseJson(message(), R"json({"repeatedInt32": [1, 2, 3, 4 ,]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest, RepeatedFieldTrailingCommaWithSpaceCommaSpace) {
EXPECT_THAT(
Testee(kP1, "RepeatedFieldTrailingCommaWithSpaceCommaSpace")
.ParseJson(message(), R"json({"repeatedInt32": [1, 2, 3, 4 , ]})json")
.ParseOnly(),
Yields(IsParseError()));
}
TEST_P(JsonRepeatedTest, RepeatedFieldTrailingCommaWithNewlines) {
EXPECT_THAT(
Testee(kP1, "RepeatedFieldTrailingCommaWithNewlines")
.ParseJson(message(),
"{\"repeatedInt32\": [\n 1,\n 2,\n 3,\n 4,\n]}")
.ParseOnly(),
Yields(IsParseError()));
}
INSTANTIATE_TEST_SUITE_P(All, JsonRepeatedTest, ValuesIn(AllTestMessageTypes()),
MessageTypeParamName);
} // namespace
} // namespace conformance
} // namespace protobuf
} // namespace google