delphimvcframework/unittests/DMVCFrameworkTests/FrameworkTestsU.pas

603 lines
18 KiB
ObjectPascal
Raw Normal View History

unit FrameworkTestsU;
2013-10-30 01:09:09 +01:00
interface
uses
TestFramework,
MVCFramework.Router,
System.Generics.Collections,
MVCFramework, Data.DB, System.SysUtils;
2013-10-30 01:09:09 +01:00
type
TTestRouting = class(TTestCase)
private
2013-11-09 10:05:14 +01:00
Router: TMVCRouter;
2013-10-30 01:09:09 +01:00
Controllers: TList<TMVCControllerClass>;
public
procedure SetUp; override;
procedure TearDown; override;
protected
procedure SameFishesDataSet(ds, ds2: TDataSet);
2013-10-30 01:09:09 +01:00
published
procedure TestWithNoParameters;
procedure TestWithNoPath;
procedure TestPathButNoParameters;
procedure TestPathWithParameters;
procedure TestWithMethodTypes;
procedure TestComplexRoutings;
2014-06-27 15:30:39 +02:00
procedure TestProduceRoutings;
procedure TestProduceRoutingsWithExplicitCharset;
procedure TestObjectToJSONObject;
procedure TestObjectListToJSONArray;
// objects mappers
procedure TestJSONObjectToObjectAndBack;
procedure TestComplexObjectToJSONObjectAndBack;
procedure TestDataSetToJSONObject;
procedure TestDataSetToJSONArray;
procedure TestObjectToJSONObjectAndBackWithStringStreamUTF16;
procedure TestObjectToJSONObjectAndBackWithStringStreamUTF8;
procedure TestCheckMapperSerializeAsStringIsEmptyStrIfObjIsNil;
2013-10-30 01:09:09 +01:00
end;
implementation
{ TTestRouting }
uses MVCFramework.Commons,
TestControllersU, DBClient,
2014-04-16 22:52:25 +02:00
Web.HTTPApp,
ObjectsMappers,
BOs,
2014-09-05 12:47:40 +02:00
{$IF CompilerVersion < 27}
2014-04-16 22:52:25 +02:00
Data.DBXJSON,
{$ELSE}
System.JSON,
2014-09-05 12:47:40 +02:00
{$ENDIF}
TestServerControllerU, System.Classes;
2013-10-30 01:09:09 +01:00
procedure TTestRouting.SameFishesDataSet(ds, ds2: TDataSet);
begin
2014-04-16 22:52:25 +02:00
CheckEquals(ds.FieldByName('Species No').AsInteger,
ds2.FieldByName('Species No').AsInteger);
CheckEquals(ds.FieldByName('Category').AsString, ds2.FieldByName('Category')
.AsString);
CheckEquals(ds.FieldByName('Common_Name').AsString,
ds2.FieldByName('Common_Name').AsString);
CheckEquals(ds.FieldByName('Species Name').AsString,
ds2.FieldByName('Species Name').AsString);
CheckEquals(ds.FieldByName('Length (cm)').AsString,
ds2.FieldByName('Length (cm)').AsString);
CheckEquals(ds.FieldByName('Length_In').AsInteger,
ds2.FieldByName('Length_In').AsInteger);
CheckEquals(ds.FieldByName('Notes').AsString, ds2.FieldByName('Notes')
.AsString);
CheckEquals(ds.FieldByName('Graphic').AsString, ds2.FieldByName('Graphic')
.AsString);
end;
2013-10-30 01:09:09 +01:00
procedure TTestRouting.SetUp;
begin
Controllers := TList<TMVCControllerClass>.Create;
Controllers.Add(TSimpleController);
Controllers.Add(TNotSoSimpleController);
2014-04-02 20:28:53 +02:00
Controllers.Add(TTestServerController);
2013-10-30 01:09:09 +01:00
Router := TMVCRouter.Create(nil);
end;
procedure TTestRouting.TearDown;
begin
Router.Free;
Controllers.Free;
end;
// procedure TTestRouting.TestClassNameMethodNameRouting;
// var
// Params: TMVCRequestParamsTable;
// ResponseContentType: string;
// ResponseContentEncoding: string;
// begin
// Params := TMVCRequestParamsTable.Create;
// try
// CheckTrue(Router.ExecuteRouting('/TNotSoSimpleController/Method1', httpGET, 'text/plain', Controllers,
// Params, ResponseContentType, ResponseContentEncoding));
// CheckEquals(0, Params.Count);
// CheckEquals('TSimpleController', Router.MVCControllerClass.ClassName);
// CheckEquals('Index', Router.MethodToCall.Name);
// finally
// Params.Free;
// end;
// end;
procedure TTestRouting.TestCheckMapperSerializeAsStringIsEmptyStrIfObjIsNil;
var
Obj: TMyStreamObject;
JSONObj: TJSONObject;
DesObj: TMyStreamObject;
begin
// ARRANGE
Obj := TMyStreamObject.Create;
try
Obj.PropStream := nil;
Obj.Prop8Stream := nil;
// ACT
JSONObj := Mapper.ObjectToJSONObject(Obj);
DesObj := Mapper.JSONObjectToObject<TMyStreamObject>(JSONObj);
try
// ASSERT
CheckTrue(TStringStream(DesObj.PropStream).DataString.IsEmpty);
CheckTrue(TStringStream(DesObj.Prop8Stream).DataString.IsEmpty);
finally
DesObj.Free;
end;
finally
Obj.Free;
end;
end;
procedure TTestRouting.TestComplexObjectToJSONObjectAndBack;
var
Obj: TMyComplexObject;
JObj: TJSONObject;
Obj2: TMyComplexObject;
begin
Obj := GetMyComplexObject;
try
JObj := Mapper.ObjectToJSONObject(Obj);
try
Obj2 := Mapper.JSONObjectToObject<TMyComplexObject>(JObj);
try
CheckTrue(Obj.Equals(Obj2));
finally
Obj2.Free;
end;
finally
JObj.Free;
end;
finally
Obj.Free;
end;
end;
2013-10-30 01:09:09 +01:00
procedure TTestRouting.TestComplexRoutings;
2014-04-02 20:28:53 +02:00
var
Params: TMVCRequestParamsTable;
ResponseContentType: string;
ResponseContentEncoding: string;
2013-10-30 01:09:09 +01:00
begin
2014-04-02 20:28:53 +02:00
Params := TMVCRequestParamsTable.Create;
try
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/path1/1', httpPOST, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2014-04-02 20:28:53 +02:00
CheckEquals('TestMultiplePaths', Router.MethodToCall.Name);
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/path2/1/2/3', httpPOST, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2014-04-02 20:28:53 +02:00
CheckEquals('TestMultiplePaths', Router.MethodToCall.Name);
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/path3/1/2/tre/3', httpPOST, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2014-04-02 20:28:53 +02:00
CheckEquals('TestMultiplePaths', Router.MethodToCall.Name);
2013-10-30 01:09:09 +01:00
2014-04-02 20:28:53 +02:00
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/path4/par1/2/par2/3/4', httpPOST,
'text/plain', 'text/plain', Controllers, 'text/plain',
TMVCMimeType.TEXT_PLAIN, Params, ResponseContentType,
ResponseContentEncoding));
2014-04-02 20:28:53 +02:00
CheckEquals('TestMultiplePaths', Router.MethodToCall.Name);
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckFalse(Router.ExecuteRouting('/path4/par1/par2/3/4/notvalidparameter',
httpPOST, 'text/plain', 'text/plain', Controllers, 'text/plain',
TMVCMimeType.TEXT_PLAIN, Params, ResponseContentType,
ResponseContentEncoding));
2014-04-02 20:28:53 +02:00
CheckNull(Router.MethodToCall);
CheckFalse(Assigned(Router.MVCControllerClass));
finally
Params.Free;
end;
2013-10-30 01:09:09 +01:00
end;
procedure TTestRouting.TestDataSetToJSONArray;
var
ds: TClientDataSet;
JObj: TJSONObject;
S: string;
ds2: TClientDataSet;
JArr: TJSONArray;
begin
ds := TClientDataSet.Create(nil);
ds2 := TClientDataSet.Create(nil);
try
ds.LoadFromFile('..\..\fishes.xml');
ds.First;
JArr := TJSONArray.Create;
try
JArr := ds.AsJSONArray;
// Mapper.DataSetToJSONArray(ds, JArr, false);
ds2.LoadFromFile('..\..\fishes.xml');
ds2.EmptyDataSet;
ds.First;
while not ds.Eof do
begin
ds2.Insert;
JObj := JArr.Get(ds.RecNo - 1) as TJSONObject;
ds2.LoadFromJSONObject(JObj);
// Mapper.JSONObjectToDataSet(JObj, ds2, false);
ds2.Post;
SameFishesDataSet(ds, ds2);
ds.Next;
end;
finally
JArr.Free;
end;
finally
ds.Free;
ds2.Free;
end;
end;
procedure TTestRouting.TestDataSetToJSONObject;
var
ds: TClientDataSet;
JObj: TJSONObject;
S: string;
ds2: TClientDataSet;
begin
ds := TClientDataSet.Create(nil);
ds2 := TClientDataSet.Create(nil);
try
ds.LoadFromFile('..\..\fishes.xml');
JObj := TJSONObject.Create;
try
JObj := ds.AsJSONObject;
// Mapper.DataSetToJSONObject(ds, JObj, false);
ds2.LoadFromFile('..\..\fishes.xml');
ds2.EmptyDataSet;
ds2.Insert;
ds2.LoadFromJSONObject(JObj);
// Mapper.JSONObjectToDataSet(JObj, ds2, false);
ds2.Post;
SameFishesDataSet(ds, ds2);
finally
JObj.Free;
end;
finally
ds.Free;
ds2.Free;
end;
end;
procedure TTestRouting.TestJSONObjectToObjectAndBack;
var
Obj: TMyObject;
JObj: TJSONObject;
Obj2: TMyObject;
begin
Obj := GetMyObject;
try
JObj := Mapper.ObjectToJSONObject(Obj);
try
Obj2 := Mapper.JSONObjectToObject<TMyObject>(JObj);
try
CheckTrue(Obj.Equals(Obj2));
finally
Obj2.Free;
end;
finally
JObj.Free;
end;
finally
Obj.Free;
end;
end;
procedure TTestRouting.TestObjectListToJSONArray;
var
2014-09-05 12:47:40 +02:00
Obj: TMyObject;
ObjList, Obj2List: TObjectList<TMyObject>;
2014-04-16 22:52:25 +02:00
JSON: TJSONArray;
I: Integer;
begin
ObjList := TObjectList<TMyObject>.Create(true);
try
for I := 1 to 10 do
begin
Obj := GetMyObject;
Obj.PropInteger := I;
ObjList.Add(Obj);
end;
2014-04-16 22:52:25 +02:00
JSON := Mapper.ObjectListToJSONArray<TMyObject>(ObjList);
2014-04-16 22:52:25 +02:00
Obj2List := Mapper.JSONArrayToObjectList<TMyObject>(JSON);
try
CheckEquals(ObjList.Count, Obj2List.Count);
for I := 0 to 9 do
begin
CheckTrue(Obj2List[I].Equals(ObjList[I]));
end;
finally
Obj2List.Free;
end;
finally
ObjList.Free;
end;
end;
procedure TTestRouting.TestObjectToJSONObject;
var
Obj: TMyObject;
2014-04-16 22:52:25 +02:00
JSON: TJSONObject;
Obj2: TMyObject;
begin
Obj := GetMyObject;
try
2014-04-16 22:52:25 +02:00
JSON := Mapper.ObjectToJSONObject(Obj);
try
2014-04-16 22:52:25 +02:00
Obj2 := Mapper.JSONObjectToObject<TMyObject>(JSON);
CheckTrue(Obj.Equals(Obj2));
finally
2014-04-16 22:52:25 +02:00
JSON.Free;
end;
finally
Obj.Free;
end;
end;
procedure TTestRouting.TestObjectToJSONObjectAndBackWithStringStreamUTF16;
var
SO: TMyStreamObject;
JSONObj: TJSONObject;
ResultSO: TMyStreamObject;
ResultStr, str: UnicodeString;
begin
// ARRANGE
str := 'This is a UTF16 String (什么是)';
SO := TMyStreamObject.Create;
try
// ACT
SO.PropStream := TStringStream.Create(str, TEncoding.Unicode);
JSONObj := Mapper.ObjectToJSONObject(SO);
ResultSO := Mapper.JSONObjectToObject<TMyStreamObject>(JSONObj);
try
ResultStr := TStringStream(ResultSO.PropStream).DataString;
// ASSERT
CheckEquals(str, ResultStr);
finally
ResultSO.Free;
end;
finally
SO.Free;
end;
end;
procedure TTestRouting.TestObjectToJSONObjectAndBackWithStringStreamUTF8;
var
SO: TMyStreamObject;
JSONObj: TJSONObject;
ResultSO: TMyStreamObject;
ResultStr, str: UTF8String;
begin
// ARRANGE
str := 'This is a UTF8 String (什么是)';
SO := TMyStreamObject.Create;
try
// ACT
SO.Prop8Stream := TStringStream.Create(str, TEncoding.UTF8);
JSONObj := Mapper.ObjectToJSONObject(SO);
ResultSO := Mapper.JSONObjectToObject<TMyStreamObject>(JSONObj);
try
ResultStr := TStringStream(ResultSO.Prop8Stream).DataString;
// ASSERT
CheckEquals(str, ResultStr);
finally
ResultSO.Free;
end;
finally
SO.Free;
end;
end;
2013-10-30 01:09:09 +01:00
procedure TTestRouting.TestPathButNoParameters;
var
2013-11-09 10:05:14 +01:00
Params: TMVCRequestParamsTable;
2013-10-30 01:09:09 +01:00
ResponseContentType: string;
2013-11-09 10:05:14 +01:00
ResponseContentEncoding: string;
2013-10-30 01:09:09 +01:00
begin
Params := TMVCRequestParamsTable.Create;
try
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/orders', httpGET, 'text/plain',
'text/plain', Controllers, 'text/plain',
TMVCConstants.DEFAULT_CONTENT_CHARSET, Params, ResponseContentType,
2014-04-10 17:30:39 +02:00
ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals(0, Params.Count);
CheckEquals('TSimpleController', Router.MVCControllerClass.ClassName);
CheckEquals('Orders', Router.MethodToCall.Name);
2014-04-10 17:30:39 +02:00
CheckEquals(TMVCConstants.DEFAULT_CONTENT_CHARSET, ResponseContentEncoding);
2013-10-30 01:09:09 +01:00
finally
Params.Free;
end;
end;
procedure TTestRouting.TestPathWithParameters;
var
2013-11-09 10:05:14 +01:00
Params: TMVCRequestParamsTable;
2013-10-30 01:09:09 +01:00
ResponseContentType: string;
2013-11-09 10:05:14 +01:00
ResponseContentEncoding: string;
2013-10-30 01:09:09 +01:00
begin
Params := TMVCRequestParamsTable.Create;
try
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/orders/789', httpGET, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals(1, Params.Count);
CheckEquals('789', Params['ordernumber']);
CheckEquals('TSimpleController', Router.MVCControllerClass.ClassName);
CheckEquals('OrderNumber', Router.MethodToCall.Name);
finally
Params.Free;
end;
end;
2014-06-27 15:30:39 +02:00
procedure TTestRouting.TestProduceRoutings;
var
Params: TMVCRequestParamsTable;
ResponseContentType: string;
ResponseContentCharset: string;
begin
Params := TMVCRequestParamsTable.Create;
try
// a GET request with a ACCEPT: application/json
CheckTrue(Router.ExecuteRouting('/orders', httpGET, '', 'application/json',
Controllers, TMVCConstants.DEFAULT_CONTENT_TYPE,
TMVCConstants.DEFAULT_CONTENT_CHARSET, Params, ResponseContentType,
2014-06-27 15:30:39 +02:00
ResponseContentCharset));
CheckEquals(0, Params.Count);
CheckEquals('TSimpleController', Router.MVCControllerClass.ClassName);
CheckEquals('OrdersProduceJSON', Router.MethodToCall.Name);
CheckEquals(TMVCConstants.DEFAULT_CONTENT_CHARSET, ResponseContentCharset);
finally
Params.Free;
end;
end;
procedure TTestRouting.TestProduceRoutingsWithExplicitCharset;
var
Params: TMVCRequestParamsTable;
ResponseContentType: string;
ResponseContentCharset: string;
begin
Params := TMVCRequestParamsTable.Create;
try
// a GET request with a ACCEPT: application/json
CheckTrue(Router.ExecuteRouting('/orders', httpGET, '',
'application/json; charset=UTF-8', Controllers,
TMVCConstants.DEFAULT_CONTENT_TYPE, TMVCConstants.DEFAULT_CONTENT_CHARSET,
Params, ResponseContentType, ResponseContentCharset));
2014-06-27 15:30:39 +02:00
CheckEquals(0, Params.Count);
CheckEquals('TSimpleController', Router.MVCControllerClass.ClassName);
CheckEquals('OrdersProduceJSON', Router.MethodToCall.Name);
CheckEquals(TMVCConstants.DEFAULT_CONTENT_CHARSET, ResponseContentCharset);
finally
Params.Free;
end;
end;
2013-10-30 01:09:09 +01:00
procedure TTestRouting.TestWithMethodTypes;
var
2013-11-09 10:05:14 +01:00
Params: TMVCRequestParamsTable;
2013-10-30 01:09:09 +01:00
ResponseContentType: string;
2013-11-09 10:05:14 +01:00
ResponseContentEncoding: string;
2013-10-30 01:09:09 +01:00
begin
Params := TMVCRequestParamsTable.Create;
try
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/orders/789', httpPOST, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals('UpdateOrderNumber', Router.MethodToCall.Name);
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/orders/789', httpPUT, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals('UpdateOrderNumber', Router.MethodToCall.Name);
2014-03-24 17:37:08 +01:00
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/orders/789', httpPATCH, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2014-03-24 17:37:08 +01:00
CheckEquals('PatchOrder', Router.MethodToCall.Name);
2013-10-30 01:09:09 +01:00
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckFalse(Router.ExecuteRouting('/orders/789', httpDELETE, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckNull(Router.MethodToCall);
CheckFalse(Assigned(Router.MVCControllerClass));
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckFalse(Router.ExecuteRouting('/orders/789', httpHEAD, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding), 'Resolved as HEAD');
2013-10-30 01:09:09 +01:00
CheckNull(Router.MethodToCall, 'Resolved as HEAD');
CheckFalse(Assigned(Router.MVCControllerClass));
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckFalse(Router.ExecuteRouting('/orders/789', httpOPTIONS, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding), 'Resolved as OPTIONS');
2013-10-30 01:09:09 +01:00
CheckNull(Router.MethodToCall, 'Resolved as OPTIONS');
CheckFalse(Assigned(Router.MVCControllerClass));
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/orders/789', httpGET, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals('OrderNumber', Router.MethodToCall.Name);
Params.Clear;
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('/orders/789', httpGET, 'text/plain',
'text/plain', Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals('OrderNumber', Router.MethodToCall.Name);
finally
Params.Free;
end;
end;
procedure TTestRouting.TestWithNoParameters;
var
2013-11-09 10:05:14 +01:00
Params: TMVCRequestParamsTable;
2013-10-30 01:09:09 +01:00
ResponseContentType: string;
2013-11-09 10:05:14 +01:00
ResponseContentEncoding: string;
2013-10-30 01:09:09 +01:00
begin
Params := TMVCRequestParamsTable.Create;
try
2014-04-01 00:02:31 +02:00
CheckTrue(Router.ExecuteRouting('/', httpGET, 'text/plain', 'text/plain',
2014-04-10 13:56:23 +02:00
Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
2014-04-01 00:02:31 +02:00
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals(0, Params.Count);
CheckEquals('TSimpleController', Router.MVCControllerClass.ClassName);
CheckEquals('Index', Router.MethodToCall.Name);
finally
Params.Free;
end;
end;
procedure TTestRouting.TestWithNoPath;
var
2013-11-09 10:05:14 +01:00
Params: TMVCRequestParamsTable;
2013-10-30 01:09:09 +01:00
ResponseContentType: string;
2013-11-09 10:05:14 +01:00
ResponseContentEncoding: string;
2013-10-30 01:09:09 +01:00
begin
Params := TMVCRequestParamsTable.Create;
try
2014-04-16 22:52:25 +02:00
CheckTrue(Router.ExecuteRouting('', httpGET, 'text/plain', 'text/plain',
2014-04-10 13:56:23 +02:00
Controllers, 'text/plain', TMVCMimeType.TEXT_PLAIN, Params,
2014-04-01 00:02:31 +02:00
ResponseContentType, ResponseContentEncoding));
2013-10-30 01:09:09 +01:00
CheckEquals(0, Params.Count);
CheckEquals('TSimpleController', Router.MVCControllerClass.ClassName);
CheckEquals('Index', Router.MethodToCall.Name);
finally
Params.Free;
end;
end;
{ TMyObject }
2013-10-30 01:09:09 +01:00
initialization
RegisterTest(TTestRouting.suite);
finalization
end.