@@ -636,6 +636,41 @@ def test_retry_after_int_stored_in_details(self):
636636 self .client ._request ("get" , "http://example.com/test" )
637637 self .assertEqual (ctx .exception .details .get ("retry_after" ), 30 )
638638
639+ def test_innererror_message_appended_to_top_level (self ):
640+ """error.innererror.message is appended to the top-level message so the
641+ offending field/dtype reaches the user instead of being hidden in the
642+ wire payload."""
643+ response = self ._make_raw_response (
644+ 400 ,
645+ json_data = {
646+ "error" : {
647+ "code" : "0x80060891" ,
648+ "message" : "Error identified in Payload provided by the user for Entity :contacts" ,
649+ "innererror" : {
650+ "message" : "Field 'birthdate' is a Date type and cannot accept a DateTime value with offset." ,
651+ "type" : "System.Exception" ,
652+ },
653+ }
654+ },
655+ )
656+ self .client ._raw_request = MagicMock (return_value = response )
657+ with self .assertRaises (HttpError ) as ctx :
658+ self .client ._request ("post" , "http://example.com/contacts" )
659+ self .assertIn ("Error identified in Payload" , str (ctx .exception ))
660+ self .assertIn ("birthdate" , str (ctx .exception ))
661+ self .assertIn ("DateTime value with offset" , str (ctx .exception ))
662+
663+ def test_no_innererror_message_unchanged (self ):
664+ """Absence of innererror leaves the top-level message untouched."""
665+ response = self ._make_raw_response (
666+ 400 ,
667+ json_data = {"error" : {"code" : "0x0" , "message" : "Bad request" }},
668+ )
669+ self .client ._raw_request = MagicMock (return_value = response )
670+ with self .assertRaises (HttpError ) as ctx :
671+ self .client ._request ("get" , "http://example.com/test" )
672+ self .assertEqual (ctx .exception .message , "Bad request" )
673+
639674
640675class TestCreateMultiple (unittest .TestCase ):
641676 """Unit tests for _ODataClient._create_multiple."""
@@ -1558,6 +1593,20 @@ def test_double_dtype_alias(self):
15581593 result = self .od ._attribute_payload ("new_Score" , "double" )
15591594 self .assertIn ("Double" , result ["@odata.type" ])
15601595
1596+ def test_float_dtype_precision_default_is_5 (self ):
1597+ """'float' must default to the max Double precision (5) so values
1598+ like 2.718 round-trip without silent truncation. Regression guard
1599+ for the previous Precision=2 default."""
1600+ result = self .od ._attribute_payload ("new_Score" , "float" )
1601+ self .assertEqual (result ["Precision" ], 5 )
1602+
1603+ def test_decimal_dtype_precision_unchanged_at_2 (self ):
1604+ """'decimal'/'money' should keep Precision=2 because that matches
1605+ currency semantics. Regression guard so a future cleanup doesn't
1606+ quietly broaden this along with float."""
1607+ result = self .od ._attribute_payload ("new_Revenue" , "decimal" )
1608+ self .assertEqual (result ["Precision" ], 2 )
1609+
15611610 def test_datetime_dtype (self ):
15621611 """'datetime' produces DateTimeAttributeMetadata."""
15631612 result = self .od ._attribute_payload ("new_CreatedDate" , "datetime" )
0 commit comments