Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions SimpleBaseLib.Tests/Delphi.Tests/Mobile/MobileTestHostFormUnit.fmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
object MobileTestHostForm: TMobileTestHostForm
Left = 0
Top = 0
Caption = 'SimpleBaseLib Tests (Mobile)'
ClientHeight = 606
ClientWidth = 360
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnShow = FormShow
DesignerMasterStyle = 3
object lblBaseUrl: TLabel
AutoSize = True
Position.X = 8.000000000000000000
Position.Y = 26.000000000000000000
Size.Width = 177.000000000000000000
Size.Height = 22.000000000000000000
Size.PlatformDefault = False
Text = 'TestInsight URL'
TabOrder = 4
end
object edtBaseUrl: TEdit
Touch.InteractiveGestures = [LongTap, DoubleTap]
Anchors = [akLeft, akTop, akRight, akBottom]
TabOrder = 0
Position.X = 8.000000000000000000
Position.Y = 56.000000000000000000
Size.Width = 344.000000000000000000
Size.Height = 32.000000000000000000
Size.PlatformDefault = False
TextPrompt = 'http://IP:PORT'
OnChange = edtBaseUrlChange
OnChangeTracking = edtBaseUrlChange
end
object btnSaveUrl: TButton
Enabled = False
Position.X = 8.000000000000000000
Position.Y = 114.000000000000000000
Size.Width = 89.000000000000000000
Size.Height = 44.000000000000000000
Size.PlatformDefault = False
TabOrder = 1
Text = 'Save URL'
OnClick = btnSaveUrlClick
end
object lblConnection: TLabel
AutoSize = True
Position.X = 8.000000000000000000
Position.Y = 222.000000000000000000
Size.Width = 344.000000000000000000
Size.Height = 22.000000000000000000
Size.PlatformDefault = False
Text = 'IDE: (status)'
TabOrder = 5
end
object btnRunTests: TButton
Enabled = False
Position.X = 8.000000000000000000
Position.Y = 166.000000000000000000
Size.Width = 89.000000000000000000
Size.Height = 44.000000000000000000
Size.PlatformDefault = False
TabOrder = 2
Text = 'Run Tests'
OnClick = btnRunTestsClick
end
object memLog: TMemo
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
DataDetectorTypes = []
Anchors = [akLeft, akTop, akRight, akBottom]
Position.X = 8.000000000000000000
Position.Y = 264.000000000000000000
Size.Width = 344.000000000000000000
Size.Height = 334.000000000000000000
Size.PlatformDefault = False
TabOrder = 3
Viewport.Width = 336.000000000000000000
Viewport.Height = 326.000000000000000000
end
end
113 changes: 113 additions & 0 deletions SimpleBaseLib.Tests/Delphi.Tests/Mobile/MobileTestHostFormUnit.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
unit MobileTestHostFormUnit;

interface

uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
FMX.Controls.Presentation, FMX.Edit, FMX.Memo.Types, FMX.ScrollBox, FMX.Memo,
MobileTestRunner;

type
TMobileTestHostForm = class(TForm)
lblBaseUrl: TLabel;
edtBaseUrl: TEdit;
btnSaveUrl: TButton;
lblConnection: TLabel;
btnRunTests: TButton;
memLog: TMemo;
procedure FormShow(Sender: TObject);
procedure edtBaseUrlChange(Sender: TObject);
procedure btnSaveUrlClick(Sender: TObject);
procedure btnRunTestsClick(Sender: TObject);
private
procedure InitializeLog;
procedure AppendLog(const ALine: string);
procedure UpdateConnectionLabel;
procedure UpdateActionButtons;
public
end;

var
MobileTestHostForm: TMobileTestHostForm;

implementation

{$R *.fmx}

procedure TMobileTestHostForm.AppendLog(const ALine: string);
begin
if ALine <> '' then
memLog.Lines.Add(ALine);
end;

procedure TMobileTestHostForm.InitializeLog;
begin
memLog.Lines.Clear;
memLog.Lines.Add('=== Test log ===');
end;

procedure TMobileTestHostForm.UpdateConnectionLabel;
var
LUrl: string;
begin
LUrl := Trim(edtBaseUrl.Text);
if not ProbeTestInsightServer(LUrl) then
lblConnection.Text := 'IDE: enter TestInsight BaseUrl'
else
lblConnection.Text := 'IDE: URL set (open TestInsight Explorer)';
end;

procedure TMobileTestHostForm.UpdateActionButtons;
var
LUrlOk: Boolean;
begin
LUrlOk := ProbeTestInsightServer(edtBaseUrl.Text);
btnSaveUrl.Enabled := LUrlOk;
btnRunTests.Enabled := LUrlOk and not MobileTestsRunning;
end;

procedure TMobileTestHostForm.edtBaseUrlChange(Sender: TObject);
begin
UpdateConnectionLabel;
UpdateActionButtons;
end;

procedure TMobileTestHostForm.FormShow(Sender: TObject);
begin
edtBaseUrl.Text := LoadTestInsightBaseUrl;
UpdateConnectionLabel;
UpdateActionButtons;
InitializeLog;
end;

procedure TMobileTestHostForm.btnSaveUrlClick(Sender: TObject);
begin
SaveTestInsightBaseUrl(edtBaseUrl.Text);
UpdateConnectionLabel;
AppendLog('Saved TestInsight BaseUrl.');
end;

procedure TMobileTestHostForm.btnRunTestsClick(Sender: TObject);
begin
if MobileTestsRunning then
Exit;

SaveTestInsightBaseUrl(edtBaseUrl.Text);
UpdateConnectionLabel;
AppendLog('Running tests (TestInsight remote)...');

RunMobileTestsAsync(edtBaseUrl.Text,
procedure(const AMessage: string)
begin
AppendLog(AMessage);
end,
procedure
begin
UpdateActionButtons;
AppendLog('Tests finished.');
end);
UpdateActionButtons;
end;

end.
201 changes: 201 additions & 0 deletions SimpleBaseLib.Tests/Delphi.Tests/Mobile/MobileTestRunner.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
unit MobileTestRunner;

interface

uses
System.SysUtils;

type
TMobileTestStatusProc = reference to procedure(const AMessage: string);
TMobileTestFinishedProc = reference to procedure;

function MobileTestsRunning: Boolean;
function LoadTestInsightBaseUrl: string;
procedure SaveTestInsightBaseUrl(const ABaseUrl: string);
function ProbeTestInsightServer(const ABaseUrl: string): Boolean;
procedure RunMobileTestsAsync(const ABaseUrl: string;
const AOnStatus: TMobileTestStatusProc; const AOnFinished: TMobileTestFinishedProc);

implementation

uses
System.Classes,
System.IniFiles,
System.IOUtils,
System.SyncObjs,
TestInsight.DUnit;

const
TestInsightIniFileName = 'TestInsightSettings.ini';
TestInsightIniSection = 'Config';
TestInsightIniBaseUrlKey = 'BaseUrl';

type
TSyncStatusInvoker = class
private
FOnStatus: TMobileTestStatusProc;
FMessage: string;
public
constructor Create(const AOnStatus: TMobileTestStatusProc; const AMessage: string);
procedure Invoke;
end;

TSyncFinishedInvoker = class
private
FOnFinished: TMobileTestFinishedProc;
public
constructor Create(const AOnFinished: TMobileTestFinishedProc);
procedure Invoke;
end;

TMobileTestThread = class(TThread)
private
FBaseUrl: string;
FOnStatus: TMobileTestStatusProc;
FOnFinished: TMobileTestFinishedProc;
protected
procedure Execute; override;
public
constructor Create(const ABaseUrl: string; const AOnStatus: TMobileTestStatusProc;
const AOnFinished: TMobileTestFinishedProc);
end;

var
GTestsRunning: Integer;

function TestInsightSettingsIniPath: string;
begin
Result := TPath.Combine(TPath.GetDocumentsPath, TestInsightIniFileName);
end;

function ReadBaseUrlFromIni(const AIniPath: string): string;
var
LIni: TIniFile;
begin
Result := '';
if not FileExists(AIniPath) then
Exit;
LIni := TIniFile.Create(AIniPath);
try
Result := Trim(LIni.ReadString(TestInsightIniSection, TestInsightIniBaseUrlKey, ''));
finally
LIni.Free;
end;
end;

function MobileTestsRunning: Boolean;
begin
Result := TInterlocked.CompareExchange(GTestsRunning, 0, 0) <> 0;
end;

constructor TSyncStatusInvoker.Create(const AOnStatus: TMobileTestStatusProc;
const AMessage: string);
begin
inherited Create;
FOnStatus := AOnStatus;
FMessage := AMessage;
end;

procedure TSyncStatusInvoker.Invoke;
begin
if Assigned(FOnStatus) then
FOnStatus(FMessage);
end;

constructor TSyncFinishedInvoker.Create(const AOnFinished: TMobileTestFinishedProc);
begin
inherited Create;
FOnFinished := AOnFinished;
end;

procedure TSyncFinishedInvoker.Invoke;
begin
if Assigned(FOnFinished) then
FOnFinished();
end;

constructor TMobileTestThread.Create(const ABaseUrl: string;
const AOnStatus: TMobileTestStatusProc; const AOnFinished: TMobileTestFinishedProc);
begin
inherited Create(True);
FreeOnTerminate := True;
FBaseUrl := Trim(ABaseUrl);
FOnStatus := AOnStatus;
FOnFinished := AOnFinished;
end;

procedure TMobileTestThread.Execute;
var
LStatusInvoker: TSyncStatusInvoker;
LFinishedInvoker: TSyncFinishedInvoker;
begin
try
try
if FBaseUrl = '' then
raise Exception.Create('TestInsight BaseUrl is empty. Enter a URL in the app and tap Save URL.');
TestInsight.DUnit.RunRegisteredTests(FBaseUrl);
except
on E: Exception do
begin
if Assigned(FOnStatus) then
begin
LStatusInvoker := TSyncStatusInvoker.Create(FOnStatus, 'Error: ' + E.Message);
try
Synchronize(LStatusInvoker.Invoke);
finally
LStatusInvoker.Free;
end;
end;
end;
end;
finally
TInterlocked.Exchange(GTestsRunning, 0);
if Assigned(FOnFinished) then
begin
LFinishedInvoker := TSyncFinishedInvoker.Create(FOnFinished);
try
Synchronize(LFinishedInvoker.Invoke);
finally
LFinishedInvoker.Free;
end;
end;
end;
end;

function LoadTestInsightBaseUrl: string;
begin
Result := ReadBaseUrlFromIni(TestInsightSettingsIniPath);
end;

procedure SaveTestInsightBaseUrl(const ABaseUrl: string);
var
LIni: TIniFile;
LPath: string;
begin
LPath := TestInsightSettingsIniPath;
ForceDirectories(TPath.GetDirectoryName(LPath));
LIni := TIniFile.Create(LPath);
try
LIni.WriteString(TestInsightIniSection, TestInsightIniBaseUrlKey, Trim(ABaseUrl));
finally
LIni.Free;
end;
end;

function ProbeTestInsightServer(const ABaseUrl: string): Boolean;
begin
{ TestInsight exposes no documented health URL; non-empty URL is the v1 check. }
Result := Trim(ABaseUrl) <> '';
end;

procedure RunMobileTestsAsync(const ABaseUrl: string;
const AOnStatus: TMobileTestStatusProc; const AOnFinished: TMobileTestFinishedProc);
begin
if TInterlocked.CompareExchange(GTestsRunning, 1, 0) <> 0 then
Exit;

with TMobileTestThread.Create(ABaseUrl, AOnStatus, AOnFinished) do
Start;
end;

end.
Loading