context: #region License
  // Copyright (c) 2007 James Newton-King
  //
  // Permission is hereby granted, free of charge, to any person
  // obtaining a copy of this software and associated documentation
  // files (the "Software"), to deal in the Software without
  // restriction, including without limitation the rights to use,
  // copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the
  // Software is furnished to do so, subject to the following
  // conditions:
  //
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  // OTHER DEALINGS IN THE SOFTWARE.
  #endregion
  
  using System;
  using System.Collections.Generic;
  using System.Globalization;
  using System.Text;
  #if !NETFX_CORE
  using NUnit.Framework;
  #else
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute;
  using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute;
  #endif
  using Newtonsoft.Json;
  using System.IO;
  using System.Xml;
  using Newtonsoft.Json.Utilities;
  
  namespace Newtonsoft.Json.Tests
  {
    [TestFixture]
    public class JsonTextReaderTest : TestFixtureBase
    {
      [Test]
      public void SurrogatePairValid()
      {
        string json = @"{ ""MATHEMATICAL ITALIC CAPITAL ALPHA"": ""\uD835\uDEE2"" }";
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
  
        Assert.IsTrue(reader.Read());
        Assert.IsTrue(reader.Read());
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.String, reader.TokenType);
  
        string s = reader.Value.ToString();
        Assert.AreEqual(2, s.Length);
  
        StringInfo stringInfo = new StringInfo(s);
        Assert.AreEqual(1, stringInfo.LengthInTextElements);
      }
  
      [Test]
      public void SurrogatePairReplacement()
      {
        // existing good surrogate pair
        Assert.AreEqual("ABC \ud800\udc00 DEF", ReadString("ABC \\ud800\\udc00 DEF"));
  
        // invalid surrogates (two high back-to-back)
        Assert.AreEqual("ABC \ufffd\ufffd DEF", ReadString("ABC \\ud800\\ud800 DEF"));
  
        // invalid surrogates (two high back-to-back)
        Assert.AreEqual("ABC \ufffd\ufffd\u1234 DEF", ReadString("ABC \\ud800\\ud800\\u1234 DEF"));
  
        // invalid surrogates (three high back-to-back)
        Assert.AreEqual("ABC \ufffd\ufffd\ufffd DEF", ReadString("ABC \\ud800\\ud800\\ud800 DEF"));
  
        // invalid surrogates (high followed by a good surrogate pair)
        Assert.AreEqual("ABC \ufffd\ud800\udc00 DEF", ReadString("ABC \\ud800\\ud800\\udc00 DEF"));
  
        // invalid high surrogate at end of string
        Assert.AreEqual("ABC \ufffd", ReadString("ABC \\ud800"));
  
        // high surrogate not followed by low surrogate
        Assert.AreEqual("ABC \ufffd DEF", ReadString("ABC \\ud800 DEF"));
  
        // low surrogate not preceded by high surrogate
        Assert.AreEqual("ABC \ufffd\ufffd DEF", ReadString("ABC \\udc00\\ud800 DEF"));
  
        // make sure unencoded invalid surrogate characters don't make it through
        Assert.AreEqual("\ufffd\ufffd\ufffd", ReadString("\udc00\ud800\ud800"));
  
        Assert.AreEqual("ABC \ufffd\b", ReadString("ABC \\ud800\\b"));
        Assert.AreEqual("ABC \ufffd ", ReadString("ABC \\ud800 "));
        Assert.AreEqual("ABC \b\ufffd", ReadString("ABC \\b\\ud800"));
      }
  
      private string ReadString(string input)
      {
        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(@"""" + input + @""""));
  
        JsonTextReader reader = new JsonTextReader(new StreamReader(ms));
        reader.Read();
  
        string s = (string)reader.Value;
  
        return s;
      }
  
      [Test]
      public void CloseInput()
      {
        MemoryStream ms = new MemoryStream();
        JsonTextReader reader = new JsonTextReader(new StreamReader(ms));
  
        Assert.IsTrue(ms.CanRead);
        reader.Close();
        Assert.IsFalse(ms.CanRead);
  
        ms = new MemoryStream();
        reader = new JsonTextReader(new StreamReader(ms)) { CloseInput = false };
  
        Assert.IsTrue(ms.CanRead);
        reader.Close();
        Assert.IsTrue(ms.CanRead);
      }
      
      [Test]
      public void YahooFinance()
      {
        string input = @"{
  ""matches"" : [
  {""t"":""C"", ""n"":""Citigroup Inc."", ""e"":""NYSE"", ""id"":""662713""}
  ,{""t"":""CHL"", ""n"":""China Mobile Ltd. (ADR)"", ""e"":""NYSE"", ""id"":""660998""}
  ,{""t"":""PTR"", ""n"":""PetroChina Company Limited (ADR)"", ""e"":""NYSE"", ""id"":""664536""}
  ,{""t"":""RIO"", ""n"":""Companhia Vale do Rio Doce (ADR)"", ""e"":""NYSE"", ""id"":""671472""}
  ,{""t"":""RIOPR"", ""n"":""Companhia Vale do Rio Doce (ADR)"", ""e"":""NYSE"", ""id"":""3512643""}
  ,{""t"":""CSCO"", ""n"":""Cisco Systems, Inc."", ""e"":""NASDAQ"", ""id"":""99624""}
  ,{""t"":""CVX"", ""n"":""Chevron Corporation"", ""e"":""NYSE"", ""id"":""667226""}
  ,{""t"":""TM"", ""n"":""Toyota Motor Corporation (ADR)"", ""e"":""NYSE"", ""id"":""655880""}
  ,{""t"":""JPM"", ""n"":""JPMorgan Chase \\x26 Co."", ""e"":""NYSE"", ""id"":""665639""}
  ,{""t"":""COP"", ""n"":""ConocoPhillips"", ""e"":""NYSE"", ""id"":""1691168""}
  ,{""t"":""LFC"", ""n"":""China Life Insurance Company Ltd. (ADR)"", ""e"":""NYSE"", ""id"":""688679""}
  ,{""t"":""NOK"", ""n"":""Nokia Corporation (ADR)"", ""e"":""NYSE"", ""id"":""657729""}
  ,{""t"":""KO"", ""n"":""The Coca-Cola Company"", ""e"":""NYSE"", ""id"":""6550""}
  ,{""t"":""VZ"", ""n"":""Verizon Communications Inc."", ""e"":""NYSE"", ""id"":""664887""}
  ,{""t"":""AMX"", ""n"":""America Movil S.A.B de C.V. (ADR)"", ""e"":""NYSE"", ""id"":""665834""}],
  ""all"" : false
  }
  ";
  
        using (JsonReader jsonReader = new JsonTextReader(new StringReader(input)))
        {
          while (jsonReader.Read())
          {
            Console.WriteLine(jsonReader.Value);
          }
        }
      }
  
      [Test]
      public void ReadConstructor()
      {
        string json = @"{""DefaultConverter"":new Date(0, ""hi""),""MemberConverter"":""1970-01-01T00:00:00Z""}";
  
        JsonReader reader = new JsonTextReader(new StreamReader(new SlowStream(json, new UTF8Encoding(false), 1)));
  
        Assert.IsTrue(reader.Read());
        Assert.IsTrue(reader.Read());
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.StartConstructor, reader.TokenType);
        Assert.AreEqual("Date", reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(0L, reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual("hi", reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.EndConstructor, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual("MemberConverter", reader.Value);
      }
  
      [Test]
      public void ParseAdditionalContent_Comma()
      {
        string json = @"[
  ""Small"",
  ""Medium"",
  ""Large""
  ],";
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Additional text encountered after finished reading JSON content: ,. Path '', line 5, position 2.",
          () =>
            {
              while (reader.Read())
              {
              }
            });
      }
  
      [Test]
      public void ParseAdditionalContent_Text()
      {
        string json = @"[
  ""Small"",
  ""Medium"",
  ""Large""
  ]content";
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
        reader.SetCharBuffer(new char[2]);
  
        reader.Read();
        Assert.AreEqual(1, reader.LineNumber);
  
        reader.Read();
        Assert.AreEqual(2, reader.LineNumber);
  
        reader.Read();
        Assert.AreEqual(3, reader.LineNumber);
  
        reader.Read();
        Assert.AreEqual(4, reader.LineNumber);
  
        reader.Read();
        Assert.AreEqual(5, reader.LineNumber);
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Additional text encountered after finished reading JSON content: c. Path '', line 5, position 2.",
          () =>
            {
              reader.Read();
            });
      }
  
      [Test]
      public void ParseAdditionalContent_Whitespace()
      {
        string json = @"[
  ""Small"",
  ""Medium"",
  ""Large""
  ]   
  
  ";
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
        while (reader.Read())
        {
        }
      }
  
      [Test]
      public void ParseAdditionalContent_WhitespaceThenText()
      {
        string json = @"'hi' a";
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Additional text encountered after finished reading JSON content: a. Path '', line 1, position 5.",
          () =>
            {
              while (reader.Read())
              {
              }
            });
      }
  
      [Test]
      public void ReadingIndented()
      {
        string input = @"{
    CPU: 'Intel',
    Drives: [
      'DVD read/writer',
      ""500 gigabyte hard drive""
    ]
  }";
  
        StringReader sr = new StringReader(input);
  
        using (JsonTextReader jsonReader = new JsonTextReader(sr))
        {
          jsonReader.SetCharBuffer(new char[5]);
  
          Assert.AreEqual(jsonReader.TokenType, JsonToken.None);
          Assert.AreEqual(0, jsonReader.LineNumber);
          Assert.AreEqual(0, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
          Assert.AreEqual(1, jsonReader.LineNumber);
          Assert.AreEqual(1, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
          Assert.AreEqual(jsonReader.Value, "CPU");
          Assert.AreEqual(2, jsonReader.LineNumber);
          Assert.AreEqual(7, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(JsonToken.String, jsonReader.TokenType);
          Assert.AreEqual("Intel", jsonReader.Value);
          Assert.AreEqual(2, jsonReader.LineNumber);
          Assert.AreEqual(15, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
          Assert.AreEqual(jsonReader.Value, "Drives");
          Assert.AreEqual(3, jsonReader.LineNumber);
          Assert.AreEqual(10, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.StartArray);
          Assert.AreEqual(3, jsonReader.LineNumber);
          Assert.AreEqual(12, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
          Assert.AreEqual(jsonReader.Value, "DVD read/writer");
          Assert.AreEqual(jsonReader.QuoteChar, '\'');
          Assert.AreEqual(4, jsonReader.LineNumber);
          Assert.AreEqual(22, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
          Assert.AreEqual(jsonReader.Value, "500 gigabyte hard drive");
          Assert.AreEqual(jsonReader.QuoteChar, '"');
          Assert.AreEqual(5, jsonReader.LineNumber);
          Assert.AreEqual(30, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.EndArray);
          Assert.AreEqual(6, jsonReader.LineNumber);
          Assert.AreEqual(4, jsonReader.LinePosition);
  
          jsonReader.Read();
          Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
          Assert.AreEqual(7, jsonReader.LineNumber);
          Assert.AreEqual(2, jsonReader.LinePosition);
  
          Assert.IsFalse(jsonReader.Read());
        }
      }
  
      [Test]
      public void Depth()
      {
        string input = @"{
    value:'Purple',
    array:[1,2,new Date(1)],
    subobject:{prop:1,proparray:[1]}
  }";
  
        StringReader sr = new StringReader(input);
  
        using (JsonReader reader = new JsonTextReader(sr))
        {
          Assert.AreEqual(0, reader.Depth);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.StartObject);
          Assert.AreEqual(0, reader.Depth);
          Assert.AreEqual("", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("value", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.String);
          Assert.AreEqual(reader.Value, @"Purple");
          Assert.AreEqual(reader.QuoteChar, '\'');
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("value", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("array", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.StartArray);
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("array", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.Integer);
          Assert.AreEqual(1L, reader.Value);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("array[0]", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.Integer);
          Assert.AreEqual(2L, reader.Value);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("array[1]", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.StartConstructor);
          Assert.AreEqual("Date", reader.Value);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("array[2]", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.Integer);
          Assert.AreEqual(1L, reader.Value);
          Assert.AreEqual(3, reader.Depth);
          Assert.AreEqual("array[2][0]", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.EndConstructor);
          Assert.AreEqual(null, reader.Value);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("array[2]", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.EndArray);
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("array", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("subobject", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.StartObject);
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("subobject", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("subobject.prop", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.Integer);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("subobject.prop", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("subobject.proparray", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.StartArray);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("subobject.proparray", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.Integer);
          Assert.AreEqual(3, reader.Depth);
          Assert.AreEqual("subobject.proparray[0]", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.EndArray);
          Assert.AreEqual(2, reader.Depth);
          Assert.AreEqual("subobject.proparray", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.EndObject);
          Assert.AreEqual(1, reader.Depth);
          Assert.AreEqual("subobject", reader.Path);
  
          reader.Read();
          Assert.AreEqual(reader.TokenType, JsonToken.EndObject);
          Assert.AreEqual(0, reader.Depth);
          Assert.AreEqual("", reader.Path);
        }
      }
  
      [Test]
      public void NullTextReader()
      {
        ExceptionAssert.Throws<ArgumentNullException>(
          @"Value cannot be null.
  Parameter name: reader",
          () =>
            {
              new JsonTextReader(null);
            });
      }
  
      [Test]
      public void UnexpectedEndOfString()
      {
        JsonReader reader = new JsonTextReader(new StringReader("'hi"));
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Unterminated string. Expected delimiter: '. Path '', line 1, position 3.",
          () =>
            {
              reader.Read();
            });
      }
  
      [Test]
      public void ReadLongString()
      {
        string s = new string('a', 10000);
        JsonReader reader = new JsonTextReader(new StringReader("'" + s + "'"));
        reader.Read();
  
        Assert.AreEqual(s, reader.Value);
      }
  
      [Test]
      public void ReadLongJsonArray()
      {
        int valueCount = 10000;
        StringWriter sw = new StringWriter();
        JsonTextWriter writer = new JsonTextWriter(sw);
        writer.WriteStartArray();
        for (int i = 0; i < valueCount; i++)
        {
          writer.WriteValue(i);
        }
        writer.WriteEndArray();
  
        string json = sw.ToString();
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
        Assert.IsTrue(reader.Read());
        for (int i = 0; i < valueCount; i++)
        {
          Assert.IsTrue(reader.Read());
          Assert.AreEqual((long)i, reader.Value);
        }
        Assert.IsTrue(reader.Read());
        Assert.IsFalse(reader.Read());
      }
  
      [Test]
      public void NullCharReading()
      {
        string json = "\0{\0'\0h\0i\0'\0:\0[\01\0,\0'\0'\0\0,\0null\0]\0,\0do\0:true\0}\0\0/*\0sd\0f\0*/\0/*\0sd\0f\0*/ \0";
        JsonTextReader reader = new JsonTextReader(new StreamReader(new SlowStream(json, new UTF8Encoding(false), 1)));
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.Integer, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.String, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.Null, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.Boolean, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.Comment, reader.TokenType);
        Assert.AreEqual("\0sd\0f\0", reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.Comment, reader.TokenType);
        Assert.AreEqual("\0sd\0f\0", reader.Value);
  
        Assert.IsFalse(reader.Read());
      }
  
      [Test]
      public void AppendCharsWhileReadingNull()
      {
        string json = @"[
    {
      ""$id"": ""1"",
      ""Name"": ""e1"",
      ""Manager"": null
    },
    {
      ""$id"": ""2"",
      ""Name"": ""e2"",
      ""Manager"": null
    },
    {
      ""$ref"": ""1""
    },
    {
      ""$ref"": ""2""
    }
  ]";
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
        reader.SetCharBuffer(new char[129]);
  
        for (int i = 0; i < 15; i++)
        {
          reader.Read();
        }
  
        reader.Read();
        Assert.AreEqual(JsonToken.Null, reader.TokenType);
      }
  
      [Test]
      public void AppendCharsWhileReadingNewLine()
      {
        string json = @"
  {
    ""description"": ""A person"",
    ""type"": ""object"",
    ""properties"":
    {
      ""name"": {""type"":""string""},
      ""hobbies"": {
        ""type"": ""array"",
        ""items"": {""type"":""string""}
      }
    }
  }
  ";
  
        JsonTextReader reader = new JsonTextReader(new StringReader(json));
        reader.SetCharBuffer(new char[129]);
  
        for (int i = 0; i < 14; i++)
        {
          Assert.IsTrue(reader.Read());
        }
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
        Assert.AreEqual("type", reader.Value);
      }
  
      [Test]
      public void ReadNullTerminatorStrings()
      {
        JsonReader reader = new JsonTextReader(new StringReader("'h\0i'"));
        Assert.IsTrue(reader.Read());
  
        Assert.AreEqual("h\0i", reader.Value);
      }
  
      [Test]
      public void UnexpectedEndOfHex()
      {
        JsonReader reader = new JsonTextReader(new StringReader(@"'h\u123"));
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Unexpected end while parsing unicode character. Path '', line 1, position 4.",
          () =>
            {
              reader.Read();
            });
      }
  
      [Test]
      public void UnexpectedEndOfControlCharacter()
      {
        JsonReader reader = new JsonTextReader(new StringReader(@"'h\"));
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Unterminated string. Expected delimiter: '. Path '', line 1, position 3.",
          () =>
            {
              reader.Read();
            });
      }
  
      [Test]
      public void ReadBytesWithBadCharacter()
      {
        JsonReader reader = new JsonTextReader(new StringReader(@"true"));
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Error reading bytes. Unexpected token: Boolean. Path '', line 1, position 4.",
          () =>
            {
              reader.ReadAsBytes();
            });
      }
  
      [Test]
      public void ReadBytesWithUnexpectedEnd()
      {
        string helloWorld = "Hello world!";
        byte[] helloWorldData = Encoding.UTF8.GetBytes(helloWorld);
  
        JsonReader reader = new JsonTextReader(new StringReader(@"'" + Convert.ToBase64String(helloWorldData)));
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Unterminated string. Expected delimiter: '. Path '', line 1, position 17.",
          () =>
            {
              reader.ReadAsBytes();
            });
      }
  
      [Test]
      public void ReadBytesNoStartWithUnexpectedEnd()
      {
        JsonReader reader = new JsonTextReader(new StringReader(@"[  "));
        Assert.IsTrue(reader.Read());
  
        Assert.IsNull(reader.ReadAsBytes());
        Assert.AreEqual(JsonToken.None, reader.TokenType);
      }
  
      [Test]
      public void UnexpectedEndWhenParsingUnquotedProperty()
      {
        JsonReader reader = new JsonTextReader(new StringReader(@"{aww"));
        Assert.IsTrue(reader.Read());
  
        ExceptionAssert.Throws<JsonReaderException>(
          "Unexpected end while parsing unquoted property name. Path '', line 1, position 4.",
          () =>
          {
            reader.Read();
          });
      }
  
      [Test]
      public void ReadNewLines()
      {
        string newLinesText = StringUtils.CarriageReturn + StringUtils.CarriageReturnLineFeed + StringUtils.LineFeed + StringUtils.CarriageReturnLineFeed + " " + StringUtils.CarriageReturn + StringUtils.CarriageReturnLineFeed;
  
        string json =
          newLinesText
          + "{" + newLinesText
          + "'" + newLinesText
          + "name1" + newLinesText
          + "'" + newLinesText
          + ":" + newLinesText
          + "[" + newLinesText
          + "new" + newLinesText
          + "Date" + newLinesText
          + "(" + newLinesText
          + "1" + newLinesText
          + "," + newLinesText
          + "null" + newLinesText
          + "/*" + newLinesText
          + "blah comment" + newLinesText
          + "*/" + newLinesText
          + ")" + newLinesText
          + "," + newLinesText
          + "1.1111" + newLinesText
          + "]" + newLinesText
          + "," + newLinesText
          + "name2" + newLinesText
          + ":" + newLinesText
          + "{" + newLinesText
          + "}" + newLinesText
          + "}" + newLinesText;
  
        int count = 0;
        StringReader sr = new StringReader(newLinesText);
        while (sr.ReadLine() != null)
        {
          count++;
        }
  
        JsonTextReader reader = new JsonTextReader(new StreamReader(new SlowStream(json, new UTF8Encoding(false), 1)));
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(7, reader.LineNumber);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(31, reader.LineNumber);
        Assert.AreEqual(newLinesText + "name1" + newLinesText, reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(37, reader.LineNumber);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(55, reader.LineNumber);
        Assert.AreEqual(JsonToken.StartConstructor, reader.TokenType);
        Assert.AreEqual("Date", reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(61, reader.LineNumber);
        Assert.AreEqual(1L, reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(73, reader.LineNumber);
        Assert.AreEqual(null, reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(91, reader.LineNumber);
        Assert.AreEqual(newLinesText + "blah comment" + newLinesText, reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(97, reader.LineNumber);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(109, reader.LineNumber);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(115, reader.LineNumber);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(133, reader.LineNumber);
        Assert.AreEqual("name2", reader.Value);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(139, reader.LineNumber);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(145, reader.LineNumber);
  
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(151, reader.LineNumber);
      }
  
      [Test]
      public void ParsingQuotedPropertyWithControlCharacters()
      {
        JsonReader reader = new JsonTextReader(new StringReader(@"{'hi\r\nbye':1}"));
        Assert.IsTrue(reader.Read());
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
        Assert.AreEqual(@"hi
  bye", reader.Value);
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.Integer, reader.TokenType);
        Assert.AreEqual(1L, reader.Value);
        Assert.IsTrue(reader.Read());
        Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
        Assert.IsFalse(reader.Read());
      }
  
      [Test]
      public void ReadBytesFollowingNumberInArray()
      {
  
gt:       string helloWorld = "Hello world!";