unit Antlr.Runtime.Tree.Tests;
{

  Delphi DUnit Test Case
  ----------------------
  This unit contains a skeleton test case class generated by the Test Case Wizard.
  Modify the generated code to correctly setup and call the methods from the unit
  being tested.

}

interface

uses
  TestFramework,
  Antlr.Runtime.Collections,
  Antlr.Runtime.Tree,
  Classes,
  SysUtils,
  Antlr.Runtime,
  Antlr.Runtime.Tools;

type
  // Test methods for class ICommonTree
  TestICommonTree = class(TTestCase)
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestSingleNode;
    procedure Test4Nodes;
    procedure TestList;
    procedure TestList2;
    procedure TestAddListToExistChildren;
    procedure TestDupTree;
    procedure TestBecomeRoot;
    procedure TestBecomeRoot2;
    procedure TestBecomeRoot3;
    procedure TestBecomeRoot5;
    procedure TestBecomeRoot6;
    procedure TestReplaceWithNoChildren;
    procedure TestReplaceWithOneChildren;
    procedure TestReplaceInMiddle;
    procedure TestReplaceAtLeft;
    procedure TestReplaceAtRight;
    procedure TestReplaceOneWithTwoAtLeft;
    procedure TestReplaceOneWithTwoAtRight;
    procedure TestReplaceOneWithTwoInMiddle;
    procedure TestReplaceTwoWithOneAtLeft;
    procedure TestReplaceTwoWithOneAtRight;
    procedure TestReplaceAllWithOne;
    procedure TestReplaceAllWithTwo;
  end;

  // Test methods for class ICommonTreeNodeStream
  TestICommonTreeNodeStream = class(TTestCase)
  private
    function CreateCommonTreeNodeStream(const T: IANTLRInterface): ITreeNodeStream;
    function GetStringOfEntireStreamContentsWithNodeTypesOnly(
      const Nodes: ITreeNodeStream): String;
    function CreateUnBufferedTreeNodeStream(const T: IANTLRInterface): ITreeNodeStream;
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestSingleNode;
    procedure Test4Nodes;
    procedure TestList;
    procedure TestFlatList;
    procedure TestListWithOneNode;
    procedure TestAoverB;
    procedure TestLT;
    procedure TestMarkRewindEntire;
    procedure TestMarkRewindInMiddle;
    procedure TestMarkRewindNested;
    procedure TestSeek;
    procedure TestSeekFromStart;
    procedure TestPushPop;
    procedure TestNestedPushPop;
    procedure TestPushPopFromEOF;
    procedure TestStackStretch;
    procedure TestBufferOverflow;
    procedure TestBufferWrap;
  end;

  // Test methods for class IRewriteRuleXxxxStream
  TestIRewriteRuleXxxxStream = class(TTestCase)
  strict private
    function CreateTreeAdaptor: ITreeAdaptor;
    function CreateTree(const Token: IToken): ITree;
    function CreateToken(const TokenType: Integer; const Text: String): IToken;
    function CreateTokenList(const Count: Integer): IList<IToken>;
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestRewriteRuleTokenStreamConstructors;
    procedure TestRewriteRuleSubtreeStreamConstructors;
    procedure TestRewriteRuleNodeStreamConstructors;

    procedure TestRRTokenStreamBehaviourWhileEmpty1;
    procedure TestRRSubtreeStreamBehaviourWhileEmpty1;
    procedure TestRRNodeStreamBehaviourWhileEmpty1;

    procedure TestRRTokenStreamBehaviourWhileEmpty2;
    procedure TestRRSubtreeStreamBehaviourWhileEmpty2;
    procedure TestRRNodeStreamBehaviourWhileEmpty2;

    procedure TestRRTokenStreamBehaviourWhileEmpty3;

    procedure TestRRTokenStreamBehaviourWithElements;
    procedure TestRRSubtreeStreamBehaviourWithElements;
    procedure TestRRNodeStreamBehaviourWithElements;
  end;

  // Test methods for class ITreeWizard
  TestITreeWizard = class(TTestCase)
  strict private
    FTokens: TStringArray;
  strict private
    type
      TRecordAllElementsVisitor = class sealed(TTreeWizard.TVisitor)
      strict private
        FList: IList<IANTLRInterface>;
      strict protected
        procedure Visit(const T: IANTLRInterface); override;
      public
        constructor Create(const AList: IList<IANTLRInterface>);
      end;

      TTest1ContextVisitor = class sealed(TANTLRObject, IContextVisitor)
      strict private
        FAdaptor: ITreeAdaptor;
        FList: IList<IANTLRInterface>;
      protected
        { IContextVisitor }
        procedure Visit(const T, Parent: IANTLRInterface; const ChildIndex: Integer;
          const Labels: IDictionary<String, IANTLRInterface>);
      public
        constructor Create(const AAdaptor: ITreeAdaptor;
          const AList: IList<IANTLRInterface>);
      end;

      TTest2ContextVisitor = class sealed(TANTLRObject, IContextVisitor)
      strict private
        FAdaptor: ITreeAdaptor;
        FList: IList<IANTLRInterface>;
      protected
        { IContextVisitor }
        procedure Visit(const T, Parent: IANTLRInterface; const ChildIndex: Integer;
          const Labels: IDictionary<String, IANTLRInterface>);
      public
        constructor Create(const AAdaptor: ITreeAdaptor;
          const AList: IList<IANTLRInterface>);
      end;
  public
    constructor Create(MethodName: String); override;
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestSingleNode;
    procedure TestSingleNodeWithArg;
    procedure TestSingleNodeTree;
    procedure TestSingleLevelTree;
    procedure TestListTree;
    procedure TestInvalidListTree;
    procedure TestDoubleLevelTree;
    procedure TestSingleNodeIndex;
    procedure TestNoRepeatsIndex;
    procedure TestRepeatsIndex;
    procedure TestNoRepeatsVisit;
    procedure TestNoRepeatsVisit2;
    procedure TestRepeatsVisit;
    procedure TestRepeatsVisit2;
    procedure TestRepeatsVisitWithContext;
    procedure TestRepeatsVisitWithNullParentAndContext;
    procedure TestVisitPattern;
    procedure TestVisitPatternMultiple;
    procedure TestVisitPatternMultipleWithLabels;
    procedure TestParse;
    procedure TestParseSingleNode;
    procedure TestParseFlatTree;
    procedure TestWildcard;
    procedure TestParseWithText;
    procedure TestParseWithTextFails;
    procedure TestParseLabels;
    procedure TestParseWithWildcardLabels;
    procedure TestParseLabelsAndTestText;
    procedure TestParseLabelsInNestedTree;
    procedure TestEquals;
    procedure TestEqualsWithText;
    procedure TestEqualsWithMismatchedText;
    procedure TestFindPattern;
  end;

implementation

procedure TestICommonTree.SetUp;
begin
end;

procedure TestICommonTree.TearDown;
begin
end;

procedure TestICommonTree.Test4Nodes;
var
  R0: ICommonTree;
begin
  // ^(101 ^(102 103) 104)
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  R0.GetChild(0).AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(104)));
  CheckNull(R0.Parent);
  CheckEquals(R0.ChildIndex,-1);
end;

procedure TestICommonTree.TestAddListToExistChildren;
var
  Root, R0, C0, C1, C2: ICommonTree;
begin
  // Add child ^(nil 101 102 103) to root ^(5 6)
  // should add 101 102 103 to end of 5's child list
  Root := TCommonTree.Create(TCommonToken.Create(5));
  Root.AddChild(TCommonTree.Create(TCommonToken.Create(6)));

  // child tree
  R0 := TCommonTree.Create(IToken(nil));
  C0 := TCommonTree.Create(TCommonToken.Create(101));
  C1 := TCommonTree.Create(TCommonToken.Create(102));
  C2 := TCommonTree.Create(TCommonToken.Create(103));
  R0.AddChild(C0);
  R0.AddChild(C1);
  R0.AddChild(C2);

  Root.AddChild(R0);

  CheckNull(Root.Parent);
  CheckEquals(Root.ChildIndex, -1);

  // check children of root all point at root
  Check(C0.Parent = Root);
  Check(C0.ChildIndex = 1);
  Check(C1.Parent = Root);
  Check(C1.ChildIndex = 2);
  Check(C2.Parent = Root);
  Check(C2.ChildIndex = 3);
end;

procedure TestICommonTree.TestBecomeRoot;
var
  OldRoot, NewRoot: ICommonTree;
  Adaptor: ITreeAdaptor;
begin
  // 5 becomes new root of ^(nil 101 102 103)
  NewRoot := TCommonTree.Create(TCommonToken.Create(5));
  OldRoot := TCommonTree.Create(IToken(nil));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(101)));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  Adaptor := TCommonTreeAdaptor.Create;
  Adaptor.BecomeRoot(NewRoot, OldRoot);
  NewRoot.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestBecomeRoot2;
var
  OldRoot, NewRoot: ICommonTree;
  Adaptor: ITreeAdaptor;
begin
  // 5 becomes new root of ^(101 102 103)
  NewRoot := TCommonTree.Create(TCommonToken.Create(5));
  OldRoot := TCommonTree.Create(TCommonToken.Create(101));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  Adaptor := TCommonTreeAdaptor.Create;
  Adaptor.BecomeRoot(NewRoot, OldRoot);
  NewRoot.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestBecomeRoot3;
var
  OldRoot, NewRoot: ICommonTree;
  Adaptor: ITreeAdaptor;
begin
  // ^(nil 5) becomes new root of ^(nil 101 102 103)
  NewRoot := TCommonTree.Create(IToken(nil));
  NewRoot.AddChild(TCommonTree.Create(TCommonToken.Create(5)));
  OldRoot := TCommonTree.Create(IToken(nil));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(101)));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  Adaptor := TCommonTreeAdaptor.Create;
  Adaptor.BecomeRoot(NewRoot, OldRoot);
  NewRoot.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestBecomeRoot5;
var
  OldRoot, NewRoot: ICommonTree;
  Adaptor: ITreeAdaptor;
begin
  // ^(nil 5) becomes new root of ^(101 102 103)
  NewRoot := TCommonTree.Create(IToken(nil));
  NewRoot.AddChild(TCommonTree.Create(TCommonToken.Create(5)));
  OldRoot := TCommonTree.Create(TCommonToken.Create(101));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  OldRoot.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  Adaptor := TCommonTreeAdaptor.Create;
  Adaptor.BecomeRoot(NewRoot, OldRoot);
  NewRoot.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestBecomeRoot6;
var
  Root0, Root1: ICommonTree;
  Adaptor: ITreeAdaptor;
begin
  // emulates construction of ^(5 6)
  Adaptor := TCommonTreeAdaptor.Create;
  Root0 := Adaptor.GetNilNode as ICommonTree;
  Root1 := Adaptor.GetNilNode as ICommonTree;
  Root1 := Adaptor.BecomeRoot(TCommonTree.Create(TCommonToken.Create(5)), Root1) as ICommonTree;
  Adaptor.AddChild(Root1, TCommonTree.Create(TCommonToken.Create(6)));
  Adaptor.AddChild(Root0, Root1);
  Root0.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestDupTree;
var
  R0, R1, Dup: ICommonTree;
  R2: ITree;
  Adaptor: ICommonTreeAdaptor;
begin
  // ^(101 ^(102 103 ^(106 107) ) 104 105)
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R0.AddChild(R1);
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R2 := TCommonTree.Create(TCommonToken.Create(106));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R1.AddChild(R2);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(104)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(105)));

  Adaptor := TCommonTreeAdaptor.Create;
  Dup := Adaptor.DupTree(R0) as ICommonTree;

  CheckNull(Dup.Parent);
  CheckEquals(Dup.ChildIndex, -1);
  Dup.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestList;
var
  R0, C0, C1, C2: ICommonTree;
begin
  // ^(nil 101 102 103)
  R0 := TCommonTree.Create(IToken(nil));
  C0 := TCommonTree.Create(TCommonToken.Create(101));
  C1 := TCommonTree.Create(TCommonToken.Create(102));
  C2 := TCommonTree.Create(TCommonToken.Create(103));
  R0.AddChild(C0);
  R0.AddChild(C1);
  R0.AddChild(C2);

  CheckNull(R0.Parent);
  CheckEquals(R0.ChildIndex, -1);
  Check(C0.Parent = R0);
  CheckEquals(C0.ChildIndex, 0);
  Check(C1.Parent = R0);
  CheckEquals(C1.ChildIndex, 1);
  Check(C2.Parent = R0);
  CheckEquals(C2.ChildIndex, 2);
end;

procedure TestICommonTree.TestList2;
var
  Root, R0, C0, C1, C2: ICommonTree;
begin
  // Add child ^(nil 101 102 103) to root 5
  // should pull 101 102 103 directly to become 5's child list
  Root := TCommonTree.Create(TClassicToken.Create(5));

  // child tree
  R0 := TCommonTree.Create(IToken(nil));
  C0 := TCommonTree.Create(TCommonToken.Create(101));
  C1 := TCommonTree.Create(TCommonToken.Create(102));
  C2 := TCommonTree.Create(TCommonToken.Create(103));
  R0.AddChild(C0);
  R0.AddChild(C1);
  R0.AddChild(C2);

  Root.AddChild(R0);

  CheckNull(Root.Parent);
  CheckEquals(Root.ChildIndex, -1);

  // check children of root all point at root
  Check(C0.Parent = Root);
  Check(C0.ChildIndex = 0);
  Check(C1.Parent = Root);
  Check(C1.ChildIndex = 1);
  Check(C2.Parent = Root);
  Check(C2.ChildIndex = 2);
end;

procedure TestICommonTree.TestReplaceAllWithOne;
var
  T, NewChild: ICommonTree;
begin
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChild := TCommonTree.Create(TCommonToken.Create(99, 'x'));
  T.ReplaceChildren(0, 2, NewChild);
  CheckEquals(T.ToStringTree, '(a x)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceAllWithTwo;
var
  Adaptor: ITreeAdaptor;
  T, NewChildren: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChildren := Adaptor.GetNilNode as ICommonTree;
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'x')));
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'y')));
  T.ReplaceChildren(0, 2, NewChildren);
  CheckEquals(T.ToStringTree, '(a x y)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceAtLeft;
var
  T, NewChild: ICommonTree;
begin
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b'))); // index 0
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChild := TCommonTree.Create(TCommonToken.Create(99, 'x'));
  T.ReplaceChildren(0, 0, NewChild);
  CheckEquals(T.ToStringTree, '(a x c d)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceAtRight;
var
  T, NewChild: ICommonTree;
begin
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd'))); // index 2
  NewChild := TCommonTree.Create(TCommonToken.Create(99, 'x'));
  T.ReplaceChildren(2, 2, NewChild);
  CheckEquals(T.ToStringTree, '(a b c x)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceInMiddle;
var
  T, NewChild: ICommonTree;
begin
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c'))); // index 1
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChild := TCommonTree.Create(TCommonToken.Create(99, 'x'));
  T.ReplaceChildren(1, 1, NewChild);
  CheckEquals(T.ToStringTree, '(a b x d)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceOneWithTwoAtLeft;
var
  Adaptor: ITreeAdaptor;
  T, NewChildren: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChildren := Adaptor.GetNilNode as ICommonTree;
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'x')));
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'y')));
  T.ReplaceChildren(0, 0, NewChildren);
  CheckEquals(T.ToStringTree, '(a x y c d)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceOneWithTwoAtRight;
var
  Adaptor: ITreeAdaptor;
  T, NewChildren: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChildren := Adaptor.GetNilNode as ICommonTree;
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'x')));
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'y')));
  T.ReplaceChildren(2, 2, NewChildren);
  CheckEquals(T.ToStringTree, '(a b c x y)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceOneWithTwoInMiddle;
var
  Adaptor: ITreeAdaptor;
  T, NewChildren: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChildren := Adaptor.GetNilNode as ICommonTree;
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'x')));
  NewChildren.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'y')));
  T.ReplaceChildren(1, 1, NewChildren);
  CheckEquals(T.ToStringTree, '(a b x y d)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceTwoWithOneAtLeft;
var
  T, NewChild: ICommonTree;
begin
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChild := TCommonTree.Create(TCommonToken.Create(99, 'x'));
  T.ReplaceChildren(0, 1, NewChild);
  CheckEquals(T.ToStringTree, '(a x d)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceTwoWithOneAtRight;
var
  T, NewChild: ICommonTree;
begin
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'b')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'c')));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(99, 'd')));
  NewChild := TCommonTree.Create(TCommonToken.Create(99, 'x'));
  T.ReplaceChildren(1, 2, NewChild);
  CheckEquals(T.ToStringTree, '(a b x)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestReplaceWithNoChildren;
var
  T, NewChild: ICommonTree;
  Error: Boolean;
begin
  Exit; // already checked. Avoid exception
  T := TCommonTree.Create(TCommonToken.Create(101));
  NewChild := TCommonTree.Create(TCommonToken.Create(5));
  Error := False;
  try
    T.ReplaceChildren(0, 0, NewChild);
  except
    Error := True;
  end;
  CheckTrue(Error);
end;

procedure TestICommonTree.TestReplaceWithOneChildren;
var
  T, C0, NewChild: ICommonTree;
begin
  // assume token type 99 and use text
  T := TCommonTree.Create(TCommonToken.Create(99, 'a'));
  C0 := TCommonTree.Create(TCommonToken.Create(99, 'b'));
  T.AddChild(C0);
  NewChild := TCommonTree.Create(TCommonToken.Create(99, 'c'));
  T.ReplaceChildren(0, 0, NewChild);
  CheckEquals(T.ToStringTree,'(a c)');
  T.SanityCheckParentAndChildIndexes;
end;

procedure TestICommonTree.TestSingleNode;
var
  T: ICommonTree;
begin
  T := TCommonTree.Create(TCommonToken.Create(101));
  CheckNull(T.Parent);
  CheckEquals(T.ChildIndex, -1);
end;

function TestICommonTreeNodeStream.CreateCommonTreeNodeStream(
  const T: IANTLRInterface): ITreeNodeStream;
begin
  Result := TCommonTreeNodeStream.Create(T);
end;

function TestICommonTreeNodeStream.CreateUnBufferedTreeNodeStream(
  const T: IANTLRInterface): ITreeNodeStream;
begin
  Result := TUnBufferedTreeNodeStream.Create(T);
end;

function TestICommonTreeNodeStream.GetStringOfEntireStreamContentsWithNodeTypesOnly(
  const Nodes: ITreeNodeStream): String;
var
  Buf: TStringBuilder;
  I, TokenType: Integer;
  T: IANTLRInterface;
begin
  Buf := TStringBuilder.Create;
  try
    for I := 0 to Nodes.Size - 1 do
    begin
      T := Nodes.LT(I + 1);
      TokenType := Nodes.TreeAdaptor.GetNodeType(T);
      if (TokenType <> TToken.DOWN) and (TokenType <> TToken.UP) then
      begin
        Buf.Append(' ');
        Buf.Append(TokenType)
      end;
    end;
    Result := Buf.ToString;
  finally
    Buf.Free;
  end;
end;

procedure TestICommonTreeNodeStream.SetUp;
begin
end;

procedure TestICommonTreeNodeStream.TearDown;
begin
end;

procedure TestICommonTreeNodeStream.Test4Nodes;
var
  T: ITree;
  Stream: ITreeNodeStream;
begin
  /// Test a tree with four nodes - ^(101 ^(102 103) 104)
  T := TCommonTree.Create(TCommonToken.Create(101));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  T.GetChild(0).AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(104)));

  Stream := CreateCommonTreeNodeStream(T);
  CheckEquals(GetStringOfEntireStreamContentsWithNodeTypesOnly(Stream),' 101 102 103 104');
  CheckEquals(Stream.ToString, ' 101 2 102 2 103 3 104 3');
end;

procedure TestICommonTreeNodeStream.TestAoverB;
var
  T: ITree;
  Stream: ITreeNodeStream;
begin
  T := TCommonTree.Create(TCommonToken.Create(101));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(102)));

  Stream := CreateCommonTreeNodeStream(T);
  CheckEquals(GetStringOfEntireStreamContentsWithNodeTypesOnly(Stream),' 101 102');
  CheckEquals(Stream.ToString, ' 101 2 102 3');
end;

procedure TestICommonTreeNodeStream.TestBufferOverflow;
var
  Buf, Buf2: TStringBuilder;
  Stream: ITreeNodeStream;
  T: ITree;
  I: Integer;
begin
  Buf := TStringBuilder.Create;
  Buf2 := TStringBuilder.Create;
  try
    // make ^(101 102 ... n)
    T := TCommonTree.Create(TCommonToken.Create(101));
    Buf.Append(' 101');
    Buf2.Append(' 101');
    Buf2.Append(' ');
    Buf2.Append(TToken.DOWN);

    for I := 0 to TUnBufferedTreeNodeStream.INITIAL_LOOKAHEAD_BUFFER_SIZE + 10 do
    begin
      T.AddChild(TCommonTree.Create(TCommonToken.Create(102 + I)));
      Buf.Append(' ');
      Buf.Append(102 + I);
      Buf2.Append(' ');
      Buf2.Append(102 + I);
    end;
    Buf2.Append(' ');
    Buf2.Append(TToken.UP);

    Stream := CreateUnBufferedTreeNodeStream(T);
    CheckEquals(GetStringOfEntireStreamContentsWithNodeTypesOnly(Stream), Buf.ToString);
    CheckEquals(Stream.ToString, Buf2.ToString);
  finally
    Buf2.Free;
    Buf.Free;
  end;
end;

/// <summary>
/// Test what happens when tail hits the end of the buffer, but there
/// is more room left.
/// </summary>
/// <remarks>
/// Specifically that would mean that head is not at 0 but has
/// advanced somewhere to the middle of the lookahead buffer.
///
/// Use Consume() to advance N nodes into lookahead.  Then use LT()
/// to load at least INITIAL_LOOKAHEAD_BUFFER_SIZE-N nodes so the
/// buffer has to wrap.
/// </remarks>
procedure TestICommonTreeNodeStream.TestBufferWrap;
const
  N = 10;
  WrapBy = 4; // wrap around by 4 nodes
var
  T: ITree;
  I, Remaining: Integer;
  Stream: ITreeNodeStream;
  Node: ITree;
begin
  // make tree with types: 1 2 ... INITIAL_LOOKAHEAD_BUFFER_SIZE+N
  T := TCommonTree.Create(IToken(nil));
  for I := 0 to TUnBufferedTreeNodeStream.INITIAL_LOOKAHEAD_BUFFER_SIZE + N - 1 do
    T.AddChild(TCommonTree.Create(TCommonToken.Create(I + 1)));

  // move head to index N
  Stream := CreateUnBufferedTreeNodeStream(T);
  for I := 1 to N do
  begin
    // consume N
    Node := Stream.LT(1) as ITree;
    CheckEquals(Node.TokenType, I);
    Stream.Consume;
  end;

  // now use LT to lookahead past end of buffer
  Remaining := TUnBufferedTreeNodeStream.INITIAL_LOOKAHEAD_BUFFER_SIZE - N;
  CheckTrue(WrapBy < N);
  for I := 1 to Remaining + WrapBy do
  begin
    // wrap past end of buffer
    Node := Stream.LT(I) as ITree; // look ahead to ith token
    CheckEquals(Node.TokenType, N + I);
  end;
end;

procedure TestICommonTreeNodeStream.TestFlatList;
var
  Root: ITree;
  Stream: ITreeNodeStream;
begin
  Root := TCommonTree.Create(IToken(nil));
  Root.AddChild(TCommonTree.Create(TCommonToken.Create(101)));
  Root.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  Root.AddChild(TCommonTree.Create(TCommonToken.Create(103)));

  Stream := CreateCommonTreeNodeStream(Root);
  CheckEquals(GetStringOfEntireStreamContentsWithNodeTypesOnly(Stream),' 101 102 103');
  CheckEquals(Stream.ToString, ' 101 102 103');
end;

procedure TestICommonTreeNodeStream.TestList;
var
  Root, T, U: ITree;
  Stream: ITreeNodeStream;
begin
  Root := TCommonTree.Create(IToken(nil));

  T := TCommonTree.Create(TCommonToken.Create(101));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  T.GetChild(0).AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(104)));

  U := TCommonTree.Create(TCommonToken.Create(105));

  Root.AddChild(T);
  Root.AddChild(U);

  Stream := CreateCommonTreeNodeStream(Root);
  CheckEquals(GetStringOfEntireStreamContentsWithNodeTypesOnly(Stream),' 101 102 103 104 105');
  CheckEquals(Stream.ToString, ' 101 2 102 2 103 3 104 3 105');
end;

procedure TestICommonTreeNodeStream.TestListWithOneNode;
var
  Root: ITree;
  Stream: ITreeNodeStream;
begin
  Root := TCommonTree.Create(IToken(nil));
  Root.AddChild(TCommonTree.Create(TCommonToken.Create(101)));

  Stream := CreateCommonTreeNodeStream(Root);
  CheckEquals(GetStringOfEntireStreamContentsWithNodeTypesOnly(Stream),' 101');
  CheckEquals(Stream.ToString, ' 101');
end;

procedure TestICommonTreeNodeStream.TestLT;
var
  T: ITree;
  Stream: ITreeNodeStream;
begin
  // ^(101 ^(102 103) 104)
  T := TCommonTree.Create(TCommonToken.Create(101));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(102)));
  T.GetChild(0).AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  T.AddChild(TCommonTree.Create(TCommonToken.Create(104)));

  Stream := CreateCommonTreeNodeStream(T);
  CheckEquals((Stream.LT(1) as ITree).TokenType,101);
  CheckEquals((Stream.LT(2) as ITree).TokenType,TToken.DOWN);
  CheckEquals((Stream.LT(3) as ITree).TokenType,102);
  CheckEquals((Stream.LT(4) as ITree).TokenType,TToken.DOWN);
  CheckEquals((Stream.LT(5) as ITree).TokenType,103);
  CheckEquals((Stream.LT(6) as ITree).TokenType,TToken.UP);
  CheckEquals((Stream.LT(7) as ITree).TokenType,104);
  CheckEquals((Stream.LT(8) as ITree).TokenType,TToken.UP);
  CheckEquals((Stream.LT(9) as ITree).TokenType,TToken.EOF);
  // check way ahead
  CheckEquals((Stream.LT(100) as ITree).TokenType,TToken.EOF);
end;

procedure TestICommonTreeNodeStream.TestMarkRewindEntire;
var
  R0, R1, R2: ITree;
  Stream: ICommonTreeNodeStream;
  M, K: Integer;
begin
  // ^(101 ^(102 103 ^(106 107) ) 104 105)
  // stream has 7 real + 6 nav nodes
  // Sequence of types: 101 DN 102 DN 103 106 DN 107 UP UP 104 105 UP EOF
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R0.AddChild(R1);
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R2 := TCommonTree.Create(TCommonToken.Create(106));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R1.AddChild(R2);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(104)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(105)));

  Stream := TCommonTreeNodeStream.Create(R0);
  M := Stream.Mark;
  for K := 1 to 13 do
  begin
    // consume til end
    Stream.LT(1);
    Stream.Consume;
  end;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.EOF);
  CheckEquals((Stream.LT(-1) as ITree).TokenType,TToken.UP);
  Stream.Rewind(M);

  for K := 1 to 13 do
  begin
    // consume til end
    Stream.LT(1);
    Stream.Consume;
  end;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.EOF);
  CheckEquals((Stream.LT(-1) as ITree).TokenType,TToken.UP);
end;

procedure TestICommonTreeNodeStream.TestMarkRewindInMiddle;
var
  R0, R1, R2: ITree;
  Stream: ICommonTreeNodeStream;
  M, K: Integer;
begin
  // ^(101 ^(102 103 ^(106 107) ) 104 105)
  // stream has 7 real + 6 nav nodes
  // Sequence of types: 101 DN 102 DN 103 106 DN 107 UP UP 104 105 UP EOF
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R0.AddChild(R1);
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R2 := TCommonTree.Create(TCommonToken.Create(106));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R1.AddChild(R2);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(104)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(105)));

  Stream := TCommonTreeNodeStream.Create(R0);
  for K := 1 to 7 do
  begin
    // consume til middle
    Stream.Consume;
  end;
  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
  M := Stream.Mark;
  Stream.Consume; // consume 107
  Stream.Consume; // consume UP
  Stream.Consume; // consume UP
  Stream.Consume; // consume 104
  Stream.Rewind(M);

  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,104);
  Stream.Consume;
  // now we're past rewind position
  CheckEquals((Stream.LT(1) as ITree).TokenType,105);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.EOF);
  CheckEquals((Stream.LT(-1) as ITree).TokenType,TToken.UP);
end;

procedure TestICommonTreeNodeStream.TestMarkRewindNested;
var
  R0, R1, R2: ITree;
  Stream: ICommonTreeNodeStream;
  M, M2: Integer;
begin
  // ^(101 ^(102 103 ^(106 107) ) 104 105)
  // stream has 7 real + 6 nav nodes
  // Sequence of types: 101 DN 102 DN 103 106 DN 107 UP UP 104 105 UP EOF
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R0.AddChild(R1);
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R2 := TCommonTree.Create(TCommonToken.Create(106));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R1.AddChild(R2);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(104)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(105)));

  Stream := TCommonTreeNodeStream.Create(R0);
  M := Stream.Mark; // MARK at start
  Stream.Consume; // consume 101
  Stream.Consume; // consume DN
  M2:= Stream.Mark; // MARK on 102
  Stream.Consume; // consume 102
  Stream.Consume; // consume DN
  Stream.Consume; // consume 103
  Stream.Consume; // consume 106
  Stream.Rewind(M2);
  CheckEquals((Stream.LT(1) as ITree).TokenType,102);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
  Stream.Consume;
  // stop at 103 and rewind to start
  Stream.Rewind(M); // REWIND to 101
  CheckEquals((Stream.LT(1) as ITree).TokenType,101);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,102);
  Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
end;

procedure TestICommonTreeNodeStream.TestNestedPushPop;
const
  IndexOf102 = 2;
  IndexOf104 = 6;
  IndexOf107 = 12;
var
  R0, R1, R2, R3: ITree;
  Stream: ICommonTreeNodeStream;
  K: Integer;
begin
  // ^(101 ^(102 103) ^(104 105) ^(106 107) 108 109)
  // stream has 9 real + 8 nav nodes
  // Sequence of types: 101 DN 102 DN 103 UP 104 DN 105 UP 106 DN 107 UP 108 109 UP
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R0.AddChild(R1);
  R2 := TCommonTree.Create(TCommonToken.Create(104));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(105)));
  R0.AddChild(R2);
  R3 := TCommonTree.Create(TCommonToken.Create(106));
  R3.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R0.AddChild(R3);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(108)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(109)));

  Stream := TCommonTreeNodeStream.Create(R0);
  CheckEquals(Stream.ToString, ' 101 2 102 2 103 3 104 2 105 3 106 2 107 3 108 109 3');

  // Assume we want to hit node 107 and then "call 102", which
  // calls 104, then return
  for K := 1 to IndexOf107 do
    // consume til 107 node
    Stream.Consume;

  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
  // CALL 102
  Stream.Push(IndexOf102);
  CheckEquals((Stream.LT(1) as ITree).TokenType,102);
  Stream.Consume; // consume 102
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
  Stream.Consume; // consume DN
  CheckEquals((Stream.LT(1) as ITree).TokenType,103);
  Stream.Consume; // consume 103

  // CALL 104
  Stream.Push(IndexOf104);
  CheckEquals((Stream.LT(1) as ITree).TokenType,104);
  Stream.Consume; // consume 104
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
  Stream.Consume; // consume DN
  CheckEquals((Stream.LT(1) as ITree).TokenType,105);
  Stream.Consume; // consume 1045
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);

  // RETURN (to UP node in 102 subtree)
  Stream.Pop;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);

  // RETURN (to empty stack)
  Stream.Pop;
  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
end;

procedure TestICommonTreeNodeStream.TestPushPop;
const
  IndexOf102 = 2;
  IndexOf107 = 12;
var
  R0, R1, R2, R3: ITree;
  Stream: ICommonTreeNodeStream;
  K: Integer;
begin
  // ^(101 ^(102 103) ^(104 105) ^(106 107) 108 109)
  // stream has 9 real + 8 nav nodes
  // Sequence of types: 101 DN 102 DN 103 UP 104 DN 105 UP 106 DN 107 UP 108 109 UP
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R0.AddChild(R1);
  R2 := TCommonTree.Create(TCommonToken.Create(104));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(105)));
  R0.AddChild(R2);
  R3 := TCommonTree.Create(TCommonToken.Create(106));
  R3.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R0.AddChild(R3);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(108)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(109)));

  Stream := TCommonTreeNodeStream.Create(R0);
  CheckEquals(Stream.ToString, ' 101 2 102 2 103 3 104 2 105 3 106 2 107 3 108 109 3');

  // Assume we want to hit node 107 and then "call 102" then return
  for K := 1 to IndexOf107 do
    // consume til 107 node
    Stream.Consume;

  // CALL 102
  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
  Stream.Push(IndexOf102);
  CheckEquals((Stream.LT(1) as ITree).TokenType,102);
  Stream.Consume; // consume 102
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
  Stream.Consume; // consume DN
  CheckEquals((Stream.LT(1) as ITree).TokenType,103);
  Stream.Consume; // consume 103
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);
  // RETURN
  Stream.Pop;
  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
end;

procedure TestICommonTreeNodeStream.TestPushPopFromEOF;
const
  IndexOf102 = 2;
  IndexOf104 = 6;
var
  R0, R1, R2, R3: ITree;
  Stream: ICommonTreeNodeStream;
begin
  // ^(101 ^(102 103) ^(104 105) ^(106 107) 108 109)
  // stream has 9 real + 8 nav nodes
  // Sequence of types: 101 DN 102 DN 103 UP 104 DN 105 UP 106 DN 107 UP 108 109 UP
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R0.AddChild(R1);
  R2 := TCommonTree.Create(TCommonToken.Create(104));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(105)));
  R0.AddChild(R2);
  R3 := TCommonTree.Create(TCommonToken.Create(106));
  R3.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R0.AddChild(R3);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(108)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(109)));

  Stream := TCommonTreeNodeStream.Create(R0);
  CheckEquals(Stream.ToString, ' 101 2 102 2 103 3 104 2 105 3 106 2 107 3 108 109 3');

  while (Stream.LA(1) <> TToken.EOF) do
    Stream.Consume;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.EOF);

  // CALL 102
  Stream.Push(IndexOf102);
  CheckEquals((Stream.LT(1) as ITree).TokenType,102);
  Stream.Consume; // consume 102
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
  Stream.Consume; // consume DN
  CheckEquals((Stream.LT(1) as ITree).TokenType,103);
  Stream.Consume; // consume 103
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);
  // RETURN (to empty stack)
  Stream.Pop;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.EOF);

  // CALL 104
  Stream.Push(IndexOf104);
  CheckEquals((Stream.LT(1) as ITree).TokenType,104);
  Stream.Consume; // consume 104
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.DOWN);
  Stream.Consume; // consume DN
  CheckEquals((Stream.LT(1) as ITree).TokenType,105);
  Stream.Consume; // consume 105
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.UP);
  // RETURN (to empty stack)
  Stream.Pop;
  CheckEquals((Stream.LT(1) as ITree).TokenType,TToken.EOF);
end;

procedure TestICommonTreeNodeStream.TestSeek;
var
  R0, R1, R2: ITree;
  Stream: ICommonTreeNodeStream;
begin
  // ^(101 ^(102 103 ^(106 107) ) 104 105)
  // stream has 7 real + 6 nav nodes
  // Sequence of types: 101 DN 102 DN 103 106 DN 107 UP UP 104 105 UP EOF
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R0.AddChild(R1);
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R2 := TCommonTree.Create(TCommonToken.Create(106));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R1.AddChild(R2);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(104)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(105)));

  Stream := TCommonTreeNodeStream.Create(R0);
  Stream.Consume; // consume 101
  Stream.Consume; // consume DN
  Stream.Consume; // consume 102
  Stream.Seek(7); // seek to 107
  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
  Stream.Consume; // consume 107
  Stream.Consume; // consume UP
  Stream.Consume; // consume UP
  CheckEquals((Stream.LT(1) as ITree).TokenType,104);
end;

procedure TestICommonTreeNodeStream.TestSeekFromStart;
var
  R0, R1, R2: ITree;
  Stream: ICommonTreeNodeStream;
begin
  // ^(101 ^(102 103 ^(106 107) ) 104 105)
  // stream has 7 real + 6 nav nodes
  // Sequence of types: 101 DN 102 DN 103 106 DN 107 UP UP 104 105 UP EOF
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  R1 := TCommonTree.Create(TCommonToken.Create(102));
  R0.AddChild(R1);
  R1.AddChild(TCommonTree.Create(TCommonToken.Create(103)));
  R2 := TCommonTree.Create(TCommonToken.Create(106));
  R2.AddChild(TCommonTree.Create(TCommonToken.Create(107)));
  R1.AddChild(R2);
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(104)));
  R0.AddChild(TCommonTree.Create(TCommonToken.Create(105)));

  Stream := TCommonTreeNodeStream.Create(R0);
  Stream.Seek(7); // seek to 107
  CheckEquals((Stream.LT(1) as ITree).TokenType,107);
  Stream.Consume; // consume 107
  Stream.Consume; // consume UP
  Stream.Consume; // consume UP
  CheckEquals((Stream.LT(1) as ITree).TokenType,104);
end;

procedure TestICommonTreeNodeStream.TestSingleNode;
var
  T: ITree;
  Stream: ITreeNodeStream;
begin
  T := TCommonTree.Create(TCommonToken.Create(101));
  Stream := CreateCommonTreeNodeStream(T);
  CheckEquals(GetStringOfEntireStreamContentsWithNodeTypesOnly(Stream),' 101');
  CheckEquals(Stream.ToString, ' 101');
end;

procedure TestICommonTreeNodeStream.TestStackStretch;
var
  R0: ICommonTree;
  Stream: ICommonTreeNodeStream;
  I: Integer;
begin
  // make more than INITIAL_CALL_STACK_SIZE pushes
  R0 := TCommonTree.Create(TCommonToken.Create(101));
  Stream := TCommonTreeNodeStream.Create(R0);

  // go 1 over initial size
  for I := 1 to TCommonTreeNodeStream.INITIAL_CALL_STACK_SIZE + 1 do
    Stream.Push(I);

  CheckEquals(Stream.Pop, 10);
  CheckEquals(Stream.Pop, 9);
end;

function TestIRewriteRuleXxxxStream.CreateToken(const TokenType: Integer;
  const Text: String): IToken;
begin
  Result := TCommonToken.Create(TokenType, Text);
end;

function TestIRewriteRuleXxxxStream.CreateTokenList(
  const Count: Integer): IList<IToken>;
var
  I: Integer;
begin
  Result := TList<IToken>.Create;
  for I := 0 to Count - 1 do
    Result.Add(TCommonToken.Create(I + 1,'test token ' + IntToStr(I + 1)
      + ' without any real context'));
end;

function TestIRewriteRuleXxxxStream.CreateTree(const Token: IToken): ITree;
begin
  Result := TCommonTree.Create(Token);
end;

function TestIRewriteRuleXxxxStream.CreateTreeAdaptor: ITreeAdaptor;
begin
  Result := TCommonTreeAdaptor.Create;
end;

procedure TestIRewriteRuleXxxxStream.SetUp;
begin
end;

procedure TestIRewriteRuleXxxxStream.TearDown;
begin
end;

procedure TestIRewriteRuleXxxxStream.TestRewriteRuleNodeStreamConstructors;
var
  NodeTest1, NodeTest2, NodeTest3: IRewriteRuleNodeStream;
begin
  NodeTest1 := TRewriteRuleNodeStream.Create(CreateTreeAdaptor,
    'RewriteRuleNodeStream test1');

  NodeTest2 := TRewriteRuleNodeStream.Create(CreateTreeAdaptor,
    'RewriteRuleNodeStream test2',
    CreateToken(1,'test token without any real context'));

  NodeTest3 := TRewriteRuleNodeStream.Create(CreateTreeAdaptor,
    'RewriteRuleNodeStream test3', CreateTokenList(4));
end;

procedure TestIRewriteRuleXxxxStream.TestRewriteRuleSubtreeStreamConstructors;
var
  SubtreeTest1, SubtreeTest2, SubtreeTest3: IRewriteRuleSubtreeStream;
begin
  SubtreeTest1 := TRewriteRuleSubtreeStream.Create(CreateTreeAdaptor,
    'RewriteRuleSubtreeStream test1');

  SubtreeTest2 := TRewriteRuleSubtreeStream.Create(CreateTreeAdaptor,
    'RewriteRuleSubtreeStream test2',
    CreateToken(1,'test token without any real context'));

  SubtreeTest3 := TRewriteRuleSubtreeStream.Create(CreateTreeAdaptor,
    'RewriteRuleSubtreeStream test3', CreateTokenList(4));
end;

procedure TestIRewriteRuleXxxxStream.TestRewriteRuleTokenStreamConstructors;
var
  TokenTest1, TokenTest2, TokenTest3: IRewriteRuleTokenStream;
begin
  TokenTest1 := TRewriteRuleTokenStream.Create(CreateTreeAdaptor,
    'RewriteRuleTokenStream test1');

  TokenTest2 := TRewriteRuleTokenStream.Create(CreateTreeAdaptor,
    'RewriteRuleTokenStream test2',
    CreateToken(1, 'test token without any real context'));

  TokenTest3 := TRewriteRuleTokenStream.Create(CreateTreeAdaptor,
    'RewriteRuleTokenStream test3', CreateTokenList(4));
end;

procedure TestIRewriteRuleXxxxStream.TestRRNodeStreamBehaviourWhileEmpty1;
const
  Description = 'RewriteRuleNodeStream test';
var
  NodeTest: IRewriteRuleNodeStream;
begin
  ExpectedException := ERewriteEmptyStreamException;
  NodeTest := TRewriteRuleNodeStream.Create(CreateTreeAdaptor, Description);

  CheckFalse(NodeTest.HasNext);
  CheckEquals(Description, NodeTest.Description);
  CheckEquals(NodeTest.Size, 0);
  NodeTest.Reset;
  CheckEquals(NodeTest.Size, 0);
  NodeTest.NextNode;
end;

procedure TestIRewriteRuleXxxxStream.TestRRNodeStreamBehaviourWhileEmpty2;
const
  Description = 'RewriteRuleNodeStream test';
var
  NodeTest: IRewriteRuleNodeStream;
begin
  ExpectedException := ERewriteEmptyStreamException;
  NodeTest := TRewriteRuleNodeStream.Create(CreateTreeAdaptor, Description);
  NodeTest.NextTree;
end;

procedure TestIRewriteRuleXxxxStream.TestRRNodeStreamBehaviourWithElements;
var
  NodeTest: IRewriteRuleNodeStream;
  Token1, Token2: IToken;
  Tree1, Tree2: ITree;
  ReturnedTree: ICommonTree;
begin
  ExpectedException := ERewriteCardinalityException;
  NodeTest := TRewriteRuleNodeStream.Create(CreateTreeAdaptor, 'RewriteRuleNodeStream test');
  Token1 := CreateToken(1, 'test token without any real context');
  Tree1 := CreateTree(Token1);

  // Test Add()
  NodeTest.Add(Tree1);
  CheckEquals(NodeTest.Size, 1);
  CheckTrue(NodeTest.HasNext);

  // Test NextNode()
  ReturnedTree := NodeTest.NextNode as ICommoNTree;
  CheckEquals(ReturnedTree.TokenType, Tree1.TokenType);
  CheckEquals(NodeTest.Size, 1);
  CheckFalse(NodeTest.HasNext);
  NodeTest.Reset;
  CheckEquals(NodeTest.Size, 1);
  CheckTrue(NodeTest.HasNext);

  // Test NextTree()
  ReturnedTree := NodeTest.NextTree as ICommonTree;
  Check(SameObj(Token1, ReturnedTree.Token));
  CheckEquals(NodeTest.Size, 1);
  CheckFalse(NodeTest.HasNext);
  NodeTest.Reset;
  CheckEquals(NodeTest.Size, 1);
  CheckTrue(NodeTest.HasNext);

  // Test, what happens with two elements
  Token2 := CreateToken(2, 'test token without any real context');
  Tree2 := CreateTree(Token2);
  NodeTest.Add(Tree2);
  CheckEquals(NodeTest.Size, 2);
  CheckTrue(NodeTest.HasNext);
  ReturnedTree := NodeTest.NextTree as ICommonTree;
  Check(SameObj(Token1, ReturnedTree.Token));
  CheckEquals(NodeTest.Size, 2);
  CheckTrue(NodeTest.HasNext);
  ReturnedTree := NodeTest.NextTree as ICommonTree;
  Check(SameObj(Token2, ReturnedTree.Token));
  CheckFalse(NodeTest.HasNext);

  // Test exception
  NodeTest.NextTree;
end;

procedure TestIRewriteRuleXxxxStream.TestRRSubtreeStreamBehaviourWhileEmpty1;
const
  Description = 'RewriteRuleSubtreeStream test';
var
  SubtreeTest: IRewriteRuleSubtreeStream;
begin
  ExpectedException := ERewriteEmptyStreamException;
  SubtreeTest := TRewriteRuleSubtreeStream.Create(CreateTreeAdaptor, Description);

  CheckFalse(SubtreeTest.HasNext);
  CheckEquals(Description, SubtreeTest.Description);
  CheckEquals(SubtreeTest.Size, 0);
  SubtreeTest.Reset;
  CheckEquals(SubtreeTest.Size, 0);
  SubtreeTest.NextNode;
end;

procedure TestIRewriteRuleXxxxStream.TestRRSubtreeStreamBehaviourWhileEmpty2;
const
  Description = 'RewriteRuleSubtreeStream test';
var
  SubtreeTest: IRewriteRuleSubtreeStream;
begin
  ExpectedException := ERewriteEmptyStreamException;
  SubtreeTest := TRewriteRuleSubtreeStream.Create(CreateTreeAdaptor, Description);
  SubtreeTest.NextTree;
end;

procedure TestIRewriteRuleXxxxStream.TestRRSubtreeStreamBehaviourWithElements;
var
  SubtreeTest: IRewriteRuleSubtreeStream;
  Token1, Token2: IToken;
  Tree1, Tree2: ITree;
  ReturnedTree: ICommonTree;
begin
  ExpectedException := ERewriteCardinalityException;
  SubtreeTest := TRewriteRuleSubtreeStream.Create(CreateTreeAdaptor, 'RewriteRuleSubtreeStream test');
  Token1 := CreateToken(1, 'test token without any real context');
  Tree1 := CreateTree(Token1);

  // Test Add()
  SubtreeTest.Add(Tree1);
  CheckEquals(SubtreeTest.Size, 1);
  CheckTrue(SubtreeTest.HasNext);

  // Test NextNode()
  Check(SameObj(SubtreeTest.NextNode, Tree1));
  CheckEquals(SubtreeTest.Size, 1);
  CheckFalse(SubtreeTest.HasNext);
  SubtreeTest.Reset;
  CheckEquals(SubtreeTest.Size, 1);
  CheckTrue(SubtreeTest.HasNext);

  // Test NextTree()
  ReturnedTree := SubtreeTest.NextTree as ICommonTree;
  Check(SameObj(Token1, ReturnedTree.Token));
  CheckEquals(SubtreeTest.Size, 1);
  CheckFalse(SubtreeTest.HasNext);
  SubtreeTest.Reset;
  CheckEquals(SubtreeTest.Size, 1);
  CheckTrue(SubtreeTest.HasNext);

  // Test, what happens with two elements
  Token2 := CreateToken(2, 'test token without any real context');
  Tree2 := CreateTree(Token2);
  SubtreeTest.Add(Tree2);
  CheckEquals(SubtreeTest.Size, 2);
  CheckTrue(SubtreeTest.HasNext);
  ReturnedTree := SubtreeTest.NextTree as ICommonTree;
  Check(SameObj(Token1, ReturnedTree.Token));
  CheckEquals(SubtreeTest.Size, 2);
  CheckTrue(SubtreeTest.HasNext);
  ReturnedTree := SubtreeTest.NextTree as ICommonTree;
  Check(SameObj(Token2, ReturnedTree.Token));
  CheckFalse(SubtreeTest.HasNext);

  // Test exception
  SubtreeTest.NextTree;
end;

procedure TestIRewriteRuleXxxxStream.TestRRTokenStreamBehaviourWhileEmpty1;
const
  Description = 'RewriteRuleTokenStream test';
var
  TokenTest: IRewriteRuleTokenStream;
begin
  ExpectedException := ERewriteEmptyStreamException;
  TokenTest := TRewriteRuleTokenStream.Create(CreateTreeAdaptor, Description);

  CheckFalse(TokenTest.HasNext);
  CheckEquals(Description, TokenTest.Description);
  CheckEquals(TokenTest.Size, 0);
  TokenTest.Reset;
  CheckEquals(TokenTest.Size, 0);
  TokenTest.NextNode;
end;

procedure TestIRewriteRuleXxxxStream.TestRRTokenStreamBehaviourWhileEmpty2;
const
  Description = 'RewriteRuleTokenStream test';
var
  TokenTest: IRewriteRuleTokenStream;
begin
  ExpectedException := ERewriteEmptyStreamException;
  TokenTest := TRewriteRuleTokenStream.Create(CreateTreeAdaptor, Description);
  TokenTest.NextTree;
end;

procedure TestIRewriteRuleXxxxStream.TestRRTokenStreamBehaviourWhileEmpty3;
const
  Description = 'RewriteRuleTokenStream test';
var
  TokenTest: IRewriteRuleTokenStream;
begin
  ExpectedException := ERewriteEmptyStreamException;
  TokenTest := TRewriteRuleTokenStream.Create(CreateTreeAdaptor, Description);
  TokenTest.NextToken;
end;

procedure TestIRewriteRuleXxxxStream.TestRRTokenStreamBehaviourWithElements;
var
  TokenTest: IRewriteRuleTokenStream;
  Token1, Token2, ReturnedToken: IToken;
  Tree: ICommonTree;
begin
  ExpectedException := ERewriteCardinalityException;
  TokenTest := TRewriteRuleTokenStream.Create(CreateTreeAdaptor, 'RewriteRuleTokenStream test');
  Token1 := CreateToken(1, 'test token without any real context');

  // Test Add()
  TokenTest.Add(Token1);
  CheckEquals(TokenTest.Size, 1);
  CheckTrue(TokenTest.HasNext);

  // Test NextNode()
  Tree := TokenTest.NextNode as ICommonTree;
  Check(SameObj(Tree.Token, Token1));
  CheckEquals(TokenTest.Size, 1);
  CheckFalse(TokenTest.HasNext);
  TokenTest.Reset;
  CheckEquals(TokenTest.Size, 1);
  CheckTrue(TokenTest.HasNext);

  // Test NextToken()
  ReturnedToken := TokenTest.NextToken;
  Check(SameObj(Token1, ReturnedToken));
  CheckEquals(TokenTest.Size, 1);
  CheckFalse(TokenTest.HasNext);
  TokenTest.Reset;
  CheckEquals(TokenTest.Size, 1);
  CheckTrue(TokenTest.HasNext);

  // Test NextTree()
  ReturnedToken := TokenTest.NextTree as IToken;
  Check(SameObj(Token1, ReturnedToken));
  CheckEquals(TokenTest.Size, 1);
  CheckFalse(TokenTest.HasNext);
  TokenTest.Reset;
  CheckEquals(TokenTest.Size, 1);
  CheckTrue(TokenTest.HasNext);

  // Test, what happens with two elements
  Token2 := CreateToken(2, 'test token without any real context');
  TokenTest.Add(Token2);
  CheckEquals(TokenTest.Size, 2);
  CheckTrue(TokenTest.HasNext);
  ReturnedToken := TokenTest.NextToken;
  Check(SameObj(Token1, ReturnedToken));
  CheckEquals(TokenTest.Size, 2);
  CheckTrue(TokenTest.HasNext);
  ReturnedToken := TokenTest.NextToken;
  Check(SameObj(Token2, ReturnedToken));
  CheckFalse(TokenTest.HasNext);

  // Test exception
  TokenTest.NextToken;
end;

constructor TestITreeWizard.Create(MethodName: String);
const
  TOKENS: array [0..11] of String = ('', '', '', '', '', 'A', 'B', 'C', 'D', 'E', 'ID', 'VAR');
var
  I: Integer;
begin
  inherited;
  SetLength(FTokens,Length(TOKENS));
  for I := 0 to Length(TOKENS) - 1 do
    FTokens[I] := TOKENS[I];
end;

procedure TestITreeWizard.SetUp;
begin
end;

procedure TestITreeWizard.TearDown;
begin
end;

procedure TestITreeWizard.TestDoubleLevelTree;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A (B C) (B D) E)') as ICommonTree;
  CheckEquals(T.ToStringTree, '(A (B C) (B D) E)');
end;

procedure TestITreeWizard.TestEquals;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T1, T2: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T1 := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  T2 := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  CheckTrue(Wiz.Equals(T1, T2, Adaptor));
end;

procedure TestITreeWizard.TestEqualsWithMismatchedText;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T1, T2: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T1 := Wiz.CreateTreeOrNode('(A B[foo] C)') as ICommonTree;
  T2 := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  CheckFalse(Wiz.Equals(T1, T2, Adaptor));
end;

procedure TestITreeWizard.TestEqualsWithText;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T1, T2: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T1 := Wiz.CreateTreeOrNode('(A B[foo] C)') as ICommonTree;
  T2 := Wiz.CreateTreeOrNode('(A B[foo] C)') as ICommonTree;
  CheckTrue(Wiz.Equals(T1, T2, Adaptor));
end;

procedure TestITreeWizard.TestFindPattern;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Subtrees, Elements: IList<IANTLRInterface>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C (A[foo] B[bar]) (D (A[big] B[dog])))') as ICommonTree;
  Subtrees := Wiz.Find(T, '(A B)');
  Elements := Subtrees;
  CheckEquals('[foo, big]', TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestInvalidListTree;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('A B C') as ICommonTree;
  CheckNull(T);
end;

procedure TestITreeWizard.TestListTree;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(nil A B C)') as ICommonTree;
  CheckEquals(T.ToStringTree, 'A B C');
end;

procedure TestITreeWizard.TestNoRepeatsIndex;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  M: IDictionary<Integer, IList<IANTLRInterface>>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C D)') as ICommonTree;
  M := Wiz.Index(T);
  CheckEquals('{5=[A], 8=[D], 7=[C], 6=[B]}' ,TCollectionUtils.DictionaryToString(M));
end;

procedure TestITreeWizard.TestNoRepeatsVisit;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C D)') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TRecordAllElementsVisitor.Create(Elements);
  Wiz.Visit(T, Wiz.GetTokenType('B'), Visitor);
  CheckEquals('[B]' ,TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestNoRepeatsVisit2;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B (A C B) B D D)') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TRecordAllElementsVisitor.Create(Elements);
  Wiz.Visit(T, Wiz.GetTokenType('C'), Visitor);
  CheckEquals('[C]' ,TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestParse;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  CheckTrue(Wiz.Parse(T, '(A B C)'));
end;

procedure TestITreeWizard.TestParseFlatTree;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(nil A B C)') as ICommonTree;
  CheckTrue(Wiz.Parse(T, '(nil A B C)'));
end;

procedure TestITreeWizard.TestParseLabels;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Labels: IDictionary<String, IANTLRInterface>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  Labels := TDictionary<String, IANTLRInterface>.Create;
  CheckTrue(Wiz.Parse(T, '(%a:A %b:B %c:C)', Labels));
  CheckEquals('A', Labels['a'].ToString);
  CheckEquals('B', Labels['b'].ToString);
  CheckEquals('C', Labels['c'].ToString);
end;

procedure TestITreeWizard.TestParseLabelsAndTestText;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Labels: IDictionary<String, IANTLRInterface>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B[foo] C)') as ICommonTree;
  Labels := TDictionary<String, IANTLRInterface>.Create;
  CheckTrue(Wiz.Parse(T, '(%a:A %b:B[foo] %c:C)', Labels));
  CheckEquals('A', Labels['a'].ToString);
  CheckEquals('foo', Labels['b'].ToString);
  CheckEquals('C', Labels['c'].ToString);
end;

procedure TestITreeWizard.TestParseLabelsInNestedTree;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Labels: IDictionary<String, IANTLRInterface>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A (B C) (D E))') as ICommonTree;
  Labels := TDictionary<String, IANTLRInterface>.Create;
  CheckTrue(Wiz.Parse(T, '(%a:A (%b:B %c:C) (%d:D %e:E) )', Labels));
  CheckEquals('A', Labels['a'].ToString);
  CheckEquals('B', Labels['b'].ToString);
  CheckEquals('C', Labels['c'].ToString);
  CheckEquals('D', Labels['d'].ToString);
  CheckEquals('E', Labels['e'].ToString);
end;

procedure TestITreeWizard.TestParseSingleNode;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('A') as ICommonTree;
  CheckTrue(Wiz.Parse(T, 'A'));
end;

procedure TestITreeWizard.TestParseWithText;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B[foo] C[bar])') as ICommonTree;
  // C pattern has no text arg so despite [bar] in t, no need
  // to match text--check structure only.
  CheckTrue(Wiz.Parse(T, '(A B[foo] C)'));
end;

procedure TestITreeWizard.TestParseWithTextFails;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  CheckFalse(Wiz.Parse(T, '(A[foo] B C)'));
end;

procedure TestITreeWizard.TestParseWithWildcardLabels;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Labels: IDictionary<String, IANTLRInterface>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  Labels := TDictionary<String, IANTLRInterface>.Create;
  CheckTrue(Wiz.Parse(T, '(A %b:. %c:.)', Labels));
  CheckEquals('B', Labels['b'].ToString);
  CheckEquals('C', Labels['c'].ToString);
end;

procedure TestITreeWizard.TestRepeatsIndex;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  M: IDictionary<Integer, IList<IANTLRInterface>>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B (A C B) B D D)') as ICommonTree;
  M := Wiz.Index(T);
  CheckEquals('{5=[A, A], 8=[D, D], 7=[C], 6=[B, B, B]}' ,TCollectionUtils.DictionaryToString(M));
end;

procedure TestITreeWizard.TestRepeatsVisit;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B (A C B) B D D)') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TRecordAllElementsVisitor.Create(Elements);
  Wiz.Visit(T, Wiz.GetTokenType('B'), Visitor);
  CheckEquals('[B, B, B]' ,TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestRepeatsVisit2;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B (A C B) B D D)') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TRecordAllElementsVisitor.Create(Elements);
  Wiz.Visit(T, Wiz.GetTokenType('A'), Visitor);
  CheckEquals('[A, A]' ,TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestRepeatsVisitWithContext;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B (A C B) B D D)') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TTest1ContextVisitor.Create(Adaptor, Elements);
  Wiz.Visit(T, Wiz.GetTokenType('B'), Visitor);
  CheckEquals('[B@A[0], B@A[1], B@A[2]]', TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestRepeatsVisitWithNullParentAndContext;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B (A C B) B D D)') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TTest1ContextVisitor.Create(Adaptor, Elements);
  Wiz.Visit(T, Wiz.GetTokenType('A'), Visitor);
  CheckEquals('[A@nil[0], A@A[1]]', TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestSingleLevelTree;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C D)') as ICommonTree;
  CheckEquals(T.ToStringTree, '(A B C D)');
end;

procedure TestITreeWizard.TestSingleNode;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('ID') as ICommonTree;
  CheckEquals(T.ToStringTree, 'ID');
end;

procedure TestITreeWizard.TestSingleNodeIndex;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  M: IDictionary<Integer, IList<IANTLRInterface>>;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('ID') as ICommonTree;
  M := Wiz.Index(T);
  CheckEquals('{10=[ID]}' ,TCollectionUtils.DictionaryToString(M));
end;

procedure TestITreeWizard.TestSingleNodeTree;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A)') as ICommonTree;
  CheckEquals(T.ToStringTree, 'A');
end;

procedure TestITreeWizard.TestSingleNodeWithArg;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('ID[foo]') as ICommonTree;
  CheckEquals(T.ToStringTree, 'foo');
end;

procedure TestITreeWizard.TestVisitPattern;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C (A B) D)') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TRecordAllElementsVisitor.Create(Elements);
  Wiz.Visit(T, '(A B)', Visitor);
  CheckEquals('[A]', TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestVisitPatternMultiple;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C (A B) (D (A B)))') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TTest1ContextVisitor.Create(Adaptor, Elements);
  Wiz.Visit(T, '(A B)', Visitor);
  CheckEquals('[A@A[2], A@D[0]]', TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestVisitPatternMultipleWithLabels;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
  Elements: IList<IANTLRInterface>;
  Visitor: IContextVisitor;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C (A[foo] B[bar]) (D (A[big] B[dog])))') as ICommonTree;
  Elements := TList<IANTLRInterface>.Create;
  Visitor := TTest2ContextVisitor.Create(Adaptor, Elements);
  Wiz.Visit(T, '(%a:A %b:B)', Visitor);
  CheckEquals('[foo@A[2]foo&bar, big@D[0]big&dog]', TCollectionUtils.ListToString(Elements));
end;

procedure TestITreeWizard.TestWildcard;
var
  Adaptor: ITreeAdaptor;
  Wiz: ITreeWizard;
  T: ICommonTree;
begin
  Adaptor := TCommonTreeAdaptor.Create;
  Wiz := TTreeWizard.Create(Adaptor, FTokens);
  T := Wiz.CreateTreeOrNode('(A B C)') as ICommonTree;
  CheckTrue(Wiz.Parse(T, '(A . .)'));
end;

{ TestITreeWizard.TRecordAllElementsVisitor }

constructor TestITreeWizard.TRecordAllElementsVisitor.Create(
  const AList: IList<IANTLRInterface>);
begin
  inherited Create;
  FList := AList;
end;

procedure TestITreeWizard.TRecordAllElementsVisitor.Visit(
  const T: IANTLRInterface);
begin
  FList.Add(T);
end;

{ TestITreeWizard.TTest1ContextVisitor }

constructor TestITreeWizard.TTest1ContextVisitor.Create(
  const AAdaptor: ITreeAdaptor; const AList: IList<IANTLRInterface>);
begin
  inherited Create;
  FAdaptor := AAdaptor;
  FList := AList;
end;

procedure TestITreeWizard.TTest1ContextVisitor.Visit(const T,
  Parent: IANTLRInterface; const ChildIndex: Integer;
  const Labels: IDictionary<String, IANTLRInterface>);
var
  S: String;
begin
  S := FAdaptor.GetNodeText(T) + '@';
  if Assigned(Parent) then
    S := S + FAdaptor.GetNodeText(Parent)
  else
    S := S + 'nil';
  FList.Add(TANTLRString.Create(S + '[' + IntToStr(ChildIndex) + ']'));
end;

{ TestITreeWizard.TTest2ContextVisitor }

constructor TestITreeWizard.TTest2ContextVisitor.Create(
  const AAdaptor: ITreeAdaptor; const AList: IList<IANTLRInterface>);
begin
  inherited Create;
  FAdaptor := AAdaptor;
  FList := AList;
end;

procedure TestITreeWizard.TTest2ContextVisitor.Visit(const T,
  Parent: IANTLRInterface; const ChildIndex: Integer;
  const Labels: IDictionary<String, IANTLRInterface>);
var
  S: String;
begin
  S := FAdaptor.GetNodeText(T) + '@';
  if Assigned(Parent) then
    S := S + FAdaptor.GetNodeText(Parent)
  else
    S := S + 'nil';
  FList.Add(TANTLRString.Create(S + '[' + IntToStr(ChildIndex) + ']'
    + Labels['a'].ToString + '&' + Labels['b'].ToString));
end;

initialization
  // Register any test cases with the test runner
  RegisterTest(TestICommonTree.Suite);
  RegisterTest(TestICommonTreeNodeStream.Suite);
  RegisterTest(TestIRewriteRuleXxxxStream.Suite);
  RegisterTest(TestITreeWizard.Suite);
end.