unit TestHighlightPas;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, testregistry, TestBase, Forms, LazLoggerBase,
  TestHighlightFoldBase, SynEdit, SynEditTypes, SynHighlighterPas,
  SynEditHighlighterFoldBase, SynEditHighlighter;

type

  // used by Fold / MarkupWord

  { TTestBaseHighlighterPas }

  TTestBaseHighlighterPas = class(TTestBaseHighlighterFoldBase)
  protected
    function PasHighLighter: TSynPasSyn;
    function CreateTheHighLighter: TSynCustomFoldHighlighter; override;
    procedure EnableFolds(AEnbledTypes: TPascalCodeFoldBlockTypes;
                          AHideTypes: TPascalCodeFoldBlockTypes = [];
                          ANoFoldTypes: TPascalCodeFoldBlockTypes = []
                         );
    procedure DebugFoldInfo(ALineIdx: Integer; AFilter: TSynFoldActions; Group: Integer=0);
    procedure DebugFoldInfo(AFilter: TSynFoldActions; Group: Integer=0);
    function FoldActionsToString(AFoldActions: TSynFoldActions): String;
    Procedure CheckPasFoldNodeInfo(AName: String; nd: TSynFoldNodeInfo;
      ALine: TLineIdx; AColumn, AAllColIndex: integer; LogXStart, LogXEnd,
      FoldLvlStart, FoldLvlEnd,  NestLvlStart, NestLvlEnd: Integer;
      FoldType, FoldTypeCompatible: TPascalCodeFoldBlockType; FoldGroup: Integer;
      FoldAction: TSynFoldActions);
    Procedure CheckPasFoldNodeInfo(AName: String; nd: TSynFoldNodeInfo;
      ALine: TLineIdx; AColumn: integer; LogXStart, LogXEnd,
      FoldLvlStart, FoldLvlEnd,  NestLvlStart, NestLvlEnd: Integer;
      FoldType, FoldTypeCompatible: TPascalCodeFoldBlockType; FoldGroup: Integer;
      FoldAction: TSynFoldActions);
  end;

  { TTestHighlighterPas }

  TTestHighlighterPas = class(TTestBaseHighlighterPas)
  protected
    FAttrProcName: TSynHighlighterAttributesModifier;
    procedure ReCreateEdit; override;

    function TestTextFoldInfo1: TStringArray;
    function TestTextFoldInfo2: TStringArray;
    function TestTextFoldInfo3: TStringArray;
    function TestTextFoldInfo4(AIfCol: Integer): TStringArray;
    function TestTextFoldInfo5: TStringArray;

  published
    procedure TestFoldInfo;
    procedure TestExtendedKeywordsAndStrings;
    procedure TestContextForProcModifiers;
    procedure TestContextForProcModifiers2;
    procedure TestContextForProperties;
    procedure TestContextForProcedure;
    procedure TestContextForProcedureNameAttr;
    procedure TestContextForInterface;
    procedure TestContextForDeprecated;
    procedure TestContextForClassModifier; // Sealed abstract
    procedure TestContextForClassHelper;
    procedure TestContextForTypeHelper;
    procedure TestContextForClassFunction; // in class,object,record
    procedure TestContextForRecordHelper;
    procedure TestContextForStatic;
    procedure TestCaretAsString;
    procedure TestFoldNodeInfo;
  end;

implementation

const
  TK_Comma   = tkSymbol;
  TK_Semi    = tkSymbol;
  TK_Dot     = tkSymbol;
  TK_Colon   = tkSymbol;
  TK_Equal   = tkSymbol;
  TK_Bracket = tkSymbol;

operator := (a: TtkTokenKind) : TExpTokenInfo;
begin
  result := default(TExpTokenInfo);
  result.ExpKind := ord(a);
  result.Flags := [etiKind];
end;

operator + (a: TtkTokenKind; b: TSynHighlighterAttributes) : TExpTokenInfo;
begin
  result := default(TExpTokenInfo);
  result.ExpKind := ord(a);
  result.ExpAttr := b;
  result.Flags := [etiKind, etiAttr];
end;

{ TTestBaseHighlighterPas }

function TTestBaseHighlighterPas.PasHighLighter: TSynPasSyn;
begin
  Result := TSynPasSyn(FTheHighLighter);
end;

function TTestBaseHighlighterPas.CreateTheHighLighter: TSynCustomFoldHighlighter;
begin
  Result := TSynPasSyn.Create(nil);
end;

procedure TTestBaseHighlighterPas.EnableFolds(AEnbledTypes: TPascalCodeFoldBlockTypes;
  AHideTypes: TPascalCodeFoldBlockTypes; ANoFoldTypes: TPascalCodeFoldBlockTypes);
var
  i: TPascalCodeFoldBlockType;
begin
  PasHighLighter.BeginUpdate;
  for i := low(TPascalCodeFoldBlockType) to high(TPascalCodeFoldBlockType) do begin
    PasHighLighter.FoldConfig[ord(i)].Enabled := i in AEnbledTypes;
    if (i in ANoFoldTypes) then
      PasHighLighter.FoldConfig[ord(i)].Modes := []
    else
      PasHighLighter.FoldConfig[ord(i)].Modes := [fmFold];
    if i in AHideTypes then
      PasHighLighter.FoldConfig[ord(i)].Modes := PasHighLighter.FoldConfig[ord(i)].Modes + [fmHide];

    PasHighLighter.FoldConfig[ord(i)].Modes := PasHighLighter.FoldConfig[ord(i)].Modes +
      PasHighLighter.FoldConfig[ord(i)].SupportedModes * [fmMarkup];
  end;
  PasHighLighter.EndUpdate;
end;

procedure TTestBaseHighlighterPas.DebugFoldInfo(ALineIdx: Integer;
  AFilter: TSynFoldActions; Group: Integer=0);
var
  i, c: LongInt;
  n: TSynFoldNodeInfo;
  l: TLazSynFoldNodeInfoList;
begin
  l := PasHighLighter.FoldNodeInfo[ALineIdx];
  c := PasHighLighter.FoldNodeInfo[ALineIdx].CountEx(AFilter, Group);
  l.ClearFilter;
  l.ActionFilter := AFilter;
  l.GroupFilter := Group;
  debugln(['### Foldinfo Line: ', ALineIdx,
           ' Cnt=', l.Count, ' CntEx=', c,
           '   PasMinLvl=', PasHighLighter.FoldBlockMinLevel(ALineIdx,1),
           ' EndLvl=',PasHighLighter.FoldBlockEndLevel(ALineIdx,1),
           //' Nestcnt=',PasHighLighter.FoldNestCount(ALineIdx,1),
            ' : ', copy(SynEdit.Lines[ALineIdx],1,40)]);
  debugln('Idx: LogXStart End  FldLvlStart End  NestLvlStart End  FldType FldTypeCompat FldGroup FldAction');
  for i := 0 to c-1 do begin
    n := l.NodeInfoEx(i, AFilter, Group);
    if sfaInvalid in n.FoldAction then
      debugln(Format('%3d %9d %3d  %11d %3d  %12d %3d  %7d %13d %8d %s',
                     [i, 0,0,  0,0, 0,0, 0, 0, 0, FoldActionsToString(n.FoldAction)]))
    else
      debugln(Format('%3d %9d %3d  %11d %3d  %12d %3d  %7d %13d %8d %s   // %s',
                     [i, n.LogXStart, n.LogXEnd,
                      n.FoldLvlStart, n.FoldLvlEnd,  n.NestLvlStart, n.NestLvlEnd,
                      PtrUInt(n.FoldType), PtrUInt(n.FoldTypeCompatible), n.FoldGroup,
                      FoldActionsToString(n.FoldAction),
                      copy(SynEdit.Lines[ALineIdx],n.LogXStart, n.LogXEnd-n.LogXStart+1)
                     ]));
  end;
end;

procedure TTestBaseHighlighterPas.DebugFoldInfo(AFilter: TSynFoldActions;
  Group: Integer=0);
var
  i: Integer;
begin
  for i := 0 to SynEdit.Lines.Count - 1 do
    DebugFoldInfo(i, AFilter, Group);
end;

function TTestBaseHighlighterPas.FoldActionsToString(
  AFoldActions: TSynFoldActions): String;
var
  s: string;
  i: TSynFoldAction;
begin
  Result:='';
  for i := low(TSynFoldAction) to high(TSynFoldAction) do
    if i in AFoldActions then begin
      WriteStr(s, i);
      Result := Result + s + ',';
    end;
  if Result <> '' then SetLength(Result, Length(Result)-1);
end;

procedure TTestBaseHighlighterPas.CheckPasFoldNodeInfo(AName: String; nd: TSynFoldNodeInfo;
  ALine: TLineIdx; AColumn, AAllColIndex: integer; LogXStart, LogXEnd, FoldLvlStart,
  FoldLvlEnd, NestLvlStart, NestLvlEnd: Integer; FoldType,
  FoldTypeCompatible: TPascalCodeFoldBlockType; FoldGroup: Integer;
  FoldAction: TSynFoldActions);
begin
  AName := BaseTestName + AName;
  AssertEquals(Format('%s (%d/%d) LineIndex',    [AName, ALine, AColumn]), ALine, nd.LineIndex);
  AssertEquals(Format('%s (%d/%d) NodeIndex',    [AName, ALine, AColumn]), AColumn, nd.NodeIndex);
  if AAllColIndex >= 0 then
  AssertEquals(Format('%s (%d/%d) NodeIndex',    [AName, ALine, AColumn]), AAllColIndex, nd.AllNodeIndex);
  if not(sfaInvalid in nd.FoldAction) then begin
    AssertEquals(Format('%s (%d/%d) LogXStart',    [AName, ALine, AColumn]), LogXStart, nd.LogXStart);
    AssertEquals(Format('%s (%d/%d) LogXEnd',      [AName, ALine, AColumn]), LogXEnd, nd.LogXEnd);
    if FoldLvlStart >= 0 then
    AssertEquals(Format('%s (%d/%d) FoldLvlStart', [AName, ALine, AColumn]), FoldLvlStart, nd.FoldLvlStart);
    if FoldLvlEnd >= 0 then
    AssertEquals(Format('%s (%d/%d) FoldLvlEnd',   [AName, ALine, AColumn]), FoldLvlEnd, nd.FoldLvlEnd);
    AssertEquals(Format('%s (%d/%d) NestLvlStart', [AName, ALine, AColumn]), NestLvlStart, nd.NestLvlStart);
    AssertEquals(Format('%s (%d/%d) NestLvlEnd',   [AName, ALine, AColumn]), NestLvlEnd, nd.NestLvlEnd);
    AssertEquals(Format('%s (%d/%d) FoldType',     [AName, ALine, AColumn]), PtrInt(FoldType), PtrInt(nd.FoldType));
    AssertEquals(Format('%s (%d/%d) FoldTypeCompatible', [AName, ALine, AColumn]),
                       PtrInt(FoldTypeCompatible), PtrInt(nd.FoldTypeCompatible));
    AssertEquals(Format('%s (%d/%d) FoldGroup:',   [AName, ALine, AColumn]), FoldGroup, nd.FoldGroup);
  end;
  AssertEquals(Format('%s (%d/%d) FoldAction',   [AName, ALine, AColumn]),
    FoldActionsToString(FoldAction),
    FoldActionsToString(nd.FoldAction - [sfaOutline..sfaOutlineNoLine]));
end;

procedure TTestBaseHighlighterPas.CheckPasFoldNodeInfo(AName: String; nd: TSynFoldNodeInfo;
  ALine: TLineIdx; AColumn: integer; LogXStart, LogXEnd, FoldLvlStart, FoldLvlEnd,
  NestLvlStart, NestLvlEnd: Integer; FoldType, FoldTypeCompatible: TPascalCodeFoldBlockType;
  FoldGroup: Integer; FoldAction: TSynFoldActions);
begin
  CheckPasFoldNodeInfo(AName, nd, ALine, AColumn, -1, LogXStart, LogXEnd,
    FoldLvlStart, FoldLvlEnd, NestLvlStart, NestLvlEnd, FoldType, FoldTypeCompatible,
    FoldGroup, FoldAction);
end;

  { TTestHighlighterPas }

procedure TTestHighlighterPas.ReCreateEdit;
begin
  inherited ReCreateEdit;
  FAttrProcName := PasHighLighter.ProcedureHeaderName;
end;

function TTestHighlighterPas.TestTextFoldInfo1: TStringArray;
begin
  SetLength(Result, 13);
  Result[0] := 'program Foo;';
  Result[1] := 'procedure a;';
  Result[2] := '{$IFDEF A}';
  Result[3] := 'begin';
  Result[4] := '{$ENDIF}';
  Result[5] := '  {$IFDEF B} with a do begin {$ENDIF}';
  Result[6] := '    writeln()';
  Result[7] := '  end;';
  Result[8] := 'end;';
  Result[9] := 'begin';
  Result[10]:= 'end.';
  Result[11]:= '//';
  Result[12]:= '';
end;

function TTestHighlighterPas.TestTextFoldInfo2: TStringArray;
begin
  // mix folds and same-line-closing
  SetLength(Result, 9);
  Result[0] := 'program Foo;';
  Result[1] := 'procedure a;';
  Result[2] := '{$IFDEF A} begin {$IFDEF B} repeat a; {$ENDIF} until b; {$IFDEF c} try {$ELSE} //x';
  Result[3] := '  //foo';
  Result[4] := '  finally repeat x; {$ENDIF C} until y;';
  Result[5] := '  repeat m; until n; end; {$ENDIF A} // end finally';
  Result[6] := 'end';
  Result[7] := 'begin end.';
  Result[8] := '';

end;

function TTestHighlighterPas.TestTextFoldInfo3: TStringArray;
begin
  SetLength(Result, 12);
  Result[0] := 'Unit Foo;';
  Result[1] := 'Interface';
  Result[2] := 'type a=Integer;';
  Result[3] := 'var';
  Result[4] := '  b:Integer';
  Result[5] := 'const';
  Result[6] := '  c = 1;';
  Result[7] := '  d = 2; {$IFDEF A}';
  Result[8] := 'Implementation';
  Result[9] := '//';
  Result[10]:= 'end.';
  Result[11]:= '';
end;

function TTestHighlighterPas.TestTextFoldInfo4(AIfCol: Integer): TStringArray;
begin
  // various mixed of pascal and ifdef blocks => actually a test for pascal highlighter
  SetLength(Result, 8);
  Result[0] := 'program p;';
  Result[1] := 'procedure A;';
  case AIfCol of
    0: Result[2] := '{$IFDEF} begin  with a do begin';
    1: Result[2] := 'begin {$IFDEF} with a do begin';
    2: Result[2] := 'begin  with a do begin {$IFDEF}';
  end;
  Result[3] := '  end; // 2';
  Result[4] := 'end; // 1';
  Result[5] := '{$ENDIF}';
  Result[6] := '//';
  Result[7] := ''; // program fold is open end

end;

function TTestHighlighterPas.TestTextFoldInfo5: TStringArray;
begin
  SetLength(Result, 13);
  Result[0] := 'Unit Foo;';
  Result[1] := 'Interface';
  Result[2] := 'type';
  Result[3] := 'TFoo<T: class> = class(TBar<T>)';
  Result[4] := 'class procedure Proc;';
  Result[5] := 'end;';
  Result[6] := 'TFoo = record';
  Result[7] := 'class procedure Proc;';
  Result[8] := 'end;';
  Result[9] := 'Implementation';
  Result[10] := '//';
  Result[11] := 'end.';
  Result[12] := '';
end;

procedure TTestHighlighterPas.TestFoldInfo;
begin
  ReCreateEdit;

  //  DebugFoldInfo([]);

  {%region}
  SetLines(TestTextFoldInfo1);
  EnableFolds([cfbtBeginEnd..cfbtNone]);
  PushBaseName('Text 1 all folds');

  AssertEquals('Len Prog',  10, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Proc',   7, PasHighLighter.FoldLineLength(1,0));
  AssertEquals('Len IF A',   2, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len Begin',  5, PasHighLighter.FoldLineLength(3,0));
  AssertEquals('Len if beg', 2, PasHighLighter.FoldLineLength(5,0));
  AssertEquals('Len PrgBeg', 1, PasHighLighter.FoldLineLength(9,0));

  AssertEquals('Len invalid', -1, PasHighLighter.FoldLineLength(4,0)); // endif
  AssertEquals('Len // (no hide)', -1, PasHighLighter.FoldLineLength(11,0));

  //                       Pg pc $I bg $E be w  e  e be  e  //
  CheckFoldOpenCounts('', [1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold],
                          [1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0]);

  EnableFolds([cfbtBeginEnd..cfbtNone], [cfbtSlashComment]);
  AssertEquals('Len // (with hide)', 0, PasHighLighter.FoldLineLength(11,0));

  //                       Pg pc $I bg $E be w  e  e be  e  //
  CheckFoldOpenCounts('', [1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0]); // TODO: does not include the //
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold], // includes the //
                          [1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold, sfaFoldFold],
                          [1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaOneLineOpen, sfaFold, sfaFoldHide],
                          [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
  {%endregion}

  {%region}
  SetLines(TestTextFoldInfo1);
  EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtBeginEnd]);
  PopPushBaseName('Text 1 all folds, except cfbtBeginEnd');

  AssertEquals('Len Prog',  10, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Proc',   7, PasHighLighter.FoldLineLength(1,0));
  AssertEquals('Len IF A',   2, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len Begin',  5, PasHighLighter.FoldLineLength(3,0));
  AssertEquals('Len if beg (not avail)', -1, PasHighLighter.FoldLineLength(5,0));
  //AssertEquals('Len PrgBeg', 1, PasHighLighter.FoldLineLength(9,0));

  AssertEquals('Len invalid', -1, PasHighLighter.FoldLineLength(4,0)); // endif
  AssertEquals('Len // (no hide)', -1, PasHighLighter.FoldLineLength(11,0));

  //                       Pg pc $I bg $E be w  e  e be  e  //
  CheckFoldOpenCounts('', [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
  {%endregion}

  {%region}
  SetLines(TestTextFoldInfo1);
  EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtBeginEnd,cfbtTopBeginEnd]);
  PopPushBaseName('Text 1 all folds, except cfbtBeginEnd,cfbtTopBeginEnd');

  AssertEquals('Len Prog',  10, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Proc',   7, PasHighLighter.FoldLineLength(1,0));
  AssertEquals('Len IF A',   2, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len Begin (not avail)',  -1, PasHighLighter.FoldLineLength(3,0));
  AssertEquals('Len if beg (not avail)', -1, PasHighLighter.FoldLineLength(5,0));
  //AssertEquals('Len PrgBeg', 1, PasHighLighter.FoldLineLength(9,0));

  AssertEquals('Len // (no hide)', -1, PasHighLighter.FoldLineLength(11,0));

  //                       Pg pc $I bg $E be w  e  e be  e  //
  CheckFoldOpenCounts('', [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
  {%endregion}



  {%region}
  SetLines(TestTextFoldInfo2);
  EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtRepeat], [cfbtSlashComment]);
  PopPushBaseName('Text 2 all folds except repeat');

  AssertEquals('Len Prog',    7, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Proc',    5, PasHighLighter.FoldLineLength(1,0));

  AssertEquals('Len IFDEF A', 3, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len Begin',   4, PasHighLighter.FoldLineLength(2,1));
  AssertEquals('Len Try',     3, PasHighLighter.FoldLineLength(2,2));
  AssertEquals('Len ELSE C',  2, PasHighLighter.FoldLineLength(2,3));

  AssertEquals('Len //',      0, PasHighLighter.FoldLineLength(3,0));
  AssertEquals('Finally',     1, PasHighLighter.FoldLineLength(4,0));

  AssertEquals('Len invalid begin end', -1, PasHighLighter.FoldLineLength(7,0));

  //                       Pg pc 4  // fi e  e  be-
  CheckFoldOpenCounts('', [1, 1, 4, 0, 1, 0, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold],
                          [1, 1, 4, 1, 1, 0, 0, 0]);
  {%endregion}

  {%region}
  SetLines(TestTextFoldInfo3);
  EnableFolds([cfbtBeginEnd..cfbtNone], [cfbtSlashComment]);
  PushBaseName('Text 3 (end-last-line)');

  AssertEquals('Len Unit',     10, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Intf',      6, PasHighLighter.FoldLineLength(1,0));
  AssertEquals('Len type(non)',-1, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len var',       1, PasHighLighter.FoldLineLength(3,0));
  AssertEquals('Len const',     2, PasHighLighter.FoldLineLength(5,0));
  AssertEquals('Len Impl',      1, PasHighLighter.FoldLineLength(8,0));
  AssertEquals('Len //',        0, PasHighLighter.FoldLineLength(9,0));

  //                       Un If ty va -  co -  $  Im // e
  CheckFoldOpenCounts('', [1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold],
                          [1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0]);
  CheckFoldInfoCounts('', [sfaCloseFold, sfaFold, sfaLastLineClose],
                          [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
  CheckFoldInfoCounts('', [sfaLastLineClose],
                          [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
  {%endregion}

  {%region}
  SetLines(TestTextFoldInfo4(0));
  EnableFolds([cfbtBeginEnd..cfbtNone], [cfbtSlashComment]);
  PushBaseName('Text 4 (mixed group) 0');

  AssertEquals('Len Prog',   6, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Proc',   3, PasHighLighter.FoldLineLength(1,0));
  AssertEquals('Len IF',     3, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len beg 1',  2, PasHighLighter.FoldLineLength(2,1));
  AssertEquals('Len beg 2',  1, PasHighLighter.FoldLineLength(2,2));
  AssertEquals('Len //',     0, PasHighLighter.FoldLineLength(6,0));

  //                       Pg Pc 3  e  e  $e //
  CheckFoldOpenCounts('', [1, 1, 3, 0, 0, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold],
                          [1, 1, 3, 0, 0, 0, 1]);
  CheckFoldInfoCounts('', [sfaCloseFold, sfaFold, sfaLastLineClose],
                          [0, 0, 0, 0, 0, 0, 2]);
  CheckFoldInfoCounts('', [sfaLastLineClose],
                          [0, 0, 0, 0, 0, 0, 2]);


  SetLines(TestTextFoldInfo4(1));
  EnableFolds([cfbtBeginEnd..cfbtNone], [cfbtSlashComment]);
  PushBaseName('Text 4 (mixed group) 1');

  AssertEquals('Len Prog',   6, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Proc',   3, PasHighLighter.FoldLineLength(1,0));
  AssertEquals('Len IF',     3, PasHighLighter.FoldLineLength(2,1));
  AssertEquals('Len beg 1',  2, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len beg 2',  1, PasHighLighter.FoldLineLength(2,2));
  AssertEquals('Len //',     0, PasHighLighter.FoldLineLength(6,0));

  //                       Pg Pc 3  e  e  $e //
  CheckFoldOpenCounts('', [1, 1, 3, 0, 0, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold],
                          [1, 1, 3, 0, 0, 0, 1]);


  SetLines(TestTextFoldInfo4(2));
  EnableFolds([cfbtBeginEnd..cfbtNone], [cfbtSlashComment]);
  PushBaseName('Text 4 (mixed group) 1');

  AssertEquals('Len Prog',   6, PasHighLighter.FoldLineLength(0,0));
  AssertEquals('Len Proc',   3, PasHighLighter.FoldLineLength(1,0));
  AssertEquals('Len IF',     3, PasHighLighter.FoldLineLength(2,2));
  AssertEquals('Len beg 1',  2, PasHighLighter.FoldLineLength(2,0));
  AssertEquals('Len beg 2',  1, PasHighLighter.FoldLineLength(2,1));
  AssertEquals('Len //',     0, PasHighLighter.FoldLineLength(6,0));

  //                       Pg Pc 3  e  e  $e //
  CheckFoldOpenCounts('', [1, 1, 3, 0, 0, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold],
                          [1, 1, 3, 0, 0, 0, 1]);
  {%endregion}

  {%region}
  SetLines(TestTextFoldInfo5);
  EnableFolds([cfbtBeginEnd..cfbtNone], [cfbtSlashComment]);
  PushBaseName('Text 5 (class in generic type)');

  AssertEquals('Len Unit',     11, PasHighLighter.FoldLineLength( 0,0));
  AssertEquals('Len Intf',      7, PasHighLighter.FoldLineLength( 1,0));
  AssertEquals('Len type',      6, PasHighLighter.FoldLineLength( 2,0));
  AssertEquals('Len class',     2, PasHighLighter.FoldLineLength( 3,0));
  AssertEquals('Len record',    2, PasHighLighter.FoldLineLength( 6,0));
  AssertEquals('Len Impl',      1, PasHighLighter.FoldLineLength( 9,0));
  AssertEquals('Len //',        0, PasHighLighter.FoldLineLength(10,0));

  //                       un in ty cl pr en re pr en im // en
  CheckFoldOpenCounts('', [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0]);
  CheckFoldInfoCounts('', [sfaOpenFold, sfaFold],
                          [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0]);
  CheckFoldInfoCounts('', [sfaCloseFold, sfaFold, sfaLastLineClose],
                          [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
  CheckFoldInfoCounts('', [sfaLastLineClose],
                          [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
  {%endregion}
end;

procedure TTestHighlighterPas.TestExtendedKeywordsAndStrings;
begin
  ReCreateEdit;
  SetLines
    ([ 'Program A;',
       'var',
       '  Foo1: String;',
       '  Foo2: AnsiString;',
       '  Foo3: WideString;',
       '  Foo4: Shortstring;',
       '  Foo5: Integer;',
       '',
       'Procedure b;',
       'begin',
       ' while Foo1 <> '''' do',
       ' continue;',
       ' exit;',
       'end',
       '',
       'begin',
       'end',
       ''
    ]);

  PushBaseName('spsmDefault');
  PasHighLighter.StringKeywordMode := spsmDefault;
  CheckTokensForLine('String', 2, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkKey, tkSymbol  ]);
  CheckTokensForLine('ansi',   3, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkKey, tkSymbol  ]);
  CheckTokensForLine('wide',   4, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkKey, tkSymbol  ]);
  CheckTokensForLine('short',  5, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkKey, tkSymbol  ]);
  CheckTokensForLine('int',    6, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]); // selftest

  PopPushBaseName('spsmStringOnly');
  PasHighLighter.StringKeywordMode := spsmStringOnly;
  CheckTokensForLine('String', 2, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkKey, tkSymbol  ]);
  CheckTokensForLine('ansi',   3, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('wide',   4, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('short',  5, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('int',    6, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]); // selftest

  PopPushBaseName('spsmNone');
  PasHighLighter.StringKeywordMode := spsmNone;
  CheckTokensForLine('String', 2, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('ansi',   3, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('wide',   4, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('short',  5, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('int',    6, [tkSpace, tkIdentifier, tkSymbol, tkSpace,   tkIdentifier, tkSymbol  ]); // selftest


  PopPushBaseName('False');
  PasHighLighter.ExtendedKeywordsMode := False;
  CheckTokensForLine('continue',  11, [tkSpace, tkIdentifier, tkSymbol ]);
  CheckTokensForLine('exit',      12, [tkSpace, tkIdentifier, tkSymbol ]);

  PopPushBaseName('True');
  PasHighLighter.ExtendedKeywordsMode := True;
  CheckTokensForLine('continue',  11, [tkSpace, tkKey, tkSymbol ]);
  CheckTokensForLine('exit',      12, [tkSpace, tkKey, tkSymbol ]);

end;

procedure TTestHighlighterPas.TestContextForProcModifiers;
begin
  {%region message modifier for procedure}
    ReCreateEdit;
    SetLines
      ([ 'Unit A; interface',
         'type TFoo=class',
           'message: message;',
           'Procedure message(message: message); message 100;',
           'property message: message read message;',
         'end;',
         'var',
         '  message: message;',
         'Procedure message(message: message);'
      ]);
  CheckTokensForLine('class field',  2,
    [ tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol ]);
  CheckTokensForLine('class, proc message',  3,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol,        // "Procedure",  " ", "message", "("
      tkIdentifier, tkSymbol, tkSpace, tkIdentifier, // "message",, ":", " ", "message"
      tkSymbol, tkSymbol, tkSpace,                   // ")", ";", " "
      tkKey, // "message" as key
      tkSpace, tkNumber, tkSymbol
    ]);
  CheckTokensForLine('property',  4,
    [ tkKey, tkSpace, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSpace, tkKey, tkSpace, tkIdentifier ]);

  CheckTokensForLine('var',  7,
    [ tkSpace, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol ]);
  CheckTokensForLine('procedure',  8,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol,        // "Procedure",  " ", "message", "("
      tkIdentifier, tkSymbol, tkSpace, tkIdentifier, // "message",, ":", " ", "message"
      tkSymbol, tkSymbol                             // ")", ";"
    ]);

  {%endregion}
end;

procedure TTestHighlighterPas.TestContextForProcModifiers2;
begin
    ReCreateEdit;
    SetLines
      ([ 'Unit A; interface',
         'type',
         'cdecl=function(cdecl:cdecl):cdecl;cdecl;',
         'type',
         'Stdcall=class(cdecl)',
         'function Stdcall(Stdcall:Stdcall):Stdcall;Stdcall;deprecated;',
         'property cdecl:cdecl read cdecl;',
         'end;',
         '',
         'cdecl=record',
         'function cdecl(cdecl:cdecl):cdecl;cdecl;deprecated;',
         'end;',
         '',
         'var',
         'Stdcall:function(cdecl:cdecl):cdecl;cdecl;',
         'var',
         'cdecl:cdecl;',
         '',
         'function Stdcall(cdecl:cdecl):cdecl;cdecl;',
         'var',
         'cdecl:cdecl deprecated;',
         'function Stdcall(cdecl:cdecl):cdecl;cdecl;deprecated;',
         ''
      ]);

  CheckTokensForLine('type cdecl',  2,
    [ tkIdentifier, TK_Equal, tkKey,  // cdecl=function
      TK_Bracket, tkIdentifier, TK_Comma, tkIdentifier, TK_Bracket,  // (cdecl:cdecl)
      TK_Colon, tkIdentifier, TK_Semi, tkKey, TK_Semi // :cdecl;cdecl;
    ]);

  CheckTokensForLine('StdCall=class',  4,
    [ tkIdentifier, TK_Equal, tkKey,  // Stdcall=class
      TK_Bracket, tkIdentifier, TK_Bracket  // (cdecl)
    ]);

  CheckTokensForLine('function/method cdecl',  5,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  // function cdecl
      TK_Bracket, tkIdentifier, TK_Comma, tkIdentifier, TK_Bracket,  // (cdecl:cdecl)
      TK_Colon, tkIdentifier, TK_Semi, tkKey, TK_Semi, // :cdecl;cdecl;
      tkKey, TK_Semi //deprecated;
    ]);

  CheckTokensForLine('property',  6,
    [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkIdentifier, tkSpace, tkKey, tkSpace, tkIdentifier, TK_Semi ]);

  CheckTokensForLine('StdCall=record',  9,
    [ tkIdentifier, TK_Equal, tkKey  // Stdcall=record
    ]);

  CheckTokensForLine('funciton in recorld',  10,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  // function cdecl
      TK_Bracket, tkIdentifier, TK_Comma, tkIdentifier, TK_Bracket,  // (cdecl:cdecl)
      TK_Colon, tkIdentifier, TK_Semi, tkKey, TK_Semi, // :cdecl;cdecl;
      tkKey, TK_Semi //deprecated;
    ]);

  CheckTokensForLine('var cdecl function',  14,
    [ tkIdentifier, TK_Equal, tkKey,  // Stdcall:function
      TK_Bracket, tkIdentifier, TK_Comma, tkIdentifier, TK_Bracket,  // (cdecl:cdecl)
      TK_Colon, tkIdentifier, TK_Semi, tkKey, TK_Semi // :cdecl;cdecl;
    ]);

  CheckTokensForLine('var cdecl:cdecl',  16,
    [ tkIdentifier, TK_Colon, tkIdentifier, TK_Semi  //cdecl:cdecl;
    ]);

  CheckTokensForLine('function',  18,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  // function StdCall
      TK_Bracket, tkIdentifier, TK_Comma, tkIdentifier, TK_Bracket,  // (cdecl:cdecl)
      TK_Colon, tkIdentifier, TK_Semi, tkKey, TK_Semi // :cdecl;cdecl;
    ]);

  CheckTokensForLine('var cdecl deprecated:cdecl',  20,
    [ tkIdentifier, TK_Colon, tkIdentifier,   //cdecl:cdecl
      tkSpace, tkKey, TK_Semi //deprecated;
    ]);

  CheckTokensForLine('function deprecated',  21,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  // function StdCall
      TK_Bracket, tkIdentifier, TK_Comma, tkIdentifier, TK_Bracket,  // (cdecl:cdecl)
      TK_Colon, tkIdentifier,TK_Semi, // :cdecl;
      tkKey, TK_Semi, // cdecl;
      tkKey, TK_Semi //deprecated;
    ]);

end;

procedure TTestHighlighterPas.TestContextForProperties;
begin
  {%region property and index}
    ReCreateEdit;
    SetLines
      ([ 'Unit A; interface',
         'type TFoo = class',
         'property Index[Index: Integer]: Integer read GetIndex write SetIndex Index 3;',
         ''
      ]);
  CheckTokensForLine('property with index',  2,
    [ tkKey, tkSpace, tkIdentifier, tkSymbol,        // "property",  " ", "Index", "["
      tkIdentifier, tkSymbol, tkSpace, tkIdentifier, // "Index",, ":", " ", "Integer"
      tkSymbol, tkSymbol, tkSpace, tkIdentifier,     // "]", ":", " ", "Integer"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'read', " ", "GetIndex"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'write', " ", "SetIndex"
      tkSpace, tkKey, tkSpace, tkNumber,             // '" ", "INDEX" (key), " ", "3"
      tkSymbol
    ]);

    SetLines
      ([ 'Unit A; interface',
         'type TFoo = class',
         'property AnIndex[Index: Index]: Index read Index write Index Index 3;',
         ''
      ]);
  CheckTokensForLine('property with index 2',  2,
    [ tkKey, tkSpace, tkIdentifier, tkSymbol,        // "property",  " ", "AnIndex", "["
      tkIdentifier, tkSymbol, tkSpace, tkIdentifier, // "Index",, ":", " ", "Index"
      tkSymbol, tkSymbol, tkSpace, tkIdentifier,     // "]", ":", " ", "Index"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'read', " ", "Index"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'write', " ", "Index"
      tkSpace, tkKey, tkSpace, tkNumber,             // '" ", "INDEX" (key), " ", "3"
      tkSymbol
    ]);

    SetLines
      ([ 'Unit A; interface',
         'type',
         'Index = Integer;',
         'Foo = Index;',
         '',
         'var',
         'Foo, Index: Index;',
         'Index: Index;',
         ''
      ]);
  CheckTokensForLine('index outside property',  2,
    [tkIdentifier, tkSpace, tkSymbol, tkSpace, tkIdentifier, tkSymbol]);
  CheckTokensForLine('index outside property',  3,
    [tkIdentifier, tkSpace, tkSymbol, tkSpace, tkIdentifier, tkSymbol]);
  CheckTokensForLine('index outside property',  6,
    [tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol]);
  CheckTokensForLine('index outside property',  7,
    [tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol]);

  {%endregion}

  {%region property and read/write}
    ReCreateEdit;
    SetLines
      ([ 'Unit A; interface',
         'type TFoo = class',
         'property read[read: read]: read read read write read;',
         ''
      ]);
  CheckTokensForLine('property "read"',  2,
    [ tkKey, tkSpace, tkIdentifier, tkSymbol,        // "property",  " ", "read", "["
      tkIdentifier, tkSymbol, tkSpace, tkIdentifier, // "read",, ":", " ", "read"
      tkSymbol, tkSymbol, tkSpace, tkIdentifier,     // "]", ":", " ", "read"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'READ', " ", "read"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'write', " ", "read"
      tkSymbol
    ]);


    ReCreateEdit;
    SetLines
      ([ 'Unit A; interface',
         'type TFoo = class',
         'property write[write: write]: write read write write write;',
         ''
      ]);
  CheckTokensForLine('property "write"',  2,
    [ tkKey, tkSpace, tkIdentifier, tkSymbol,        // "property",  " ", "write", "["
      tkIdentifier, tkSymbol, tkSpace, tkIdentifier, // "write",, ":", " ", "write"
      tkSymbol, tkSymbol, tkSpace, tkIdentifier,     // "]", ":", " ", "write"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'read', " ", "write"
      tkSpace, tkKey, tkSpace, tkIdentifier,      // " ", 'write', " ", "write"
      tkSymbol
    ]);
  {%endregion}

  {%region property and default}
    ReCreateEdit;
    SetLines
      ([ 'Unit A; interface',
         'type TFoo = class',
         'default,default:default;',
         'private type',
         'default=integer;',
         'private',
         'a: default;',
         'default:default.default;',
 {8}     'function default(default:default):default;',
 {9}     'function default(default:default.default):default.default;',
{10}     'property default[default:default]:default read default write default; default;',
{11}     'property default:default read default default default;',
{12}     'property default:default index default read default default default-default+default;',
         // property could read a field inside an embedded record
{13}     'property default:default.default index {C} default.default read {C} default.default {C} default default.default * default.default;',
{14}     'property default: default index not default.default read default default -default.default;',
{15}     'property default: default.default index specialize default<default, default>.default read default default default.default;',
{16}     'property default: specialize default<default, default> index specialize default<default, default>.default read default default specialize default<default, default>.default;',
         ''
      ]);

  CheckTokensForLine('FIELD: default,default:default;',  2,
    [ tkIdentifier, TK_Comma, tkIdentifier,    // default , default
      TK_Colon, tkIdentifier, TK_Semi                   // : default;
    ]);

  CheckTokensForLine('TYPE: default=integer;',  4,
    [ tkIdentifier, TK_Equal, tkIdentifier, TK_Semi // default = integer ;
    ]);

  CheckTokensForLine('FIELD: default:default.default;',  7,
    [ tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi   // default : default . default ;
    ]);

  CheckTokensForLine('function default(default:default):default;',  8,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,                         // function default
      TK_Bracket, tkIdentifier, TK_Colon, tkIdentifier, TK_Bracket,  // ( default : default )
      TK_Colon, tkIdentifier, TK_Semi                       // : default;
    ]);

  CheckTokensForLine('function default(default:default.default):default.default;',  9,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,                           // function default
      TK_Bracket, tkIdentifier, TK_Colon,                     // ( default :
      tkIdentifier, TK_Dot, tkIdentifier, TK_Bracket,         // default . default )
      TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi  // : default . default;
    ]);

  CheckTokensForLine('property default[default:default]:default read default write default; default;',  10,
    [ tkKey, tkSpace, tkIdentifier, TK_Bracket, tkIdentifier,     // property default[default
      TK_Colon, tkIdentifier, TK_Bracket, TK_Colon, tkIdentifier, // :default]:default
      tkSpace, tkKey, tkSpace, tkIdentifier,  // read default
      tkSpace, tkKey, tkSpace, tkIdentifier,  // write default
      TK_Semi, tkSpace, tkKey, TK_Semi // ; default;
    ]);

  CheckTokensForLine('property default:default read default default default;',  11,
    [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkIdentifier,   //property default:default
      tkSpace, tkKey, tkSpace, tkIdentifier, // read default
      tkSpace, tkKey, tkSpace, tkIdentifier, TK_Semi  // default default;
    ]);

  CheckTokensForLine('property default:default index default read default default default-default+default;',  12,
    [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkIdentifier,  // property default:default
      tkSpace, tkKey, tkSpace, tkIdentifier, // index default
      tkSpace, tkKey, tkSpace, tkIdentifier, // read default
      tkSpace, tkKey, tkSpace, tkIdentifier, // default default
      tkSymbol, tkIdentifier, tkSymbol, tkIdentifier, TK_Semi // -default+default;
    ]);

  CheckTokensForLine('property default:default.default index {C} default.default read {C} default.default {C} default default.default * default.default;',  13,
    [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier,  // property default:default.default
      tkSpace, tkKey, tkSpace, tkComment, tkSpace, // index (C}
      tkIdentifier, TK_Dot, tkIdentifier, tkSpace, // default.default
      tkKey, tkSpace, tkComment, tkSpace,          // read (C}
      tkIdentifier, TK_Dot, tkIdentifier, tkSpace, // default.default
      tkComment, tkSpace, // (C}
      tkKey, tkSpace, tkIdentifier, TK_Dot, tkIdentifier, tkSpace,  // default default.default
      tkSymbol, tkSpace, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi // * default.default;
    ]);

  CheckTokensForLine('property default: default index not default.default read default default -default.default;',  14,
    [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkSpace, tkIdentifier, tkSpace,  // property default:default
      tkKey, tkSpace, tkKey, tkSpace, tkIdentifier, TK_Dot, tkIdentifier, tkSpace, // index not default.default
      tkKey, tkSpace, tkIdentifier, tkSpace,  //read default
      tkKey, tkSpace, tkSymbol, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi // default -default.default;
    ]);

  CheckTokensForLine('property default: default.default index specialize default<default, default>.default read default default default.default;',  15,
    [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkSpace, tkIdentifier, TK_Dot, tkIdentifier, tkSpace,  // property default: default.default
      tkKey, tkSpace, tkKey, tkSpace, // index specialize
      tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol,  //default<default, default>
      tkSymbol, tkIdentifier, tkSpace,  // .default
      tkKey, tkSpace, tkIdentifier, tkSpace,  // read default
      tkKey, tkSpace, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi  // default default.default;
    ]);

  CheckTokensForLine('property default: specialize default<default, default> index specialize default<default, default>.default read default default specialize default<default, default>.default;',  16,
    [ tkKey, tkSpace, tkIdentifier, TK_Colon, tkSpace,  // property default:
      tkKey, tkSpace, //specialize
      tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, tkSpace,  //default<default, default>
      tkKey, tkSpace, tkKey, tkSpace,  // index specialize
      tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol,  // default<default, default>
      tkSymbol, tkIdentifier, tkSpace, // .default
      tkKey, tkSpace, tkIdentifier, tkSpace, // read default
      tkKey, tkSpace, tkKey, tkSpace, // default specialize
      tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, // default<default, default>
      tkSymbol, tkIdentifier, TK_Semi // .default;
    ]);






  {%endregion}
end;

procedure TTestHighlighterPas.TestContextForProcedure;
var
  AtP, AtI, AtK: TSynHighlighterAttributes;
begin
  ReCreateEdit;
  AtP := PasHighLighter.ProcedureHeaderName;
  AtI := PasHighLighter.IdentifierAttri;
  AtK := PasHighLighter.KeywordAttribute;

  SetLines
    ([ 'Unit A;',
       'interface',
       '',
       'type',
       '  IBar = interface',
{5}    '     procedure p1;',
       '     procedure p2;',
       '  end;',
       '',
       'var',
{10}   '  Foo: Procedure of object;', // no folding // do not end var block
       '',
       'type',
       '  TBar= ',
       '    Function(): Boolean;',  // no folding // do not end type block
{15}   '',
       'Procedure a;', // no folding in interface
       '',
       'implementation',
       '',
{20}   'var',
       '  Foo2: Procedure of object;', // no folding // do not end var block
       '',
       'type',
       '  TBar2: ',
{25}   '    Function(): Boolean;',  // no folding // do not end type block
       '',
       'Procedure a;', // fold
       'var',
       '  Foo3: Procedure of object;', // no folding // do not end var block
       '',
       'begin end;',
       '',
       'end.',
       ''
    ]);
  EnableFolds([cfbtBeginEnd..cfbtNone]);
  CheckFoldOpenCounts('', [ 1, 1, 0,
                            1 {type}, 1, 0, 0, 0, 0,
                            1 {var}, 0, 0, 1 {type}, 0, 0, 0,
                            0 {Proc}, 0,
                            1 {impl}, 0, 1 {var}, 0, 0, 1 {type}, 0, 0, 0,
                            1 {proc}, 1 {var}, 0, 0, 0, 0, 0
                     ]);
  AssertEquals('Len var 1 ',   2, PasHighLighter.FoldLineLength(9, 0));
  AssertEquals('Len type 1 ',  3, PasHighLighter.FoldLineLength(12, 0));
  AssertEquals('Len var 2 ',   2, PasHighLighter.FoldLineLength(20, 0));
  AssertEquals('Len type 2 ',  3, PasHighLighter.FoldLineLength(23, 0));
  AssertEquals('Len var 3 ',   2, PasHighLighter.FoldLineLength(28, 0));


  CheckTokensForLine('IBar.p1',   5, [ tkSpace, tkKey + AtK, tkSpace, tkIdentifier + AtP, tkSymbol ]);
  CheckTokensForLine('IBar.p2',   6, [ tkSpace, tkKey + AtK, tkSpace, tkIdentifier + AtP, tkSymbol ]);
  CheckTokensForLine('foo p of', 10, [ tkSpace, tkIdentifier, tkSymbol, tkSpace,
    tkKey + AtK, tkSpace, tkKey + AtK {of}, tkSpace, tkKey, tkSymbol
    ]);
  CheckTokensForLine('TBar',     14, [ tkSpace, tkKey + AtK, tkSymbol, tkSymbol, tkSymbol,
    tkSpace, tkIdentifier + AtI, tkSymbol
    ]);


end;

procedure TTestHighlighterPas.TestContextForProcedureNameAttr;
begin
  ReCreateEdit;

  SetLines
    ([ 'Unit A;',
{ 1}   'interface',
{  }   '',
{  }   'TFoo=class',
{ 4}   'Procedure Bar;',
{ 5}   'function Bar:boolean;',
{ 6}   'function Bar(a:t.x):t.x;',
{  }   'end',
{  }   '',
{ 9}   'Procedure Bar;',
{10}   'function Bar:boolean;',
{11}   'function Bar(a:t.x):t.x;',
{  }   '',
{  }   'implementation',
{14}   'Procedure TFoo.Bar;',
{  }   'begin end;',
{16}   'function TFoo.Bar:boolean;',
{  }   'begin end;',
{18}   'function TFoo.Bar(a:t.x):t.x;',
{  }   'begin end;',
{20}   'Procedure Bar;',
{  }   'begin end;',
{22}   'function Bar:boolean;',
{  }   'begin end;',
{24}   'function Bar(a:t.x):t.x;',
{  }   'begin end;',
{  }   '',
{  }   'var',
{28}   'p1:procedure deprecated;', // deprecated is not the name
{29}   'p2:procedure(a:int64) deprecated;',
{30}   'f1:function:int64 deprecated;',
{  }   '',
{  }   'end.',
       ''
    ]);


  CheckTokensForLine('procedure Bar in class',  4,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, TK_Semi     // Procedure Bar;
    ]);

  CheckTokensForLine('function Bar:boolean in class',  5,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,      // function Bar
      TK_Colon, tkIdentifier, TK_Semi  //: boolean;
    ]);

  CheckTokensForLine('function Bar(a:t.x):boolean in class',  6,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,      // function Bar
      TK_Bracket, tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Bracket,  // (a:t.x)
      TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi  // :t.x;
    ]);


  CheckTokensForLine('procedure Bar',  9,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, TK_Semi     // Procedure Bar;
    ]);

  CheckTokensForLine('function Bar:boolean',  10,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,      // function Bar
      TK_Colon, tkIdentifier, TK_Semi  //: boolean;
    ]);

  CheckTokensForLine('function Bar(a:t.x):boolean', 11,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,      // function Bar
      TK_Bracket, tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Bracket,  // (a:t.x)
      TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi  // :t.x;
    ]);


  CheckTokensForLine('procedure TFoo.Bar', 14,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, TK_Dot + FAttrProcName, tkIdentifier + FAttrProcName, TK_Semi     // Procedure TFoo.Bar;
    ]);

  CheckTokensForLine('function TFoo.Bar:boolean', 16,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, TK_Dot + FAttrProcName, tkIdentifier + FAttrProcName,      // function TFoo.Bar
      TK_Colon, tkIdentifier, TK_Semi  //: boolean;
    ]);

  CheckTokensForLine('function TFoo.Bar(a:t.x):boolean', 18,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, TK_Dot + FAttrProcName, tkIdentifier + FAttrProcName,      // function TFoo.Bar
      TK_Bracket, tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Bracket,  // (a:t.x)
      TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi  // :t.x;
    ]);



  CheckTokensForLine('procedure Bar', 20,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName, TK_Semi     // Procedure TFoo.Bar;
    ]);

  CheckTokensForLine('function Bar:boolean', 22,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,      // function TFoo.Bar
      TK_Colon, tkIdentifier, TK_Semi  //: boolean;
    ]);

  CheckTokensForLine('function Bar(a:t.x):boolean', 24,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,      // function TFoo.Bar
      TK_Bracket, tkIdentifier, TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Bracket,  // (a:t.x)
      TK_Colon, tkIdentifier, TK_Dot, tkIdentifier, TK_Semi  // :t.x;
    ]);



  CheckTokensForLine('var p1:procedure deprecated;', 28,
    [ tkIdentifier, TK_Colon, tkKey, tkSpace, tkKey, TK_Semi     // p1:procedure deprecated;
    ]);

  CheckTokensForLine('var p2:procedure(a:int64) deprecated;', 29,
    [ tkIdentifier, TK_Colon, tkKey,   // p2:procedure
    TK_Bracket, tkIdentifier, TK_Colon, tkIdentifier, TK_Bracket,    // (a:int64)
    tkSpace, tkKey, TK_Semi  //deprecated;
    ]);

  CheckTokensForLine('var f1:function:int64 deprecated;', 30,
    [ tkIdentifier, TK_Colon, tkKey,   // f1:function
    TK_Colon, tkIdentifier, tkSpace, tkKey, TK_Semi    // :int64 deprecated;
    ]);


end;

procedure TTestHighlighterPas.TestContextForInterface;
var
  AtP, AtI, AtK: TSynHighlighterAttributes;
begin
  ReCreateEdit;
  AtK := PasHighLighter.KeywordAttribute;

  SetLines
    ([ 'Unit A;',
       'interface',
       '',
       'type',
       '  IBar = interface',
       '     procedure p1;',
       '     procedure p2;',
       '  end;',
       '',
       'var',
       '  IBar2: interface', // not allowed "anonymous class"
       '     procedure p1;',
       '     procedure p2;',
       '',
       'implementation',
       ''
    ]);
  EnableFolds([cfbtBeginEnd..cfbtNone]);
  CheckFoldOpenCounts('', [ 1, 1, 0,
                            1 {type}, 1, 0, 0, 0, 0,
                            1 {var},  0, 0, 0, 0, 0
                            // implementation
                     ]);
  AssertEquals('Len type ',  5, PasHighLighter.FoldLineLength(3, 0));
  AssertEquals('Len intf ',  3, PasHighLighter.FoldLineLength(4, 0));
  AssertEquals('Len var  ',  1, PasHighLighter.FoldLineLength(9, 0)); // ends at next procedure

  CheckTokensForLine('unit "interface"',  1,
    [ tkKey + AtK ]);
  CheckTokensForLine('type "interface"',  4,
    [ tkSpace, tkIdentifier, tkSpace, tkSymbol, tkSpace, tkKey + AtK ]);
  CheckTokensForLine('var "interface"',  10,
    [ tkSpace, tkIdentifier, tkSymbol, tkSpace, tkKey + AtK ]); // not allowed, still a keyword
end;

procedure TTestHighlighterPas.TestContextForDeprecated;
  procedure SubTest(s: String);

    procedure SubTest2(struct: String);
    begin
      SetLines
        ([  'Unit A; interface',
            'type',
            'TFoo='+struct,
               s+': '+s+' '+s+';',  // nameDEPRECATED: typeDEPRECATED deprecated;
              'foo, '+s+', bar: Integer '+s+';',
              'procedure '+s+'('+s+': '+s+'); '+s+';',
            'end',
            ''
        ]);

      CheckTokensForLine('member in class', 3,
        [tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
      CheckTokensForLine('multi member in class', 4,
        [tkIdentifier, tkSymbol,   tkSpace, tkIdentifier, tkSymbol,   tkSpace,tkIdentifier, tkSymbol, // ... ":"
        tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
      CheckTokensForLine('procedure in class', 5,
        [tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol { ( }, tkIdentifier, tkSymbol { : },
         tkSpace, tkIdentifier, tkSymbol { ) }, tkSymbol, tkSpace, tkKey {the one and only}, tkSymbol
        ]);


      if struct = 'record' then
        exit;

      SetLines
        ([  'Unit A; interface',
            'type',
            'TFoo='+struct,
               s+': '+s+' '+s+';',  // nameDEPRECATED: typeDEPRECATED deprecated;
              'foo, '+s+', bar: Integer '+s+';',
              'procedure '+s+'('+s+': '+s+'); '+s+';',
            'private',
               s+': '+s+' '+s+';',  // nameDEPRECATED: typeDEPRECATED deprecated;
              'foo, '+s+', bar: Integer '+s+';',
              'property '+s+': '+s+' read '+s+'; '+s+';',
              'procedure '+s+'('+s+': '+s+'); '+s+';',
            'end',
            ''
        ]);

      CheckTokensForLine('member in class', 3,
        [tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
      CheckTokensForLine('multi member in class', 4,
        [tkIdentifier, tkSymbol,   tkSpace, tkIdentifier, tkSymbol,   tkSpace,tkIdentifier, tkSymbol, // ... ":"
        tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
      CheckTokensForLine('procedure in class', 5,
        [tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol { ( }, tkIdentifier, tkSymbol { : },
         tkSpace, tkIdentifier, tkSymbol { ) }, tkSymbol, tkSpace, tkKey {the one and only}, tkSymbol
        ]);

      CheckTokensForLine('member in class-sect', 7,
        [tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
      CheckTokensForLine('multi member in class-sect', 8,
        [tkIdentifier, tkSymbol,   tkSpace, tkIdentifier, tkSymbol,   tkSpace,tkIdentifier, tkSymbol, // ... ":"
        tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
      CheckTokensForLine('property in class-sect', 9,
        [tkKey, tkSpace, tkIdentifier, tkSymbol { : }, tkSpace, tkIdentifier, tkSpace,
         tkKey { read }, tkSpace, tkIdentifier, tkSymbol { ; }, tkSpace, tkKey {the one and only}, tkSymbol
        ]);
      CheckTokensForLine('procedure in class-sect', 10,
        [tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol { ( }, tkIdentifier, tkSymbol { : },
         tkSpace, tkIdentifier, tkSymbol { ) }, tkSymbol, tkSpace, tkKey {the one and only}, tkSymbol
        ]);

    end;

  begin
    PushBaseName('test for '+s);
    ReCreateEdit;
    SetLines
      ([  'Unit A; interface',
          'var',
           s+': '+s+' '+s+';',  // nameDEPRECATED: typeDEPRECATED deprecated;
          'foo, '+s+', bar: Integer '+s+';',
          'type',
          s+' = '+s+' '+s+';',   // nameDEPRECATED = typeDEPRECATED deprecated;
          'procedure '+s+'('+s+': '+s+'); '+s+';',
          'var',
          s+':procedure '+s+';',
          ''
      ]);
    CheckTokensForLine('var', 2,
      [tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
    CheckTokensForLine('multi var', 3,
      [tkIdentifier, tkSymbol,   tkSpace, tkIdentifier, tkSymbol,   tkSpace,tkIdentifier, tkSymbol, // ... ":"
      tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
    CheckTokensForLine('type', 5,
      [tkIdentifier, tkSpace, tkSymbol, tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
    CheckTokensForLine('procedure', 6,
      [tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol { ( }, tkIdentifier, tkSymbol { : },
       tkSpace, tkIdentifier, tkSymbol { ) }, tkSymbol, tkSpace, tkKey {the one and only}, tkSymbol
      ]);
    CheckTokensForLine('var a:procedure DEPRECATED;', 8,
      [tkIdentifier, TK_Colon, tkKey, tkSpace, tkKey {the one and only}, TK_Semi]);


    PushBaseName('class');
    SubTest2('class');
    PopPushBaseName('object');
    SubTest2('object');
    PopPushBaseName('record');
    SubTest2('record');
    PopBaseName;


    SetLines
      ([  'Program a',
          'procedure '+s+'('+s+': '+s+');',
          'var',
             s+': '+s+' '+s+';',  // nameDEPRECATED: typeDEPRECATED deprecated;
            'foo, '+s+', bar: Integer '+s+';',
          'begin end;',
          ''
      ]);

    CheckTokensForLine('procedure in implement', 1,
      [tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol { ( }, tkIdentifier, tkSymbol { : },
       tkSpace, tkIdentifier, tkSymbol { ) }, tkSymbol
      ]);
    CheckTokensForLine('var in procedure', 3,
      [tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);
    CheckTokensForLine('multi var in procedure', 4,
      [tkIdentifier, tkSymbol,   tkSpace, tkIdentifier, tkSymbol,   tkSpace,tkIdentifier, tkSymbol, // ... ":"
      tkSpace, tkIdentifier, tkSpace, tkKey {the one and only}, tkSymbol]);



    // after class declaration
    SetLines
      ([  'Unit A; interface',
          'type',
          'TFoo=class',
            'foo: Integer;',
          'end '+s+';',
          ''
      ]);
    CheckTokensForLine('after class declaration', 4,
      [tkKey, tkSpace, tkKey, tkSymbol]);

    PopBaseName;
  end;
begin
  SubTest('deprecated');
  SubTest('unimplemented');
  SubTest('experimental');
  SubTest('platform');
end;

procedure TTestHighlighterPas.TestContextForClassModifier;
begin
  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',
       'type',
       'TFoo = class sealed abstract',
         'a, sealed, abstract: Integer;',
         'procedure Foo; abstract;',
        'end;',
       ''
    ]);

  CheckTokensForLine('class declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSpace,
      tkKey {sealed}, tkSpace, tkKey {abstract}
    ]);
  CheckTokensForLine('var in class "',  3,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);
  CheckTokensForLine('procedure in class "',  4,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  tkSymbol, tkSpace, tkKey,  tkSymbol ]);



  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',
       'type',
       'TFoo = class {} sealed abstract',
         'a, sealed, abstract: Integer;',
         'procedure Foo; abstract;',
        'end;',
       ''
    ]);

  CheckTokensForLine('class declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSpace, tkComment, tkSpace,
      tkKey {sealed}, tkSpace, tkKey {abstract}
    ]);
  CheckTokensForLine('var in class "',  3,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);
  CheckTokensForLine('procedure in class "',  4,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  tkSymbol, tkSpace, tkKey,  tkSymbol ]);



  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',
       'type',
       'TFoo = class {}',
       ' sealed abstract',
         'a, sealed, abstract: Integer;',
         'procedure Foo; abstract;',
        'end;',
       ''
    ]);

  CheckTokensForLine('class declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSpace, tkComment
    ]);
  CheckTokensForLine('class declaration"',  3,
    [ tkSpace, tkKey {sealed}, tkSpace, tkKey {abstract}
    ]);
  CheckTokensForLine('var in class "',  4,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);
  CheckTokensForLine('procedure in class "',  5,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  tkSymbol, tkSpace, tkKey,  tkSymbol ]);




  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',
       'type',
       'TFoo = class(sealed) sealed abstract',
         'helper, sealed, abstract: Integer;',
         'procedure Foo; abstract;',
        'end;',
       ''
    ]);

  CheckTokensForLine('class declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSymbol, tkIdentifier, tkSymbol, tkSpace,
      tkKey {sealed}, tkSpace,
      tkKey {abstract}
    ]);
  CheckTokensForLine('var in class "',  3,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);
  CheckTokensForLine('procedure in class "',  4,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  tkSymbol, tkSpace, tkKey,  tkSymbol ]);


end;

procedure TTestHighlighterPas.TestContextForClassHelper;
begin
  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',
       'type',
       'TFoo = class helper for TBar',
         'helper, sealed, abstract: Integer;',
         'procedure Foo; abstract;',
        'end;',
       ''
    ]);
  CheckTokensForLine('class declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSpace, tkKey {helper}, tkSpace, tkKey {for},
      tkSpace, tkIdentifier
    ]);
  CheckTokensForLine('var in class "',  3,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);
  CheckTokensForLine('procedure in class "',  4,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  tkSymbol, tkSpace, tkKey,  tkSymbol ]);


  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',
       'type',
       'TFoo = class helper(helper) for helper',
         'helper, sealed, abstract: Integer;',
         'procedure Foo; abstract;',
        'end;',
       ''
    ]);
  CheckTokensForLine('class declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSpace, tkKey {helper}, tkSymbol, tkIdentifier, tkSymbol,
      tkSpace, tkKey {for},
      tkSpace, tkIdentifier
    ]);
  CheckTokensForLine('var in class "',  3,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);
  CheckTokensForLine('procedure in class "',  4,
    [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  tkSymbol, tkSpace, tkKey,  tkSymbol ]);

end;

procedure TTestHighlighterPas.TestContextForTypeHelper;
  procedure DoChecks;
  begin
    CheckTokensForLine('not a helper',  2,
      [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
        tkKey {type}, tkSpace, tkIdentifier {helper}, tkSpace, tkKey {for}, tkSpace, tkIdentifier, tkSymbol
      ]);
    AssertEquals('not a helper / no fold', 0, PasHighLighter.FoldOpenCount(2));

    CheckTokensForLine('helper',  5,
      [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
        tkKey {type}, tkSpace, tkKey {helper}, tkSpace, tkKey {for}, tkSpace, tkIdentifier
      ]);
    CheckTokensForLine('procedure in helper',  6,
      [ tkKey, tkSpace, tkIdentifier + FAttrProcName,  tkSymbol, tkSpace, tkKey,  tkSymbol ]);
    CheckTokensForLine('uniq type',  8,
      [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
        tkKey {type}, tkSpace, tkIdentifier, tkSymbol
      ]);
    AssertEquals('uniq type / no fold', 0, PasHighLighter.FoldOpenCount(8));

    CheckTokensForLine('not a helper, switched off',  11,
      [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
        tkKey {type}, tkSpace, tkIdentifier {helper}, tkSpace, tkKey {for}, tkSpace, tkIdentifier, tkSymbol
      ]);
    AssertEquals('not a helper, switched off / no fold', 0, PasHighLighter.FoldOpenCount(11));
  end;

begin
  ReCreateEdit;
  SetLines
    ([ 'Unit A; {$mode objfpc} interface',
       'type',
       'helper = type helper for helper;',
       'type',
       '{$modeswitch typehelpers}',
       'helper = type helper for helper',
         'procedure Foo; static;',
        'end;',
       'helper = type integer;',
       'type',
       '{$modeswitch typehelpers-}',
       'helper = type helper for helper;',
       '{$modeswitch typehelpers}',
       ''
    ]);

  DoChecks;
  SynEdit.TestTypeText(1, 2, ' ');
  DoChecks; // modeswitch on rescan

  PasHighLighter.FoldConfig[ord(cfbtClass)].Enabled := False;
  DoChecks;

end;

procedure TTestHighlighterPas.TestContextForClassFunction;
var
  i: Integer;
const
  t: array[0..2] of string = ('class', 'object', 'record');
begin
  for i:= 0 to 2 do begin
  ReCreateEdit;
  EnableFolds([cfbtBeginEnd..cfbtNone]);

  SetLines
    ([ 'Unit A; interface',
       'type',
       'TFoo = '+t[i],
         'class function f1: boolean;',
         'class procedure p1(v: boolean);',
        'end;',
       ''
    ]);
  //   unit/iface,  type,  record, -,-
  CheckFoldOpenCounts('', [2, 1, 1, 0, 0]);
  CheckTokensForLine('class function',  3,
    [ tkKey, tkSpace, tkKey, tkSpace,  tkIdentifier + FAttrProcName, tkSymbol, tkSpace,  tkIdentifier, tkSymbol  ]);
  CheckTokensForLine('class procedure',  4,
    [ tkKey, tkSpace, tkKey, tkSpace,  tkIdentifier + FAttrProcName, tkSymbol, tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSymbol  ]);

  end;
end;

procedure TTestHighlighterPas.TestContextForRecordHelper;
begin
  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface {$mode delphi}',
       'type',
       'TFoo = record helper for TBar',
         'helper, sealed, abstract: Integer;',
        'end;',
       ''
    ]);
  CheckTokensForLine('record declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSpace, tkKey {helper}, tkSpace, tkKey {for},
      tkSpace, tkIdentifier
    ]);
  CheckTokensForLine('var in class "',  3,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);


  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface  {$mode delphi}',
       'type',
       'TFoo = record helper(helper) for helper',
         'helper, sealed, abstract: Integer;',
        'end;',
       ''
    ]);
  CheckTokensForLine('record declaration"',  2,
    [ tkIdentifier, tkSpace, tkSymbol, tkSpace,
      tkKey {class}, tkSpace, tkKey {helper}, tkSymbol, tkIdentifier, tkSymbol,
      tkSpace, tkKey {for},
      tkSpace, tkIdentifier
    ]);
  CheckTokensForLine('var in class "',  3,
    [ tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol, tkSpace,  tkIdentifier, tkSymbol,
      tkSpace, tkIdentifier, tkSymbol
    ]);

end;

procedure TTestHighlighterPas.TestContextForStatic;
begin
  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',
       'type',
       'static=class end;',
       'TFoo=class(static)',
       '  Ffoo,static: static; static;',
       '  static: static; static;',  // static as var-name can be first in list, IF previous was static modifier
       '  function static(static:static): static; static;',
       '  property static[static:static]: static read static write static;',
       'public',
       '  Ffoo,static: static; static;',
       '  static: static; static;',  // static as var-name can be first in list, IF previous was static modifier
       '  function static(static:static): static; static;',
       '  property static[static:static]: static read static write static;',
       'end;',
       ''
    ]);

  CheckTokensForLine('static = class',      2,
                     [tkIdentifier, tkSymbol, tkKey, tkSpace, tkKey, tkSymbol]);
  CheckTokensForLine('Tfoo=class(static)',  3,
  [tkIdentifier, tkSymbol, tkKey,tkSymbol, tkIdentifier, tkSymbol]);
  CheckTokensForLine('fields',              4,
                     [tkSpace, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, tkSpace, tkKey, tkSymbol]);
  CheckTokensForLine('fields 2',            5,
                     [tkSpace, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, tkSpace, tkKey, tkSymbol]);
  CheckTokensForLine('function',            6,
                     [tkSpace, tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol,
                      tkSymbol, tkSpace, tkIdentifier, tkSymbol, // : #32 static ;
                      tkSpace, tkKey, tkSymbol                   // #32 static ;
                     ]);
  CheckTokensForLine('property',            7,
                     [tkSpace, tkKey, tkSpace, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol,
                      tkSymbol, tkSpace, tkIdentifier,           // : #32 static
                      tkSpace, tkKey, tkSpace, tkIdentifier,     // #32 read static
                      tkSpace, tkKey, tkSpace, tkIdentifier,     // #32 write static
                      tkSymbol                   // ;
                     ]);
  CheckTokensForLine('pup fields',          9,
                     [tkSpace, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, tkSpace, tkKey, tkSymbol]);
  CheckTokensForLine('pup fields 2',       10,
                     [tkSpace, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, tkSpace, tkKey, tkSymbol]);
  CheckTokensForLine('pup function',       11,
                     [tkSpace, tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol,
                      tkSymbol, tkSpace, tkIdentifier, tkSymbol, // : #32 static ;
                      tkSpace, tkKey, tkSymbol                   // #32 static ;
                     ]);
  CheckTokensForLine('pup property',       12,
                     [tkSpace, tkKey, tkSpace, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol,
                      tkSymbol, tkSpace, tkIdentifier,           // : #32 static
                      tkSpace, tkKey, tkSpace, tkIdentifier,     // #32 read static
                      tkSpace, tkKey, tkSpace, tkIdentifier,     // #32 write static
                      tkSymbol                   // ;
                     ]);
end;

procedure TTestHighlighterPas.TestCaretAsString;
begin
  ReCreateEdit;
  SetLines
    ([ 'Unit A; interface',  // 0
       'var',
         'a:char=^o;',
         'a:somestring=^o^c;',
         'b:^char=nil;',
       'type',
         'c=^char;',         // 6
         'c=type ^char;',         // 6
       'implementation',
       'function x(f:^char=^k^c):^v;', // actually the compiler does not allow ^ as pointer for result
       'var',
         'a:char=^o;',       // 11
         'b:^char=nil;',     // 12
       'type',
         'c=^char;',
       'begin',
         'i:=^f;',
         'x:=GetTypeData(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF});', // 17
         'c:=p^;',
         'c:=p ^;',
         'c:=p(**)^;',
         'c:=p{} ^;',     // 21
         'i:=f(1)^;',     // 22
         'i:=f[1]^;',
         'i:=f^^;',
         'c:=p^+^i''e''^a#13^x;',
         'c:=x=^a and ^a=k and(^a^a=z);',
       'end;',
       ''
    ]);

  CheckTokensForLine('a:char=^o;',   2,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkSymbol]);
  CheckTokensForLine('a:char=^o^c;',   3,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkString, tkSymbol]);
  CheckTokensForLine('b:^char=nil;',   4,
                     [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol, tkKey, tkSymbol]);
  CheckTokensForLine('c=^char;',   6,
                     [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol]);
  CheckTokensForLine('c=type ^char;',   7,
                     [tkIdentifier, tkSymbol, tkKey, tkSpace, tkSymbol, tkIdentifier, tkSymbol]);

  CheckTokensForLine('function x(f:^char=^k):^v;',   9,
                     [tkKey, tkSpace, tkIdentifier + FAttrProcName, tkSymbol, tkIdentifier,  // function x(f
                      tkSymbol, tkSymbol, tkIdentifier, tkSymbol, tkString,  tkString,  // :^char=^k
                      tkSymbol, tkSymbol, tkSymbol, tkIdentifier, tkSymbol]);          // ):^v;
  CheckTokensForLine('LOCAL a:char=^o;',   11,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkSymbol]);
  CheckTokensForLine('LOCAL b:^char=nil;',   12,
                     [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol, tkKey, tkSymbol]);
  CheckTokensForLine('LOCAL c=^char;',   14,
                     [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol]);
  CheckTokensForLine('i:=^f',   16,
                     [tkIdentifier, tkSymbol, tkString, tkSymbol]);

  CheckTokensForLine('x:=GetTypeData(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF});',   17,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol,    // x:=GetTypeData(
                      tkIdentifier, tkSymbol, tkSymbol, tkIdentifier,    // PropInfo^.PropType
                      tkDirective, tkSymbol, tkDirective, tkSymbol, tkSymbol]);  // {$IFNDEF FPC}^{$ENDIF});

  CheckTokensForLine('c:=p^;',   18,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSymbol]);
  CheckTokensForLine('c:=p ^;',   19,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSpace, tkSymbol, tkSymbol]);
  CheckTokensForLine('c:=p(**)^;',   20,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkComment, tkSymbol, tkSymbol]);
  CheckTokensForLine('c:=p{} ^;',   21,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkComment, tkSpace, tkSymbol, tkSymbol]);

  CheckTokensForLine('c:=p(1)^;',   22,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkNumber, tkSymbol, tkSymbol]);
  CheckTokensForLine('c:=p[1]^;',   23,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkNumber, tkSymbol, tkSymbol]);
  CheckTokensForLine('c:=p^^;',   24,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSymbol, tkSymbol]);

  CheckTokensForLine('c:=p^+^i''e''^a#13^x;',   25,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSymbol, // c:=p^+
                      tkString, tkString, tkString, tkString, tkString, tkSymbol  // ^i'e'^a#13^x;
                     ]);
  CheckTokensForLine('c:=x=^a and ^a=k and(^a^a=z);',   26,
                     [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkSpace, // c:=x=^a
                      tkKey, tkSpace, tkString, tkSymbol, tkIdentifier, tkSpace, // and ^a=k
                      tkKey, tkSymbol, tkString, tkString, tkSymbol, tkIdentifier,  // and(^a^a=z
                      tkSymbol, tkSymbol                                            // );'
                     ]);

end;

procedure TTestHighlighterPas.TestFoldNodeInfo;
  Procedure CheckNode(ALine: TLineIdx; AFilter: TSynFoldActions; AFoldGroup: Integer;
    AColumn: integer;
    AAllColIndex, LogXStart, LogXEnd,  FoldLvlStart, FoldLvlEnd,  NestLvlStart, NestLvlEnd: Integer;
    FoldType, FoldTypeCompatible: TPascalCodeFoldBlockType; FoldGroup: Integer;
    FoldAction: TSynFoldActions);
  var
    nd: TSynFoldNodeInfo;
    l: TLazSynFoldNodeInfoList;
  begin
    l := PasHighLighter.FoldNodeInfo[ALine];

    // use NodeInfoEx
    nd := PasHighLighter.FoldNodeInfo[ALine].NodeInfoEx(AColumn, AFilter, AFoldGroup);
    CheckPasFoldNodeInfo('', nd, ALine, AColumn, AAllColIndex, LogXStart, LogXEnd, FoldLvlStart,
      FoldLvlEnd, NestLvlStart, NestLvlEnd, FoldType, FoldTypeCompatible,
      FoldGroup, FoldAction);

    // use filter
    l.ClearFilter;
    l.ActionFilter := AFilter;
    l.GroupFilter := AFoldGroup;
    nd := PasHighLighter.FoldNodeInfo[ALine].Item[AColumn];
    CheckPasFoldNodeInfo('', nd, ALine, AColumn, AAllColIndex, LogXStart, LogXEnd, FoldLvlStart,
      FoldLvlEnd, NestLvlStart, NestLvlEnd, FoldType, FoldTypeCompatible,
      FoldGroup, FoldAction);
  end;
  Procedure CheckNode(ALine: TLineIdx; AFilter: TSynFoldActions; AFoldGroup: Integer;
    AColumn: integer;
    LogXStart, LogXEnd,  FoldLvlStart, FoldLvlEnd,  NestLvlStart, NestLvlEnd: Integer;
    FoldType, FoldTypeCompatible: TPascalCodeFoldBlockType; FoldGroup: Integer;
    FoldAction: TSynFoldActions);
  begin
    CheckNode(ALine, AFilter, AFoldGroup, AColumn, -1, LogXStart, LogXEnd,
      FoldLvlStart, FoldLvlEnd, NestLvlStart, NestLvlEnd, FoldType, FoldTypeCompatible,
      FoldGroup, FoldAction);
  end;
begin
  ReCreateEdit;
  PushBaseName('');
  //  // +(\d+) +(\d+) +(\d+) +(\d+) +(\d+) +(\d+) +(\d+) +(\d+) +(\d+) +(\d+) +(\S+)
  // CheckNode( 0, [], 0,   $1,   $2, $3,   $4, $5,   $6, $7,   $8, $9,  $10, [$11]);

  //Line, [filter], group,   Idx,   LogXStart End   FldLvlStart End   NestLvlStart End   FldType FldTypeCompat   FldGroup  [FldAction]

  {%region TEXT 1}

    {%region TEXT 1 -- [cfbtBeginEnd..cfbtNone], []}
      PopPushBaseName('Text 1 -- [cfbtBeginEnd..cfbtNone], [], 0');
      SetLines(TestTextFoldInfo1);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([]);

      CheckFoldInfoCounts('', [], 0, [1, 1, 1, 1, 1, 3, 0, 1, 2, 1, 2, 2]);

      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=1
      CheckNode( 0, [], 0,   0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=2
      CheckNode( 1, [], 0,   0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   {$ifdef a}                                                   # pasminlvl=2 endlvl=2
      CheckNode( 2, [], 0,   0,   0,   1, 7,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 3:   begin                                                        # pasminlvl=2 endlvl=3
      CheckNode( 3, [], 0,   0,   0,   0, 5,   2, 3,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 4:   {$endif}                                                     # pasminlvl=3 endlvl=3
      CheckNode( 4, [], 0,   0,   0,   1, 7,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 5:     {$ifdef b} if a then begin {$endif}                        zz# pasminlvl=3 endlvl=4
      CheckNode( 5, [], 0,   0,   0,   3, 9,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 5, [], 0,   1,   1,   23, 28,   3, 4,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      CheckNode( 5, [], 0,   2,   2,   30, 36,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine]);
      // Line 6:       writeln()                                                # pasminlvl=4 endlvl=4
      // Line 7:     end;                                                       # pasminlvl=3 endlvl=3
      CheckNode( 7, [], 0,   0,   0,   2, 5,   4, 3,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 8:   end;                                                         # pasminlvl=1 endlvl=1
      CheckNode( 8, [], 0,   0,   0,   0, 3,   3, 2,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 8, [], 0,   1,   1,   0, 3,   2, 1,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 9:   begin                                                        # pasminlvl=1 endlvl=2
      CheckNode( 9, [], 0,   0,   0,   0, 5,   1, 2,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [], 0,   0,   0,   0, 3,   2, 1,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode(10, [], 0,   1,   1,   0, 3,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 11:   //                                                          # pasminlvl=0 endlvl=0
      CheckNode(11, [], 0,   0,   0,   0, 2,   0, 1,   0, 1,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOneLineOpen, sfaSingleLine]);
      CheckNode(11, [], 0,   1,   1,   2, 2,   1, 0,   1, 0,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaOneLineClose,sfaLastLineClose, sfaSingleLine]);
    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone], []}

    {%region TEXT 1 -- [cfbtBeginEnd..cfbtNone], [] grp=1}
      PopPushBaseName('Text 1 -- [cfbtBeginEnd..cfbtNone], [], grp=1');
      SetLines(TestTextFoldInfo1);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([],1);

      CheckFoldInfoCounts('', [], 1, [1, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, 2]);

      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=1
      CheckNode( 0, [], 1,   0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=2
      CheckNode( 1, [], 1,   0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   {$ifdef a}                                                   # pasminlvl=2 endlvl=2
      // Line 3:   begin                                                        # pasminlvl=2 endlvl=3
      CheckNode( 3, [], 1,   0,   0,   0, 5,   2, 3,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 4:   {$endif}                                                     # pasminlvl=3 endlvl=3
      // Line 5:     {$ifdef b} if a then begin {$endif}                                                    # pasminlvl=3 endlvl=4
      CheckNode( 5, [], 1,   0,   1,   23, 28,   3, 4,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 6:       writeln()                                                # pasminlvl=4 endlvl=4
      // Line 7:     end;                                                       # pasminlvl=3 endlvl=3
      CheckNode( 7, [], 1,   0,   0,   2, 5,   4, 3,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 8:   end;                                                         # pasminlvl=1 endlvl=1
      CheckNode( 8, [], 1,   0,   0,   0, 3,   3, 2,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 8, [], 1,   1,   1,   0, 3,   2, 1,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 9:   begin                                                        # pasminlvl=1 endlvl=2
      CheckNode( 9, [], 1,   0,   0,   0, 5,   1, 2,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [], 1,   0,   0,   0, 3,   2, 1,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode(10, [], 1,   1,   1,   0, 3,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 11:   //                                                          # pasminlvl=0 endlvl=0
      CheckNode(11, [], 1,   0,   0,   0, 2,   0, 1,   0, 1,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOneLineOpen, sfaSingleLine]);
      CheckNode(11, [], 1,   1,   1,   2, 2,   1, 0,   1, 0,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaOneLineClose,sfaLastLineClose, sfaSingleLine]);
    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone], [] grp=1}

    {%region TEXT 1 -- [cfbtBeginEnd,cfbtIfDef], [] grp=1}
      PopPushBaseName('Text 1 -- [cfbtBeginEnd,cfbtIfDef], [], grp=4');
      SetLines(TestTextFoldInfo1);
      EnableFolds([cfbtBeginEnd,cfbtIfDef]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([],4);

      CheckFoldInfoCounts('', [], 1, [1, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, 2]);

      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=0
      CheckNode( 0, [], 1,   0,   0, 7,   0, 0,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold, sfaMultiLine]);   // program
      // Line 1:   procedure a;                                                 # pasminlvl=0 endlvl=0
      CheckNode( 1, [], 1,   0,   0, 9,   1, 1,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold, sfaMultiLine]);   // procedure
      // Line 2:   {$ifdef a}                                                   # pasminlvl=0 endlvl=0
      // Line 3:   begin                                                        # pasminlvl=0 endlvl=0
      CheckNode( 3, [], 1,   0,   0, 5,   2, 2,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold, sfaMultiLine]);   // begin
      // Line 4:   {$endif}                                                     # pasminlvl=0 endlvl=0
      // Line 5:     {$ifdef b} if a then begin {$endif}                                                    # pasminlvl=0 endlvl=1
      CheckNode( 5, [], 1,   0,   23, 28,   0, 1,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);   //  begin
      // Line 6:       writeln()                                                # pasminlvl=1 endlvl=1
      // Line 7:     end;                                                       # pasminlvl=0 endlvl=0
      CheckNode( 7, [], 1,   0,   2, 5,   1, 0,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);   //  end
      // Line 8:   end;                                                         # pasminlvl=0 endlvl=0
      CheckNode( 8, [], 1,   0,   0, 3,   3, 3,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold, sfaMultiLine]);   // end;
      CheckNode( 8, [], 1,   1,   0, 3,   2, 2,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold, sfaMultiLine]);   // end;
      // Line 9:   begin                                                        # pasminlvl=0 endlvl=1
      CheckNode( 9, [], 1,   0,   0, 5,   0, 1,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);   // begin
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [], 1,   0,   0, 3,   1, 0,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);   // end.
      CheckNode(10, [], 1,   1,   0, 3,   1, 1,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold, sfaMultiLine]);   // end.
      // Line 11:   //                                                          # pasminlvl=0 endlvl=0
      CheckNode(11, [], 1,   0,   0, 2,   0, 0,   0, 1,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold, sfaMultiLine]);   // //
      CheckNode(11, [], 1,   1,   2, 2,   1, 1,   1, 0,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaLastLineClose, sfaMultiLine]);   // /
    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone], [] grp=4}

    {%region TEXT 1 -- [cfbtBeginEnd..cfbtNone], [sfaFold, sfaMultiLine]}
      PopPushBaseName('Text 1 -- [cfbtBeginEnd..cfbtNone], [sfaFold, sfaMultiLine], 0');
      SetLines(TestTextFoldInfo1);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([sfaFold, sfaMultiLine]);

      CheckFoldInfoCounts('', [sfaFold, sfaMultiLine], 0, [1, 1, 1, 1, 1, 1, 0, 1, 2, 1, 2, 0]);

      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=1
      CheckNode( 0, [sfafold, sfaMultiLine], 0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=2
      CheckNode( 1, [sfafold, sfaMultiLine], 0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   {$ifdef a}                                                   # pasminlvl=2 endlvl=2
      CheckNode( 2, [sfafold, sfaMultiLine], 0,   0,   1, 7,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 3:   begin                                                        # pasminlvl=2 endlvl=3
      CheckNode( 3, [sfafold, sfaMultiLine], 0,   0,   0, 5,   2, 3,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 4:   {$endif}                                                     # pasminlvl=3 endlvl=3
      CheckNode( 4, [sfafold, sfaMultiLine], 0,   0,   1, 7,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold,sfaFoldFold,sfaMultiLine]);
      // Line 5:     {$ifdef b} if a then begin {$endif}                                                    # pasminlvl=3 endlvl=4
      CheckNode( 5, [sfafold, sfaMultiLine], 0,   0,   23, 28,   3, 4,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 6:       writeln()                                                # pasminlvl=4 endlvl=4
      // Line 7:     end;                                                       # pasminlvl=3 endlvl=3
      CheckNode( 7, [sfafold, sfaMultiLine], 0,   0,   2, 5,   4, 3,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 8:   end;                                                         # pasminlvl=1 endlvl=1
      CheckNode( 8, [sfafold, sfaMultiLine], 0,   0,   0, 3,   3, 2,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 8, [sfafold, sfaMultiLine], 0,   1,   0, 3,   2, 1,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 9:   begin                                                        # pasminlvl=1 endlvl=2
      CheckNode( 9, [sfafold, sfaMultiLine], 0,   0,   0, 5,   1, 2,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [sfafold, sfaMultiLine], 0,   0,   0, 3,   2, 1,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode(10, [sfafold, sfaMultiLine], 0,   1,   0, 3,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 11:   //                                                          # pasminlvl=0 endlvl=0

    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone], [sfaFold, sfaMultiLine]}

    {%region TEXT 1 -- [cfbtBeginEnd..cfbtNone], [sfaMarkup, sfaMultiLine]}
      PopPushBaseName('Text 1 -- [cfbtBeginEnd..cfbtNone]-cfbtIfDef, [sfaMarkup, sfaMultiLine], 0');
      SetLines(TestTextFoldInfo1);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtIfDef]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([sfaMarkup, sfaMultiLine]);

      CheckFoldInfoCounts('', [sfaMarkup, sfaMultiLine], 0, [1, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, 0]);
      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=1
      CheckNode( 0, [sfamarkup, sfaMultiLine], 0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=2
      CheckNode( 1, [sfamarkup, sfaMultiLine], 0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   {$ifdef a}                                                   # pasminlvl=2 endlvl=2
// TODO add check for IFDEF
      // Line 3:   begin                                                        # pasminlvl=2 endlvl=3
      CheckNode( 3, [sfamarkup, sfaMultiLine], 0,   0,   0, 5,   2, 3,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 4:   {$endif}                                                     # pasminlvl=3 endlvl=3
      // Line 5:     {$ifdef b} if a then begin {$endif}                                                    # pasminlvl=3 endlvl=4
// TODO add chek for IFDEF
      CheckNode( 5, [sfamarkup, sfaMultiLine], 0,   0,   23, 28,   3, 4,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 6:       writeln()                                                # pasminlvl=4 endlvl=4
      // Line 7:     end;                                                       # pasminlvl=3 endlvl=3
      CheckNode( 7, [sfamarkup, sfaMultiLine], 0,   0,   2, 5,   4, 3,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 8:   end;                                                         # pasminlvl=1 endlvl=1
      CheckNode( 8, [sfamarkup, sfaMultiLine], 0,   0,   0, 3,   3, 2,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 8, [sfamarkup, sfaMultiLine], 0,   1,   0, 3,   2, 1,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 9:   begin                                                        # pasminlvl=1 endlvl=2
      CheckNode( 9, [sfamarkup, sfaMultiLine], 0,   0,   0, 5,   1, 2,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [sfamarkup, sfaMultiLine], 0,   0,   0, 3,   2, 1,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode(10, [sfamarkup, sfaMultiLine], 0,   1,   0, 3,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 11:   //                                                          # pasminlvl=0 endlvl=0

    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone], [sfaMarkup, sfaMultiLine]}

    {%region TEXT 1 -- [cfbtBeginEnd..cfbtNone], [sfaMarkup, sfaMultiLine]}
      PopPushBaseName('Text 1 -- [cfbtBeginEnd..cfbtNone], [sfaMarkup, sfaMultiLine], cfbtIfDef 0');
      SetLines(TestTextFoldInfo1);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], [], [cfbtIfDef]);
      //DebugFoldInfo([sfaMarkup, sfaMultiLine]);

      CheckFoldInfoCounts('', [sfaMarkup, sfaMultiLine], 0, [1, 1, 1, 1, 1, 3, 0, 1, 2, 1, 2, 0]);
      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=1
      CheckNode( 0, [sfamarkup, sfaMultiLine], 0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=2
      CheckNode( 1, [sfamarkup, sfaMultiLine], 0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   {$ifdef a}                                                   # pasminlvl=2 endlvl=2
// TODO add chek for IFDEF
      // Line 3:   begin                                                        # pasminlvl=2 endlvl=3
      CheckNode( 3, [sfamarkup, sfaMultiLine], 0,   0,   0, 5,   2, 3,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 4:   {$endif}                                                     # pasminlvl=3 endlvl=3
      // Line 5:     {$ifdef b} if a then begin {$endif}                                                    # pasminlvl=3 endlvl=4
// TODO add chek for IFDEF
      CheckNode( 5, [sfamarkup, sfaMultiLine], 0,   1,   23, 28,   3, 4,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 6:       writeln()                                                # pasminlvl=4 endlvl=4
      // Line 7:     end;                                                       # pasminlvl=3 endlvl=3
      CheckNode( 7, [sfamarkup, sfaMultiLine], 0,   0,   2, 5,   4, 3,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 8:   end;                                                         # pasminlvl=1 endlvl=1
      CheckNode( 8, [sfamarkup, sfaMultiLine], 0,   0,   0, 3,   3, 2,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 8, [sfamarkup, sfaMultiLine], 0,   1,   0, 3,   2, 1,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 9:   begin                                                        # pasminlvl=1 endlvl=2
      CheckNode( 9, [sfamarkup, sfaMultiLine], 0,   0,   0, 5,   1, 2,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [sfamarkup, sfaMultiLine], 0,   0,   0, 3,   2, 1,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode(10, [sfamarkup, sfaMultiLine], 0,   1,   0, 3,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 11:   //                                                          # pasminlvl=0 endlvl=0

    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone], [sfaMarkup, sfaMultiLine]}

    {%region TEXT 1 -- [cfbtBeginEnd..cfbtNone]-[cfbtProcedure], [cfbtSlashComment]}
      PopPushBaseName('Text 1 -- [cfbtBeginEnd..cfbtNone]-[cfbtProcedure], [cfbtSlashComment], 0');
      SetLines(TestTextFoldInfo1);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtProcedure]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], [cfbtSlashComment]);
      //DebugFoldInfo([]);

      CheckFoldInfoCounts('', [], 0, [1, 1, 1, 1, 1, 3, 0, 1, 2, 1, 2, 2, 0]);

      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=1
      CheckNode( 0, [], 0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=1
      CheckNode( 1, [], 0,   0,   0, 9,   1, 1,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold, sfaMultiLine]);
      // Line 2:   {$ifdef a}                                                   # pasminlvl=1 endlvl=1
      CheckNode( 2, [], 0,   0,   1, 7,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 3:   begin                                                        # pasminlvl=1 endlvl=2
      CheckNode( 3, [], 0,   0,   0, 5,   1, 2,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 4:   {$endif}                                                     # pasminlvl=2 endlvl=2
      CheckNode( 4, [], 0,   0,   1, 7,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 5:     {$ifdef b} if a then begin {$endif}                                                    # pasminlvl=2 endlvl=3
      CheckNode( 5, [], 0,   0,   3, 9,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 5, [], 0,   1,   23, 28,   2, 3,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      CheckNode( 5, [], 0,   2,   30, 36,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine]);
      // Line 6:       writeln()                                                # pasminlvl=3 endlvl=3
      // Line 7:     end;                                                       # pasminlvl=2 endlvl=2
      CheckNode( 7, [], 0,   0,   2, 5,   3, 2,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 8:   end;                                                         # pasminlvl=1 endlvl=1
      CheckNode( 8, [], 0,   0,   0, 3,   2, 1,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 8, [], 0,   1,   0, 3,   2, 2,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold, sfaMultiLine]);
      // Line 9:   begin                                                        # pasminlvl=1 endlvl=2
      CheckNode( 9, [], 0,   0,   0, 5,   1, 2,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [], 0,   0,   0, 3,   2, 1,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode(10, [], 0,   1,   0, 3,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 11:   //                                                          # pasminlvl=0 endlvl=0
      CheckNode(11, [], 0,   0,   0, 2,   0, 1,   0, 1,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaFold,sfaFoldHide,sfaOneLineOpen, sfaSingleLine]);
      CheckNode(11, [], 0,   1,   2, 2,   1, 0,   1, 0,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold,sfaOneLineClose,sfaLastLineClose, sfaSingleLine]);
    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone]-[cfbtProcedure], [cfbtSlashComment]}

  {%endregion TEXT 1}


  {%region TEXT 2}

    {%region TEXT 2 -- [cfbtBeginEnd..cfbtNone], []}
      PopPushBaseName('Text 2 -- [cfbtBeginEnd..cfbtNone], [], 0');
      SetLines(TestTextFoldInfo2);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([]);

      CheckFoldInfoCounts('', [], 0, [1, 1, 10, 2, 4, 5, 2, 3]);

      // Line 0:   program foo;                                                 # pasminlvl=0 endlvl=1
      CheckNode( 0, [], 0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=2
      CheckNode( 1, [], 0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   {$ifdef a} begin {$ifdef b} repeat a; {$endif} until b; {$ifdef c} try {$else} //x                                                     zz# pasminlvl=2 endlvl=4
      CheckNode( 2, [], 0,   0,   1, 7,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);            // {$IFDEF A}
      CheckNode( 2, [], 0,   1,   11, 16,   2, 3,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);  // begin
      CheckNode( 2, [], 0,   2,   18, 24,   1, 2,   1, 2,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]);           // {$IFDEF B}
      CheckNode( 2, [], 0,   3,   28, 34,   3, 4,   3, 4,
                                  cfbtRepeat, cfbtRepeat,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]); // repeat a;
      CheckNode( 2, [], 0,   4,   39, 45,   2, 1,   2, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine]);                      // {$ENDIF}
      CheckNode( 2, [], 0,   5,   47, 52,   4, 3,   4, 3,
                                  cfbtRepeat, cfbtRepeat,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine]);            // until b;
      CheckNode( 2, [], 0,   6,   57, 63,   1, 2,   1, 2,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]);           // {$IFDEF c}
      CheckNode( 2, [], 0,   7,   67, 70,   3, 4,   3, 4,
                                  cfbtTry, cfbtTry,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);// try
      CheckNode( 2, [], 0,   8,   72, 77,   2, 1,   2, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine, sfaCloseAndOpen]);                      // {$ELSE}
      CheckNode( 2, [], 0,   9,   72, 77,   1, 2,   1, 2,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaMarkup,sfaOpen, sfaOpenFold,sfaFold,sfaFoldFold, sfaMultiLine, sfaCloseAndOpen]);          // {$ELSE}
      // Line 3:     //foo                                                      # pasminlvl=4 endlvl=4
      CheckNode( 3, [], 0,   0,   2, 4,   4, 5,   4, 5,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 3, [], 0,   1,   7, 7,   5, 4,   5, 4,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaOneLineClose, sfaCloseForNextLine, sfaSingleLine]);
      // Line 4:     finally repeat x; {$endif c} until y;                                      # pasminlvl=4 endlvl=5
      CheckNode( 4, [], 0,   0,   2, 9,   4, 5,   4, 5,
                                  cfbtExcept, cfbtExcept,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      CheckNode( 4, [], 0,   1,   10, 16,   5, 6,   5, 6,
                                  cfbtRepeat, cfbtRepeat,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 4, [], 0,   2,   21, 27,   2, 1,   2, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      CheckNode( 4, [], 0,   3,   31, 36,   6, 5,   6, 5,
                                  cfbtRepeat, cfbtRepeat,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine]);
      // Line 5:     repeat m; until n; end; {$endif a} //                                      # pasminlvl=3 endlvl=3
      CheckNode( 5, [], 0,   0,   2, 8,   5, 6,   5, 6,
                                  cfbtRepeat, cfbtRepeat,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 5, [], 0,   1,   12, 17,   6, 5,   6, 5,
                                  cfbtRepeat, cfbtRepeat,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine]);
      CheckNode( 5, [], 0,   2,   21, 24,   5, 4,   5, 4,
                                  cfbtExcept, cfbtExcept,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 5, [], 0,   3,   21, 24,   4, 3,   4, 3,
                                  cfbtTry, cfbtTry,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 5, [], 0,   4,   27, 33,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 6:   end                                                          # pasminlvl=1 endlvl=1
      CheckNode( 6, [], 0,   0,   0, 3,   3, 2,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 6, [], 0,   1,   0, 3,   2, 1,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 7:   begin end.                                                   # pasminlvl=0 endlvl=0
      CheckNode( 7, [], 0,   0,   0, 5,   1, 2,   1, 2,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaMarkup,sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 7, [], 0,   1,   6, 9,   2, 1,   2, 1,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaMarkup,sfaOneLineClose, sfaSingleLine]);
      CheckNode( 7, [], 0,   2,   6, 9,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
    {%endregion TEXT 2 -- [cfbtBeginEnd..cfbtNone], []}

  {%region TEXT 2}


  {%region TEXT 3}

    {%region TEXT 3 -- [cfbtBeginEnd..cfbtNone], []}
      PopPushBaseName('Text 3 -- [cfbtBeginEnd..cfbtNone], [], 0');
      SetLines(TestTextFoldInfo3);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([]);

      CheckFoldInfoCounts('', [], 0, [1, 1, 2, 1, 1, 1, 0, 3, 1, 3, 2]);

      // Line 0:   unit foo;                                                    # pasminlvl=0 endlvl=1
      CheckNode( 0, [], 0,   0,   0, 4,   0, 1,   0, 1,
                                  cfbtUnit, cfbtUnit,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   interface                                                    # pasminlvl=1 endlvl=2
      CheckNode( 1, [], 0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   type a=integer;                                              # pasminlvl=2 endlvl=2
      CheckNode( 2, [], 0,   0,   0, 4,   2, 3,   2, 3,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 2, [], 0,   1,   15, 15,   3, 2,   3, 2,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaOneLineClose, sfaCloseForNextLine, sfaSingleLine]);
      // Line 3:   var                                                          # pasminlvl=2 endlvl=3
      CheckNode( 3, [], 0,   0,   0, 3,   2, 3,   2, 3,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 4:     b:integer                                                  # pasminlvl=2 endlvl=2
      CheckNode( 4, [], 0,   0,   11, 11,   3, 2,   3, 2,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold, sfaCloseForNextLine, sfaMultiLine]);
      // Line 5:   const                                                        # pasminlvl=2 endlvl=3
      CheckNode( 5, [], 0,   0,   0, 5,   2, 3,   2, 3,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 6:     c = 1;                                                     # pasminlvl=3 endlvl=3
      // Line 7:     d = 2; {$ifdef a}                                          # pasminlvl=1 endlvl=1
      CheckNode( 7, [], 0,   0,   10, 16,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      CheckNode( 7, [], 0,   1,   19, 19,   3, 2,   3, 2,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold, sfaCloseForNextLine, sfaMultiLine]);
      CheckNode( 7, [], 0,   2,   19, 19,   2, 1,   2, 1,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold, sfaCloseForNextLine, sfaMultiLine]);
      // Line 8:   implementation                                               # pasminlvl=1 endlvl=2
      CheckNode( 8, [], 0,   0,   0, 14,   1, 2,   1, 2,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 9:   //, unit-section                                             # pasminlvl=1 endlvl=1
      CheckNode( 9, [], 0,   0,   0, 2,   2, 3,   2, 3,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 9, [], 0,   1,   2, 2,   3, 2,   3, 2,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaOneLineClose, sfaCloseForNextLine, sfaSingleLine]);
      CheckNode( 9, [], 0,   2,   2, 2,   2, 1,   2, 1,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold, sfaCloseForNextLine, sfaMultiLine]);
      // Line 10:   end.                                                        # pasminlvl=0 endlvl=0
      CheckNode(10, [], 0,   0,   0, 3,   1, 0,   1, 0,
                                  cfbtUnit, cfbtUnit,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold, sfaMultiLine]);
      CheckNode(10, [], 0,   1,   4, 4,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold,sfaFoldFold,sfaLastLineClose, sfaMultiLine]);
    {%endregion TEXT 3 -- [cfbtBeginEnd..cfbtNone], []}

  {%region TEXT 3}


  {%region TEXT 4}

    {%region TEXT 4 -- [cfbtBeginEnd..cfbtNone], []}
      PopPushBaseName('Text 4(1) -- [cfbtBeginEnd..cfbtNone], [], 0');
      SetLines(TestTextFoldInfo4(1));
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([]);

      CheckFoldInfoCounts('', [], 0, [1, 1,3, 1, 2, 1, 3]);

      // Line 0:   program p;                                                   # pasminlvl=0 endlvl=1
      CheckNode( 0, [], 0,   0,   0, 7,   0, 1,   0, 1,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 1:   procedure a;                                                 # pasminlvl=1 endlvl=2
      CheckNode( 1, [], 0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 2:   begin {$ifdef} if a then begin                                             # pasminlvl=2 endlvl=4
      CheckNode( 2, [], 0,   0,   0, 5,   2, 3,   2, 3,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      CheckNode( 2, [], 0,   1,   7, 13,   0, 1,   0, 1,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      CheckNode( 2, [], 0,   2,   25, 30,   3, 4,   3, 4,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 3:     end; // 2                                                  # pasminlvl=3 endlvl=3
      CheckNode( 3, [], 0,   0,   2, 5,   4, 3,   4, 3,
                                  cfbtBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 4:   end; // 1                                                    # pasminlvl=1 endlvl=1
      CheckNode( 4, [], 0,   0,   0, 3,   3, 2,   3, 2,
                                  cfbtTopBeginEnd, cfbtBeginEnd,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      CheckNode( 4, [], 0,   1,   0, 3,   2, 1,   2, 1,
                                  cfbtProcedure, cfbtProcedure,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold, sfaMultiLine]);
      // Line 5:   {$endif}                                                     # pasminlvl=1 endlvl=1
      CheckNode( 5, [], 0,   0,   1, 7,   1, 0,   1, 0,
                                  cfbtIfDef, cfbtIfDef,  FOLDGROUP_IFDEF,
                                  [sfaClose, sfaCloseFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
      // Line 6:   //                                                           # pasminlvl=1 endlvl=0
      CheckNode( 6, [], 0,   0,   0, 2,   1, 2,   1, 2,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOneLineOpen, sfaSingleLine]);
      CheckNode( 6, [], 0,   1,   2, 2,   2, 1,   2, 1,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaOneLineClose,sfaLastLineClose, sfaSingleLine]);
      CheckNode( 6, [], 0,   2,   2, 2,   1, 0,   1, 0,
                                  cfbtProgram, cfbtProgram,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold,sfaLastLineClose, sfaMultiLine]);
    {%endregion TEXT 4 -- [cfbtBeginEnd..cfbtNone], []}

  {%region TEXT 4}

  {%region TEXT 5}

    {%region TEXT 5 -- [cfbtBeginEnd..cfbtNone], []}
      PopPushBaseName('Text 5 -- [cfbtBeginEnd..cfbtNone], [], 0');
      SetLines(TestTextFoldInfo5);
      EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []);
      //DebugFoldInfo([]);

      CheckFoldInfoCounts('', [], 0, [1, 1, 1, 1, 0, 1, 1, 0, 3, 1, 3, 1]);

      // Line 0:   unit foo;
      CheckNode( 0, [], 0,   0,   0, 4,   0, 1,   0, 1,
                                  cfbtUnit, cfbtUnit,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold, sfaFold, sfaFoldFold, sfaMultiLine]);
      // Line 1:   interface
      CheckNode( 1, [], 0,   0,   0, 9,   1, 2,   1, 2,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold, sfaFold, sfaFoldFold, sfaMultiLine]);
      // Line 2:   type
      CheckNode( 2, [], 0,   0,   0, 4,   2, 3,   2, 3,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaFold, sfaFoldFold, sfaMultiLine, sfaOpenFold]);
      // Line 3:   TFoo<T: class> = class(TBar<T>)
      CheckNode( 3, [], 0,   0,   17, 22,   3, 4,   3, 4,
                                  cfbtClass, cfbtClass,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaFold, sfaFoldFold, sfaMultiLine, sfaMarkup, sfaOpenFold]);
      // Line 4:   class procedure Proc;
      CheckNode( 4, [], 0,   -1,    0, 0,   4, 4,   4, 4,
                                  cfbtNone, cfbtNone,  FOLDGROUP_PASCAL,
                                  [sfaInvalid]);
      // Line 5:   end.
      CheckNode( 5, [], 0,   0,    0, 3,   4, 3,   4, 3,
                                  cfbtClass, cfbtClass,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaFold, sfaMultiLine, sfaMarkup, sfaCloseFold]);
      CheckNode( 6, [], 0,   0,     7, 13,   3, 4,   3, 4,
                                  cfbtRecord, cfbtRecord,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaFold, sfaFoldFold, sfaMultiLine, sfaMarkup, sfaOpenFold]);
      // Line 7:   class procedure Proc;
      CheckNode( 7, [], 0,   -1,    0, 0,   4, 4,   4, 4,
                                  cfbtNone, cfbtNone,  FOLDGROUP_PASCAL,
                                  [sfaInvalid]);
      // Line 8:   end.
      CheckNode( 8, [], 0,   0,    0, 3,   4, 3,   4, 3,
                                  cfbtRecord, cfbtRecord,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaFold, sfaMultiLine, sfaMarkup, sfaCloseFold]);
      CheckNode( 8, [], 0,   1,    4, 4,   3, 2,   3, 2,
                                  cfbtVarType, cfbtVarType,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaFold, sfaMultiLine, sfaCloseForNextLine, sfaCloseFold]);
      CheckNode( 8, [], 0,   2,    4, 4,   2, 1,   2, 1,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaFold, sfaMultiLine, sfaCloseForNextLine, sfaCloseFold]);
      // Line 9:   implementation
      CheckNode( 9, [], 0,   0,   0, 14,   1, 2,   1, 2,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOpenFold,sfaFold, sfaFoldFold, sfaMultiLine]);
      // Line 10:   //, unit-section
      CheckNode(10, [], 0,   0,   0, 2,   2, 3,   2, 3,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaOpen, sfaOneLineOpen, sfaSingleLine]);
      CheckNode(10, [], 0,   1,   2, 2,   3, 2,   3, 2,
                                  cfbtSlashComment, cfbtSlashComment,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaOneLineClose, sfaCloseForNextLine, sfaSingleLine]);
      CheckNode(10, [], 0,   2,   2, 2,   2, 1,   2, 1,
                                  cfbtUnitSection, cfbtUnitSection,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold, sfaCloseForNextLine, sfaMultiLine]);
      // Line 11:   end.
      CheckNode(11, [], 0,   0,   0, 3,   1, 0,   1, 0,
                                  cfbtUnit, cfbtUnit,  FOLDGROUP_PASCAL,
                                  [sfaClose, sfaCloseFold,sfaFold, sfaMultiLine]);
    {%endregion TEXT 5 -- [cfbtBeginEnd..cfbtNone], []}

  {%region TEXT 5}
end;

initialization

  RegisterTest(TTestHighlighterPas);
end.

