unit tcgenerics; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fpcunit, pastree, testregistry, pscanner, tctypeparser; Type { TTestGenerics } TTestGenerics = Class(TBaseTestTypeParser) Published Procedure TestObjectGenerics; Procedure TestRecordGenerics; Procedure TestArrayGenerics; Procedure TestGenericConstraint; Procedure TestGenericInterfaceConstraint; // ToDo Procedure TestDeclarationConstraint; Procedure TestSpecializationDelphi; Procedure TestDeclarationDelphi; Procedure TestDeclarationDelphiSpecialize; Procedure TestDeclarationFPC; Procedure TestMethodImplementation; Procedure TestInlineSpecializationInArgument; Procedure TestSpecializeNested; Procedure TestInlineSpecializeInStatement; Procedure TestInlineSpecializeInStatementDelphi; Procedure TestGenericFunction; end; implementation procedure TTestGenerics.TestObjectGenerics; begin Add([ 'Type', 'Generic TSomeClass = Object', ' b : T;', 'end;', '']); ParseDeclarations; end; procedure TTestGenerics.TestRecordGenerics; begin Add([ 'Type', ' Generic TSome = Record', ' b : T;', ' end;', '']); ParseDeclarations; end; procedure TTestGenerics.TestArrayGenerics; begin Add([ 'Type', ' Generic TSome = array of T;', '']); ParseDeclarations; end; procedure TTestGenerics.TestGenericConstraint; begin Add([ 'Type', 'Generic TSomeClass = class', ' b : T;', 'end;', 'Generic TBird = class', ' c : TBird;', 'end;', 'Generic TEagle = class', 'end;', 'Generic TEagle = class', 'end;', '']); ParseDeclarations; end; procedure TTestGenerics.TestGenericInterfaceConstraint; begin Add([ 'Type', 'TIntfA = interface end;', 'TIntfB = interface end;', 'TBird = class(TInterfacedObject,TIntfA,TIntfB) end;', 'Generic TAnt = class', ' b: T;', ' c: TAnt;', 'end;', 'Generic TFly = class', ' b: S;', ' c: TFly;', 'end;', '']); ParseDeclarations; end; procedure TTestGenerics.TestDeclarationConstraint; Var T : TPasClassType; begin Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ; Source.Add('Type'); Source.Add(' TSomeClass = Class(TObject)'); Source.Add(' b : T;'); Source.Add(' end;'); ParseDeclarations; AssertNotNull('have generic definition',Declarations.Classes); AssertEquals('have generic definition',1,Declarations.Classes.Count); AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType); T:=TPasClassType(Declarations.Classes[0]); AssertNotNull('have generic templates',T.GenericTemplateTypes); AssertEquals('1 template types',1,T.GenericTemplateTypes.Count); AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent); AssertEquals('Type constraint is recorded','T2',TPasGenericTemplateType(T.GenericTemplateTypes[0]).TypeConstraint); end; procedure TTestGenerics.TestSpecializationDelphi; begin ParseType('TFPGList',TPasSpecializeType,''); end; procedure TTestGenerics.TestDeclarationDelphi; Var T : TPasClassType; begin Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ; Source.Add('Type'); Source.Add(' TSomeClass = Class(TObject)'); Source.Add(' b : T;'); Source.Add(' b2 : T2;'); Source.Add(' end;'); ParseDeclarations; AssertNotNull('have generic definition',Declarations.Classes); AssertEquals('have generic definition',1,Declarations.Classes.Count); AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType); T:=TPasClassType(Declarations.Classes[0]); AssertNotNull('have generic templates',T.GenericTemplateTypes); AssertEquals('2 template types',2,T.GenericTemplateTypes.Count); AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent); AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent); end; procedure TTestGenerics.TestDeclarationDelphiSpecialize; Var T : TPasClassType; begin Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ; Source.Add('Type'); Source.Add(' TSomeClass = Class(TSomeGeneric)'); Source.Add(' b : T;'); Source.Add(' b2 : T2;'); Source.Add(' end;'); ParseDeclarations; AssertNotNull('have generic definition',Declarations.Classes); AssertEquals('have generic definition',1,Declarations.Classes.Count); AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType); T:=TPasClassType(Declarations.Classes[0]); AssertEquals('Name is correct','TSomeClass',T.Name); AssertNotNull('have generic templates',T.GenericTemplateTypes); AssertEquals('2 template types',2,T.GenericTemplateTypes.Count); AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent); AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent); end; procedure TTestGenerics.TestDeclarationFPC; Var T : TPasClassType; begin Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches; Source.Add('Type'); Source.Add(' TSomeClass = Class(TObject)'); Source.Add(' b : T;'); Source.Add(' b2 : T2;'); Source.Add(' end;'); ParseDeclarations; AssertNotNull('have generic definition',Declarations.Classes); AssertEquals('have generic definition',1,Declarations.Classes.Count); AssertEquals('Pascal class',TPasClassType,TObject(Declarations.Classes[0]).ClassType); T:=TPasClassType(Declarations.Classes[0]); AssertNotNull('have generic templates',T.GenericTemplateTypes); AssertEquals('2 template types',2,T.GenericTemplateTypes.Count); AssertSame('Parent 0 is class',T,TPasElement(T.GenericTemplateTypes[0]).Parent); AssertSame('Parent 1 is class',T,TPasElement(T.GenericTemplateTypes[1]).Parent); end; procedure TTestGenerics.TestMethodImplementation; begin With source do begin Add('unit afile;'); Add('{$MODE DELPHI}'); Add('interface'); Add('type'); Add(' TTest = object'); Add(' procedure foo(v:T);'); Add(' end;'); Add('implementation'); Add('procedure TTest.foo;'); Add('begin'); Add('end;'); end; ParseModule; end; procedure TTestGenerics.TestInlineSpecializationInArgument; begin With source do begin Add('unit afile;'); Add('{$MODE DELPHI}'); Add('interface'); Add('type'); Add(' TFoo=class'); Add(' procedure foo(var Node:TSomeGeneric;const index:Integer);'); Add(' end;'); Add('implementation'); end; ParseModule; end; procedure TTestGenerics.TestSpecializeNested; begin Add([ 'Type', ' generic TSomeClass = class(specialize TOther>) end;', '']); ParseDeclarations; end; procedure TTestGenerics.TestInlineSpecializeInStatement; begin Add([ 'begin', ' t:=specialize a;', ' t:=a.specialize b;', '']); ParseModule; end; procedure TTestGenerics.TestInlineSpecializeInStatementDelphi; begin Add([ 'begin', ' vec:=TVector.create;', ' b:=a>;', ' t:=a.b;', ' t:=a.c;', // forbidden:' t:=a.d>;', '']); ParseModule; end; procedure TTestGenerics.TestGenericFunction; begin Add([ 'generic function IfThen(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;', 'begin', 'end;', 'begin', ' specialize IfThen(true,2,3);', '']); ParseModule; end; initialization RegisterTest(TTestGenerics); end.