@@ -219,6 +219,73 @@ TEST_F(TestFixedShapeTensorType, MetadataSerializationRoundtrip) {
219219 CheckDeserializationRaises (ext_type_, storage_type,
220220 R"( {"shape":[3],"dim_names":["x","y"]})" ,
221221 " Invalid dim_names" );
222+
223+ // Validate shape values must be integers. Error message should include the
224+ // JSON type name of the offending value.
225+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"shape":[3.5,4]})" ,
226+ " shape must contain integers, got Number" );
227+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"shape":["3","4"]})" ,
228+ " shape must contain integers, got String" );
229+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"shape":[null]})" ,
230+ " shape must contain integers, got Null" );
231+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"shape":[true]})" ,
232+ " shape must contain integers, got True" );
233+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"shape":[false]})" ,
234+ " shape must contain integers, got False" );
235+
236+ // Validate shape values must be non-negative
237+ CheckDeserializationRaises (ext_type_, fixed_size_list (int64 (), 1 ), R"( {"shape":[-1]})" ,
238+ " shape must have non-negative values" );
239+
240+ // Validate product of shape matches storage list_size
241+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"shape":[3,3]})" ,
242+ " Product of shape dimensions" );
243+
244+ // Validate permutation member must be an array with integer values
245+ CheckDeserializationRaises (ext_type_, storage_type,
246+ R"( {"shape":[3,4],"permutation":"invalid"})" ,
247+ " permutation must be an array, got String" );
248+ CheckDeserializationRaises (ext_type_, storage_type,
249+ R"( {"shape":[3,4],"permutation":{"a":1}})" ,
250+ " permutation must be an array, got Object" );
251+ CheckDeserializationRaises (ext_type_, storage_type,
252+ R"( {"shape":[3,4],"permutation":[1.5,0.5]})" ,
253+ " permutation must contain integers, got Number" );
254+ CheckDeserializationRaises (ext_type_, storage_type,
255+ R"( {"shape":[3,4],"permutation":["a","b"]})" ,
256+ " permutation must contain integers, got String" );
257+
258+ // Validate permutation values must be unique integers in [0, N-1]
259+ CheckDeserializationRaises (ext_type_, storage_type,
260+ R"( {"shape":[3,4],"permutation":[0,0]})" ,
261+ " Permutation indices" );
262+ CheckDeserializationRaises (ext_type_, storage_type,
263+ R"( {"shape":[3,4],"permutation":[0,5]})" ,
264+ " Permutation indices" );
265+ CheckDeserializationRaises (ext_type_, storage_type,
266+ R"( {"shape":[3,4],"permutation":[-1,0]})" ,
267+ " Permutation indices" );
268+
269+ // Validate dim_names member must be an array with string values
270+ CheckDeserializationRaises (ext_type_, storage_type,
271+ R"( {"shape":[3,4],"dim_names":"invalid"})" ,
272+ " dim_names must be an array, got String" );
273+ CheckDeserializationRaises (ext_type_, storage_type,
274+ R"( {"shape":[3,4],"dim_names":[1,2]})" ,
275+ " dim_names must contain strings, got Number" );
276+ CheckDeserializationRaises (ext_type_, storage_type,
277+ R"( {"shape":[3,4],"dim_names":[null,null]})" ,
278+ " dim_names must contain strings, got Null" );
279+ }
280+
281+ TEST_F (TestFixedShapeTensorType, MakeValidatesShape) {
282+ // Negative shape values should be rejected
283+ EXPECT_RAISES_WITH_MESSAGE_THAT (
284+ Invalid, testing::HasSubstr (" shape must have non-negative values" ),
285+ FixedShapeTensorType::Make (value_type_, {-1 }));
286+ EXPECT_RAISES_WITH_MESSAGE_THAT (
287+ Invalid, testing::HasSubstr (" shape must have non-negative values" ),
288+ FixedShapeTensorType::Make (value_type_, {3 , -1 , 4 }));
222289}
223290
224291TEST_F (TestFixedShapeTensorType, RoundtripBatch) {
@@ -794,6 +861,32 @@ TEST_F(TestVariableShapeTensorType, MetadataSerializationRoundtrip) {
794861 " Invalid: permutation" );
795862 CheckDeserializationRaises (ext_type_, storage_type, R"( {"dim_names":["x","y"]})" ,
796863 " Invalid: dim_names" );
864+
865+ // Validate permutation member must be an array with integer values. Error
866+ // message should include the JSON type name of the offending value.
867+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"permutation":"invalid"})" ,
868+ " permutation must be an array, got String" );
869+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"permutation":[1.5,0.5,2.5]})" ,
870+ " permutation must contain integers, got Number" );
871+ CheckDeserializationRaises (ext_type_, storage_type,
872+ R"( {"permutation":[null,null,null]})" ,
873+ " permutation must contain integers, got Null" );
874+
875+ // Validate dim_names member must be an array with string values
876+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"dim_names":"invalid"})" ,
877+ " dim_names must be an array, got String" );
878+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"dim_names":[1,2,3]})" ,
879+ " dim_names must contain strings, got Number" );
880+
881+ // Validate uniform_shape member must be an array with integer-or-null values
882+ CheckDeserializationRaises (ext_type_, storage_type, R"( {"uniform_shape":"invalid"})" ,
883+ " uniform_shape must be an array, got String" );
884+ CheckDeserializationRaises (ext_type_, storage_type,
885+ R"( {"uniform_shape":[1.5,null,null]})" ,
886+ " uniform_shape must contain integers or nulls, got Number" );
887+ CheckDeserializationRaises (ext_type_, storage_type,
888+ R"( {"uniform_shape":["x",null,null]})" ,
889+ " uniform_shape must contain integers or nulls, got String" );
797890}
798891
799892TEST_F (TestVariableShapeTensorType, RoundtripBatch) {
0 commit comments