diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index 601cb783..d80e0ae0 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -2522,6 +2522,170 @@ bye", reader.Value); Assert.AreEqual(JsonToken.EndConstructor, reader.TokenType); } + [Test] + public void SingleLineComments() + { + string json = @"//comment*//*hi*/ +{//comment +Name://comment +true//comment after true" + StringUtils.CarriageReturn + @" +,//comment after comma" + StringUtils.CarriageReturnLineFeed + @" +""ExpiryDate""://comment" + StringUtils.LineFeed + @" +new +" + StringUtils.LineFeed + + @"Date +(//comment +null//comment +), + ""Price"": 3.99, + ""Sizes"": //comment +[//comment + + ""Small""//comment +]//comment +}//comment +//comment 1 "; + + JsonTextReader reader = new JsonTextReader(new StreamReader(new SlowStream(json, new UTF8Encoding(false), 1))); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual("comment*//*hi*/", reader.Value); + Assert.AreEqual(2, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(2, reader.LineNumber); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual(3, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("Name", reader.Value); + Assert.AreEqual(3, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual(4, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Boolean, reader.TokenType); + Assert.AreEqual(true, reader.Value); + Assert.AreEqual(4, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual("comment after true", reader.Value); + Assert.AreEqual(5, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual("comment after comma", reader.Value); + Assert.AreEqual(7, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("ExpiryDate", reader.Value); + Assert.AreEqual(8, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual(9, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartConstructor, reader.TokenType); + Assert.AreEqual(13, reader.LineNumber); + Assert.AreEqual("Date", reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.AreEqual(14, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual(15, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndConstructor, reader.TokenType); + Assert.AreEqual(15, reader.LineNumber); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("Price", reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + Assert.AreEqual("Sizes", reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.String, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.EndObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual("comment ", reader.Value); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual("comment 1 ", reader.Value); + + Assert.IsFalse(reader.Read()); + } + + [Test] + public void JustSinglelineComment() + { + string json = @"//comment"; + + JsonTextReader reader = new JsonTextReader(new StreamReader(new SlowStream(json, new UTF8Encoding(false), 1))); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.Comment, reader.TokenType); + Assert.AreEqual("comment", reader.Value); + + Assert.IsFalse(reader.Read()); + } + + [Test] + public void ErrorReadingComment() + { + string json = @"/"; + + JsonTextReader reader = new JsonTextReader(new StreamReader(new SlowStream(json, new UTF8Encoding(false), 1))); + + ExceptionAssert.Throws( + "Unexpected end while parsing comment. Path '', line 1, position 1.", + () => { reader.Read(); }); + } + [Test] public void ParseOctalNumber() { diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index a92283b7..aba09f59 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -1383,6 +1383,54 @@ _____'propertyName': NaN }", stringWriter.ToString()); } } + + [Test] + public void WriteComments() + { + string json = @"//comment*//*hi*/ +{//comment +Name://comment +true//comment after true" + StringUtils.CarriageReturn + @" +,//comment after comma" + StringUtils.CarriageReturnLineFeed + @" +""ExpiryDate""://comment" + StringUtils.LineFeed + @" +new +" + StringUtils.LineFeed + + @"Constructor +(//comment +null//comment +), + ""Price"": 3.99, + ""Sizes"": //comment +[//comment + + ""Small""//comment +]//comment +}//comment +//comment 1 "; + + JsonTextReader r = new JsonTextReader(new StringReader(json)); + + StringWriter sw = new StringWriter(); + JsonTextWriter w = new JsonTextWriter(sw); + w.Formatting = Formatting.Indented; + + w.WriteToken(r, true); + + Assert.AreEqual(@"/*comment*//*hi*/*/{/*comment*/ + ""Name"": /*comment*/ true/*comment after true*//*comment after comma*/, + ""ExpiryDate"": /*comment*/ new Constructor( + /*comment*/, + null + /*comment*/ + ), + ""Price"": 3.99, + ""Sizes"": /*comment*/ [ + /*comment*/ + ""Small"" + /*comment*/ + ]/*comment*/ +}/*comment *//*comment 1 */", sw.ToString()); + } } public class CustomJsonTextWriter : JsonTextWriter diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index 6a34fb83..8148c450 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -75,4 +75,4 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("6.0.1.16909")] +[assembly: AssemblyFileVersion("6.0.1.16919")] diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index fb9c25de..6aba0c74 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -1310,10 +1310,19 @@ namespace Newtonsoft.Json // should have already parsed / character before reaching this method _charPos++; - if (!EnsureChars(1, false) || _chars[_charPos] != '*') - throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); + if (!EnsureChars(1, false)) + throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); + + bool singlelineComment; + + if (_chars[_charPos] == '*') + singlelineComment = false; + else if (_chars[_charPos] == '/') + singlelineComment = true; else - _charPos++; + throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); + + _charPos++; int initialPosition = _charPos; @@ -1327,7 +1336,13 @@ namespace Newtonsoft.Json if (_charsUsed == _charPos) { if (ReadData(true) == 0) - throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); + { + if (!singlelineComment) + throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); + + _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); + commentFinished = true; + } } else { @@ -1337,21 +1352,34 @@ namespace Newtonsoft.Json case '*': _charPos++; - if (EnsureChars(0, true)) + if (!singlelineComment) { - if (_chars[_charPos] == '/') + if (EnsureChars(0, true)) { - _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition - 1); + if (_chars[_charPos] == '/') + { + _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition - 1); - _charPos++; - commentFinished = true; + _charPos++; + commentFinished = true; + } } } break; case StringUtils.CarriageReturn: + if (singlelineComment) + { + _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); + commentFinished = true; + } ProcessCarriageReturn(true); break; case StringUtils.LineFeed: + if (singlelineComment) + { + _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); + commentFinished = true; + } ProcessLineFeed(); break; default: @@ -1410,7 +1438,9 @@ namespace Newtonsoft.Json if (!EnsureChars(1, false)) return false; - return (_chars[_charPos + 1] == '*'); + var nextChart = _chars[_charPos + 1]; + + return (nextChart == '*' || nextChart == '/'); case ')': if (CurrentState == State.Constructor || CurrentState == State.ConstructorStart) return true; diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index 08253f81..8bfddb03 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -91,5 +91,5 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("6.0.1.16909")] +[assembly: AssemblyFileVersion("6.0.1.16919")] [assembly: CLSCompliant(true)]