1818#include " google/cloud/testing_util/is_proto_equal.h"
1919#include " google/cloud/testing_util/status_matchers.h"
2020#include " absl/strings/cord.h"
21+ #include " absl/strings/substitute.h"
2122#include < google/protobuf/text_format.h>
2223#include < google/type/date.pb.h>
2324#include < gmock/gmock.h>
@@ -40,6 +41,7 @@ namespace {
4041using ::google::cloud::testing_util::IsOk;
4142using ::google::cloud::testing_util::IsOkAndHolds;
4243using ::google::cloud::testing_util::IsProtoEqual;
44+ using ::google::cloud::testing_util::StatusIs;
4345using ::google::protobuf::TextFormat;
4446using ::testing::Not;
4547
@@ -1749,40 +1751,44 @@ TEST(Value, OutputStreamMatchesT) {
17491751}
17501752
17511753void TestTypeAndValuesMatch (std::string const & type_text,
1752- std::string const & value_text, bool expected) {
1754+ std::string const & value_text,
1755+ Status const & expected_status) {
17531756 google::bigtable::v2::Type type;
17541757 ASSERT_TRUE (TextFormat::ParseFromString (type_text, &type));
17551758 google::bigtable::v2::Value value;
17561759 ASSERT_TRUE (TextFormat::ParseFromString (value_text, &value));
17571760 auto result = Value::TypeAndValuesMatch (type, value);
1758- if (expected) {
1759- EXPECT_STATUS_OK (result);
1760- } else {
1761- EXPECT_THAT (result, Not (IsOk ()));
1762- }
1761+ EXPECT_THAT (result,
1762+ StatusIs (expected_status.code (), expected_status.message ()));
17631763}
17641764
17651765TEST (Value, TypeAndValuesMatchScalar) {
1766- TestTypeAndValuesMatch (" int64_type {}" , " int_value: 123" , true );
1767- TestTypeAndValuesMatch (" string_type {}" , " string_value: 'hello'" , true );
1768- TestTypeAndValuesMatch (" bool_type {}" , " bool_value: true" , true );
1769- TestTypeAndValuesMatch (" float64_type {}" , " float_value: 3.14" , true );
1770- TestTypeAndValuesMatch (" float32_type {}" , " float_value: 3.14" , true );
1771- TestTypeAndValuesMatch (" bytes_type {}" , " bytes_value: 'bytes'" , true );
1766+ TestTypeAndValuesMatch (" int64_type {}" , " int_value: 123" , Status{} );
1767+ TestTypeAndValuesMatch (" string_type {}" , " string_value: 'hello'" , Status{} );
1768+ TestTypeAndValuesMatch (" bool_type {}" , " bool_value: true" , Status{} );
1769+ TestTypeAndValuesMatch (" float64_type {}" , " float_value: 3.14" , Status{} );
1770+ TestTypeAndValuesMatch (" float32_type {}" , " float_value: 3.14" , Status{} );
1771+ TestTypeAndValuesMatch (" bytes_type {}" , " bytes_value: 'bytes'" , Status{} );
17721772 TestTypeAndValuesMatch (" timestamp_type {}" ,
1773- " timestamp_value: { seconds: 123 }" , true );
1774- TestTypeAndValuesMatch (" date_type {} " ,
1775- " date_value: { year: 2025, month: 1, day: 1 }" , true );
1773+ " timestamp_value: { seconds: 123 }" , Status{} );
1774+ TestTypeAndValuesMatch (
1775+ " date_type {} " , " date_value: { year: 2025, month: 1, day: 1 }" , Status{} );
17761776}
17771777
17781778TEST (Value, TypeAndValuesMatchScalarMismatch) {
1779- TestTypeAndValuesMatch (" int64_type {}" , " string_value: 'mismatch'" , false );
1780- TestTypeAndValuesMatch (" string_type {}" , " int_value: 123" , false );
1779+ TestTypeAndValuesMatch (
1780+ " int64_type {}" , " string_value: 'mismatch'" ,
1781+ internal::InternalError (
1782+ " Value kind must be INT_VALUE for columns of type: INT64" ));
1783+ TestTypeAndValuesMatch (
1784+ " string_type {}" , " int_value: 123" ,
1785+ internal::InternalError (
1786+ " Value kind must be STRING_VALUE for columns of type: STRING" ));
17811787}
17821788
17831789TEST (Value, TypeAndValuesMatchNullScalar) {
1784- TestTypeAndValuesMatch (" int64_type {}" , " " , true );
1785- TestTypeAndValuesMatch (" string_type {}" , " " , true );
1790+ TestTypeAndValuesMatch (" int64_type {}" , " " , Status{} );
1791+ TestTypeAndValuesMatch (" string_type {}" , " " , Status{} );
17861792}
17871793
17881794TEST (Value, TypeAndValuesMatchArray) {
@@ -1795,7 +1801,7 @@ TEST(Value, TypeAndValuesMatchArray) {
17951801 values { int_value: 2 }
17961802 }
17971803 )pb" ;
1798- TestTypeAndValuesMatch (type, matching_value, true );
1804+ TestTypeAndValuesMatch (type, matching_value, Status{} );
17991805}
18001806
18011807TEST (Value, TypeAndValuesMatchArrayMismatchElementType) {
@@ -1808,14 +1814,20 @@ TEST(Value, TypeAndValuesMatchArrayMismatchElementType) {
18081814 values { string_value: "2" }
18091815 }
18101816 )pb" ;
1811- TestTypeAndValuesMatch (type, mismatched_value, false );
1817+ TestTypeAndValuesMatch (
1818+ type, mismatched_value,
1819+ internal::InternalError (
1820+ " Value kind must be INT_VALUE for columns of type: INT64" ));
18121821}
18131822
18141823TEST (Value, TypeAndValuesMatchArrayMismatchScalar) {
18151824 auto const * type = R"pb(
18161825 array_type { element_type { int64_type {} } }
18171826 )pb" ;
1818- TestTypeAndValuesMatch (type, " int_value: 123" , false );
1827+ TestTypeAndValuesMatch (type, " int_value: 123" ,
1828+ internal::InternalError (" Value kind must be "
1829+ " ARRAY_VALUE for columns of "
1830+ " type: MAP" ));
18191831}
18201832
18211833TEST (Value, TypeAndValuesMatchArrayWithNull) {
@@ -1829,7 +1841,7 @@ TEST(Value, TypeAndValuesMatchArrayWithNull) {
18291841 values { int_value: 3 }
18301842 }
18311843 )pb" ;
1832- TestTypeAndValuesMatch (type, value_with_null, true );
1844+ TestTypeAndValuesMatch (type, value_with_null, Status{} );
18331845}
18341846
18351847TEST (Value, TypeAndValuesMatchStruct) {
@@ -1851,7 +1863,7 @@ TEST(Value, TypeAndValuesMatchStruct) {
18511863 values { int_value: 42 }
18521864 }
18531865 )pb" ;
1854- TestTypeAndValuesMatch (type, matching_value, true );
1866+ TestTypeAndValuesMatch (type, matching_value, Status{} );
18551867}
18561868
18571869TEST (Value, TypeAndValuesMatchStructMismatchFieldType) {
@@ -1873,7 +1885,10 @@ TEST(Value, TypeAndValuesMatchStructMismatchFieldType) {
18731885 values { string_value: "42" }
18741886 }
18751887 )pb" ;
1876- TestTypeAndValuesMatch (type, mismatched_value, false );
1888+ TestTypeAndValuesMatch (
1889+ type, mismatched_value,
1890+ internal::InternalError (
1891+ " Value kind must be INT_VALUE for columns of type: INT64" ));
18771892}
18781893
18791894TEST (Value, TypeAndValuesMatchStructMismatchFieldCount) {
@@ -1886,16 +1901,20 @@ TEST(Value, TypeAndValuesMatchStructMismatchFieldCount) {
18861901 auto const * mismatched_value = R"pb(
18871902 array_value { values { string_value: "John" } }
18881903 )pb" ;
1889- // The current implementation has a bug and will return true here.
1890- // This test will fail until the bug is fixed.
1891- TestTypeAndValuesMatch (type, mismatched_value, false );
1904+ TestTypeAndValuesMatch (
1905+ type, mismatched_value,
1906+ internal::InternalError (
1907+ " received Struct with 1 values, but metadata has 2 fields" ));
18921908}
18931909
18941910TEST (Value, TypeAndValuesMatchStructMismatchScalar) {
18951911 auto const * type = R"pb(
18961912 struct_type { fields { type { string_type {} } } }
18971913 )pb" ;
1898- TestTypeAndValuesMatch (type, " string_value: 'John'" , false );
1914+ TestTypeAndValuesMatch (
1915+ type, " string_value: 'John'" ,
1916+ internal::InternalError (
1917+ " Value kind must be ARRAY_VALUE for columns of type: STRUCT" ));
18991918}
19001919
19011920TEST (Value, TypeAndValuesMatchStructWithNull) {
@@ -1911,7 +1930,7 @@ TEST(Value, TypeAndValuesMatchStructWithNull) {
19111930 values {}
19121931 }
19131932 )pb" ;
1914- TestTypeAndValuesMatch (type, value_with_null, true );
1933+ TestTypeAndValuesMatch (type, value_with_null, Status{} );
19151934}
19161935
19171936TEST (Value, TypeAndValuesMatchMap) {
@@ -1931,7 +1950,7 @@ TEST(Value, TypeAndValuesMatchMap) {
19311950 }
19321951 }
19331952 )pb" ;
1934- TestTypeAndValuesMatch (type, matching_value, true );
1953+ TestTypeAndValuesMatch (type, matching_value, Status{} );
19351954}
19361955
19371956TEST (Value, TypeAndValuesMatchMapMismatchKeyType) {
@@ -1951,7 +1970,10 @@ TEST(Value, TypeAndValuesMatchMapMismatchKeyType) {
19511970 }
19521971 }
19531972 )pb" ;
1954- TestTypeAndValuesMatch (type, mismatched_value, false );
1973+ TestTypeAndValuesMatch (
1974+ type, mismatched_value,
1975+ internal::InternalError (
1976+ " Value kind must be STRING_VALUE for columns of type: STRING" ));
19551977}
19561978
19571979TEST (Value, TypeAndValuesMatchMapMismatchValueType) {
@@ -1971,7 +1993,10 @@ TEST(Value, TypeAndValuesMatchMapMismatchValueType) {
19711993 }
19721994 }
19731995 )pb" ;
1974- TestTypeAndValuesMatch (type, mismatched_value, false );
1996+ TestTypeAndValuesMatch (
1997+ type, mismatched_value,
1998+ internal::InternalError (
1999+ " Value kind must be INT_VALUE for columns of type: INT64" ));
19752000}
19762001
19772002TEST (Value, TypeAndValuesMatchMapMismatchScalar) {
@@ -1981,7 +2006,10 @@ TEST(Value, TypeAndValuesMatchMapMismatchScalar) {
19812006 value_type { int64_type {} }
19822007 }
19832008 )pb" ;
1984- TestTypeAndValuesMatch (type, " string_value: 'foo'" , false );
2009+ TestTypeAndValuesMatch (
2010+ type, " string_value: 'foo'" ,
2011+ internal::InternalError (
2012+ " Value kind must be ARRAY_VALUE for columns of type: MAP" ));
19852013}
19862014
19872015TEST (Value, TypeAndValuesMatchMapMalformedEntry) {
@@ -1994,7 +2022,9 @@ TEST(Value, TypeAndValuesMatchMapMalformedEntry) {
19942022 auto const * malformed_value = R"pb(
19952023 array_value { values { array_value { values { string_value: "key1" } } } }
19962024 )pb" ;
1997- TestTypeAndValuesMatch (type, malformed_value, false );
2025+ TestTypeAndValuesMatch (
2026+ type, malformed_value,
2027+ internal::InternalError (" ARRAY_VALUE must contain entries of 2 values" ));
19982028}
19992029
20002030TEST (Value, TypeAndValuesMatchMapWithNullValue) {
@@ -2014,7 +2044,36 @@ TEST(Value, TypeAndValuesMatchMapWithNullValue) {
20142044 }
20152045 }
20162046 )pb" ;
2017- TestTypeAndValuesMatch (type, value_with_null, true );
2047+ TestTypeAndValuesMatch (type, value_with_null, Status{});
2048+ }
2049+
2050+ TEST (Value, TypeAndValuesMatchDepthExceeded) {
2051+ std::string type_text = " int64_type {}" ;
2052+ std::string value_text = " int_value: 1" ;
2053+
2054+ // Each layer of struct nesting increases the depth count. The initial call is
2055+ // at depth 1. With the current implementation, each level of nesting
2056+ // increases the depth by 2. To exceed the limit of 10, we need 5 levels of
2057+ // nesting, which will result in a call with depth 11.
2058+ for (int i = 0 ; i < 5 ; ++i) {
2059+ type_text =
2060+ absl::Substitute (" struct_type { fields { type { $0 } } }" , type_text);
2061+ value_text = absl::Substitute (" array_value { values { $0 } }" , value_text);
2062+ }
2063+
2064+ TestTypeAndValuesMatch (
2065+ type_text, value_text,
2066+ internal::InternalError (" Nested value depth exceeds 10 levels" ));
2067+
2068+ // Verify that nesting up to the limit is fine. 4 levels of nesting will
2069+ // result in a maximum depth of 9.
2070+ type_text = " int64_type {}" ;
2071+ value_text = " int_value: 1" ;
2072+ for (int i = 0 ; i < 4 ; ++i) {
2073+ type_text = " struct_type { fields { type { " + type_text + " } } }" ;
2074+ value_text = " array_value { values { " + value_text + " } }" ;
2075+ }
2076+ TestTypeAndValuesMatch (type_text, value_text, Status{});
20182077}
20192078
20202079} // namespace
0 commit comments