mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
Added more unit tests for MVCActiveRecord
This commit is contained in:
parent
23b3826f02
commit
9d7ff23c11
1
.gitignore
vendored
1
.gitignore
vendored
@ -74,3 +74,4 @@ __pycache__/
|
||||
*.ini
|
||||
*.bmp
|
||||
samples/renders/bin/uploadedfiles/
|
||||
samples/winecellarclient_mobile/Android/
|
||||
|
Binary file not shown.
408
unittests/general/Several/ActiveRecordTestsU.pas
Normal file
408
unittests/general/Several/ActiveRecordTestsU.pas
Normal file
@ -0,0 +1,408 @@
|
||||
// ***************************************************************************
|
||||
//
|
||||
// Delphi MVC Framework
|
||||
//
|
||||
// Copyright (c) 2010-2020 Daniele Teti and the DMVCFramework Team
|
||||
//
|
||||
// https://github.com/danieleteti/delphimvcframework
|
||||
//
|
||||
// ***************************************************************************
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// *************************************************************************** }
|
||||
|
||||
unit ActiveRecordTestsU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
DUnitX.TestFramework, FireDAC.Comp.Client, FireDAC.ConsoleUI.Wait, FireDAC.VCLUI.Wait;
|
||||
|
||||
type
|
||||
|
||||
[TestFixture]
|
||||
TTestActiveRecord = class(TObject)
|
||||
private
|
||||
fConnection: TFDConnection;
|
||||
procedure LoadData;
|
||||
public
|
||||
[Setup]
|
||||
procedure Setup;
|
||||
[Teardown]
|
||||
procedure Teardown;
|
||||
[Test]
|
||||
procedure TestCRUD;
|
||||
[Test]
|
||||
procedure TestLifeCycle;
|
||||
[Test]
|
||||
procedure TestRQL;
|
||||
[Test]
|
||||
procedure TestMultiThreading;
|
||||
[Test]
|
||||
procedure TestNullables;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Classes, System.IOUtils, BOs, MVCFramework.ActiveRecord,
|
||||
System.SysUtils, System.Threading, System.Generics.Collections;
|
||||
|
||||
const
|
||||
CON_DEF_NAME = 'SQLITECONNECTION';
|
||||
|
||||
var
|
||||
GDBFileName: String = '';
|
||||
|
||||
procedure CreateSqlitePrivateConnDef(AIsPooled: boolean);
|
||||
var
|
||||
LParams: TStringList;
|
||||
begin
|
||||
LParams := TStringList.Create;
|
||||
try
|
||||
GDBFileName := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)), 'sqlitetest.db');
|
||||
LParams.Add('Database=' + GDBFileName);
|
||||
LParams.Add('OpenMode=CreateUTF8');
|
||||
if AIsPooled then
|
||||
begin
|
||||
LParams.Add('Pooled=True');
|
||||
LParams.Add('POOL_MaximumItems=100');
|
||||
end
|
||||
else
|
||||
begin
|
||||
LParams.Add('Pooled=False');
|
||||
end;
|
||||
FDManager.AddConnectionDef(CON_DEF_NAME, 'SQLite', LParams);
|
||||
finally
|
||||
LParams.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.TestCRUD;
|
||||
var
|
||||
lCustomer: TCustomer;
|
||||
lID: Integer;
|
||||
begin
|
||||
Assert.AreEqual(Int64(0), TMVCActiveRecord.Count<TCustomer>());
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
lCustomer.CompanyName := 'bit Time Professionals';
|
||||
lCustomer.City := 'Rome, IT';
|
||||
lCustomer.Note := 'note1';
|
||||
lCustomer.ID := -1; { don't be fooled by the default! }
|
||||
lCustomer.Insert;
|
||||
lID := lCustomer.ID;
|
||||
Assert.AreEqual(1, lID);
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomer>(lID);
|
||||
try
|
||||
Assert.IsFalse(lCustomer.Code.HasValue);
|
||||
Assert.IsFalse(lCustomer.Rating.HasValue);
|
||||
lCustomer.Code := '1234';
|
||||
lCustomer.Rating := 3;
|
||||
lCustomer.Note := lCustomer.Note + 'noteupdated';
|
||||
lCustomer.Update;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomer>(lID);
|
||||
try
|
||||
Assert.AreEqual('1234', lCustomer.Code.Value);
|
||||
Assert.AreEqual(3, lCustomer.Rating.Value);
|
||||
Assert.AreEqual('note1noteupdated', lCustomer.Note);
|
||||
Assert.AreEqual('bit Time Professionals', lCustomer.CompanyName.Value);
|
||||
Assert.AreEqual('Rome, IT', lCustomer.City);
|
||||
Assert.AreEqual(1, lCustomer.ID);
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomer>(lID);
|
||||
try
|
||||
lCustomer.Delete;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomer>(lID, False);
|
||||
Assert.IsNull(lCustomer);
|
||||
|
||||
Assert.WillRaise(
|
||||
procedure
|
||||
begin
|
||||
TMVCActiveRecord.GetByPK<TCustomer>(lID, True);
|
||||
end, EMVCActiveRecordNotFound);
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.TestLifeCycle;
|
||||
var
|
||||
lCustomer: TCustomerWithLF;
|
||||
lID: Integer;
|
||||
begin
|
||||
lCustomer := TCustomerWithLF.Create;
|
||||
try
|
||||
lCustomer.CompanyName := 'bit Time Professionals';
|
||||
lCustomer.City := 'Rome, IT';
|
||||
lCustomer.Note := 'note1';
|
||||
lCustomer.Insert;
|
||||
Assert.AreEqual
|
||||
('OnValidation|OnBeforeInsert|OnBeforeInsertOrUpdate|OnBeforeExecuteSQL|MapObjectToParams|OnAfterInsert|OnAfterInsertOrUpdate',
|
||||
lCustomer.GetHistory);
|
||||
lID := lCustomer.ID;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithLF>(lID);
|
||||
try
|
||||
Assert.AreEqual('OnBeforeLoad|MapDatasetToObject|OnAfterLoad', lCustomer.GetHistory);
|
||||
lCustomer.ClearHistory;
|
||||
lCustomer.City := 'XXX';
|
||||
lCustomer.Update;
|
||||
Assert.AreEqual
|
||||
('OnValidation|OnBeforeUpdate|OnBeforeInsertOrUpdate|OnBeforeExecuteSQL|MapObjectToParams|OnAfterUpdate|OnAfterInsertOrUpdate',
|
||||
lCustomer.GetHistory);
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetOneByWhere<TCustomerWithLF>('id = ?', [lID]);
|
||||
try
|
||||
Assert.AreEqual('OnBeforeLoad|MapDatasetToObject|OnAfterLoad', lCustomer.GetHistory);
|
||||
lCustomer.ClearHistory;
|
||||
lCustomer.Delete;
|
||||
Assert.AreEqual('OnBeforeDelete|OnBeforeExecuteSQL|MapObjectToParams|OnAfterDelete', lCustomer.GetHistory);
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.TestMultiThreading;
|
||||
begin
|
||||
LoadData;
|
||||
Assert.AreEqual(Trunc(20 * 30), TMVCActiveRecord.Count(TCustomerWithLF));
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.TestNullables;
|
||||
var
|
||||
lTest: TNullablesTest;
|
||||
lCustomer: TCustomer;
|
||||
lID: Integer;
|
||||
begin
|
||||
TMVCActiveRecord.DeleteAll(TNullablesTest);
|
||||
|
||||
lTest := TNullablesTest.Create();
|
||||
try
|
||||
lTest.f_int2 := 2;
|
||||
lTest.f_int4 := 4;
|
||||
lTest.f_int8 := 8;
|
||||
lTest.f_blob := TStringStream.Create('Hello World');
|
||||
lTest.Insert;
|
||||
finally
|
||||
lTest.Free;
|
||||
end;
|
||||
|
||||
lTest := TMVCActiveRecord.GetFirstByWhere<TNullablesTest>('f_int2 = ?', [2]);
|
||||
try
|
||||
Assert.IsTrue(lTest.f_int2.HasValue);
|
||||
Assert.IsTrue(lTest.f_int4.HasValue);
|
||||
Assert.IsTrue(lTest.f_int8.HasValue);
|
||||
Assert.IsFalse(lTest.f_string.HasValue);
|
||||
Assert.IsFalse(lTest.f_bool.HasValue);
|
||||
Assert.IsFalse(lTest.f_date.HasValue);
|
||||
Assert.IsFalse(lTest.f_time.HasValue);
|
||||
Assert.IsFalse(lTest.f_datetime.HasValue);
|
||||
Assert.IsFalse(lTest.f_float4.HasValue);
|
||||
Assert.IsFalse(lTest.f_float8.HasValue);
|
||||
Assert.IsFalse(lTest.f_bool.HasValue);
|
||||
Assert.IsNotNull(lTest);
|
||||
lTest.f_int2 := lTest.f_int2.Value + 2;
|
||||
lTest.f_int4 := lTest.f_int4.Value + 4;
|
||||
lTest.f_int8 := lTest.f_int8.Value + 8;
|
||||
lTest.f_blob.Free;
|
||||
lTest.f_blob := nil;
|
||||
lTest.Update;
|
||||
finally
|
||||
lTest.Free;
|
||||
end;
|
||||
|
||||
lTest := TMVCActiveRecord.GetFirstByWhere<TNullablesTest>('f_int2 = ?', [4]);
|
||||
try
|
||||
Assert.IsTrue(lTest.f_int2.ValueOrDefault = 4);
|
||||
Assert.IsTrue(lTest.f_int4.ValueOrDefault = 8);
|
||||
Assert.IsTrue(lTest.f_int8.ValueOrDefault = 16);
|
||||
Assert.IsFalse(lTest.f_string.HasValue);
|
||||
Assert.IsFalse(lTest.f_bool.HasValue);
|
||||
Assert.IsFalse(lTest.f_date.HasValue);
|
||||
Assert.IsFalse(lTest.f_time.HasValue);
|
||||
Assert.IsFalse(lTest.f_datetime.HasValue);
|
||||
Assert.IsFalse(lTest.f_float4.HasValue);
|
||||
Assert.IsFalse(lTest.f_float8.HasValue);
|
||||
Assert.IsFalse(lTest.f_bool.HasValue);
|
||||
Assert.IsFalse(Assigned(lTest.f_blob), 'Blob contains a value when should not');
|
||||
TMVCActiveRecord.DeleteRQL(TNullablesTest, 'eq(f_int2,4)');
|
||||
finally
|
||||
lTest.Free;
|
||||
end;
|
||||
|
||||
Assert.IsNull(TMVCActiveRecord.GetFirstByWhere<TNullablesTest>('f_int2 = 4', [], False));
|
||||
|
||||
lTest := TNullablesTest.Create;
|
||||
try
|
||||
lTest.f_int2 := 2;
|
||||
lTest.f_int4 := 4;
|
||||
lTest.f_int8 := 8;
|
||||
lTest.f_string := 'Hello World';
|
||||
lTest.f_bool := True;
|
||||
lTest.f_date := EncodeDate(2020, 02, 01);
|
||||
lTest.f_time := EncodeTime(12, 24, 36, 0);
|
||||
lTest.f_datetime := Now;
|
||||
lTest.f_float4 := 1234.5678;
|
||||
lTest.f_float8 := 12345678901234567890.0123456789;
|
||||
lTest.f_currency := 1234567890.1234;
|
||||
lTest.Insert;
|
||||
finally
|
||||
lTest.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.TestRQL;
|
||||
var
|
||||
lCustomers: TObjectList<TCustomer>;
|
||||
const
|
||||
RQL1 = 'or(eq(City, "Rome"),eq(City, "London"))';
|
||||
begin
|
||||
Assert.AreEqual(Int64(0), TMVCActiveRecord.Count(TCustomer));
|
||||
LoadData;
|
||||
lCustomers := TMVCActiveRecord.SelectRQL<TCustomer>(RQL1, MAXINT);
|
||||
try
|
||||
Assert.AreEqual(240, lCustomers.Count);
|
||||
for var lCustomer in lCustomers do
|
||||
begin
|
||||
Assert.IsMatch('^(Rome|London)$', lCustomer.City);
|
||||
end;
|
||||
finally
|
||||
lCustomers.Free;
|
||||
end;
|
||||
TMVCActiveRecord.DeleteRQL(TCustomer, RQL1);
|
||||
Assert.AreEqual(Int64(0), TMVCActiveRecord.Count<TCustomer>(RQL1));
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.LoadData;
|
||||
var
|
||||
lTasks: TArray<ITask>;
|
||||
lProc: TProc;
|
||||
const
|
||||
Cities: array [0 .. 4] of string = ('Rome', 'New York', 'London', 'Melbourne', 'Berlin');
|
||||
CompanySuffix: array [0 .. 5] of string = ('Corp.', 'Inc.', 'Ltd.', 'Srl', 'SPA', 'doo');
|
||||
Stuff: array [0 .. 4] of string = ('Burger', 'GAS', 'Motors', 'House', 'Boats');
|
||||
begin
|
||||
TMVCActiveRecord.DeleteRQL(TCustomer, 'in(City,["Rome","New York","London","Melbourne","Berlin"])');
|
||||
lProc := procedure
|
||||
var
|
||||
lCustomer: TCustomer;
|
||||
I: Integer;
|
||||
begin
|
||||
ActiveRecordConnectionsRegistry.AddDefaultConnection(TFDConnection.Create(nil), True);
|
||||
try
|
||||
ActiveRecordConnectionsRegistry.GetCurrent.ConnectionDefName := CON_DEF_NAME;
|
||||
for I := 1 to 30 do
|
||||
begin
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
lCustomer.Code := Format('%5.5d', [TThread.CurrentThread.ThreadID, I]);
|
||||
lCustomer.City := Cities[I mod Length(Cities)];
|
||||
lCustomer.CompanyName := Format('%s %s %s', [lCustomer.City, Stuff[Random(High(Stuff) + 1)],
|
||||
CompanySuffix[Random(High(CompanySuffix) + 1)]]);
|
||||
lCustomer.Note := Stuff[I mod Length(Stuff)];
|
||||
lCustomer.Insert;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
ActiveRecordConnectionsRegistry.RemoveDefaultConnection;
|
||||
end;
|
||||
end;
|
||||
|
||||
lTasks := [
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc),
|
||||
TTask.Run(lProc)];
|
||||
TTask.WaitForAll(lTasks);
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.Setup;
|
||||
begin
|
||||
fConnection := TFDConnection.Create(nil);
|
||||
fConnection.ConnectionDefName := CON_DEF_NAME;
|
||||
|
||||
if FDManager.ConnectionDefs.FindConnectionDef(CON_DEF_NAME) = nil then
|
||||
begin
|
||||
CreateSqlitePrivateConnDef(True);
|
||||
if TFile.Exists(GDBFileName) then
|
||||
begin
|
||||
TFile.Delete(GDBFileName);
|
||||
end;
|
||||
|
||||
fConnection.Open;
|
||||
for var lSQL in SQLs do
|
||||
begin
|
||||
fConnection.ExecSQL(lSQL);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
fConnection.Open;
|
||||
end;
|
||||
|
||||
ActiveRecordConnectionsRegistry.AddDefaultConnection(fConnection);
|
||||
TMVCActiveRecord.DeleteAll(TCustomer);
|
||||
end;
|
||||
|
||||
procedure TTestActiveRecord.Teardown;
|
||||
begin
|
||||
ActiveRecordConnectionsRegistry.RemoveDefaultConnection();
|
||||
fConnection.Close;
|
||||
FreeAndNil(fConnection);
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
TDUnitX.RegisterTestFixture(TTestActiveRecord);
|
||||
|
||||
finalization
|
||||
|
||||
end.
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// Delphi MVC Framework
|
||||
//
|
||||
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
|
||||
// Copyright (c) 2010-2020 Daniele Teti and the DMVCFramework Team
|
||||
//
|
||||
// https://github.com/danieleteti/delphimvcframework
|
||||
//
|
||||
@ -28,9 +28,125 @@ interface
|
||||
|
||||
uses
|
||||
system.TimeSpan, system.SysUtils, generics.collections, system.Classes,
|
||||
system.Rtti, MVCFramework.Serializer.Commons, JsonDataObjects;
|
||||
system.Rtti, MVCFramework.Serializer.Commons, JsonDataObjects, MVCFramework.ActiveRecord, MVCFramework.Nullables,
|
||||
MVCFramework.SQLGenerators.SQLite, FireDAC.Stan.Param, Data.DB;
|
||||
|
||||
const
|
||||
SQLs: array [0 .. 1] of string = (
|
||||
'CREATE TABLE customers (id INTEGER NOT NULL, code varchar (20), description varchar (200), city varchar (200), note TEXT, rating INTEGER, PRIMARY KEY (id))',
|
||||
'CREATE TABLE nullables_test(f_int2 int2, f_int8 int8, f_int4 int4, f_string varchar, f_bool BOOLEAN, ' +
|
||||
'f_date TIMESTAMP, f_time TIMESTAMP, f_datetime TIMESTAMP, f_float4 float4, f_float8 float8, ' +
|
||||
'f_currency numeric(18,4), f_blob BLOB)'
|
||||
);
|
||||
|
||||
type
|
||||
|
||||
[MVCTable('customers')]
|
||||
TCustomer = class(TMVCActiveRecord)
|
||||
private
|
||||
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
|
||||
fID: Integer;
|
||||
[MVCTableField('code')]
|
||||
fCode: NullableString;
|
||||
[MVCTableField('description')]
|
||||
fCompanyName: NullableString;
|
||||
[MVCTableField('city')]
|
||||
fCity: string;
|
||||
[MVCTableField('rating')]
|
||||
fRating: NullableInteger;
|
||||
[MVCTableField('note')]
|
||||
fNote: String;
|
||||
public
|
||||
property ID: Integer read fID write fID;
|
||||
property Code: NullableString read fCode write fCode;
|
||||
property CompanyName: NullableString read fCompanyName write fCompanyName;
|
||||
property City: string read fCity write fCity;
|
||||
property Rating: NullableInteger read fRating write fRating;
|
||||
property Note: String read fNote write fNote;
|
||||
end;
|
||||
|
||||
[MVCTable('customers')]
|
||||
TCustomerWithLF = class(TCustomer)
|
||||
private
|
||||
fHistory: TList<String>;
|
||||
public
|
||||
constructor Create; override;
|
||||
destructor Destroy; override;
|
||||
function GetHistory: String;
|
||||
procedure ClearHistory;
|
||||
protected
|
||||
procedure OnValidation; override;
|
||||
procedure OnAfterLoad; override;
|
||||
procedure OnBeforeLoad; override;
|
||||
procedure OnBeforeInsert; override;
|
||||
procedure OnAfterInsert; override;
|
||||
procedure OnBeforeUpdate; override;
|
||||
procedure OnAfterUpdate; override;
|
||||
procedure OnBeforeDelete; override;
|
||||
procedure OnAfterDelete; override;
|
||||
procedure OnBeforeInsertOrUpdate; override;
|
||||
procedure OnBeforeExecuteSQL(var SQL: String); override;
|
||||
procedure OnAfterInsertOrUpdate; override;
|
||||
procedure MapObjectToParams(const Params: TFDParams; var Handled: Boolean); override;
|
||||
procedure MapDatasetToObject(const DataSet: TDataSet; const Options: TMVCActiveRecordLoadOptions;
|
||||
var Handled: Boolean); override;
|
||||
end;
|
||||
|
||||
[MVCTable('nullables_test')]
|
||||
TNullablesTest = class(TMVCActiveRecord)
|
||||
private
|
||||
[MVCTableField('f_int2')]
|
||||
ff_int2: NullableInt16;
|
||||
[MVCTableField('f_int4')]
|
||||
ff_int4: NullableInt32;
|
||||
[MVCTableField('f_int8')]
|
||||
ff_int8: NullableInt64;
|
||||
[MVCTableField('f_date')]
|
||||
ff_date: NullableDate;
|
||||
[MVCTableField('f_time')]
|
||||
ff_time: NullableTime;
|
||||
[MVCTableField('f_bool')]
|
||||
ff_bool: NullableBoolean;
|
||||
[MVCTableField('f_datetime')]
|
||||
ff_datetime: NullableDateTime;
|
||||
[MVCTableField('f_float4')]
|
||||
ff_float4: NullableSingle;
|
||||
[MVCTableField('f_float8')]
|
||||
ff_float8: NullableDouble;
|
||||
[MVCTableField('f_string')]
|
||||
ff_string: NullableString;
|
||||
[MVCTableField('f_currency')]
|
||||
ff_currency: NullableCurrency;
|
||||
[MVCTableField('f_blob')]
|
||||
ff_blob: TStream;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
// f_int2 int2 NULL,
|
||||
property f_int2: NullableInt16 read ff_int2 write ff_int2;
|
||||
// f_int4 int4 NULL,
|
||||
property f_int4: NullableInt32 read ff_int4 write ff_int4;
|
||||
// f_int8 int8 NULL,
|
||||
property f_int8: NullableInt64 read ff_int8 write ff_int8;
|
||||
// f_string varchar NULL,
|
||||
property f_string: NullableString read ff_string write ff_string;
|
||||
// f_bool bool NULL,
|
||||
property f_bool: NullableBoolean read ff_bool write ff_bool;
|
||||
// f_date date NULL,
|
||||
property f_date: NullableDate read ff_date write ff_date;
|
||||
// f_time time NULL,
|
||||
property f_time: NullableTime read ff_time write ff_time;
|
||||
// f_datetime timestamp NULL,
|
||||
property f_datetime: NullableDateTime read ff_datetime write ff_datetime;
|
||||
// f_float4 float4 NULL,
|
||||
property f_float4: NullableSingle read ff_float4 write ff_float4;
|
||||
// f_float8 float8 NULL,
|
||||
property f_float8: NullableDouble read ff_float8 write ff_float8;
|
||||
// f_currency numeric(18,4) NULL
|
||||
property f_currency: NullableCurrency read ff_currency write ff_currency;
|
||||
// f_blob bytea NULL
|
||||
property f_blob: TStream read ff_blob write ff_blob;
|
||||
end;
|
||||
|
||||
TMyObject = class
|
||||
private
|
||||
FPropString: string;
|
||||
@ -40,7 +156,7 @@ type
|
||||
FPropUInt64: UInt64;
|
||||
FPropUInt16: word;
|
||||
FPropInt16: smallint;
|
||||
FPropBoolean: boolean;
|
||||
FPropBoolean: Boolean;
|
||||
FPropDateTime: TDateTime;
|
||||
FPropDate: TDate;
|
||||
FPropInteger: Integer;
|
||||
@ -55,7 +171,7 @@ type
|
||||
procedure SetPropUInt64(const Value: UInt64);
|
||||
procedure SetPropInt16(const Value: smallint);
|
||||
procedure SetPropUInt16(const Value: word);
|
||||
procedure SetPropBoolean(const Value: boolean);
|
||||
procedure SetPropBoolean(const Value: Boolean);
|
||||
procedure SetPropDate(const Value: TDate);
|
||||
procedure SetPropDateTime(const Value: TDateTime);
|
||||
procedure SetPropInteger(const Value: Integer);
|
||||
@ -65,7 +181,7 @@ type
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function Equals(Obj: TMyObject): boolean; reintroduce;
|
||||
function Equals(Obj: TMyObject): Boolean; reintroduce;
|
||||
property PropString: string read FPropString write SetPropString;
|
||||
property PropAnsiString: AnsiString read FPropAnsiString
|
||||
write SetPropAnsiString;
|
||||
@ -75,7 +191,7 @@ type
|
||||
property PropUInt64: UInt64 read FPropUInt64 write SetPropUInt64;
|
||||
property PropUInt16: word read FPropUInt16 write SetPropUInt16;
|
||||
property PropInt16: smallint read FPropInt16 write SetPropInt16;
|
||||
property PropBoolean: boolean read FPropBoolean write SetPropBoolean;
|
||||
property PropBoolean: Boolean read FPropBoolean write SetPropBoolean;
|
||||
property PropDate: TDate read FPropDate write SetPropDate;
|
||||
property PropTime: TTime read FPropTime write SetPropTime;
|
||||
property PropDateTime: TDateTime read FPropDateTime write SetPropDateTime;
|
||||
@ -107,7 +223,7 @@ type
|
||||
procedure SetValueAsInteger(const Value: TValue);
|
||||
procedure SetValueAsString(const Value: TValue);
|
||||
public
|
||||
function Equals(Obj: TObject): boolean; reintroduce;
|
||||
function Equals(Obj: TObject): Boolean; reintroduce;
|
||||
// [TValueAsType(TypeInfo(String))]
|
||||
property ValueAsString: TValue read FValueAsString write SetValueAsString;
|
||||
// [TValueAsType(TypeInfo(Integer))]
|
||||
@ -136,7 +252,7 @@ type
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function Equals(Obj: TObject): boolean; override;
|
||||
function Equals(Obj: TObject): Boolean; override;
|
||||
|
||||
property Prop1: string read FProp1 write SetProp1;
|
||||
property PropStringList: TStringList read FPropStringList write SetPropStringList;
|
||||
@ -154,7 +270,7 @@ type
|
||||
procedure SetProp8Stream(const Value: TStream);
|
||||
procedure SetImageStream(const Value: TStream);
|
||||
public
|
||||
function Equals(Obj: TMyStreamObject): boolean; reintroduce;
|
||||
function Equals(Obj: TMyStreamObject): Boolean; reintroduce;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
[MVCSerializeAsString]
|
||||
@ -173,27 +289,27 @@ type
|
||||
function GetFullName: string;
|
||||
procedure SetFirstName(const Value: string);
|
||||
procedure SetLastName(const Value: string);
|
||||
function GetIsAdult: boolean;
|
||||
function GetIsAdult: Boolean;
|
||||
procedure SetAge(const Value: Integer);
|
||||
public
|
||||
constructor Create(aFirstName, aLastName: string; aAge: Integer);
|
||||
function Equals(Obj: TObject): boolean; override;
|
||||
function Equals(Obj: TObject): Boolean; override;
|
||||
property FirstName: string read FFirstName write SetFirstName;
|
||||
property LastName: string read FLastName write SetLastName;
|
||||
property Age: Integer read FAge write SetAge;
|
||||
property IsAdult: boolean read GetIsAdult;
|
||||
property IsAdult: Boolean read GetIsAdult;
|
||||
property FullName: string read GetFullName;
|
||||
end;
|
||||
|
||||
TMyClass = class
|
||||
private
|
||||
FID: Integer;
|
||||
fID: Integer;
|
||||
FDescription: string;
|
||||
procedure SetId(ID: Integer);
|
||||
procedure SetDescription(Description: string);
|
||||
public
|
||||
function Equals(Obj: TObject): boolean; override;
|
||||
property ID: Integer read FID write SetId;
|
||||
function Equals(Obj: TObject): Boolean; override;
|
||||
property ID: Integer read fID write SetId;
|
||||
property Description: string read FDescription write SetDescription;
|
||||
constructor Create(ID: Integer; Description: string); overload;
|
||||
end;
|
||||
@ -206,7 +322,7 @@ type
|
||||
|
||||
TMyIntfObject = class(TInterfacedObject, IMyInterface)
|
||||
private
|
||||
FID: Integer;
|
||||
fID: Integer;
|
||||
FValue: string;
|
||||
public
|
||||
constructor Create(const ID: Integer; const Value: string);
|
||||
@ -240,7 +356,7 @@ type
|
||||
public
|
||||
constructor Create; virtual;
|
||||
destructor Destroy; override;
|
||||
function Equals(Obj: TObject): boolean; override;
|
||||
function Equals(Obj: TObject): Boolean; override;
|
||||
property PropStringList: TStringList read FPropStringList write SetPropStringList;
|
||||
property PropStringArray: TArray<string> read FPropStringArray write SetPropStringArray;
|
||||
[MVCSerializeAsString]
|
||||
@ -361,7 +477,7 @@ end;
|
||||
constructor TMyObject.Create;
|
||||
begin
|
||||
inherited;
|
||||
fPropJSONObject := TJsonObject.Create;
|
||||
fPropJSONObject := TJSONObject.Create;
|
||||
end;
|
||||
|
||||
destructor TMyObject.Destroy;
|
||||
@ -370,7 +486,7 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TMyObject.Equals(Obj: TMyObject): boolean;
|
||||
function TMyObject.Equals(Obj: TMyObject): Boolean;
|
||||
begin
|
||||
Result := true;
|
||||
Result := Result and (Self.PropString = Obj.PropString);
|
||||
@ -397,7 +513,7 @@ begin
|
||||
FPropAnsiString := Value;
|
||||
end;
|
||||
|
||||
procedure TMyObject.SetPropBoolean(const Value: boolean);
|
||||
procedure TMyObject.SetPropBoolean(const Value: Boolean);
|
||||
begin
|
||||
FPropBoolean := Value;
|
||||
end;
|
||||
@ -479,7 +595,7 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TMyComplexObject.Equals(Obj: TObject): boolean;
|
||||
function TMyComplexObject.Equals(Obj: TObject): Boolean;
|
||||
var
|
||||
co: TMyComplexObject;
|
||||
begin
|
||||
@ -561,7 +677,7 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TMyStreamObject.Equals(Obj: TMyStreamObject): boolean;
|
||||
function TMyStreamObject.Equals(Obj: TMyStreamObject): Boolean;
|
||||
var
|
||||
lPMemSelf: PByte;
|
||||
lPMemOther: PByte;
|
||||
@ -617,7 +733,7 @@ begin
|
||||
FAge := aAge;
|
||||
end;
|
||||
|
||||
function TMyObjectWithLogic.Equals(Obj: TObject): boolean;
|
||||
function TMyObjectWithLogic.Equals(Obj: TObject): Boolean;
|
||||
var
|
||||
lOther: TMyObjectWithLogic;
|
||||
begin
|
||||
@ -636,7 +752,7 @@ begin
|
||||
Result := FirstName + ' ' + LastName; // logic
|
||||
end;
|
||||
|
||||
function TMyObjectWithLogic.GetIsAdult: boolean;
|
||||
function TMyObjectWithLogic.GetIsAdult: Boolean;
|
||||
begin
|
||||
Result := Age >= 18; // logic
|
||||
end;
|
||||
@ -691,7 +807,7 @@ begin
|
||||
Self.SetDescription(Description);
|
||||
end;
|
||||
|
||||
function TMyClass.Equals(Obj: TObject): boolean;
|
||||
function TMyClass.Equals(Obj: TObject): Boolean;
|
||||
begin
|
||||
Result := Obj is TMyClass;
|
||||
if Result then
|
||||
@ -708,12 +824,12 @@ end;
|
||||
|
||||
procedure TMyClass.SetId(ID: Integer);
|
||||
begin
|
||||
Self.FID := ID;
|
||||
Self.fID := ID;
|
||||
end;
|
||||
|
||||
{ TMyObjectWithTValue }
|
||||
|
||||
function TMyObjectWithTValue.Equals(Obj: TObject): boolean;
|
||||
function TMyObjectWithTValue.Equals(Obj: TObject): Boolean;
|
||||
var
|
||||
lOther: TMyObjectWithTValue;
|
||||
begin
|
||||
@ -746,7 +862,7 @@ end;
|
||||
constructor TMyIntfObject.Create(const ID: Integer; const Value: string);
|
||||
begin
|
||||
inherited Create;
|
||||
FID := ID;
|
||||
fID := ID;
|
||||
FValue := Value;
|
||||
end;
|
||||
|
||||
@ -757,7 +873,7 @@ end;
|
||||
|
||||
function TMyIntfObject.GetID: Integer;
|
||||
begin
|
||||
Result := FID;
|
||||
Result := fID;
|
||||
end;
|
||||
|
||||
{ TObjectWithCustomType }
|
||||
@ -778,7 +894,7 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TObjectWithCustomType.Equals(Obj: TObject): boolean;
|
||||
function TObjectWithCustomType.Equals(Obj: TObject): Boolean;
|
||||
var
|
||||
lOther: TObjectWithCustomType;
|
||||
begin
|
||||
@ -814,4 +930,122 @@ begin
|
||||
FPropStringList := Value;
|
||||
end;
|
||||
|
||||
{ TCustomerWithLF }
|
||||
|
||||
procedure TCustomerWithLF.ClearHistory;
|
||||
begin
|
||||
fHistory.Clear;
|
||||
end;
|
||||
|
||||
constructor TCustomerWithLF.Create;
|
||||
begin
|
||||
inherited;
|
||||
fHistory := TList<String>.Create;
|
||||
end;
|
||||
|
||||
destructor TCustomerWithLF.Destroy;
|
||||
begin
|
||||
fHistory.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TCustomerWithLF.GetHistory: String;
|
||||
begin
|
||||
Result := String.Join('|', fHistory.ToArray);
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.MapDatasetToObject(const DataSet: TDataSet;
|
||||
const Options: TMVCActiveRecordLoadOptions; var Handled: Boolean);
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('MapDatasetToObject');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.MapObjectToParams(const Params: TFDParams;
|
||||
var Handled: Boolean);
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('MapObjectToParams');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnAfterDelete;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnAfterDelete');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnAfterInsert;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnAfterInsert');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnAfterInsertOrUpdate;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnAfterInsertOrUpdate');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnAfterLoad;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnAfterLoad');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnAfterUpdate;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnAfterUpdate');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnBeforeDelete;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnBeforeDelete');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnBeforeExecuteSQL(var SQL: String);
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnBeforeExecuteSQL');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnBeforeInsert;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnBeforeInsert');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnBeforeInsertOrUpdate;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnBeforeInsertOrUpdate');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnBeforeLoad;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnBeforeLoad');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnBeforeUpdate;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnBeforeUpdate');
|
||||
end;
|
||||
|
||||
procedure TCustomerWithLF.OnValidation;
|
||||
begin
|
||||
inherited;
|
||||
fHistory.Add('OnValidation');
|
||||
end;
|
||||
|
||||
{ TNullablesTest }
|
||||
|
||||
destructor TNullablesTest.Destroy;
|
||||
begin
|
||||
ff_blob.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -40,7 +40,8 @@ uses
|
||||
MVCFramework.Tests.Serializer.Entities in '..\..\common\MVCFramework.Tests.Serializer.Entities.pas',
|
||||
MVCFramework.Tests.Serializer.EntitiesModule in '..\..\common\MVCFramework.Tests.Serializer.EntitiesModule.pas' {EntitiesModule: TDataModule},
|
||||
MVCFramework.Tests.Serializer.Intf in '..\..\common\MVCFramework.Tests.Serializer.Intf.pas',
|
||||
MVCFramework.Serializer.JsonDataObjects.OptionalCustomTypes in '..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.OptionalCustomTypes.pas';
|
||||
MVCFramework.Serializer.JsonDataObjects.OptionalCustomTypes in '..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.OptionalCustomTypes.pas',
|
||||
ActiveRecordTestsU in 'ActiveRecordTestsU.pas';
|
||||
|
||||
{$R *.RES}
|
||||
{$IFDEF CONSOLE_TESTRUNNER}
|
||||
|
@ -197,6 +197,7 @@
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\common\MVCFramework.Tests.Serializer.Intf.pas"/>
|
||||
<DCCReference Include="..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.OptionalCustomTypes.pas"/>
|
||||
<DCCReference Include="ActiveRecordTestsU.pas"/>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// Delphi MVC Framework
|
||||
//
|
||||
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
|
||||
// Copyright (c) 2010-2020 Daniele Teti and the DMVCFramework Team
|
||||
//
|
||||
// https://github.com/danieleteti/delphimvcframework
|
||||
//
|
||||
|
@ -1206,7 +1206,7 @@ var
|
||||
begin
|
||||
r := RESTClient.doGET('/responses/nocontent', []);
|
||||
Assert.areEqual<Integer>(HTTP_STATUS.NoContent, r.ResponseCode);
|
||||
Assert.isTrue(r.ResponseText.Contains('thisisthereason'));
|
||||
Assert.isTrue(r.ResponseText.Contains('No Content'));
|
||||
Assert.IsEmpty(r.BodyAsString);
|
||||
end;
|
||||
|
||||
|
BIN
unittests/general/Several/Win32/GUI/sqlitetest.db
Normal file
BIN
unittests/general/Several/Win32/GUI/sqlitetest.db
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user