From c41d1d7d788137b22b9fd09a4a20f7c86d7c512a Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Mon, 6 May 2019 18:00:49 -0700 Subject: [PATCH] Add JsonException and make JsonSerializationException derive from JsonException and be internal (dotnet/corefx#37275) Commit migrated from https://github.com/dotnet/corefx/commit/f6762c0e37641bf31b9957dc51e74089bac5a310 --- .../tests/BinaryFormatterTestData.cs | 14 +- .../tests/EqualityExtensions.cs | 3 +- .../System.Text.Json/ref/System.Text.Json.cs | 17 +- .../System.Text.Json/src/Resources/Strings.resx | 5 +- .../System.Text.Json/src/System.Text.Json.csproj | 5 +- .../Text/Json/Document/JsonDocument.Parse.cs | 16 +- .../src/System/Text/Json/JsonCommentHandling.cs | 2 +- .../src/System/Text/Json/JsonException.cs | 86 ++++++++++ .../System/Text/Json/Reader/JsonReaderException.cs | 51 +----- .../System/Text/Json/Reader/JsonReaderOptions.cs | 6 +- .../Json/Reader/Utf8JsonReader.MultiSegment.cs | 2 +- .../src/System/Text/Json/Reader/Utf8JsonReader.cs | 4 +- .../Text/Json/Serialization/JsonPropertyInfo.cs | 2 +- .../Serialization/JsonPropertyInfoNotNullable.cs | 8 +- .../Json/Serialization/JsonPropertyInfoNullable.cs | 10 +- .../JsonSerializer.Read.HandleArray.cs | 98 +++++++---- .../JsonSerializer.Read.HandleNull.cs | 6 +- .../JsonSerializer.Read.HandleObject.cs | 6 +- .../Json/Serialization/JsonSerializer.Read.Span.cs | 7 +- .../Serialization/JsonSerializer.Read.Stream.cs | 8 +- .../Serialization/JsonSerializer.Read.String.cs | 8 +- .../Text/Json/Serialization/JsonSerializer.Read.cs | 146 +++++++++-------- .../Json/Serialization/JsonSerializerOptions.cs | 6 +- .../Text/Json/Serialization/ReadStackFrame.cs | 2 +- .../System/Text/Json/ThrowHelper.Serialization.cs | 49 +++++- .../src/System/Text/Json/ThrowHelper.cs | 2 +- .../System.Text.Json/tests/JsonDocumentTests.cs | 44 ++--- .../System.Text.Json/tests/JsonTestHelper.cs | 2 +- .../tests/Serialization/DictionaryTests.cs | 12 +- .../tests/Serialization/EnumTests.cs | 2 +- .../tests/Serialization/ExceptionTests.cs | 83 ++++++++++ .../tests/Serialization/Object.ReadTests.cs | 14 +- .../tests/Serialization/OptionsTests.cs | 8 +- .../tests/Serialization/PolymorphicTests.cs | 4 +- .../tests/Serialization/PropertyNameTests.cs | 2 - .../tests/Serialization/TestClasses.cs | 40 ++--- .../tests/Serialization/Value.ReadTests.cs | 180 ++++++++++----------- .../tests/System.Text.Json.Tests.csproj | 3 +- .../tests/Utf8JsonReaderTests.MultiSegment.cs | 20 +-- .../System.Text.Json/tests/Utf8JsonReaderTests.cs | 74 ++++----- 40 files changed, 638 insertions(+), 419 deletions(-) create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/JsonException.cs create mode 100644 src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs index 57c2dc1..ff40a8e 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs @@ -472,8 +472,18 @@ namespace System.Runtime.Serialization.Formatters.Tests yield return new object[] { PopulateException(isolatedStorageException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } }; #if netcoreapp - var jsonReaderException = new JsonReaderException("message", lineNumber: 0, bytePositionInLine: 0); - yield return new object[] { PopulateException(jsonReaderException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNTeXN0ZW0uVGV4dC5Kc29uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Y2M3YjEzZmZjZDJkZGQ1MQUBAAAAJFN5c3RlbS5UZXh0Lkpzb24uSnNvblJlYWRlckV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCkxpbmVOdW1iZXISQnl0ZVBvc2l0aW9uSW5MaW5lAQEDAwEBAQABAAEHAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgkJAgAAAAYDAAAAJFN5c3RlbS5UZXh0Lkpzb24uSnNvblJlYWRlckV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoAAAAAAAAAAAAAAAAAAAAABAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp30) } }; + var jsonException = new JsonException("message", path: "path", lineNumber: 1, bytePositionInLine: 2, innerException: exception); + yield return new object[] { PopulateException(jsonException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNTeXN0ZW0uVGV4dC5Kc29uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Y2M3YjEzZmZjZDJkZGQ1MQUBAAAAHlN5c3RlbS5UZXh0Lkpzb24uSnNvbkV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCkxpbmVOdW1iZXISQnl0ZVBvc2l0aW9uSW5MaW5lBFBhdGgBAQMDAQEBAAEAAQcDAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgxTeXN0ZW0uSW50NjQMU3lzdGVtLkludDY0AgAAAAYDAAAAHlN5c3RlbS5UZXh0Lkpzb24uSnNvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCAkBAAAAAAAAAAgJAgAAAAAAAAAGCwAAAARwYXRoBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netcoreapp30) } }; + + var jsonExceptionNulls = new JsonException("message", null, null, null); + yield return new object[] { PopulateException(jsonExceptionNulls), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNTeXN0ZW0uVGV4dC5Kc29uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Y2M3YjEzZmZjZDJkZGQ1MQUBAAAAHlN5c3RlbS5UZXh0Lkpzb24uSnNvbkV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCkxpbmVOdW1iZXISQnl0ZVBvc2l0aW9uSW5MaW5lBFBhdGgBAQMDAQEBAAEAAQcDAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAm5TeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXW5TeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAGAwAAAB5TeXN0ZW0uVGV4dC5Kc29uLkpzb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAKBgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp30) } }; + + // The JsonReaderException is internal. + Exception jsonReaderException = (Exception)typeof(JsonException).Assembly.GetType("System.Text.Json.JsonReaderException", throwOnError: true) + .GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(long), typeof(long) }, null ) + .Invoke(new object[] { "message", 1, 2 }); + + yield return new object[] { PopulateException(jsonReaderException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNTeXN0ZW0uVGV4dC5Kc29uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Y2M3YjEzZmZjZDJkZGQ1MQUBAAAAJFN5c3RlbS5UZXh0Lkpzb24uSnNvblJlYWRlckV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCkxpbmVOdW1iZXISQnl0ZVBvc2l0aW9uSW5MaW5lBFBhdGgBAQMDAQEBAAEAAQcDAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgxTeXN0ZW0uSW50NjQMU3lzdGVtLkludDY0AgAAAAYDAAAAJFN5c3RlbS5UZXh0Lkpzb24uSnNvblJlYWRlckV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoICQEAAAAAAAAACAkCAAAAAAAAAAoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp30) } }; #endif var keyNotFoundException = new KeyNotFoundException("message", exception); diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/EqualityExtensions.cs b/src/libraries/System.Runtime.Serialization.Formatters/tests/EqualityExtensions.cs index 9b53861..028610c 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/EqualityExtensions.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/tests/EqualityExtensions.cs @@ -1202,7 +1202,7 @@ namespace System.Runtime.Serialization.Formatters.Tests } #if netcoreapp - public static void IsEqual(this JsonReaderException @this, JsonReaderException other, bool isSamePlatform) + public static void IsEqual(this JsonException @this, JsonException other, bool isSamePlatform) { if (@this == null && other == null) return; @@ -1210,6 +1210,7 @@ namespace System.Runtime.Serialization.Formatters.Tests Assert.NotNull(@this); Assert.NotNull(other); IsEqual(@this as Exception, other as Exception, isSamePlatform); + Assert.Equal(@this.Path, other.Path); Assert.Equal(@this.LineNumber, other.LineNumber); Assert.Equal(@this.BytePositionInLine, other.BytePositionInLine); } diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index cb0b5a2..fe1345d 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -113,6 +113,16 @@ namespace System.Text.Json public override int GetHashCode() { throw null; } public override string ToString() { throw null; } } + public partial class JsonException : System.Exception + { + protected JsonException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } + public JsonException(string message, string path, long? lineNumber, long? bytePositionInLine) { } + public JsonException(string message, string path, long? lineNumber, long? bytePositionInLine, System.Exception innerException) { } + public long? BytePositionInLine { get { throw null; } } + public long? LineNumber { get { throw null; } } + public string Path { get { throw null; } } + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } + } public readonly partial struct JsonProperty { private readonly object _dummy; @@ -120,13 +130,6 @@ namespace System.Text.Json public System.Text.Json.JsonElement Value { get { throw null; } } public override string ToString() { throw null; } } - public sealed partial class JsonReaderException : System.Exception - { - public JsonReaderException(string message, long lineNumber, long bytePositionInLine) { } - public long BytePositionInLine { get { throw null; } } - public long LineNumber { get { throw null; } } - public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } - } public partial struct JsonReaderOptions { private int _dummyPrimitive; diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx index c7ac357..c2a1da6 100644 --- a/src/libraries/System.Text.Json/src/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx @@ -289,7 +289,7 @@ The provided data of length {0} has remaining bytes {1}. - The JSON value from {0} could not be converted to {1}. + The JSON value could not be converted to {0}. The specified type {0} must derive from the specific value's type {1}. @@ -336,4 +336,7 @@ The JSON property name for '{0}.{1}' cannot be null. + + An item with the same property name '{0}' has already been added. + \ No newline at end of file diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 1bdb995..99d08f7 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -15,6 +15,7 @@ + @@ -34,9 +35,9 @@ - + @@ -166,4 +167,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs index 22f7401..9c22f53 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs @@ -33,7 +33,7 @@ namespace System.Text.Json /// /// A JsonDocument representation of the JSON value. /// - /// + /// /// does not represent a valid single JSON value. /// /// @@ -65,7 +65,7 @@ namespace System.Text.Json /// /// A JsonDocument representation of the JSON value. /// - /// + /// /// does not represent a valid single JSON value. /// /// @@ -106,7 +106,7 @@ namespace System.Text.Json /// /// A JsonDocument representation of the JSON value. /// - /// + /// /// does not represent a valid single JSON value. /// /// @@ -146,7 +146,7 @@ namespace System.Text.Json /// /// A Task to produce a JsonDocument representation of the JSON value. /// - /// + /// /// does not represent a valid single JSON value. /// /// @@ -200,7 +200,7 @@ namespace System.Text.Json /// /// A JsonDocument representation of the JSON value. /// - /// + /// /// does not represent a valid single JSON value. /// /// @@ -238,7 +238,7 @@ namespace System.Text.Json /// /// A JsonDocument representation of the JSON value. /// - /// + /// /// does not represent a valid single JSON value. /// /// @@ -291,7 +291,7 @@ namespace System.Text.Json /// /// The current token does not start or represent a value. /// - /// + /// /// A value could not be read from the reader. /// public static bool TryParseValue(ref Utf8JsonReader reader, out JsonDocument document) @@ -331,7 +331,7 @@ namespace System.Text.Json /// /// The current token does not start or represent a value. /// - /// + /// /// A value could not be read from the reader. /// public static JsonDocument ParseValue(ref Utf8JsonReader reader) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonCommentHandling.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonCommentHandling.cs index d5d8f8a..afe1fbf 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonCommentHandling.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonCommentHandling.cs @@ -12,7 +12,7 @@ namespace System.Text.Json /// /// By default, do no allow comments within the JSON input. /// Comments are treated as invalid JSON if found and a - /// is thrown. + /// is thrown. /// Disallow = 0, /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonException.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonException.cs new file mode 100644 index 0000000..b7022d7 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonException.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; + +namespace System.Text.Json +{ + /// + /// Defines a custom exception object that is thrown when invalid JSON text is encountered, when the defined maximum depth is passed, + /// or the JSON text is not compatible with the type of a property on an object. + /// + [Serializable] + public class JsonException : Exception + { + /// + /// Creates a new exception object to relay error information to the user. + /// + /// The context specific error message. + /// The line number at which the invalid JSON was encountered (starting at 0) when deserializing. + /// The byte count within the current line where the invalid JSON was encountered (starting at 0). + /// The object's property path where the invalid JSON was encountered. + /// The exception that caused the current exception. + /// + /// Note that the counts the number of bytes (i.e. UTF-8 code units) and not characters or scalars. + /// + public JsonException(string message, string path, long? lineNumber, long? bytePositionInLine, Exception innerException) : base(message, innerException) + { + LineNumber = lineNumber; + BytePositionInLine = bytePositionInLine; + Path = path; + } + + /// + /// Creates a new exception object to relay error information to the user. + /// + /// The context specific error message. + /// The object's property path where the invalid JSON was encountered. + /// The line number at which the invalid JSON was encountered (starting at 0) when deserializing. + /// The byte count within the current line where the invalid JSON was encountered (starting at 0). + /// + /// Note that the counts the number of bytes (i.e. UTF-8 code units) and not characters or scalars. + /// + public JsonException(string message, string path, long? lineNumber, long? bytePositionInLine) : base(message) + { + LineNumber = lineNumber; + BytePositionInLine = bytePositionInLine; + Path = path; + } + + protected JsonException(SerializationInfo info, StreamingContext context) : base(info, context) + { + LineNumber = (long?)info.GetValue("LineNumber", typeof(long?)); + BytePositionInLine = (long?)info.GetValue("BytePositionInLine", typeof(long?)); + Path = info.GetString("Path"); + } + + /// + /// Sets the with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("LineNumber", LineNumber, typeof(long?)); + info.AddValue("BytePositionInLine", BytePositionInLine, typeof(long?)); + info.AddValue("Path", Path, typeof(string)); + } + + /// + /// The number of lines read so far before the exception (starting at 0). + /// + public long? LineNumber { get; private set; } + + /// + /// The number of bytes read within the current line before the exception (starting at 0). + /// + public long? BytePositionInLine { get; private set; } + + /// + /// The property path within the JSON where the exception was encountered. + /// + public string Path { get; private set; } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderException.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderException.cs index f724941..d0a9067 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderException.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderException.cs @@ -6,61 +6,16 @@ using System.Runtime.Serialization; namespace System.Text.Json { - /// - /// Defines a custom exception object that is thrown by the whenever it - /// encounters an invalid JSON text while reading through it. This exception is also thrown - /// whenever you read past the defined maximum depth. - /// + // This class exists because the serializer needs to catch reader-originated exceptions in order to throw JsonException which has Path information. [Serializable] - public sealed class JsonReaderException : Exception + internal sealed class JsonReaderException : JsonException { - /// - /// Creates a new exception object to relay error information to the user. - /// - /// The context specific error message. - /// The line number at which the invalid JSON was encountered (starting at 0). - /// The byte count within the current line where the invalid JSON was encountered (starting at 0). - /// - /// Note that the counts the number of bytes (i.e. UTF-8 code units) and not characters or scalars. - /// - public JsonReaderException(string message, long lineNumber, long bytePositionInLine) : base(message) + public JsonReaderException(string message, long lineNumber, long bytePositionInLine) : base(message, path : null, lineNumber, bytePositionInLine) { - LineNumber = lineNumber; - BytePositionInLine = bytePositionInLine; - } - - internal JsonReaderException(string message, in JsonReaderState state) : base(message) - { - LineNumber = state._lineNumber; - BytePositionInLine = state._bytePositionInLine; } private JsonReaderException(SerializationInfo info, StreamingContext context) : base(info, context) { - LineNumber = info.GetInt64("LineNumber"); - BytePositionInLine = info.GetInt64("BytePositionInLine"); - } - - /// - /// Sets the with information about the exception. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("LineNumber", LineNumber, typeof(long)); - info.AddValue("BytePositionInLine", BytePositionInLine, typeof(long)); } - - /// - /// The number of lines read so far before the exception (starting at 0). - /// - public long LineNumber { get; private set; } - - /// - /// The number of bytes read within the current line before the exception (starting at 0). - /// - public long BytePositionInLine { get; private set; } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderOptions.cs index e5d1b83..7e1fb7e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/JsonReaderOptions.cs @@ -15,13 +15,13 @@ namespace System.Text.Json /// /// Defines how the should handle comments when reading through the JSON. - /// By default is thrown if a comment is encountered. + /// By default is thrown if a comment is encountered. /// public JsonCommentHandling CommentHandling { get; set; } /// /// Gets or sets the maximum depth allowed when reading JSON, with the default (i.e. 0) indicating a max depth of 64. - /// Reading past this depth will throw a . + /// Reading past this depth will throw a . /// public int MaxDepth { @@ -38,7 +38,7 @@ namespace System.Text.Json /// /// Defines whether an extra comma at the end of a list of JSON values in an object or array /// is allowed (and ignored) within the JSON payload being read. - /// By default, it's set to false, and is thrown if a trailing comma is encountered. + /// By default, it's set to false, and is thrown if a trailing comma is encountered. /// public bool AllowTrailingCommas { get; set; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs index e0680f8..bca3f5a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs @@ -622,7 +622,7 @@ namespace System.Text.Json return indexOfFirstMismatch; } - private JsonReaderException GetInvalidLiteralMultiSegment(ReadOnlySpan span) + private JsonException GetInvalidLiteralMultiSegment(ReadOnlySpan span) { byte firstByte = span[0]; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs index 0a36d74..e2b5fa1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs @@ -13,7 +13,7 @@ namespace System.Text.Json /// Provides a high-performance API for forward-only, read-only access to the UTF-8 encoded JSON text. /// It processes the text sequentially with no caching and adheres strictly to the JSON RFC /// by default (https://tools.ietf.org/html/rfc8259). When it encounters invalid JSON, it throws - /// a JsonReaderException with basic error information like line number and byte position on the line. + /// a JsonException with basic error information like line number and byte position on the line. /// Since this type is a ref struct, it does not directly support async. However, it does provide /// support for reentrancy to read incomplete data, and continue reading once more data is presented. /// To be able to set max depth while reading OR allow skipping comments, create an instance of @@ -242,7 +242,7 @@ namespace System.Text.Json /// Read the next JSON token from input source. /// /// True if the token was read successfully, else false. - /// + /// /// Thrown when an invalid JSON token is encountered according to the JSON RFC /// or if the current depth exceeds the recursive limit set by the max depth. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs index 81dedb6..3849ba4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs @@ -259,7 +259,7 @@ namespace System.Text.Json.Serialization return (TAttribute)PropertyInfo?.GetCustomAttribute(typeof(TAttribute), inherit: false); } - public abstract void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state); + public abstract void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader); public abstract IList CreateConverterList(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs index 14c445c..9c09216 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNotNullable.cs @@ -59,7 +59,7 @@ namespace System.Text.Json.Serialization } } - ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.PropertyPath); } } @@ -68,14 +68,14 @@ namespace System.Text.Json.Serialization { if (ValueConverter == null || !ValueConverter.TryRead(RuntimePropertyType, ref reader, out TRuntimeProperty value)) { - ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.PropertyPath); return; } - JsonSerializer.ApplyValueToEnumerable(ref value, options, ref state.Current); + JsonSerializer.ApplyValueToEnumerable(ref value, options, ref state, ref reader); } - public override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state) + public override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { Debug.Assert(state.Current.JsonPropertyInfo != null); state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value : null); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs index afdfcdc..5a3ce95 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoNullable.cs @@ -56,7 +56,7 @@ namespace System.Text.Json.Serialization } } - ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.PropertyPath); } } @@ -64,19 +64,19 @@ namespace System.Text.Json.Serialization { if (ValueConverter == null || !ValueConverter.TryRead(typeof(TProperty), ref reader, out TProperty value)) { - ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.PropertyPath); return; } // Converting to TProperty? here lets us share a common ApplyValue() with ApplyNullValue(). TProperty? nullableValue = new TProperty?(value); - JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state.Current); + JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state, ref reader); } - public override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state) + public override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { TProperty? nullableValue = null; - JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state.Current); + JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state, ref reader); } // todo: have the caller check if current.Enumerator != null and call WriteEnumerable of the underlying property directly to avoid an extra virtual call. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs index 9646ce3..d80b173 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs @@ -41,7 +41,7 @@ namespace System.Text.Json.Serialization Type arrayType = jsonPropertyInfo.RuntimePropertyType; if (!typeof(IEnumerable).IsAssignableFrom(arrayType) || (arrayType.IsArray && arrayType.GetArrayRank() > 1)) { - ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(arrayType, reader, state); + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(arrayType, reader, state.PropertyPath); } Debug.Assert(state.Current.IsPropertyEnumerable || state.Current.IsDictionary); @@ -85,7 +85,8 @@ namespace System.Text.Json.Serialization private static bool HandleEndArray( JsonSerializerOptions options, - ref ReadStack state) + ref ReadStack state, + ref Utf8JsonReader reader) { bool lastFrame = state.IsLastFrame; @@ -142,7 +143,7 @@ namespace System.Text.Json.Serialization // else there must be an outer object, so we'll return false here. } - ApplyObjectToEnumerable(value, options, ref state.Current, setPropertyDirectly: setPropertyDirectly); + ApplyObjectToEnumerable(value, options, ref state, ref reader, setPropertyDirectly: setPropertyDirectly); if (!valueReturning) { @@ -153,41 +154,56 @@ namespace System.Text.Json.Serialization } // If this method is changed, also change ApplyValueToEnumerable. - internal static void ApplyObjectToEnumerable(object value, JsonSerializerOptions options, ref ReadStackFrame frame, bool setPropertyDirectly = false) + internal static void ApplyObjectToEnumerable( + object value, + JsonSerializerOptions options, + ref ReadStack state, + ref Utf8JsonReader reader, + bool setPropertyDirectly = false) { - if (frame.IsEnumerable) + if (state.Current.IsEnumerable) { - if (frame.TempEnumerableValues != null) + if (state.Current.TempEnumerableValues != null) { - frame.TempEnumerableValues.Add(value); + state.Current.TempEnumerableValues.Add(value); } else { - ((IList)frame.ReturnValue).Add(value); + ((IList)state.Current.ReturnValue).Add(value); } } - else if (!setPropertyDirectly && frame.IsPropertyEnumerable) + else if (!setPropertyDirectly && state.Current.IsPropertyEnumerable) { - Debug.Assert(frame.JsonPropertyInfo != null); - Debug.Assert(frame.ReturnValue != null); - if (frame.TempEnumerableValues != null) + Debug.Assert(state.Current.JsonPropertyInfo != null); + Debug.Assert(state.Current.ReturnValue != null); + if (state.Current.TempEnumerableValues != null) { - frame.TempEnumerableValues.Add(value); + state.Current.TempEnumerableValues.Add(value); } else { - ((IList)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue)).Add(value); + ((IList)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue)).Add(value); } } - else if (frame.IsDictionary) + else if (state.Current.IsDictionary) { - Debug.Assert(frame.ReturnValue != null); - ((IDictionary)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue)).Add(frame.KeyName, value); + Debug.Assert(state.Current.ReturnValue != null); + IDictionary dictionary = (IDictionary)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue); + string key = state.Current.KeyName; + Debug.Assert(!string.IsNullOrEmpty(key)); + if (!dictionary.Contains(key)) + { + dictionary.Add(key, value); + } + else + { + ThrowHelper.ThrowJsonException_DeserializeDuplicateKey(key, reader, state.PropertyPath); + } } else { - Debug.Assert(frame.JsonPropertyInfo != null); - frame.JsonPropertyInfo.SetValueAsObject(frame.ReturnValue, value); + Debug.Assert(state.Current.JsonPropertyInfo != null); + state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value); } } @@ -195,41 +211,53 @@ namespace System.Text.Json.Serialization internal static void ApplyValueToEnumerable( ref TProperty value, JsonSerializerOptions options, - ref ReadStackFrame frame) + ref ReadStack state, + ref Utf8JsonReader reader) { - if (frame.IsEnumerable) + if (state.Current.IsEnumerable) { - if (frame.TempEnumerableValues != null) + if (state.Current.TempEnumerableValues != null) { - ((IList)frame.TempEnumerableValues).Add(value); + ((IList)state.Current.TempEnumerableValues).Add(value); } else { - ((IList)frame.ReturnValue).Add(value); + ((IList)state.Current.ReturnValue).Add(value); } } - else if (frame.IsPropertyEnumerable) + else if (state.Current.IsPropertyEnumerable) { - Debug.Assert(frame.JsonPropertyInfo != null); - Debug.Assert(frame.ReturnValue != null); - if (frame.TempEnumerableValues != null) + Debug.Assert(state.Current.JsonPropertyInfo != null); + Debug.Assert(state.Current.ReturnValue != null); + if (state.Current.TempEnumerableValues != null) { - ((IList)frame.TempEnumerableValues).Add(value); + ((IList)state.Current.TempEnumerableValues).Add(value); } else { - ((IList)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue)).Add(value); + ((IList)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue)).Add(value); } } - else if (frame.IsDictionary) + else if (state.Current.IsDictionary) { - Debug.Assert(frame.ReturnValue != null); - ((IDictionary)frame.JsonPropertyInfo.GetValueAsObject(frame.ReturnValue)).Add(frame.KeyName, value); + Debug.Assert(state.Current.ReturnValue != null); + IDictionary dictionary = (IDictionary)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue); + + string key = state.Current.KeyName; + Debug.Assert(!string.IsNullOrEmpty(key)); + if (!dictionary.ContainsKey(key)) // The IDictionary.TryAdd extension method is not available in netstandard. + { + dictionary.Add(key, value); + } + else + { + ThrowHelper.ThrowJsonException_DeserializeDuplicateKey(key, reader, state.PropertyPath); + } } else { - Debug.Assert(frame.JsonPropertyInfo != null); - frame.JsonPropertyInfo.SetValueAsObject(frame.ReturnValue, value); + Debug.Assert(state.Current.JsonPropertyInfo != null); + state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs index ad97372..028c634 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleNull.cs @@ -27,18 +27,18 @@ namespace System.Text.Json.Serialization JsonPropertyInfo propertyInfo = state.Current.JsonPropertyInfo; if (!propertyInfo.CanBeNull) { - ThrowHelper.ThrowJsonReaderException_DeserializeCannotBeNull(reader, state); + ThrowHelper.ThrowJsonException_DeserializeCannotBeNull(reader, state.PropertyPath); } if (state.Current.IsEnumerable || state.Current.IsDictionary) { - ApplyObjectToEnumerable(null, options, ref state.Current); + ApplyObjectToEnumerable(null, options, ref state, ref reader); return false; } if (state.Current.IsPropertyEnumerable) { - state.Current.JsonPropertyInfo.ApplyNullValue(options, ref state); + state.Current.JsonPropertyInfo.ApplyNullValue(options, ref state, ref reader); return false; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs index ae17128..cd7e02d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleObject.cs @@ -31,7 +31,7 @@ namespace System.Text.Json.Serialization Debug.Assert(state.Current.JsonClassInfo.Type.GetGenericArguments().Length >= 1); if (state.Current.JsonClassInfo.Type.GetGenericArguments()[0].UnderlyingSystemType != typeof(string)) { - ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state); + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state.PropertyPath); } ClassType classType = state.Current.JsonClassInfo.ElementClassInfo.ClassType; @@ -66,7 +66,7 @@ namespace System.Text.Json.Serialization state.Current.ReturnValue = classInfo.CreateObject(); } - private static bool HandleEndObject(JsonSerializerOptions options, ref ReadStack state) + private static bool HandleEndObject(JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { bool isLastFrame = state.IsLastFrame; if (state.Current.Drain) @@ -87,7 +87,7 @@ namespace System.Text.Json.Serialization } state.Pop(); - ApplyObjectToEnumerable(value, options, ref state.Current); + ApplyObjectToEnumerable(value, options, ref state, ref reader); return false; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs index 8dd266a..3d2ebb6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs @@ -12,7 +12,7 @@ namespace System.Text.Json.Serialization /// A representation of the JSON value. /// JSON text to parse. /// Options to control the behavior during parsing. - /// + /// /// Thrown when the JSON is invalid, /// is not compatible with the JSON, /// or when there is remaining data in the Stream. @@ -32,7 +32,7 @@ namespace System.Text.Json.Serialization /// /// Thrown if is null. /// - /// + /// /// Thrown when the JSON is invalid, /// is not compatible with the JSON, /// or when there is remaining data in the Stream. @@ -60,8 +60,7 @@ namespace System.Text.Json.Serialization if (reader.BytesConsumed != utf8Json.Length) { readerState = reader.CurrentState; - throw new JsonReaderException(SR.Format(SR.DeserializeDataRemaining, - utf8Json.Length, utf8Json.Length - readerState.BytesConsumed), readerState); + ThrowHelper.ThrowJsonException_DeserializeDataRemaining(utf8Json.Length, utf8Json.Length - readerState.BytesConsumed); } return result; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs index b067059..19fdc98 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs @@ -22,7 +22,7 @@ namespace System.Text.Json.Serialization /// /// The which may be used to cancel the read operation. /// - /// + /// /// Thrown when the JSON is invalid, /// is not compatible with the JSON, /// or when there is remaining data in the Stream. @@ -52,7 +52,7 @@ namespace System.Text.Json.Serialization /// /// Thrown if or is null. /// - /// + /// /// Thrown when the JSON is invalid, /// the is not compatible with the JSON, /// or when there is remaining data in the Stream. @@ -180,9 +180,7 @@ namespace System.Text.Json.Serialization if (bytesInBuffer != 0) { - throw new JsonReaderException( - SR.Format(SR.DeserializeDataRemaining, totalBytesRead, bytesInBuffer), - readerState); + ThrowHelper.ThrowJsonException_DeserializeDataRemaining(totalBytesRead, bytesInBuffer); } return (TValue)state.Current.ReturnValue; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs index 37aa8ed..ad3133f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs @@ -15,7 +15,7 @@ namespace System.Text.Json.Serialization /// /// Thrown if is null. /// - /// + /// /// Thrown when the JSON is invalid, /// is not compatible with the JSON, /// or when there is remaining data in the Stream. @@ -41,7 +41,7 @@ namespace System.Text.Json.Serialization /// /// Thrown if or is null. /// - /// + /// /// Thrown when the JSON is invalid, /// the is not compatible with the JSON, /// or when there is remaining data in the Stream. @@ -76,8 +76,8 @@ namespace System.Text.Json.Serialization if (reader.BytesConsumed != jsonBytes.Length) { readerState = reader.CurrentState; - throw new JsonReaderException(SR.Format(SR.DeserializeDataRemaining, - jsonBytes.Length, jsonBytes.Length - readerState.BytesConsumed), readerState); + ThrowHelper.ThrowJsonException_DeserializeDataRemaining( + jsonBytes.Length, jsonBytes.Length - readerState.BytesConsumed); } return result; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs index b73e3a6..69cd87d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.cs @@ -21,101 +21,109 @@ namespace System.Text.Json.Serialization ref Utf8JsonReader reader, ref ReadStack state) { - while (reader.Read()) + try { - JsonTokenType tokenType = reader.TokenType; - - if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False)) + while (reader.Read()) { - Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False); + JsonTokenType tokenType = reader.TokenType; - if (HandleValue(tokenType, options, ref reader, ref state)) - { - return; - } - } - else if (tokenType == JsonTokenType.PropertyName) - { - if (!state.Current.Drain) + if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False)) { - Debug.Assert(state.Current.ReturnValue != default); - Debug.Assert(state.Current.JsonClassInfo != default); + Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False); - if (state.Current.IsDictionary) + if (HandleValue(tokenType, options, ref reader, ref state)) { - string keyName = reader.GetString(); - if (options.DictionaryKeyPolicy != null) - { - keyName = options.DictionaryKeyPolicy.ConvertName(keyName); - } - - state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetPolicyProperty(); - state.Current.KeyName = keyName; + return; } - else + } + else if (tokenType == JsonTokenType.PropertyName) + { + if (!state.Current.Drain) { - ReadOnlySpan propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; - if (reader._stringHasEscaping) - { - int idx = propertyName.IndexOf(JsonConstants.BackSlash); - Debug.Assert(idx != -1); - propertyName = GetUnescapedString(propertyName, idx); - } + Debug.Assert(state.Current.ReturnValue != default); + Debug.Assert(state.Current.JsonClassInfo != default); - state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(options, propertyName, ref state.Current); - if (state.Current.JsonPropertyInfo == null) + if (state.Current.IsDictionary) { - state.Current.JsonPropertyInfo = s_missingProperty; + string keyName = reader.GetString(); + if (options.DictionaryKeyPolicy != null) + { + keyName = options.DictionaryKeyPolicy.ConvertName(keyName); + } + + state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetPolicyProperty(); + state.Current.KeyName = keyName; } + else + { + ReadOnlySpan propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; + if (reader._stringHasEscaping) + { + int idx = propertyName.IndexOf(JsonConstants.BackSlash); + Debug.Assert(idx != -1); + propertyName = GetUnescapedString(propertyName, idx); + } + + state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(options, propertyName, ref state.Current); + if (state.Current.JsonPropertyInfo == null) + { + state.Current.JsonPropertyInfo = s_missingProperty; + } - state.Current.PropertyIndex++; + state.Current.PropertyIndex++; + } } } - } - else if (tokenType == JsonTokenType.StartObject) - { - if (!state.Current.IsProcessingProperty) - { - HandleStartObject(options, ref reader, ref state); - } - else if (HandleValue(tokenType, options, ref reader, ref state)) - { - return; - } - } - else if (tokenType == JsonTokenType.EndObject) - { - if (HandleEndObject(options, ref state)) + else if (tokenType == JsonTokenType.StartObject) { - return; + if (!state.Current.IsProcessingProperty) + { + HandleStartObject(options, ref reader, ref state); + } + else if (HandleValue(tokenType, options, ref reader, ref state)) + { + return; + } } - } - else if (tokenType == JsonTokenType.StartArray) - { - if (!state.Current.IsProcessingProperty) + else if (tokenType == JsonTokenType.EndObject) { - HandleStartArray(options, ref reader, ref state); + if (HandleEndObject(options, ref state, ref reader)) + { + return; + } } - else if (HandleValue(tokenType, options, ref reader, ref state)) + else if (tokenType == JsonTokenType.StartArray) { - return; + if (!state.Current.IsProcessingProperty) + { + HandleStartArray(options, ref reader, ref state); + } + else if (HandleValue(tokenType, options, ref reader, ref state)) + { + return; + } } - } - else if (tokenType == JsonTokenType.EndArray) - { - if (HandleEndArray(options, ref state)) + else if (tokenType == JsonTokenType.EndArray) { - return; + if (HandleEndArray(options, ref state, ref reader)) + { + return; + } } - } - else if (tokenType == JsonTokenType.Null) - { - if (HandleNull(ref reader, ref state, options)) + else if (tokenType == JsonTokenType.Null) { - return; + if (HandleNull(ref reader, ref state, options)) + { + return; + } } } } + catch (JsonReaderException e) + { + // Re-throw with Path information. + ThrowHelper.ReThrowWithPath(e, state.PropertyPath); + } return; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 34129b5..7f9938c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -38,7 +38,7 @@ namespace System.Text.Json.Serialization /// /// Defines whether an extra comma at the end of a list of JSON values in an object or array /// is allowed (and ignored) within the JSON payload being deserialized. - /// By default, it's set to false, and is thrown if a trailing comma is encountered. + /// By default, it's set to false, and is thrown if a trailing comma is encountered. /// /// /// Thrown if this property is set after serialization or deserialization has occurred. @@ -145,7 +145,7 @@ namespace System.Text.Json.Serialization /// /// Gets or sets the maximum depth allowed when serializing or deserializing JSON, with the default (i.e. 0) indicating a max depth of 64. - /// Going past this depth will throw a . + /// Going past this depth will throw a . /// /// /// Thrown if this property is set after serialization or deserialization has occurred. @@ -205,7 +205,7 @@ namespace System.Text.Json.Serialization /// /// Defines how the comments are handled during deserialization. - /// By default is thrown if a comment is encountered. + /// By default is thrown if a comment is encountered. /// /// /// Thrown if this property is set after serialization or deserialization has occurred. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs index dda53fc..5c3ab72 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStackFrame.cs @@ -127,7 +127,7 @@ namespace System.Text.Json.Serialization } else { - ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(propType, reader, state); + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(propType, reader, state.PropertyPath); return null; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs index ac7f1f3..c46ebbd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.Json.Serialization; @@ -17,15 +18,15 @@ namespace System.Text.Json } [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowJsonReaderException_DeserializeUnableToConvertValue(Type propertyType, in Utf8JsonReader reader, in ReadStack state) + public static void ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType, in Utf8JsonReader reader, string path) { - throw new JsonReaderException(SR.Format(SR.DeserializeUnableToConvertValue, state.PropertyPath, propertyType.FullName), reader.CurrentState); + ThowJsonException(SR.Format(SR.DeserializeUnableToConvertValue, propertyType.FullName), in reader, path); } [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowJsonReaderException_DeserializeCannotBeNull(in Utf8JsonReader reader, in ReadStack state) + public static void ThrowJsonException_DeserializeCannotBeNull(in Utf8JsonReader reader, string path) { - throw new JsonReaderException(SR.Format(SR.DeserializeCannotBeNull, state.PropertyPath), reader.CurrentState); + ThowJsonException(SR.DeserializeCannotBeNull, in reader, path); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -51,5 +52,45 @@ namespace System.Text.Json { throw new InvalidOperationException(SR.Format(SR.SerializerPropertyNameNull, jsonClassInfo.Type.FullName, jsonPropertyInfo.PropertyInfo.Name)); } + + public static void ThrowJsonException_DeserializeDataRemaining(long length, long bytesRemaining) + { + throw new JsonException(SR.Format(SR.DeserializeDataRemaining, length, bytesRemaining), path: null, lineNumber: null, bytePositionInLine: null); + } + + public static void ThrowJsonException_DeserializeDuplicateKey(string key, in Utf8JsonReader reader, string path) + { + ThowJsonException(SR.Format(SR.DeserializeDuplicateKey, key), in reader, path); + } + + private static void ThowJsonException(string message, in Utf8JsonReader reader, string path) + { + long lineNumber = reader.CurrentState._lineNumber; + long bytePositionInLine = reader.CurrentState._bytePositionInLine; + + message += $" Path: {path} | LineNumber: {lineNumber} | BytePositionInLine: {bytePositionInLine}."; + throw new JsonException(message, path, lineNumber, bytePositionInLine); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ReThrowWithPath(JsonException exception, string path) + { + Debug.Assert(exception.Path == null); + + string message = exception.Message; + + // Insert the "Path" portion before "LineNumber" and "BytePositionInLine". + int iPos = message.LastIndexOf(" LineNumber: ", StringComparison.InvariantCulture); + if (iPos >= 0) + { + message = $"{message.Substring(0, iPos)} Path: {path} |{message.Substring(iPos)}"; + } + else + { + message += $" Path: {path}."; + } + + throw new JsonException(message, path, exception.LineNumber, exception.BytePositionInLine, exception); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs index fd94858..a69e504 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs @@ -223,7 +223,7 @@ namespace System.Text.Json } [MethodImpl(MethodImplOptions.NoInlining)] - public static JsonReaderException GetJsonReaderException(ref Utf8JsonReader json, ExceptionResource resource, byte nextByte, ReadOnlySpan bytes) + public static JsonException GetJsonReaderException(ref Utf8JsonReader json, ExceptionResource resource, byte nextByte, ReadOnlySpan bytes) { string message = GetResourceString(ref json, resource, nextByte, Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Length)); diff --git a/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs index 469090e..36abf6b 100644 --- a/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs @@ -416,7 +416,7 @@ namespace System.Text.Json.Tests public static void ParseJson_SeekableStream_BadBOM(string json) { byte[] data = Encoding.UTF8.GetBytes(json); - Assert.Throws(() => JsonDocument.Parse(new MemoryStream(data))); + Assert.ThrowsAny(() => JsonDocument.Parse(new MemoryStream(data))); } [Theory] @@ -424,7 +424,7 @@ namespace System.Text.Json.Tests public static Task ParseJson_SeekableStream_Async_BadBOM(string json) { byte[] data = Encoding.UTF8.GetBytes(json); - return Assert.ThrowsAsync(() => JsonDocument.ParseAsync(new MemoryStream(data))); + return Assert.ThrowsAnyAsync(() => JsonDocument.ParseAsync(new MemoryStream(data))); } [Theory] @@ -433,7 +433,7 @@ namespace System.Text.Json.Tests { byte[] data = Encoding.UTF8.GetBytes(json); - Assert.Throws( + Assert.ThrowsAny( () => JsonDocument.Parse( new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, data))); } @@ -444,7 +444,7 @@ namespace System.Text.Json.Tests { byte[] data = Encoding.UTF8.GetBytes(json); - return Assert.ThrowsAsync( + return Assert.ThrowsAnyAsync( () => JsonDocument.ParseAsync( new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, data))); } @@ -1579,22 +1579,22 @@ namespace System.Text.Json.Tests [InlineData("[ 1")] public static Task CheckUnparsable(string json) { - Assert.Throws(() => JsonDocument.Parse(json)); + Assert.ThrowsAny(() => JsonDocument.Parse(json)); byte[] utf8 = Encoding.UTF8.GetBytes(json); - Assert.Throws(() => JsonDocument.Parse(utf8)); + Assert.ThrowsAny(() => JsonDocument.Parse(utf8)); ReadOnlySequence singleSeq = new ReadOnlySequence(utf8); - Assert.Throws(() => JsonDocument.Parse(singleSeq)); + Assert.ThrowsAny(() => JsonDocument.Parse(singleSeq)); ReadOnlySequence multiSegment = JsonTestHelper.SegmentInto(utf8, 6); - Assert.Throws(() => JsonDocument.Parse(multiSegment)); + Assert.ThrowsAny(() => JsonDocument.Parse(multiSegment)); Stream stream = new MemoryStream(utf8); - Assert.Throws(() => JsonDocument.Parse(stream)); + Assert.ThrowsAny(() => JsonDocument.Parse(stream)); stream.Seek(0, SeekOrigin.Begin); - return Assert.ThrowsAsync(() => JsonDocument.ParseAsync(stream)); + return Assert.ThrowsAnyAsync(() => JsonDocument.ParseAsync(stream)); } [Fact] @@ -1625,7 +1625,7 @@ namespace System.Text.Json.Tests string badJson = $"[{okayJson}]"; - Assert.Throws(() => JsonDocument.Parse(badJson)); + Assert.ThrowsAny(() => JsonDocument.Parse(badJson)); } [Fact] @@ -1654,10 +1654,10 @@ namespace System.Text.Json.Tests Assert.Equal(OkayCount, depth); } - Assert.Throws(() => JsonDocument.Parse(okayJson, new JsonReaderOptions { MaxDepth = 32 })); - Assert.Throws(() => JsonDocument.Parse(okayJson)); - Assert.Throws(() => JsonDocument.Parse(okayJson, new JsonReaderOptions { MaxDepth = 0 })); - Assert.Throws(() => JsonDocument.Parse(okayJson, new JsonReaderOptions { MaxDepth = 64 })); + Assert.ThrowsAny(() => JsonDocument.Parse(okayJson, new JsonReaderOptions { MaxDepth = 32 })); + Assert.ThrowsAny(() => JsonDocument.Parse(okayJson)); + Assert.ThrowsAny(() => JsonDocument.Parse(okayJson, new JsonReaderOptions { MaxDepth = 0 })); + Assert.ThrowsAny(() => JsonDocument.Parse(okayJson, new JsonReaderOptions { MaxDepth = 64 })); } [Fact] @@ -2365,7 +2365,7 @@ namespace System.Text.Json.Tests [Fact] public static void ParseDefaultReader() { - Assert.Throws(() => + Assert.ThrowsAny(() => { Utf8JsonReader reader = default; JsonDocument.ParseValue(ref reader); @@ -2504,7 +2504,7 @@ namespace System.Text.Json.Tests } Assert.NotNull(ex); - Assert.IsType(ex); + Assert.IsAssignableFrom(ex); BuildSegmentedReader(out reader, utf8.AsMemory((int)position), 0, state, true); @@ -2695,7 +2695,7 @@ namespace System.Text.Json.Tests } Assert.NotNull(ex); - Assert.IsType(ex); + Assert.IsAssignableFrom(ex); Assert.Equal(initialPosition, reader.BytesConsumed); @@ -2739,7 +2739,7 @@ namespace System.Text.Json.Tests } Assert.NotNull(ex); - Assert.IsType(ex); + Assert.IsAssignableFrom(ex); Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); Assert.Equal(startPosition, reader.BytesConsumed); @@ -2757,7 +2757,7 @@ namespace System.Text.Json.Tests } Assert.NotNull(ex); - Assert.IsType(ex); + Assert.IsAssignableFrom(ex); Assert.Null(doc); Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); @@ -2799,7 +2799,7 @@ namespace System.Text.Json.Tests } Assert.NotNull(ex); - Assert.IsType(ex); + Assert.IsAssignableFrom(ex); Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); Assert.Equal(startPosition, reader.BytesConsumed); @@ -2846,7 +2846,7 @@ namespace System.Text.Json.Tests } Assert.NotNull(ex); - Assert.IsType(ex); + Assert.IsAssignableFrom(ex); Assert.Equal(JsonTokenType.PropertyName, reader.TokenType); Assert.Equal(startPosition, reader.BytesConsumed); diff --git a/src/libraries/System.Text.Json/tests/JsonTestHelper.cs b/src/libraries/System.Text.Json/tests/JsonTestHelper.cs index 6c7cc0d..fa644da 100644 --- a/src/libraries/System.Text.Json/tests/JsonTestHelper.cs +++ b/src/libraries/System.Text.Json/tests/JsonTestHelper.cs @@ -603,7 +603,7 @@ namespace System.Text.Json throw new ThrowsException(typeof(E)); } - if (ex.GetType() != typeof(E)) + if (!(ex is E)) { throw new ThrowsException(typeof(E), ex); } diff --git a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs b/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs index 92fdeaa..eb232cb 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs @@ -54,21 +54,25 @@ namespace System.Text.Json.Serialization.Tests [Fact] public static void DuplicateKeysFail() { - // todo: this should throw a JsonReaderException - Assert.Throws(() => JsonSerializer.Parse>( + // Strongly-typed IDictionary<,> case. + Assert.Throws(() => JsonSerializer.Parse>( @"{""Hello"":""World"", ""Hello"":""World""}")); + + // Weakly-typed IDictionary case. + Assert.Throws(() => JsonSerializer.Parse>( + @"{""Hello"":null, ""Hello"":null}")); } [Fact] public static void DictionaryOfObjectFail() { - Assert.Throws(() => JsonSerializer.Parse>(@"{""Key1"":1")); + Assert.Throws(() => JsonSerializer.Parse>(@"{""Key1"":1")); } [Fact] public static void FirstGenericArgNotStringFail() { - Assert.Throws(() => JsonSerializer.Parse>(@"{""Key1"":1}")); + Assert.Throws(() => JsonSerializer.Parse>(@"{""Key1"":1}")); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs b/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs index d8b6ea0..d541456 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs @@ -21,7 +21,7 @@ namespace System.Text.Json.Serialization.Tests [Fact] public static void EnumAsStringFail() { - Assert.Throws(() => JsonSerializer.Parse(s_jsonStringEnum)); + Assert.Throws(() => JsonSerializer.Parse(s_jsonStringEnum)); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs b/src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs new file mode 100644 index 0000000..ccb8fda --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Reflection; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class ExceptionTests + { + [Fact] + public static void RootThrownFromReader() + { + try + { + int i2 = JsonSerializer.Parse("12bad"); + Assert.True(false, "Expected JsonException was not thrown."); + } + catch (JsonException e) + { + Assert.Equal(0, e.LineNumber); + Assert.Equal(2, e.BytePositionInLine); + Assert.Equal("[System.Int32]", e.Path); + Assert.Contains("Path: [System.Int32] | LineNumber: 0 | BytePositionInLine: 2.", e.Message); + + // Verify Path is not repeated. + Assert.True(e.Message.IndexOf("Path:") == e.Message.LastIndexOf("Path:")); + } + } + + [Fact] + public static void ThrownFromSerializer() + { + try + { + JsonSerializer.Parse>(@"{""Key"":1, ""Key"":2}"); + Assert.True(false, "Expected JsonException was not thrown."); + } + catch (JsonException e) + { + Assert.Equal(0, e.LineNumber); + Assert.Equal(17, e.BytePositionInLine); + Assert.Contains("LineNumber: 0 | BytePositionInLine: 17.", e.Message); + Assert.Contains("[System.Collections.Generic.IDictionary`2", e.Path); + + // Verify Path is not repeated. + Assert.True(e.Message.IndexOf("Path:") == e.Message.LastIndexOf("Path:")); + } + } + + [Fact] + public static void ThrownFromReader() + { + string json = Encoding.UTF8.GetString(BasicCompany.s_data); + + json = json.Replace(@"""zip"" : 98052", @"""zip"" : bad"); + + try + { + JsonSerializer.Parse(json); + Assert.True(false, "Expected JsonException was not thrown."); + } + catch (JsonException e) + { + Assert.Equal(18, e.LineNumber); + Assert.Equal(8, e.BytePositionInLine); + Assert.Equal("[System.Text.Json.Serialization.Tests.BasicCompany].mainSite.zip", e.Path); + Assert.Contains("Path: [System.Text.Json.Serialization.Tests.BasicCompany].mainSite.zip | LineNumber: 18 | BytePositionInLine: 8.", + e.Message); + + // Verify Path is not repeated. + Assert.True(e.Message.IndexOf("Path:") == e.Message.LastIndexOf("Path:")); + + Assert.NotNull(e.InnerException); + JsonException inner = (JsonException)e.InnerException; + Assert.Equal(18, inner.LineNumber); + Assert.Equal(8, inner.BytePositionInLine); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs b/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs index 6e455d8..bcc76b7 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs @@ -80,21 +80,21 @@ namespace System.Text.Json.Serialization.Tests [Fact] public static void ReadObjectFail() { - Assert.Throws(() => JsonSerializer.Parse("blah")); - Assert.Throws(() => JsonSerializer.Parse("blah")); + Assert.Throws(() => JsonSerializer.Parse("blah")); + Assert.Throws(() => JsonSerializer.Parse("blah")); - Assert.Throws(() => JsonSerializer.Parse("true")); + Assert.Throws(() => JsonSerializer.Parse("true")); - Assert.Throws(() => JsonSerializer.Parse("null.")); - Assert.Throws(() => JsonSerializer.Parse("null.")); + Assert.Throws(() => JsonSerializer.Parse("null.")); + Assert.Throws(() => JsonSerializer.Parse("null.")); } [Fact] public static void ParseUntyped() { // Not supported until we are able to deserialize into JsonElement. - Assert.Throws(() => JsonSerializer.Parse("[]")); - Assert.Throws(() => JsonSerializer.Parse("[]")); + Assert.Throws(() => JsonSerializer.Parse("[]")); + Assert.Throws(() => JsonSerializer.Parse("[]")); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs index be416b0..2806ee5 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs @@ -59,7 +59,7 @@ namespace System.Text.Json.Serialization.Tests [Fact] public static void AllowTrailingCommas() { - Assert.Throws(() => JsonSerializer.Parse("[1,]")); + Assert.Throws(() => JsonSerializer.Parse("[1,]")); var options = new JsonSerializerOptions(); options.AllowTrailingCommas = true; @@ -93,11 +93,11 @@ namespace System.Text.Json.Serialization.Tests [Fact] public static void ReadCommentHandling() { - Assert.Throws(() => JsonSerializer.Parse("/* commment */")); + Assert.Throws(() => JsonSerializer.Parse("/* commment */")); var options = new JsonSerializerOptions(); - Assert.Throws(() => JsonSerializer.Parse("/* commment */", options)); + Assert.Throws(() => JsonSerializer.Parse("/* commment */", options)); options = new JsonSerializerOptions(); options.ReadCommentHandling = JsonCommentHandling.Allow; @@ -117,7 +117,7 @@ namespace System.Text.Json.Serialization.Tests options = new JsonSerializerOptions(); options.MaxDepth = 1; - Assert.Throws(() => JsonSerializer.Parse(BasicCompany.s_data, options)); + Assert.Throws(() => JsonSerializer.Parse(BasicCompany.s_data, options)); } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs b/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs index 8f8a4d8..eaa0cd5 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs @@ -42,8 +42,8 @@ namespace System.Text.Json.Serialization.Tests [Fact] public static void ReadPrimitivesFail() { - Assert.Throws(() => JsonSerializer.Parse(@"")); - Assert.Throws(() => JsonSerializer.Parse(@"a")); + Assert.Throws(() => JsonSerializer.Parse(@"")); + Assert.Throws(() => JsonSerializer.Parse(@"a")); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs b/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs index b9de228..5f35532 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Text.Json.Tests; using Xunit; namespace System.Text.Json.Serialization.Tests diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs index 1bc8df1..919f18b 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs @@ -898,26 +898,26 @@ namespace System.Text.Json.Serialization.Tests public string name { get; set; } public static readonly byte[] s_data = Encoding.UTF8.GetBytes( - "{" + - @"""name"" : ""Microsoft""," + - @"""sites"" : [" + - "{" + - @"""street"" : ""1 Lone Tree Rd S""," + - @"""city"" : ""Fargo""," + - @"""zip"" : 58104" + - "}," + - "{" + - @"""street"" : ""8055 Microsoft Way""," + - @"""city"" : ""Charlotte""," + - @"""zip"" : 28273" + - "}" + - @"]," + - @"""mainSite"" : " + - "{" + - @"""street"" : ""1 Microsoft Way""," + - @"""city"" : ""Redmond""," + - @"""zip"" : 98052" + - "}" + + "{\n" + + @"""name"" : ""Microsoft""," + "\n" + + @"""sites"" :[" + "\n" + + "{\n" + + @"""street"" : ""1 Lone Tree Rd S""," + "\n" + + @"""city"" : ""Fargo""," + "\n" + + @"""zip"" : 58104" + "\n" + + "},\n" + + "{\n" + + @"""street"" : ""8055 Microsoft Way""," + "\n" + + @"""city"" : ""Charlotte""," + "\n" + + @"""zip"" : 28273" + "\n" + + "}\n" + + "],\n" + + @"""mainSite"":" + "\n" + + "{\n" + + @"""street"" : ""1 Microsoft Way""," + "\n" + + @"""city"" : ""Redmond""," + "\n" + + @"""zip"" : 98052" + "\n" + + "}\n" + "}"); public void Initialize() diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs index cb5ee2e..7072238 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs @@ -37,10 +37,10 @@ namespace System.Text.Json.Serialization.Tests [Fact] public static void ReadPrimitivesFail() { - Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"a"))); - Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[1,a]"))); - Assert.Throws(() => JsonSerializer.Parse(@"null")); - Assert.Throws(() => JsonSerializer.Parse(@"""""")); + Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"a"))); + Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[1,a]"))); + Assert.Throws(() => JsonSerializer.Parse(@"null")); + Assert.Throws(() => JsonSerializer.Parse(@"""""")); } [Fact] @@ -70,80 +70,80 @@ namespace System.Text.Json.Serialization.Tests public static void ReadPrimitiveArrayFail() { // Invalid data - Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[1,""a""]"))); + Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[1,""a""]"))); // Multidimensional arrays currently not supported - Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"))); + Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"))); } [Fact] public static void ReadPrimitiveExtraBytesFail() { - Assert.Throws(() => JsonSerializer.Parse("[2] {3}")); - Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[2] {3}"))); + Assert.Throws(() => JsonSerializer.Parse("[2] {3}")); + Assert.Throws(() => JsonSerializer.Parse(Encoding.UTF8.GetBytes(@"[2] {3}"))); } [Fact] public static void RangeFail() { // These have custom code because the reader doesn't natively support: - Assert.Throws(() => JsonSerializer.Parse((byte.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((byte.MaxValue + 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((byte.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((byte.MaxValue + 1).ToString())); - - Assert.Throws(() => JsonSerializer.Parse((sbyte.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((sbyte.MaxValue + 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((sbyte.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((sbyte.MaxValue + 1).ToString())); - - Assert.Throws(() => JsonSerializer.Parse((short.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((short.MaxValue + 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((short.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((short.MaxValue + 1).ToString())); - - Assert.Throws(() => JsonSerializer.Parse((ushort.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((ushort.MaxValue + 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((ushort.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse((ushort.MaxValue + 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((byte.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((byte.MaxValue + 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((byte.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((byte.MaxValue + 1).ToString())); + + Assert.Throws(() => JsonSerializer.Parse((sbyte.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((sbyte.MaxValue + 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((sbyte.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((sbyte.MaxValue + 1).ToString())); + + Assert.Throws(() => JsonSerializer.Parse((short.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((short.MaxValue + 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((short.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((short.MaxValue + 1).ToString())); + + Assert.Throws(() => JsonSerializer.Parse((ushort.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((ushort.MaxValue + 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((ushort.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse((ushort.MaxValue + 1).ToString())); // To ensure range failure, just use double's MinValue and MaxValue (instead of float.MinValue\MaxValue +-1) - Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString())); - Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString())); - Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString())); - Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString())); + Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString())); + Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString())); + Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString())); + Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString())); // These are natively supported by the reader: - Assert.Throws(() => JsonSerializer.Parse(((long)int.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse(((long)int.MaxValue + 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse(((long)int.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse(((long)int.MaxValue + 1).ToString())); - - Assert.Throws(() => JsonSerializer.Parse(((long)uint.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse(((long)uint.MaxValue + 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse(((long)uint.MinValue - 1).ToString())); - Assert.Throws(() => JsonSerializer.Parse(((long)uint.MaxValue + 1).ToString())); - - Assert.Throws(() => JsonSerializer.Parse(long.MinValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(long.MaxValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(long.MinValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(long.MaxValue.ToString() + "0")); - - Assert.Throws(() => JsonSerializer.Parse(ulong.MinValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(ulong.MaxValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(ulong.MinValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(ulong.MaxValue.ToString() + "0")); - - Assert.Throws(() => JsonSerializer.Parse(decimal.MinValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(decimal.MaxValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(decimal.MinValue.ToString() + "0")); - Assert.Throws(() => JsonSerializer.Parse(decimal.MaxValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(((long)int.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse(((long)int.MaxValue + 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse(((long)int.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse(((long)int.MaxValue + 1).ToString())); + + Assert.Throws(() => JsonSerializer.Parse(((long)uint.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse(((long)uint.MaxValue + 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse(((long)uint.MinValue - 1).ToString())); + Assert.Throws(() => JsonSerializer.Parse(((long)uint.MaxValue + 1).ToString())); + + Assert.Throws(() => JsonSerializer.Parse(long.MinValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(long.MaxValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(long.MinValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(long.MaxValue.ToString() + "0")); + + Assert.Throws(() => JsonSerializer.Parse(ulong.MinValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(ulong.MaxValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(ulong.MinValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(ulong.MaxValue.ToString() + "0")); + + Assert.Throws(() => JsonSerializer.Parse(decimal.MinValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(decimal.MaxValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(decimal.MinValue.ToString() + "0")); + Assert.Throws(() => JsonSerializer.Parse(decimal.MaxValue.ToString() + "0")); // todo: determine why these don't throw (issue with reader?) - //Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString() + "0")); - //Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString() + "0")); - //Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString() + "0")); - //Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString() + "0")); + //Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString() + "0")); + //Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString() + "0")); + //Assert.Throws(() => JsonSerializer.Parse(double.MinValue.ToString() + "0")); + //Assert.Throws(() => JsonSerializer.Parse(double.MaxValue.ToString() + "0")); } [Fact] @@ -190,51 +190,51 @@ namespace System.Text.Json.Serialization.Tests { string unexpectedString = @"""unexpected string"""; - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); - Assert.Throws(() => JsonSerializer.Parse("1")); + Assert.Throws(() => JsonSerializer.Parse("1")); - Assert.Throws(() => JsonSerializer.Parse("1")); - Assert.Throws(() => JsonSerializer.Parse("1")); + Assert.Throws(() => JsonSerializer.Parse("1")); + Assert.Throws(() => JsonSerializer.Parse("1")); - Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); + Assert.Throws(() => JsonSerializer.Parse(unexpectedString)); } [Fact] @@ -623,7 +623,7 @@ namespace System.Text.Json.Serialization.Tests { JsonSerializer.Parse(data); } - catch (JsonReaderException exception) + catch (JsonException exception) { exceptionThrown = true; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj index d371902..1183e02 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -30,6 +30,7 @@ + @@ -72,4 +73,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.MultiSegment.cs b/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.MultiSegment.cs index c945bdd..2c5eaf3 100644 --- a/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.MultiSegment.cs +++ b/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.MultiSegment.cs @@ -280,9 +280,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException for multi-segment data was not thrown."); + Assert.True(false, "Expected JsonException for multi-segment data was not thrown."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedBytePosition, ex.BytePositionInLine); @@ -308,9 +308,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException for multi-segment data was not thrown."); + Assert.True(false, "Expected JsonException for multi-segment data was not thrown."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedBytePosition, ex.BytePositionInLine); @@ -328,9 +328,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(0, ex.LineNumber); Assert.Equal(0, ex.BytePositionInLine); @@ -422,9 +422,9 @@ namespace System.Text.Json.Tests break; } } - Assert.True(false, "Expected JsonReaderException due to invalid JSON."); + Assert.True(false, "Expected JsonException due to invalid JSON."); } - catch (JsonReaderException) + catch (JsonException) { } } @@ -829,7 +829,7 @@ namespace System.Text.Json.Tests Assert.Contains(reader.TokenType, new[] { JsonTokenType.EndArray, JsonTokenType.EndObject }); } - JsonTestHelper.AssertThrows(reader, (jsonReader) => + JsonTestHelper.AssertThrows(reader, (jsonReader) => { jsonReader.Read(); if (commentHandling == JsonCommentHandling.Allow && jsonReader.TokenType == JsonTokenType.Comment) @@ -940,7 +940,7 @@ namespace System.Text.Json.Tests if (expectThrow) { - JsonTestHelper.AssertThrows(reader, (jsonReader) => + JsonTestHelper.AssertThrows(reader, (jsonReader) => { while (jsonReader.Read()) ; diff --git a/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs b/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs index f8c0dac..ea7a443 100644 --- a/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs +++ b/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs @@ -862,9 +862,9 @@ namespace System.Text.Json.Tests if (maxDepth < json.CurrentDepth) maxDepth = json.CurrentDepth; } - Assert.True(false, $"Expected JsonReaderException was not thrown. Max depth allowed = {json.CurrentState.Options.MaxDepth} | Max depth reached = {maxDepth}"); + Assert.True(false, $"Expected JsonException was not thrown. Max depth allowed = {json.CurrentState.Options.MaxDepth} | Max depth reached = {maxDepth}"); } - catch (JsonReaderException) + catch (JsonException) { } jsonStr = JsonTestHelper.WriteDepthArray(depth - 1); @@ -881,9 +881,9 @@ namespace System.Text.Json.Tests if (maxDepth < json.CurrentDepth) maxDepth = json.CurrentDepth; } - Assert.True(false, $"Expected JsonReaderException was not thrown. Max depth allowed = {json.CurrentState.Options.MaxDepth} | Max depth reached = {maxDepth}"); + Assert.True(false, $"Expected JsonException was not thrown. Max depth allowed = {json.CurrentState.Options.MaxDepth} | Max depth reached = {maxDepth}"); } - catch (JsonReaderException) + catch (JsonException) { } } @@ -1029,9 +1029,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown."); + Assert.True(false, "Expected JsonException was not thrown."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedBytePosition, ex.BytePositionInLine); @@ -1079,9 +1079,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown."); + Assert.True(false, "Expected JsonException was not thrown."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedBytePosition, ex.BytePositionInLine); @@ -1105,9 +1105,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown."); + Assert.True(false, "Expected JsonException was not thrown."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedBytePosition, ex.BytePositionInLine); @@ -1130,9 +1130,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedBytePosition, ex.BytePositionInLine); @@ -1157,9 +1157,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedBytePosition, ex.BytePositionInLine); @@ -1186,9 +1186,9 @@ namespace System.Text.Json.Tests while (jsonSlice.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with multi-segment data."); + Assert.True(false, "Expected JsonException was not thrown with multi-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { string errorMessage = $"expectedLineNumber: {expectedlineNumber} | actual: {ex.LineNumber} | index: {i} | option: {commentHandling}"; string firstSegmentString = Encoding.UTF8.GetString(dataUtf8, 0, i); @@ -1589,9 +1589,9 @@ namespace System.Text.Json.Tests break; } } - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedPosition, ex.BytePositionInLine); @@ -1649,9 +1649,9 @@ namespace System.Text.Json.Tests break; } } - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedPosition, ex.BytePositionInLine); @@ -1686,9 +1686,9 @@ namespace System.Text.Json.Tests } } - Assert.True(false, "Expected JsonReaderException was not thrown with multi-segment data."); + Assert.True(false, "Expected JsonException was not thrown with multi-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedPosition, ex.BytePositionInLine); @@ -1763,9 +1763,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedPosition, ex.BytePositionInLine); @@ -1778,9 +1778,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedPosition, ex.BytePositionInLine); @@ -1849,9 +1849,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedlineNumber, ex.LineNumber); Assert.Equal(expectedPosition, ex.BytePositionInLine); @@ -1868,9 +1868,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(0, ex.LineNumber); Assert.Equal(0, ex.BytePositionInLine); @@ -1887,9 +1887,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(0, ex.LineNumber); Assert.Equal(1, ex.BytePositionInLine); @@ -1913,9 +1913,9 @@ namespace System.Text.Json.Tests { while (json.Read()) ; - Assert.True(false, "Expected JsonReaderException was not thrown with single-segment data."); + Assert.True(false, "Expected JsonException was not thrown with single-segment data."); } - catch (JsonReaderException ex) + catch (JsonException ex) { Assert.Equal(expectedLineNumber, ex.LineNumber); Assert.Equal(expectedConsumed, ex.BytePositionInLine); @@ -2218,7 +2218,7 @@ namespace System.Text.Json.Tests Assert.Contains(reader.TokenType, new[] { JsonTokenType.EndArray, JsonTokenType.EndObject }); } - JsonTestHelper.AssertThrows(reader, (jsonReader) => + JsonTestHelper.AssertThrows(reader, (jsonReader) => { jsonReader.Read(); if (commentHandling == JsonCommentHandling.Allow && jsonReader.TokenType == JsonTokenType.Comment) @@ -2325,7 +2325,7 @@ namespace System.Text.Json.Tests if (expectThrow) { - JsonTestHelper.AssertThrows(reader, (jsonReader) => + JsonTestHelper.AssertThrows(reader, (jsonReader) => { while (jsonReader.Read()) ; @@ -2426,7 +2426,7 @@ namespace System.Text.Json.Tests { if (expectThrow) { - Assert.Throws(() => PartialReaderLoop(utf8, state)); + Assert.ThrowsAny(() => PartialReaderLoop(utf8, state)); } else { -- 2.7.4