diff options
Diffstat (limited to 'csharp/src')
-rw-r--r-- | csharp/src/Google.Protobuf.Test/JsonParserTest.cs | 44 | ||||
-rw-r--r-- | csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs | 4 | ||||
-rw-r--r-- | csharp/src/Google.Protobuf/Google.Protobuf.csproj | 1 | ||||
-rw-r--r-- | csharp/src/Google.Protobuf/InvalidJsonException.cs | 53 | ||||
-rw-r--r-- | csharp/src/Google.Protobuf/JsonParser.cs | 4 | ||||
-rw-r--r-- | csharp/src/Google.Protobuf/JsonTokenizer.cs | 42 | ||||
-rw-r--r-- | csharp/src/Google.Protobuf/MessageParser.cs | 2 |
7 files changed, 110 insertions, 40 deletions
diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs index b1c7b46c..29b3088c 100644 --- a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs @@ -370,19 +370,19 @@ namespace Google.Protobuf } [Test] - [TestCase("+0")] - [TestCase("00")] - [TestCase("-00")] - [TestCase("--1")] - [TestCase("+1")] - [TestCase("1.5", Ignore = true, Reason = "Desired behaviour unclear")] - [TestCase("1e10")] - [TestCase("2147483648")] - [TestCase("-2147483649")] - public void NumberToInt32_Invalid(string jsonValue) + [TestCase("+0", typeof(InvalidJsonException))] + [TestCase("00", typeof(InvalidJsonException))] + [TestCase("-00", typeof(InvalidJsonException))] + [TestCase("--1", typeof(InvalidJsonException))] + [TestCase("+1", typeof(InvalidJsonException))] + [TestCase("1.5", typeof(InvalidProtocolBufferException), Ignore = true, Reason = "Desired behaviour unclear")] + [TestCase("1e10", typeof(InvalidProtocolBufferException))] + [TestCase("2147483648", typeof(InvalidProtocolBufferException))] + [TestCase("-2147483649", typeof(InvalidProtocolBufferException))] + public void NumberToInt32_Invalid(string jsonValue, System.Type expectedExceptionType) { string json = "{ \"singleInt32\": " + jsonValue + "}"; - Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json)); + Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json)); } [Test] @@ -486,7 +486,7 @@ namespace Google.Protobuf public void NumberToDouble_Invalid(string jsonValue) { string json = "{ \"singleDouble\": " + jsonValue + "}"; - Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json)); + Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json)); } [Test] @@ -506,17 +506,17 @@ namespace Google.Protobuf } [Test] - [TestCase("3.402824e38")] - [TestCase("-3.402824e38")] - [TestCase("1,0")] - [TestCase("1.0.0")] - [TestCase("+1")] - [TestCase("00")] - [TestCase("--1")] - public void NumberToFloat_Invalid(string jsonValue) + [TestCase("3.402824e38", typeof(InvalidProtocolBufferException))] + [TestCase("-3.402824e38", typeof(InvalidProtocolBufferException))] + [TestCase("1,0", typeof(InvalidJsonException))] + [TestCase("1.0.0", typeof(InvalidJsonException))] + [TestCase("+1", typeof(InvalidJsonException))] + [TestCase("00", typeof(InvalidJsonException))] + [TestCase("--1", typeof(InvalidJsonException))] + public void NumberToFloat_Invalid(string jsonValue, System.Type expectedExceptionType) { string json = "{ \"singleFloat\": " + jsonValue + "}"; - Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json)); + Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json)); } // The simplest way of testing that the value has parsed correctly is to reformat it, @@ -721,7 +721,7 @@ namespace Google.Protobuf public void DataAfterObject() { string json = "{} 10"; - Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json)); + Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json)); } } } diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs index 868d9f75..1b3c8e9f 100644 --- a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs @@ -223,7 +223,7 @@ namespace Google.Protobuf { Assert.IsNotNull(tokenizer.Next()); } - Assert.Throws<InvalidProtocolBufferException>(() => tokenizer.Next()); + Assert.Throws<InvalidJsonException>(() => tokenizer.Next()); } [Test] @@ -346,7 +346,7 @@ namespace Google.Protobuf } Assert.AreEqual(expectedTokens[i], actualToken); } - Assert.Throws<InvalidProtocolBufferException>(() => tokenizer.Next()); + Assert.Throws<InvalidJsonException>(() => tokenizer.Next()); } } } diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index 00399438..24fe7746 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -84,6 +84,7 @@ <Compile Include="FieldCodec.cs" />
<Compile Include="FrameworkPortability.cs" />
<Compile Include="IDeepCloneable.cs" />
+ <Compile Include="InvalidJsonException.cs" />
<Compile Include="JsonFormatter.cs" />
<Compile Include="JsonParser.cs" />
<Compile Include="JsonToken.cs" />
diff --git a/csharp/src/Google.Protobuf/InvalidJsonException.cs b/csharp/src/Google.Protobuf/InvalidJsonException.cs new file mode 100644 index 00000000..b5434201 --- /dev/null +++ b/csharp/src/Google.Protobuf/InvalidJsonException.cs @@ -0,0 +1,53 @@ +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System.IO; + +namespace Google.Protobuf +{ + /// <summary> + /// Thrown when an attempt is made to parse invalid JSON, e.g. using + /// a non-string property key, or including a redundant comma. Parsing a protocol buffer + /// message represented in JSON using <see cref="JsonParser"/> can throw both this + /// exception and <see cref="InvalidProtocolBufferException"/> depending on the situation. This + /// exception is only thrown for "pure JSON" errors, whereas <c>InvalidProtocolBufferException</c> + /// is thrown when the JSON may be valid in and of itself, but cannot be parsed as a protocol buffer + /// message. + /// </summary> + public sealed class InvalidJsonException : IOException + { + internal InvalidJsonException(string message) + : base(message) + { + } + } +}
\ No newline at end of file diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs index 9710e675..85ef1a01 100644 --- a/csharp/src/Google.Protobuf/JsonParser.cs +++ b/csharp/src/Google.Protobuf/JsonParser.cs @@ -332,6 +332,8 @@ namespace Google.Protobuf /// </summary> /// <typeparam name="T">The type of message to create.</typeparam> /// <param name="json">The JSON to parse.</param> + /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception> + /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception> public T Parse<T>(string json) where T : IMessage, new() { return Parse<T>(new StringReader(json)); @@ -342,6 +344,8 @@ namespace Google.Protobuf /// </summary> /// <typeparam name="T">The type of message to create.</typeparam> /// <param name="jsonReader">Reader providing the JSON to parse.</param> + /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception> + /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception> public T Parse<T>(TextReader jsonReader) where T : IMessage, new() { T message = new T(); diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs index 108ccebe..5ed1e449 100644 --- a/csharp/src/Google.Protobuf/JsonTokenizer.cs +++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs @@ -88,6 +88,7 @@ namespace Google.Protobuf /// </remarks> /// <returns>The next token in the stream. This is never null.</returns> /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception> + /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception> internal JsonToken Next() { if (bufferedToken != null) @@ -182,7 +183,7 @@ namespace Google.Protobuf ValidateAndModifyStateForValue("Invalid state to read a number token: "); return JsonToken.Value(number); default: - throw new InvalidProtocolBufferException("Invalid first character of token: " + next.Value); + throw new InvalidJsonException("Invalid first character of token: " + next.Value); } } } @@ -191,7 +192,7 @@ namespace Google.Protobuf { if ((validStates & state) == 0) { - throw new InvalidProtocolBufferException(errorPrefix + state); + throw reader.CreateException(errorPrefix + state); } } @@ -207,13 +208,13 @@ namespace Google.Protobuf char c = reader.ReadOrFail("Unexpected end of text while reading string"); if (c < ' ') { - throw new InvalidProtocolBufferException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c)); + throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c)); } if (c == '"') { if (haveHighSurrogate) { - throw new InvalidProtocolBufferException("Invalid use of surrogate pair code units"); + throw reader.CreateException("Invalid use of surrogate pair code units"); } return value.ToString(); } @@ -226,7 +227,7 @@ namespace Google.Protobuf // followed by an escaped low surrogate or vice versa... and that couldn't even be represented in UTF-8. if (haveHighSurrogate != char.IsLowSurrogate(c)) { - throw new InvalidProtocolBufferException("Invalid use of surrogate pair code units"); + throw reader.CreateException("Invalid use of surrogate pair code units"); } haveHighSurrogate = char.IsHighSurrogate(c); value.Append(c); @@ -260,7 +261,7 @@ namespace Google.Protobuf case 'u': return ReadUnicodeEscape(); default: - throw new InvalidProtocolBufferException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c)); + throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c)); } } @@ -288,7 +289,7 @@ namespace Google.Protobuf } else { - throw new InvalidProtocolBufferException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c)); + throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c)); } result = (result << 4) + nybble; } @@ -306,11 +307,11 @@ namespace Google.Protobuf char? next = reader.Read(); if (next == null) { - throw new InvalidProtocolBufferException("Unexpected end of text while reading literal token " + text); + throw reader.CreateException("Unexpected end of text while reading literal token " + text); } if (next.Value != text[i]) { - throw new InvalidProtocolBufferException("Unexpected character while reading literal token " + text); + throw reader.CreateException("Unexpected character while reading literal token " + text); } } } @@ -354,7 +355,7 @@ namespace Google.Protobuf } catch (OverflowException) { - throw new InvalidProtocolBufferException("Numeric value out of range: " + builder); + throw reader.CreateException("Numeric value out of range: " + builder); } } @@ -363,14 +364,14 @@ namespace Google.Protobuf char first = reader.ReadOrFail("Invalid numeric literal"); if (first < '0' || first > '9') { - throw new InvalidProtocolBufferException("Invalid numeric literal"); + throw reader.CreateException("Invalid numeric literal"); } builder.Append(first); int digitCount; char? next = ConsumeDigits(builder, out digitCount); if (first == '0' && digitCount != 0) { - throw new InvalidProtocolBufferException("Invalid numeric literal: leading 0 for non-zero value."); + throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value."); } return next; } @@ -382,7 +383,7 @@ namespace Google.Protobuf char? next = ConsumeDigits(builder, out digitCount); if (digitCount == 0) { - throw new InvalidProtocolBufferException("Invalid numeric literal: fraction with no trailing digits"); + throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits"); } return next; } @@ -393,7 +394,7 @@ namespace Google.Protobuf char? next = reader.Read(); if (next == null) { - throw new InvalidProtocolBufferException("Invalid numeric literal: exponent with no trailing digits"); + throw reader.CreateException("Invalid numeric literal: exponent with no trailing digits"); } if (next == '-' || next == '+') { @@ -407,7 +408,7 @@ namespace Google.Protobuf next = ConsumeDigits(builder, out digitCount); if (digitCount == 0) { - throw new InvalidProtocolBufferException("Invalid numeric literal: exponent without value"); + throw reader.CreateException("Invalid numeric literal: exponent without value"); } return next; } @@ -615,7 +616,7 @@ namespace Google.Protobuf char? next = Read(); if (next == null) { - throw new InvalidProtocolBufferException(messageOnFailure); + throw CreateException(messageOnFailure); } return next.Value; } @@ -628,6 +629,15 @@ namespace Google.Protobuf } nextChar = c; } + + /// <summary> + /// Creates a new exception appropriate for the current state of the reader. + /// </summary> + internal InvalidJsonException CreateException(string message) + { + // TODO: Keep track of and use the location. + return new InvalidJsonException(message); + } } } } diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs index 70c52ba6..8f2717c5 100644 --- a/csharp/src/Google.Protobuf/MessageParser.cs +++ b/csharp/src/Google.Protobuf/MessageParser.cs @@ -148,6 +148,8 @@ namespace Google.Protobuf /// </summary> /// <param name="json">The JSON to parse.</param> /// <returns>The parsed message.</returns> + /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception> + /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception> public T ParseJson(string json) { T message = factory(); |