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 Newtonsoft.Json.Linq.JsonPath;
  #if DNXCORE50
  using Xunit;
  using Test = Xunit.FactAttribute;
  using Assert = Newtonsoft.Json.Tests.XUnitAssert;
  #else
  using NUnit.Framework;
  #endif
  using Newtonsoft.Json.Linq;
  #if NET20
  using Newtonsoft.Json.Utilities.LinqBridge;
  #else
  using System.Linq;
  
  #endif
  
  namespace Newtonsoft.Json.Tests.Linq.JsonPath
  {
      [TestFixture]
      public class JPathParseTests : TestFixtureBase
      {
          [Test]
          public void BooleanQuery_TwoValues()
          {
              JPath path = new JPath("[?(1 > 2)]");
              Assert.AreEqual(1, path.Filters.Count);
              BooleanQueryExpression booleanExpression = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(1, (int)(JValue)booleanExpression.Left);
              Assert.AreEqual(2, (int)(JValue)booleanExpression.Right);
              Assert.AreEqual(QueryOperator.GreaterThan, booleanExpression.Operator);
          }
  
          [Test]
          public void BooleanQuery_TwoPaths()
          {
              JPath path = new JPath("[?(@.price > @.max_price)]");
              Assert.AreEqual(1, path.Filters.Count);
              BooleanQueryExpression booleanExpression = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              List<PathFilter> leftPaths = (List<PathFilter>)booleanExpression.Left;
              List<PathFilter> rightPaths = (List<PathFilter>)booleanExpression.Right;
  
              Assert.AreEqual("price", ((FieldFilter)leftPaths[0]).Name);
              Assert.AreEqual("max_price", ((FieldFilter)rightPaths[0]).Name);
              Assert.AreEqual(QueryOperator.GreaterThan, booleanExpression.Operator);
          }
  
          [Test]
          public void SingleProperty()
          {
              JPath path = new JPath("Blah");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void SingleQuotedProperty()
          {
              JPath path = new JPath("['Blah']");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void SingleQuotedPropertyWithWhitespace()
          {
              JPath path = new JPath("[  'Blah'  ]");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void SingleQuotedPropertyWithDots()
          {
              JPath path = new JPath("['Blah.Ha']");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("Blah.Ha", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void SingleQuotedPropertyWithBrackets()
          {
              JPath path = new JPath("['[*]']");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("[*]", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void SinglePropertyWithRoot()
          {
              JPath path = new JPath("$.Blah");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void SinglePropertyWithRootWithStartAndEndWhitespace()
          {
              JPath path = new JPath(" $.Blah ");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void RootWithBadWhitespace()
          {
              ExceptionAssert.Throws<JsonException>(() => { new JPath("$ .Blah"); }, @"Unexpected character while parsing path:  ");
          }
  
          [Test]
          public void NoFieldNameAfterDot()
          {
              ExceptionAssert.Throws<JsonException>(() => { new JPath("$.Blah."); }, @"Unexpected end while parsing path.");
          }
  
          [Test]
          public void RootWithBadWhitespace2()
          {
              ExceptionAssert.Throws<JsonException>(() => { new JPath("$. Blah"); }, @"Unexpected character while parsing path:  ");
          }
  
          [Test]
          public void WildcardPropertyWithRoot()
          {
              JPath path = new JPath("$.*");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual(null, ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void WildcardArrayWithRoot()
          {
              JPath path = new JPath("$.[*]");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual(null, ((ArrayIndexFilter)path.Filters[0]).Index);
          }
  
          [Test]
          public void RootArrayNoDot()
          {
              JPath path = new JPath("$[1]");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual(1, ((ArrayIndexFilter)path.Filters[0]).Index);
          }
  
          [Test]
          public void WildcardArray()
          {
              JPath path = new JPath("[*]");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual(null, ((ArrayIndexFilter)path.Filters[0]).Index);
          }
  
          [Test]
          public void WildcardArrayWithProperty()
          {
              JPath path = new JPath("[ * ].derp");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual(null, ((ArrayIndexFilter)path.Filters[0]).Index);
              Assert.AreEqual("derp", ((FieldFilter)path.Filters[1]).Name);
          }
  
          [Test]
          public void QuotedWildcardPropertyWithRoot()
          {
              JPath path = new JPath("$.['*']");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("*", ((FieldFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void SingleScanWithRoot()
          {
              JPath path = new JPath("$..Blah");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual("Blah", ((ScanFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void WildcardScanWithRoot()
          {
              JPath path = new JPath("$..*");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual(null, ((ScanFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void WildcardScanWithRootWithWhitespace()
          {
              JPath path = new JPath("$..* ");
              Assert.AreEqual(1, path.Filters.Count);
              Assert.AreEqual(null, ((ScanFilter)path.Filters[0]).Name);
          }
  
          [Test]
          public void TwoProperties()
          {
              JPath path = new JPath("Blah.Two");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              Assert.AreEqual("Two", ((FieldFilter)path.Filters[1]).Name);
          }
  
          [Test]
          public void OnePropertyOneScan()
          {
              JPath path = new JPath("Blah..Two");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              Assert.AreEqual("Two", ((ScanFilter)path.Filters[1]).Name);
          }
  
          [Test]
          public void SinglePropertyAndIndexer()
          {
              JPath path = new JPath("Blah[0]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              Assert.AreEqual(0, ((ArrayIndexFilter)path.Filters[1]).Index);
          }
  
          [Test]
          public void SinglePropertyAndExistsQuery()
          {
              JPath path = new JPath("Blah[ ?( @..name ) ]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
              Assert.AreEqual(QueryOperator.Exists, expressions.Operator);
              List<PathFilter> paths = (List<PathFilter>)expressions.Left;
              Assert.AreEqual(1, paths.Count);
              Assert.AreEqual("name", ((ScanFilter)paths[0]).Name);
          }
  
          [Test]
          public void SinglePropertyAndFilterWithWhitespace()
          {
              JPath path = new JPath("Blah[ ?( @.name=='hi' ) ]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
              Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
              Assert.AreEqual("hi", (string)(JToken)expressions.Right);
          }
  
          [Test]
          public void SinglePropertyAndFilterWithEscapeQuote()
          {
              JPath path = new JPath(@"Blah[ ?( @.name=='h\'i' ) ]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
              Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
              Assert.AreEqual("h'i", (string)(JToken)expressions.Right);
          }
  
          [Test]
          public void SinglePropertyAndFilterWithDoubleEscape()
          {
              JPath path = new JPath(@"Blah[ ?( @.name=='h\\i' ) ]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
              Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
              Assert.AreEqual("h\\i", (string)(JToken)expressions.Right);
          }
  
          [Test]
          public void SinglePropertyAndFilterWithUnknownEscape()
          {
              ExceptionAssert.Throws<JsonException>(() => { new JPath(@"Blah[ ?( @.name=='h\i' ) ]"); }, @"Unknown escape character: \i");
          }
  
          [Test]
          public void SinglePropertyAndFilterWithFalse()
          {
              JPath path = new JPath("Blah[ ?( @.name==false ) ]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
              Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
              Assert.AreEqual(false, (bool)(JToken)expressions.Right);
          }
  
          [Test]
          public void SinglePropertyAndFilterWithTrue()
          {
              JPath path = new JPath("Blah[ ?( @.name==true ) ]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
              Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
              Assert.AreEqual(true, (bool)(JToken)expressions.Right);
          }
  
          [Test]
          public void SinglePropertyAndFilterWithNull()
          {
              JPath path = new JPath("Blah[ ?( @.name==null ) ]");
              Assert.AreEqual(2, path.Filters.Count);
              Assert.AreEqual("Blah", ((FieldFilter)path.Filters[0]).Name);
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[1]).Expression;
              Assert.AreEqual(QueryOperator.Equals, expressions.Operator);
              Assert.AreEqual(null, ((JValue)expressions.Right).Value);
          }
  
          [Test]
          public void FilterWithScan()
          {
              JPath path = new JPath("[?(@..name<>null)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              List<PathFilter> paths = (List<PathFilter>)expressions.Left;
              Assert.AreEqual("name", ((ScanFilter)paths[0]).Name);
          }
  
          [Test]
          public void FilterWithNotEquals()
          {
              JPath path = new JPath("[?(@.name<>null)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(QueryOperator.NotEquals, expressions.Operator);
          }
  
          [Test]
          public void FilterWithNotEquals2()
          {
              JPath path = new JPath("[?(@.name!=null)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(QueryOperator.NotEquals, expressions.Operator);
          }
  
          [Test]
          public void FilterWithLessThan()
          {
              JPath path = new JPath("[?(@.name<null)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(QueryOperator.LessThan, expressions.Operator);
          }
  
          [Test]
          public void FilterWithLessThanOrEquals()
          {
              JPath path = new JPath("[?(@.name<=null)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(QueryOperator.LessThanOrEquals, expressions.Operator);
          }
  
          [Test]
          public void FilterWithGreaterThan()
          {
              JPath path = new JPath("[?(@.name>null)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(QueryOperator.GreaterThan, expressions.Operator);
          }
  
          [Test]
          public void FilterWithGreaterThanOrEquals()
          {
              JPath path = new JPath("[?(@.name>=null)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(QueryOperator.GreaterThanOrEquals, expressions.Operator);
          }
  
          [Test]
          public void FilterWithInteger()
          {
              JPath path = new JPath("[?(@.name>=12)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(12, (int)(JToken)expressions.Right);
          }
  
          [Test]
          public void FilterWithNegativeInteger()
          {
              JPath path = new JPath("[?(@.name>=-12)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(-12, (int)(JToken)expressions.Right);
          }
  
          [Test]
          public void FilterWithFloat()
          {
              JPath path = new JPath("[?(@.name>=12.1)]");
              BooleanQueryExpression expressions = (BooleanQueryExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(12.1d, (double)(JToken)expressions.Right);
          }
  
          [Test]
          public void FilterExistWithAnd()
          {
              JPath path = new JPath("[?(@.name&&@.title)]");
              CompositeExpression expressions = (CompositeExpression)((QueryFilter)path.Filters[0]).Expression;
              Assert.AreEqual(QueryOperator.And, expressions.Operator);
              Assert.AreEqual(2, expressions.Expressions.Count);
  
              var first = (BooleanQueryExpression)expressions.Expressions[0];
              var firstPaths = (List<PathFilter>)first.Left;
              Assert.AreEqual("name", ((FieldFilter)firstPaths[0]).Name);
              Assert.AreEqual(QueryOperator.Exists, first.Operator);
  
  
gt:             var second = (BooleanQueryExpression)expressions.Expressions[1];