fpc/packages/fcl-passrc/tests/tcgenerics.pp
2019-02-20 02:22:27 +00:00

236 lines
6.6 KiB
ObjectPascal

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 TestDeclarationConstraint;
Procedure TestSpecializationDelphi;
Procedure TestDeclarationDelphi;
Procedure TestDeclarationDelphiSpecialize;
Procedure TestDeclarationFPC;
Procedure TestMethodImplementation;
Procedure TestInlineSpecializationInArgument;
Procedure TestSpecializeNested;
Procedure TestInlineSpecializeInStatement;
Procedure TestGenericFunction; // ToDo
end;
implementation
procedure TTestGenerics.TestObjectGenerics;
begin
Add([
'Type',
'Generic TSomeClass<T> = Object',
' b : T;',
'end;',
'']);
ParseDeclarations;
end;
procedure TTestGenerics.TestRecordGenerics;
begin
Add([
'Type',
' Generic TSome<T> = Record',
' b : T;',
' end;',
'']);
ParseDeclarations;
end;
procedure TTestGenerics.TestArrayGenerics;
begin
Add([
'Type',
' Generic TSome<T> = array of T;',
'']);
ParseDeclarations;
end;
procedure TTestGenerics.TestGenericConstraint;
begin
Add([
'Type',
'Generic TSomeClass<T: TObject> = class',
' b : T;',
'end;',
'']);
ParseDeclarations;
end;
procedure TTestGenerics.TestDeclarationConstraint;
Var
T : TPasClassType;
begin
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
Source.Add('Type');
Source.Add(' TSomeClass<T: T2> = 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<integer>',TPasSpecializeType,'');
end;
procedure TTestGenerics.TestDeclarationDelphi;
Var
T : TPasClassType;
begin
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
Source.Add('Type');
Source.Add(' TSomeClass<T,T2> = 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<T,T2> = Class(TSomeGeneric<Integer,Integer>)');
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<T;T2> = 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<T> = object');
Add(' procedure foo(v:T);');
Add(' end;');
Add('implementation');
Add('procedure TTest<T>.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<TBoundingBox>;const index:Integer);');
Add(' end;');
Add('implementation');
end;
ParseModule;
end;
procedure TTestGenerics.TestSpecializeNested;
begin
Add([
'Type',
' generic TSomeClass<A,B> = class(specialize TOther<A,specialize TAnother<B>>) end;',
'']);
ParseDeclarations;
end;
procedure TTestGenerics.TestInlineSpecializeInStatement;
begin
Add([
'begin',
' vec:=TVector<double>.create;',
' b:=a<b;',
' t:=a<b.c<d,e.f>>;',
'']);
ParseModule;
end;
procedure TTestGenerics.TestGenericFunction;
begin
Add([
'generic function IfThen<T>(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;',
'begin',
'end;',
'begin',
//' specialize IfThen<word>(true,2,3);',
'']);
ParseModule;
end;
initialization
RegisterTest(TTestGenerics);
end.