mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-02 16:43:40 +02:00
867 lines
24 KiB
ObjectPascal
867 lines
24 KiB
ObjectPascal
{
|
|
Copyright (C) 2004-2014 Dean Zobec, contributors
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
Modified:
|
|
Graeme Geldenhuys <graemeg@gmail.com>
|
|
Darius Blaszijk <dhkblaszyk@zeelandnet.nl>
|
|
Reinier Olislagers <reinierolislagers@gmail.com>
|
|
}
|
|
|
|
unit GuiTestRunner;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
|
ExtCtrls, Buttons, ComCtrls, ActnList, Menus, Clipbrd, StdCtrls,
|
|
testdecorator, xmltestreport,
|
|
fpcunit, testregistry, SynEdit, SynHighlighterXML, gettext, Translations;
|
|
|
|
type
|
|
|
|
{ TGUITestRunner }
|
|
|
|
TGUITestRunner = class(TForm, ITestListener)
|
|
actCopy: TAction;
|
|
actCut: TAction;
|
|
ActCloseForm: TAction;
|
|
actCopyErrorMsg: TAction;
|
|
ActCheckCurrentSuite: TAction;
|
|
ActCheckAll: TAction;
|
|
ActRunHighlightedTest: TAction;
|
|
ActUncheckAll: TAction;
|
|
ActUncheckCurrentSuite: TAction;
|
|
btnRunHighlighted: TBitBtn;
|
|
ilNodeStates: TImageList;
|
|
Memo1: TMemo;
|
|
MenuItem4: TMenuItem;
|
|
MenuItem5: TMenuItem;
|
|
MenuItem6: TMenuItem;
|
|
MenuItem7: TMenuItem;
|
|
MenuItem8: TMenuItem;
|
|
miRunTest: TMenuItem;
|
|
miShowfailureMsg: TMenuItem;
|
|
pbBar: TPaintBox;
|
|
PopupMenu3: TPopupMenu;
|
|
RunAction: TAction;
|
|
ActionList1: TActionList;
|
|
ActionList2: TActionList;
|
|
BtnRun: TBitBtn;
|
|
BtnClose: TBitBtn;
|
|
TestTreeImageList: TImageList;
|
|
ResultsXMLImageList: TImageList;
|
|
MenuItem1: TMenuItem;
|
|
MenuItem2: TMenuItem;
|
|
MenuItem3: TMenuItem;
|
|
PopupMenu1: TPopupMenu;
|
|
PopupMenu2: TPopupMenu;
|
|
SaveDialog: TSaveDialog;
|
|
Splitter1: TSplitter;
|
|
TestTree: TTreeView;
|
|
SynXMLSyn1: TSynXMLSyn;
|
|
PageControl1: TPageControl;
|
|
Panel1: TPanel;
|
|
Panel2: TPanel;
|
|
XMLToolBar: TToolBar;
|
|
CopyXMLToolButton: TToolButton;
|
|
CutXMLToolButton: TToolButton;
|
|
SaveAsToolButton: TToolButton;
|
|
tsTestTree: TTabSheet;
|
|
tsResultsXML: TTabSheet;
|
|
XMLSynEdit: TSynEdit;
|
|
procedure ActCheckAllExecute(Sender: TObject);
|
|
procedure ActCheckCurrentSuiteExecute(Sender: TObject);
|
|
procedure ActCloseFormExecute(Sender: TObject);
|
|
procedure ActRunHighlightedTestExecute(Sender: TObject);
|
|
procedure ActUncheckAllExecute(Sender: TObject);
|
|
procedure ActRunHighLightedTestUpdate(Sender: TObject);
|
|
procedure ActUncheckCurrentSuiteExecute(Sender: TObject);
|
|
procedure RunExecute(Sender: TObject);
|
|
procedure GUITestRunnerCreate(Sender: TObject);
|
|
procedure GUITestRunnerShow(Sender: TObject);
|
|
procedure MenuItem3Click(Sender: TObject);
|
|
procedure SaveAsToolButtonClick(Sender: TObject);
|
|
procedure TestTreeCreateNodeClass(Sender: TCustomTreeView;
|
|
var NodeClass: TTreeNodeClass);
|
|
procedure TestTreeMouseDown(Sender: TOBject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure TestTreeSelectionChanged(Sender: TObject);
|
|
procedure actCopyErrorMsgExecute(Sender: TObject);
|
|
procedure actCopyErrorMsgUpdate(Sender: TObject);
|
|
procedure pbBarPaint(Sender: TObject);
|
|
procedure actCopyExecute(Sender: TObject);
|
|
procedure actCutExecute(Sender: TObject);
|
|
private
|
|
failureCounter: Integer;
|
|
errorCounter: Integer;
|
|
testsCounter: Integer;
|
|
skipsCounter: Integer;
|
|
barColor: TColor;
|
|
testSuite: TTest;
|
|
procedure BuildTree(rootNode: TTreeNode; aSuite: TTestSuite);
|
|
function FindNode(aTest: TTest): TTreeNode;
|
|
procedure ResetNodeColors;
|
|
procedure PaintNodeError(aNode: TTreeNode);
|
|
procedure PaintNodeFailure(aNode: TTreeNode);
|
|
procedure PaintNodeIgnore(aNode: TTreeNode);
|
|
procedure PaintNodeNonFailed(aNode: TTreeNode);
|
|
procedure PaintNodeBusy(aNode: TTreeNode);
|
|
procedure MemoLog(LogEntry: string);
|
|
procedure EnableRunActions(AValue: boolean);
|
|
public
|
|
procedure AddFailure(ATest: TTest; AFailure: TTestFailure);
|
|
procedure AddError(ATest: TTest; AError: TTestFailure);
|
|
procedure StartTest(ATest: TTest);
|
|
procedure EndTest(ATest: TTest);
|
|
procedure RunTest(ATest: TTest);
|
|
procedure StartTestSuite(ATestSuite: TTestSuite);
|
|
procedure EndTestSuite(ATestSuite: TTestSuite);
|
|
end;
|
|
|
|
var
|
|
TestRunner: TGUITestRunner;
|
|
|
|
resourcestring
|
|
rsAllTests = 'All Tests';
|
|
rsRun = 'Run ';
|
|
rsRuns = 'Runs: %s/%s';
|
|
rsErrors = '%s Errors: %s';
|
|
rsFailures = '%s Failures: %s';
|
|
rsMessage = 'Message: %s';
|
|
rsException = 'Exception: %s';
|
|
rsExceptionMes = 'Exception message: %s';
|
|
rsExceptionCla = 'Exception class: %s';
|
|
rsUnitName = 'Unit name: %s';
|
|
rsMethodName = 'Method name: %s';
|
|
rsLineNumber = 'Line number: %s';
|
|
rsRunning = 'Running %s';
|
|
rsNumberOfExec = 'Number of executed tests: %s Time elapsed: %s';
|
|
// Visual components captions
|
|
sfrmGUITest = 'FPCUnit - run unit test';
|
|
sbtnRun = 'Run';
|
|
sbtnRunH = 'Run highlighted test';
|
|
sbtnClose = 'Close';
|
|
stshTree = 'Testcase tree';
|
|
stshResults = 'Results XML';
|
|
sactRunAction = '&Run';
|
|
sactRunActionH = 'Run all checked test(s)';
|
|
sactCloseForm = 'Quit';
|
|
sactCloseFormH = 'Quit Testting';
|
|
sactCheckCurrentSuite = 'Check the Current Suite';
|
|
sactUncheckCurrentSuite = 'Uncheck the Current Suite';
|
|
sactCheckAll = 'Check all Tests';
|
|
sactUncheckAll = 'Uncheck all tests';
|
|
sactRunHighlightedTest = 'Run highlighted test';
|
|
smiRunTest = ' &Run all selected (checked) tests';
|
|
smiShowfail= 'Copy message to clipboard';
|
|
smiCopy = '&Copy';
|
|
smiCut = 'C&ut';
|
|
smiCopyClipbrd = 'Copy to clipboard';
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses
|
|
xmlwrite
|
|
;
|
|
const
|
|
// TestTreeImageList indexes:
|
|
imgGreenBall = 0; //success result
|
|
imgRedBall = 2;
|
|
imgPurpleBall = 3;
|
|
imgWarningSign = 4; //failure result
|
|
imgInfoSign = 11; //error result
|
|
imgGrayBall = 12; //default
|
|
imgBlueBall = 13; //busy
|
|
|
|
type
|
|
|
|
TTreeNodeState=(tsUnChecked, tsChecked);
|
|
|
|
type
|
|
|
|
{ TMessageTreeNode }
|
|
|
|
TMessageTreeNode = class(TTreeNode)
|
|
private
|
|
FMessage: string;
|
|
public
|
|
property Message: string read FMessage write FMessage;
|
|
end;
|
|
|
|
function FirstLine(const s: string): string;
|
|
var
|
|
NewLinePos: integer;
|
|
begin
|
|
NewLinePos := pos(LineEnding, s);
|
|
if NewLinePos > 0 then
|
|
Result := copy(s, 1, NewLinePos-1)
|
|
else
|
|
Result := s;
|
|
end;
|
|
|
|
{ TGUITestRunner }
|
|
|
|
procedure TGUITestRunner.actCopyExecute(Sender: TObject);
|
|
begin
|
|
Clipboard.AsText := XMLSynEdit.Lines.Text;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.actCutExecute(Sender: TObject);
|
|
begin
|
|
Clipboard.AsText := XMLSynEdit.Lines.Text;
|
|
XMLSynEdit.Lines.Clear;
|
|
end;
|
|
|
|
procedure TGUITestRunner.GUITestRunnerCreate(Sender: TObject);
|
|
begin
|
|
barColor := clGreen;
|
|
TestTree.Items.Clear;
|
|
BuildTree(TestTree.Items.AddObject(nil, rsAllTests, GetTestRegistry),
|
|
GetTestRegistry);
|
|
PageControl1.ActivePage := tsTestTree;
|
|
//
|
|
BtnRun.Caption:= sbtnRun;
|
|
btnRunHighlighted.Caption := sbtnRunH;
|
|
BtnClose.Caption:= sbtnClose;
|
|
tsTestTree.Caption:= stshTree;
|
|
tsResultsXML.Caption:= stshResults;
|
|
//
|
|
Caption:= sfrmGUITest;
|
|
RunAction.Caption:= sactRunAction;
|
|
RunAction.Hint:= sactRunActionH;
|
|
ActCloseForm.Caption:= sactCloseForm;
|
|
ActCloseForm.Hint:= sactCloseFormH;
|
|
ActCheckCurrentSuite.Caption:= sactCheckCurrentSuite;
|
|
ActUncheckCurrentSuite.Caption:= sactUncheckCurrentSuite;
|
|
ActCheckAll.Caption:= sactCheckAll;
|
|
ActUncheckAll.Caption:= sactUncheckAll;
|
|
ActRunHighlightedTest.Caption:= sactRunHighlightedTest;
|
|
miRunTest.Caption:= smiRunTest;
|
|
miShowfailureMsg.Caption:= smiShowfail;
|
|
MenuItem1.Caption:= smiCopy;
|
|
MenuItem2.Caption:= smiCut;
|
|
MenuItem3.Caption:= smiCopyClipbrd;
|
|
// Select the first entry in the tree in order to immediately activate the
|
|
// Run All tests button:
|
|
if TestTree.Items.Count>0 then begin
|
|
TestTree.Items.SelectOnlyThis(TestTree.Items[0]);
|
|
TestTree.Items[0].Expand(False);
|
|
end;
|
|
end;
|
|
|
|
procedure TGUITestRunner.RunExecute(Sender: TObject);
|
|
begin
|
|
testSuite := GetTestRegistry;
|
|
TestTree.Selected := TestTree.Items[0];
|
|
RunTest(testSuite);
|
|
end;
|
|
|
|
procedure TGUITestRunner.ActCloseFormExecute(Sender: TObject);
|
|
begin
|
|
Close;
|
|
end;
|
|
|
|
procedure TGUITestRunner.ActCheckAllExecute(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to TestTree.Items.Count -1 do
|
|
TestTree.Items[i].StateIndex := ord(tsChecked);
|
|
end;
|
|
|
|
procedure TGUITestRunner.ActCheckCurrentSuiteExecute(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if (TestTree.Selected <> nil) and (TestTree.Selected.Data <> nil) then
|
|
begin
|
|
TestTree.Selected.StateIndex := ord(tsChecked);
|
|
for i := 0 to TestTree.Selected.Count - 1 do
|
|
TestTree.Selected.Items[i].StateIndex := ord(tsChecked);
|
|
end;
|
|
end;
|
|
|
|
procedure TGUITestRunner.ActRunHighlightedTestExecute(Sender: TObject);
|
|
begin
|
|
if (TestTree.Selected <> nil) and (TestTree.Selected.Data <> nil) then
|
|
begin
|
|
testSuite := TTest(TestTree.Selected.Data);
|
|
end;
|
|
RunTest(testSuite);
|
|
end;
|
|
|
|
procedure TGUITestRunner.ActUncheckAllExecute(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to TestTree.Items.Count -1 do
|
|
TestTree.Items[i].StateIndex := ord(tsUnChecked);
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.ActRunHighLightedTestUpdate(Sender: TObject);
|
|
begin
|
|
(Sender as TAction).Enabled := ((TestTree.Selected <> nil)
|
|
and (TestTree.Selected.Data <> nil));
|
|
end;
|
|
|
|
procedure TGUITestRunner.ActUncheckCurrentSuiteExecute(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if (TestTree.Selected <> nil) and (TestTree.Selected.Data <> nil) then
|
|
begin
|
|
TestTree.Selected.StateIndex := ord(tsUnchecked);
|
|
for i := 0 to TestTree.Selected.Count - 1 do
|
|
TestTree.Selected.Items[i].StateIndex := ord(tsUnChecked);
|
|
end;
|
|
end;
|
|
|
|
procedure TGUITestRunner.GUITestRunnerShow(Sender: TObject);
|
|
begin
|
|
if (ParamStrUTF8(1) = '--now') or (ParamStrUTF8(1) = '-n') then
|
|
RunExecute(Self);
|
|
end;
|
|
|
|
procedure TGUITestRunner.MenuItem3Click(Sender: TObject);
|
|
begin
|
|
Clipboard.AsText := Memo1.Lines.Text;
|
|
end;
|
|
|
|
procedure TGUITestRunner.SaveAsToolButtonClick(Sender: TObject);
|
|
begin
|
|
if SaveDialog.Execute then
|
|
XMLSynEdit.Lines.SaveToFile(SaveDialog.FileName);
|
|
end;
|
|
|
|
procedure TGUITestRunner.TestTreeCreateNodeClass(Sender: TCustomTreeView;
|
|
var NodeClass: TTreeNodeClass);
|
|
begin
|
|
NodeClass := TMessageTreeNode;
|
|
end;
|
|
|
|
procedure TGUITestRunner.TestTreeMouseDown(Sender: TOBject;
|
|
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
|
|
procedure ChangeCheck(aNode: TTreeNode; aCheck: TTreeNodeState);
|
|
var
|
|
i: integer;
|
|
n: TTreeNode;
|
|
begin
|
|
if Assigned(aNode) then
|
|
begin
|
|
aNode.StateIndex := ord(aCheck);
|
|
if (TTest(aNode.Data) is TTestSuite) then
|
|
for i := 0 to aNode.Count - 1 do
|
|
begin
|
|
n := aNode.Items[i];
|
|
ChangeCheck(n, aCheck);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ht: THitTests;
|
|
lNode: TTreeNode;
|
|
begin
|
|
ht := (Sender as TTreeview).GetHitTestInfoAt(X, Y);
|
|
if htOnStateIcon in ht then
|
|
begin
|
|
lNode := (Sender as TTreeview).GetNodeAt(X, Y);
|
|
case lNode.StateIndex of
|
|
0: ChangeCheck(lNode, tsChecked);
|
|
1: ChangeCheck(lNode, tsUnChecked);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.TestTreeSelectionChanged(Sender: TObject);
|
|
begin
|
|
if ((Sender as TTreeView).Selected <> nil) and
|
|
Assigned((Sender as TTreeview).Selected.Data) then
|
|
begin
|
|
btnRunHighlighted.Visible := true;
|
|
btnRunHighlighted.Caption := rsRun + (Sender as TTreeview).Selected.Text;
|
|
end
|
|
else
|
|
begin
|
|
btnRunHighlighted.Visible := false;
|
|
btnRunHighlighted.Caption := '';
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.actCopyErrorMsgExecute(Sender: TObject);
|
|
begin
|
|
ClipBoard.AsText := (TestTree.Selected as TMessageTreeNode).Message;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.actCopyErrorMsgUpdate(Sender: TObject);
|
|
begin
|
|
(Sender as TAction).Enabled := Assigned(TestTree.selected) and
|
|
(Copy(TestTree.Selected.Text, 1, 9) = 'Message: ');
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.pbBarPaint(Sender: TObject);
|
|
var
|
|
msg: string;
|
|
alltests: integer;
|
|
OldStyle: TBrushStyle;
|
|
begin
|
|
with (Sender as TPaintBox) do
|
|
begin
|
|
Canvas.Lock;
|
|
Canvas.Brush.Color := clSilver;
|
|
Canvas.Rectangle(0, 0, Width, Height);
|
|
Canvas.Font.Color := clWhite;
|
|
if Assigned(TestSuite) then
|
|
begin
|
|
alltests := TestSuite.CountTestCases;
|
|
if alltests - skipsCounter <> 0 then
|
|
begin
|
|
if FailureCounter + ErrorCounter = 0 then
|
|
barColor := clGreen;
|
|
Canvas.Brush.Color := barColor;
|
|
Canvas.Rectangle(0, 0, round(TestsCounter / (alltests - skipsCounter) * Width), Height);
|
|
msg := Format(rsRuns, [IntToStr(TestsCounter), IntToStr(alltests -
|
|
skipsCounter)]);
|
|
msg := Format(rsErrors, [msg, IntToStr(ErrorCounter)]);
|
|
msg := Format(rsFailures, [msg, IntToStr(FailureCounter)]);
|
|
OldStyle := Canvas.Brush.Style;
|
|
Canvas.Brush.Style := bsClear;
|
|
Canvas.Textout(10, 10, msg);
|
|
Canvas.Brush.Style := OldStyle;
|
|
end;
|
|
end;
|
|
Canvas.UnLock;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.BuildTree(rootNode: TTreeNode; aSuite: TTestSuite);
|
|
var
|
|
node: TTreeNode;
|
|
i: integer;
|
|
begin
|
|
rootNode.StateIndex := Ord(tsChecked);
|
|
for i := 0 to ASuite.Tests.Count - 1 do
|
|
begin
|
|
node := TestTree.Items.AddChildObject(rootNode, ASuite.Test[i].TestName, ASuite.Test[i]);
|
|
if ASuite.Test[i] is TTestSuite then
|
|
BuildTree(Node, TTestSuite(ASuite.Test[i]))
|
|
else
|
|
if TObject(ASuite.Test[i]).InheritsFrom(TTestDecorator) then
|
|
BuildTree(Node, TTestSuite(TTestDecorator(ASuite.Test[i]).Test));
|
|
node.ImageIndex := imgGrayBall;
|
|
node.SelectedIndex := imgGrayBall;
|
|
node.StateIndex := ord(tsChecked);
|
|
end;
|
|
ResetNodeColors;
|
|
end;
|
|
|
|
|
|
function TGUITestRunner.FindNode(aTest: TTest): TTreeNode;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := nil;
|
|
for i := 0 to TestTree.Items.Count -1 do
|
|
if (TTest(TestTree.Items[i].data) = aTest) then
|
|
begin
|
|
Result := TestTree.Items[i];
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.ResetNodeColors;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to TestTree.Items.Count - 1 do
|
|
begin
|
|
TestTree.Items[i].ImageIndex := imgGrayBall;
|
|
TestTree.Items[i].SelectedIndex := imgGrayBall;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.PaintNodeError(aNode: TTreeNode);
|
|
begin
|
|
while Assigned(aNode) do
|
|
begin
|
|
aNode.ImageIndex := imgRedBall;
|
|
aNode.SelectedIndex := imgRedBall;
|
|
if aNode.AbsoluteIndex<>0 then begin
|
|
aNode.Expand(True);
|
|
end;
|
|
aNode := aNode.Parent;
|
|
if Assigned(aNode) and
|
|
((aNode.ImageIndex in [imgGreenBall, imgPurpleBall, imgGrayBall, imgBlueBall]) or
|
|
(ANode.ImageIndex = -1)) then
|
|
PaintNodeError(aNode);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.PaintNodeFailure(aNode: TTreeNode);
|
|
begin
|
|
while Assigned(aNode) do
|
|
begin
|
|
if ((aNode.ImageIndex in [imgGreenBall, imgGrayBall, imgBlueBall]) or
|
|
(ANode.ImageIndex = -1)) then
|
|
begin
|
|
aNode.ImageIndex := imgPurpleBall;
|
|
aNode.SelectedIndex := imgPurpleBall;
|
|
if aNode.AbsoluteIndex<>0 then begin
|
|
aNode.Expand(true);
|
|
end;
|
|
end;
|
|
aNode := aNode.Parent;
|
|
if Assigned(aNode) and ((aNode.ImageIndex in [imgGreenBall, imgGrayBall, imgBlueBall]) or
|
|
(ANode.ImageIndex = -1)) then
|
|
PaintNodeFailure(aNode);
|
|
end;
|
|
end;
|
|
|
|
procedure TGUITestRunner.PaintNodeIgnore(aNode: TTreeNode);
|
|
// Test results with Ignore
|
|
var
|
|
noFailedSibling: boolean;
|
|
i: integer;
|
|
begin
|
|
if Assigned(aNode) then
|
|
begin
|
|
if ((aNode.ImageIndex in [imgGrayBall, imgBlueBall]) or
|
|
(ANode.ImageIndex = -1)) then
|
|
begin
|
|
aNode.ImageIndex := imgGreenBall;
|
|
aNode.SelectedIndex := imgGreenBall;
|
|
end;
|
|
end;
|
|
if Assigned(aNode.Parent) then
|
|
if aNode.Index = aNode.Parent.Count -1 then
|
|
begin
|
|
aNode := aNode.Parent;
|
|
noFailedSibling := true;
|
|
for i := 0 to aNode.Count -2 do
|
|
begin
|
|
if aNode.Items[i].ImageIndex <> imgGreenBall then
|
|
noFailedSibling := false;;
|
|
end;
|
|
if (aNode.ImageIndex = imgBlueBall) and
|
|
noFailedSibling then
|
|
PaintNodeIgnore(aNode);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.PaintNodeNonFailed(aNode: TTreeNode);
|
|
var
|
|
noFailedSibling: boolean;
|
|
i: integer;
|
|
begin
|
|
if Assigned(aNode) then
|
|
begin
|
|
if ((aNode.ImageIndex in [imgGrayBall, imgBlueBall]) or
|
|
(ANode.ImageIndex = -1)) then
|
|
begin
|
|
aNode.ImageIndex := imgGreenBall;
|
|
aNode.SelectedIndex := imgGreenBall;
|
|
end;
|
|
end;
|
|
if Assigned(aNode.Parent) then
|
|
if aNode.Index = aNode.Parent.Count -1 then
|
|
begin
|
|
aNode := aNode.Parent;
|
|
noFailedSibling := true;
|
|
for i := 0 to aNode.Count -2 do
|
|
begin
|
|
if aNode.Items[i].ImageIndex <> imgGreenBall then
|
|
noFailedSibling := false;;
|
|
end;
|
|
if (aNode.ImageIndex = imgBlueBall) and
|
|
noFailedSibling then
|
|
PaintNodeNonFailed(aNode);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.PaintNodeBusy(aNode: TTreeNode);
|
|
var
|
|
BusySibling: boolean;
|
|
i: integer;
|
|
begin
|
|
if Assigned(aNode) then
|
|
begin
|
|
aNode.ImageIndex := imgBlueBall;
|
|
aNode.SelectedIndex := imgBlueBall;
|
|
end;
|
|
if Assigned(aNode.Parent) then
|
|
begin
|
|
if aNode.Index = aNode.Parent.Count -1 then
|
|
begin
|
|
aNode := aNode.Parent;
|
|
BusySibling := true;
|
|
for i := 0 to aNode.Count -2 do
|
|
begin
|
|
if aNode.Items[i].ImageIndex <> imgGreenBall then
|
|
BusySibling := false;;
|
|
end;
|
|
if (aNode.ImageIndex = imgBlueBall) and
|
|
BusySibling then
|
|
PaintNodeBusy(aNode);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.MemoLog(LogEntry: string);
|
|
begin
|
|
Memo1.Lines.Add(TimeToStr(Now) + ' - ' + LogEntry);
|
|
end;
|
|
|
|
procedure TGUITestRunner.EnableRunActions(AValue: boolean);
|
|
begin
|
|
ActRunHighlightedTest.Enabled := AValue;
|
|
RunAction.Enabled := AValue;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.AddFailure(ATest: TTest; AFailure: TTestFailure);
|
|
var
|
|
FailureNode: TTreeNode;
|
|
node: TMessageTreeNode;
|
|
begin
|
|
FailureNode := FindNode(ATest);
|
|
if Assigned(FailureNode) then
|
|
begin
|
|
node := TestTree.Items.AddChild(FailureNode,
|
|
Format(rsMessage, [FirstLine(AFailure.ExceptionMessage)]))
|
|
as TMessageTreeNode;
|
|
if not(AFailure.IsIgnoredTest) then
|
|
begin
|
|
// Genuine failure
|
|
node.Message := AFailure.ExceptionMessage;
|
|
node.ImageIndex := imgWarningSign;
|
|
node.SelectedIndex := imgWarningSign;
|
|
node := TestTree.Items.AddChild(FailureNode,
|
|
Format(rsException, [AFailure.ExceptionClassName])) as TMessageTreeNode;
|
|
node.ImageIndex := imgWarningSign;
|
|
node.SelectedIndex := imgWarningSign;
|
|
PaintNodeFailure(FailureNode);
|
|
end
|
|
else
|
|
begin
|
|
// Although reported as a failure, the test was set up
|
|
// to be ignored so it is actually a success of sorts
|
|
node.Message := AFailure.ExceptionMessage;
|
|
node.ImageIndex := imgGreenBall;
|
|
node.SelectedIndex := imgGreenBall;
|
|
node := TestTree.Items.AddChild(FailureNode,
|
|
Format(rsException, [AFailure.ExceptionClassName])) as TMessageTreeNode;
|
|
node.ImageIndex := imgGreenBall;
|
|
node.SelectedIndex := imgGreenBall;
|
|
PaintNodeIgnore(FailureNode);
|
|
end;
|
|
end;
|
|
|
|
if not(AFailure.IsIgnoredTest) then
|
|
begin
|
|
Inc(failureCounter);
|
|
if errorCounter = 0 then
|
|
barColor := clFuchsia;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.AddError(ATest: TTest; AError: TTestFailure);
|
|
var
|
|
ErrorNode, node: TTreeNode;
|
|
MessageNode: TMessageTreeNode;
|
|
begin
|
|
ErrorNode := FindNode(ATest);
|
|
if Assigned(ErrorNode) then
|
|
begin
|
|
MessageNode := TestTree.Items.AddChild(ErrorNode,
|
|
Format(rsExceptionMes, [FirstLine(AError.ExceptionMessage)]))
|
|
as TMessageTreeNode;
|
|
MessageNode.Message := AError.ExceptionMessage;
|
|
MessageNode.ImageIndex := imgWarningSign;
|
|
MessageNode.SelectedIndex := imgWarningSign;
|
|
node := TestTree.Items.AddChild(ErrorNode, Format(rsExceptionCla, [
|
|
AError.ExceptionClassName]));
|
|
node.ImageIndex := imgWarningSign;
|
|
node.SelectedIndex := imgWarningSign;
|
|
if (AError.SourceUnitName <> '') and
|
|
(AError.FailedMethodName <> '')
|
|
then
|
|
begin
|
|
node := TestTree.Items.AddChild(ErrorNode, Format(rsUnitName, [
|
|
AError.SourceUnitName]));
|
|
node.ImageIndex := imgInfoSign;
|
|
node.SelectedIndex := imgInfoSign;
|
|
node := TestTree.Items.AddChild(ErrorNode, Format(rsMethodName, [
|
|
AError.FailedMethodName]));
|
|
node.ImageIndex := imgInfoSign;
|
|
node.SelectedIndex := imgInfoSign;
|
|
node := TestTree.Items.AddChild(ErrorNode, Format(rsLineNumber, [IntToStr(
|
|
AError.LineNumber)]));
|
|
node.ImageIndex := imgInfoSign;
|
|
node.SelectedIndex := imgInfoSign;
|
|
end;
|
|
PaintNodeError(ErrorNode);
|
|
end;
|
|
Inc(errorCounter);
|
|
barColor := clRed;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.StartTest(ATest: TTest);
|
|
var
|
|
Node: TTreeNode;
|
|
begin
|
|
TestTree.BeginUpdate;
|
|
Node := FindNode(ATest);
|
|
Node.DeleteChildren;
|
|
PaintNodeBusy(Node);
|
|
if Node.Level=1 then begin
|
|
Node.MakeVisible;
|
|
end;
|
|
if assigned(Node.Parent) and (Node.Parent.Level=1) then begin
|
|
Node.Parent.MakeVisible;
|
|
end;
|
|
Application.ProcessMessages;
|
|
TestTree.EndUpdate;
|
|
end;
|
|
|
|
|
|
procedure TGUITestRunner.EndTest(ATest: TTest);
|
|
var
|
|
Node: TTreeNode;
|
|
begin
|
|
TestTree.BeginUpdate;
|
|
Inc(testsCounter);
|
|
Node := FindNode(ATest);
|
|
PaintNodeNonFailed(Node);
|
|
pbbar.Refresh;
|
|
Application.ProcessMessages;
|
|
TestTree.EndUpdate;
|
|
end;
|
|
|
|
procedure TGUITestRunner.RunTest(ATest: TTest);
|
|
procedure SkipUncheckedTests(aResult: TTestResult; aNode: TTreeNode);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if (aNode.StateIndex = ord(tsUnChecked)) and (TTest(aNode.Data) is TTestCase) then
|
|
aResult.AddToSkipList(TTest(aNode.Data) as TTestCase);
|
|
for i := 0 to aNode.Count - 1 do
|
|
SkipUncheckedTests(aResult, aNode.Items[i]);
|
|
end;
|
|
|
|
var
|
|
TestResult:TTestResult;
|
|
w: TXMLResultsWriter;
|
|
m: TMemoryStream;
|
|
|
|
begin
|
|
barcolor := clGreen;
|
|
ResetNodeColors;
|
|
failureCounter := 0;
|
|
errorCounter := 0;
|
|
testsCounter := 0;
|
|
skipsCounter := 0;
|
|
EnableRunActions(false);
|
|
TestResult := TTestResult.Create;
|
|
try
|
|
SkipUncheckedTests(TestResult, TestTree.Selected);
|
|
skipsCounter := TestResult.NumberOfSkippedTests;
|
|
TestResult.AddListener(self);
|
|
pbBar.Invalidate;
|
|
w := TXMLResultsWriter.Create(nil);
|
|
try
|
|
w.FileName := 'null'; // prevents output to the console
|
|
TestResult.AddListener(w);
|
|
|
|
MemoLog(Format(rsRunning, [TestTree.Selected.Text]));
|
|
aTest.Run(TestResult);
|
|
MemoLog(Format(rsNumberOfExec, [IntToStr(TestResult.RunTests),
|
|
FormatDateTime('hh:nn:ss.zzz', Now - TestResult.StartingTime)]));
|
|
|
|
w.WriteResult(TestResult);
|
|
m := TMemoryStream.Create;
|
|
try
|
|
try
|
|
WriteXMLFile(w.Document, m);
|
|
m.Position := 0;
|
|
XMLSynEdit.Lines.LoadFromStream(m);
|
|
except
|
|
on E: Exception do
|
|
XMLSynEdit.Lines.Text:='WriteXMLFile exception: '+E.ClassName+'/'+E.Message;
|
|
end;
|
|
finally
|
|
m.Free;
|
|
end;
|
|
pbBar.Invalidate;
|
|
finally
|
|
w.Free;
|
|
end;
|
|
finally
|
|
EnableRunActions(true);
|
|
|
|
TestResult.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TGUITestRunner.StartTestSuite(ATestSuite: TTestSuite);
|
|
begin
|
|
// do nothing
|
|
end;
|
|
|
|
procedure TGUITestRunner.EndTestSuite(ATestSuite: TTestSuite);
|
|
begin
|
|
// do nothing
|
|
end;
|
|
|
|
procedure TranslateResStrings;
|
|
var
|
|
Lang, FallbackLang, S: String;
|
|
|
|
begin
|
|
GetLanguageIDs(Lang,FallbackLang); // in unit gettext
|
|
S:=AppendPathDelim(AppendPathDelim(ExtractFileDir(ParamStr(0))) + 'languages');
|
|
if FallbackLang = 'pt' then
|
|
Lang := 'pb';
|
|
TranslateUnitResourceStrings('guitestrunner',S+'guitestrunner.%s.po', Lang,FallbackLang);
|
|
end;
|
|
|
|
initialization
|
|
TranslateResStrings;
|
|
|
|
end.
|
|
|