Added more unit tests for MVCActiveRecord

This commit is contained in:
Daniele Teti 2020-01-08 23:59:41 +01:00
parent 23b3826f02
commit 9d7ff23c11
9 changed files with 678 additions and 33 deletions

1
.gitignore vendored
View File

@ -74,3 +74,4 @@ __pycache__/
*.ini
*.bmp
samples/renders/bin/uploadedfiles/
samples/winecellarclient_mobile/Android/

Binary file not shown.

View 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.

View File

@ -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.

View File

@ -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}

View File

@ -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>

View File

@ -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
//

View File

@ -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;

Binary file not shown.