Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding VCL GUI Logger #147

Merged
merged 15 commits into from
Jun 1, 2016
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
103 changes: 103 additions & 0 deletions DUnitX.Assert.Ex.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{***************************************************************************}
{ }
{ DUnitX }
{ }
{ Copyright (C) 2016 Vincent Parrett }
{ }
{ vincent@finalbuilder.com }
{ http://www.finalbuilder.com }
{ }
{ }
{***************************************************************************}
{ }
{ 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 DUnitX.Assert.Ex;

// This unit should contain DUnitX specific Assert commands and mechanisms
// in order to keep DUnitX.Assert framework neutral and usable in other
// test frameworks such as DUnit.

interface

{$I DUnitX.inc}

uses
DUnitX.Assert,
DUnitX.ComparableFormat;

type
Assert = class(DUnitX.Assert.Assert)
private
class procedure FailStrCompare(const expected, actual: string; const compformat: TDUnitXComparableFormatClass = nil; const message : string = ''; const errorAddrs : pointer = nil);
public
class procedure AreEqual(const expected, actual : string; const compformat: TDUnitXComparableFormatClass; const ignoreCase : boolean; const message : string = ''); overload;
class procedure AreEqual(const expected, actual : string; const compformat: TDUnitXComparableFormatClass; const message : string = ''); overload;

//Reintroduced from Assert to throw ETestFailureStrCompare
class procedure AreEqual(const expected : string; const actual : string; const ignoreCase : boolean; const message : string = ''); reintroduce; overload;
//Reintroduced from Assert to throw ETestFailureStrCompare
class procedure AreEqual(const expected : string; const actual : string; const message : string = ''); reintroduce; overload;
end;

implementation

uses
{$IFDEF USE_NS}
System.SysUtils,
{$ELSE}
SysUtils,
{$ENDIF}
DUnitX.ResStrs,
DUnitX.Exceptions;

class procedure Assert.AreEqual(const expected, actual: string; const compformat: TDUnitXComparableFormatClass; const ignoreCase: boolean; const message: string);
begin
DoAssert;
if ignoreCase then
begin
if not SameText(expected,actual) then
FailStrCompare(expected, actual, compformat, message, ReturnAddress);
end
else if not SameStr(expected,actual) then
FailStrCompare(expected, actual, compformat, message, ReturnAddress);
end;

class procedure Assert.AreEqual(const expected, actual: string; const compformat: TDUnitXComparableFormatClass; const message: string);
begin
AreEqual(expected, actual, compformat, IgnoreCaseDefault, message);
end;

class procedure Assert.AreEqual(const expected, actual : string; const ignoreCase : boolean; const message: string);
begin
AreEqual(expected, actual, nil, ignoreCase, message);
end;

class procedure Assert.AreEqual(const expected : string; const actual : string; const message : string);
begin
Assert.AreEqual(expected, actual, IgnoreCaseDefault, message);
end;

class procedure Assert.FailStrCompare(const expected, actual: string; const compformat : TDUnitXComparableFormatClass; const message: string; const errorAddrs: pointer);
begin
//If we have been given a return then use it. (makes the exception appear on level above in the stack)
if errorAddrs <> nil then
raise ETestFailureStrCompare.Create(expected, actual, message, compformat) at errorAddrs
else
//Otherwise use the return address we can currently get to for where to raise the exception
raise ETestFailureStrCompare.Create(expected, actual, message, compformat) at ReturnAddress;
end;

end.
75 changes: 68 additions & 7 deletions DUnitX.Assert.pas
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@

unit DUnitX.Assert;

interface
// This unit should ONLY contain Assert commands and mechanisms that are
// not directly tied to DUnitX to keep the file neutral and usable in other
// test frameworks such as DUnit. DUnitX specific implementations should be
// implemented in DUnitX.Assert.Ex.pas

interface

{$I DUnitX.inc}

Expand All @@ -47,11 +51,13 @@ interface

Copy link
Contributor

@sglienke sglienke May 2, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

D'oh - did you understand what these fields were for? This was to not couple the assert class with the framework (yes, I could use this in a DUnit project!) but now you went back how it was before by hardcoding the exceptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize that is why this was done. There weren't any comments explaining that, so I thought it was just something left over from the past, or a way around a circular reference. I had to eliminate the "generic" exception because I couldn't get away with just message - I needed to add custom data to the exception. I could revert the changes and make some new exception classes, but dumb down to the lowest common denominator if any class var is nil (for instance, if fTestFailureStrCompare = nil, raise fTestFailure) and I think that would satisfy the requirement.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case you might want to add your new feature either as helper for the Assert class or via Event that can produce the proper exception. In any case try to keep Assert as simple as possible without cluttering it with special framework related cases (personally I see the diffing logic as special case).

I for example also had the problem of comparing long strings (xml) via unit test and the DUnit error message was not very helpful telling me that differs from so I implemented my own CheckEqualsString method that only shows a snippet where the strings differ and the position where that is)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Assert is going to need to stay framework-agnostic, then yes my changes will have to be done differently. I can't really go the helper route because you can only have one helper per class and the helper would also have to be included in the project or a uses clause (could confuse people), and that would limit anyone else from adding a helper later. One of my goals was to integrate this directly in Assert. While you consider the diffing logic a special case, it is not only for diffing, that is just how the GUI logger uses it. It could be used by automated systems to save the data out and add as artifacts in the CI so people could review the output in a more digestible format. The problem is the data that you are asserting is locked in a string error message which makes it hard to act on if desired.

While I knew Assert was supposed to remain as self-contained as possible (which it still is), I did not know it was supposed to remain framework independent (which it now is not because of the exceptions). I will see about getting the latter back - I am not exactly sure the best way to do that but will explore some options.

Assert = class
private
class var fIgnoreCaseDefault: boolean;
class var fOnAssert: TProc;
class var fTestFailure: ExceptClass;
class var fTestPass: ExceptClass;
class procedure CheckExceptionClass(E: Exception; const exceptionClass: ExceptClass);
class procedure CheckExceptionClassDescendant(E: Exception; const exceptionClass: ExceptClass);
protected
class function AddLineBreak(const msg: string): string;
class procedure DoAssert; inline;
public
Expand All @@ -76,9 +82,12 @@ Assert = class
class procedure AreEqual(const expected, actual : cardinal; const message : string = '');overload;
class procedure AreEqual(const expected, actual : boolean; const message : string = '');overload;

class procedure AreEqual(const expected, actual: TGUID; const message : string = '');overload;

class procedure AreEqualMemory(const expected : Pointer; const actual : Pointer; const size : Cardinal; const message : string = '');

class procedure AreNotEqual(const expected : string; const actual : string; const ignoreCase : boolean = true; const message : string = '');overload;
class procedure AreNotEqual(const expected : string; const actual : string; const ignoreCase : boolean; const message : string = '');overload;
class procedure AreNotEqual(const expected : string; const actual : string; const message : string = '');overload;

class procedure AreNotEqual(const expected, actual : Extended; const tolerance : Extended; const message : string = '');overload;
class procedure AreNotEqual(const expected, actual : Extended; const message : string = '');overload;
Expand All @@ -92,6 +101,7 @@ Assert = class
class procedure AreNotEqual<T>(const expected, actual : T; const message : string = '');overload;
{$ENDIF}
class procedure AreNotEqual(const expected, actual : Integer; const message : string = '');overload;
class procedure AreNotEqual(const expected, actual : TGUID; const message : string = '');overload;
class procedure AreNotEqualMemory(const expected : Pointer; const actual : Pointer; const size : Cardinal; const message : string = '');

class procedure AreSame(const expected, actual : TObject; const message : string = '');overload;
Expand Down Expand Up @@ -206,10 +216,14 @@ Assert = class
/// </summary>
class procedure WillNotRaiseAny(const AMethod : TTestMethod; const msg : string = ''); overload;

class procedure Contains(const theString : string; const subString : string; const ignoreCase : boolean = true; const message : string = '');overload;
class procedure DoesNotContain(const theString : string; const subString : string; const ignoreCase : boolean = true; const message : string = '');overload;
class procedure StartsWith(const subString : string; const theString : string;const ignoreCase : boolean = true; const message : string = '');
class procedure EndsWith(const subString : string; const theString : string;const ignoreCase : boolean = true; const message : string = '');
class procedure Contains(const theString : string; const subString : string; const ignoreCase : boolean; const message : string = ''); overload;
class procedure Contains(const theString : string; const subString : string; const message : string = ''); overload;
class procedure DoesNotContain(const theString : string; const subString : string; const ignoreCase : boolean; const message : string = ''); overload;
class procedure DoesNotContain(const theString : string; const subString : string; const message : string = ''); overload;
class procedure StartsWith(const subString : string; const theString : string; const ignoreCase : boolean; const message : string = ''); overload;
class procedure StartsWith(const subString : string; const theString : string; const message : string = ''); overload;
class procedure EndsWith(const subString : string; const theString : string; const ignoreCase : boolean; const message : string = ''); overload;
class procedure EndsWith(const subString : string; const theString : string; const message : string = ''); overload;
class procedure InheritsFrom(const descendant : TClass; const parent : TClass; const message : string = '');
{$IFDEF DELPHI_XE_UP}
//Delphi 2010 compiler bug breaks this
Expand All @@ -223,6 +237,9 @@ Assert = class
class property OnAssert: TProc read fOnAssert write fOnAssert;
class property TestFailure: ExceptClass read fTestFailure write fTestFailure;
class property TestPass: ExceptClass read fTestPass write fTestPass;
class property IgnoreCaseDefault: boolean read fIgnoreCaseDefault write fIgnoreCaseDefault;

class constructor Create;
end;

{$IFDEF DELPHI_XE_DOWN}
Expand Down Expand Up @@ -613,6 +630,11 @@ class procedure Assert.Pass(const message: string);
raise fTestPass.Create(message);
end;

class procedure Assert.StartsWith(const subString, theString, message: string);
begin
Assert.StartsWith(subString, theString, fIgnoreCaseDefault, message);
end;

class function Assert.Implements<T>(value: IInterface; const message: string) : T;
begin
DoAssert;
Expand Down Expand Up @@ -1016,7 +1038,7 @@ class procedure Assert.WillRaiseWithMessage(const AMethod: TTestLocalMethod; con

class procedure Assert.AreEqual(const expected : string; const actual : string; const message : string);
begin
Assert.AreEqual(expected, actual, true, message);
Assert.AreEqual(expected, actual, fIgnoreCaseDefault, message);
end;

class procedure Assert.AreEqual(const expected, actual : string; const ignoreCase : boolean; const message: string);
Expand Down Expand Up @@ -1052,6 +1074,11 @@ class procedure Assert.CheckExceptionClassDescendant(E: Exception;
FailFmt(SCheckExceptionClassDescError, [E.ClassName, exceptionClass.ClassName, E.message], ReturnAddress);
end;

class procedure Assert.Contains(const theString, subString, message: string);
begin
Contains(theString, subString, fIgnoreCaseDefault, message);
end;

class procedure Assert.Contains(const theString : string; const subString : string; const ignoreCase : boolean; const message : string);
begin
DoAssert;
Expand All @@ -1064,12 +1091,22 @@ class procedure Assert.Contains(const theString : string; const subString : stri
FailFmt(SStrDoesNotContain, [theString,subString,message], ReturnAddress);
end;

class constructor Assert.Create;
begin
fIgnoreCaseDefault := true;
end;

class procedure Assert.DoAssert;
begin
if Assigned(fOnAssert) then
fOnAssert();
end;

class procedure Assert.DoesNotContain(const theString, subString, message: string);
begin
DoesNotContain(theString, subString, fIgnoreCaseDefault, message);
end;

class procedure Assert.DoesNotContain(const theString, subString: string; const ignoreCase: boolean; const message: string);
begin
DoAssert;
Expand Down Expand Up @@ -1120,4 +1157,28 @@ class procedure Assert.StartsWith(const subString : string; const theString : st
FailFmt(SStrDoesNotStartWith, [theString,subString,message], ReturnAddress);
end;

class procedure Assert.AreEqual(const expected, actual: TGUID; const message: string);
begin
DoAssert;
if not IsEqualGUID(expected, actual) then
FailFmt(SUnexpectedErrorGUID, [GUIDToString(expected), GUIDToString(actual), message], ReturnAddress);
end;

class procedure Assert.AreNotEqual(const expected, actual: TGUID; const message: string);
begin
DoAssert;
if IsEqualGUID(expected, actual) then
FailFmt(SEqualsErrorGUID,[GUIDToString(expected), GUIDToString(actual), message], ReturnAddress);
end;

class procedure Assert.AreNotEqual(const expected, actual, message: string);
begin
AreNotEqual(expected, actual, fIgnoreCaseDefault, message);
end;

class procedure Assert.EndsWith(const subString, theString, message: string);
begin
Assert.EndsWith(subString, theString, fIgnoreCaseDefault, message);
end;

end.
41 changes: 41 additions & 0 deletions DUnitX.ComparableFormat.Csv.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{***************************************************************************}
{ }
{ DUnitX }
{ }
{ Copyright (C) 2016 Vincent Parrett }
{ }
{ vincent@finalbuilder.com }
{ http://www.finalbuilder.com }
{ }
{ }
{***************************************************************************}
{ }
{ 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 DUnitX.ComparableFormat.Csv;

interface

{$I DUnitX.inc}

uses
DUnitX.ComparableFormat;

type
TDUnitXComparableFormatCsv = class abstract(TDUnitXComparableFormat);

implementation

end.
41 changes: 41 additions & 0 deletions DUnitX.ComparableFormat.Xml.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{***************************************************************************}
{ }
{ DUnitX }
{ }
{ Copyright (C) 2016 Vincent Parrett }
{ }
{ vincent@finalbuilder.com }
{ http://www.finalbuilder.com }
{ }
{ }
{***************************************************************************}
{ }
{ 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 DUnitX.ComparableFormat.Xml;

interface

{$I DUnitX.inc}

uses
DUnitX.ComparableFormat;

type
TDUnitXComparableFormatXml = class abstract(TDUnitXComparableFormat);

implementation

end.
39 changes: 39 additions & 0 deletions DUnitX.ComparableFormat.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{***************************************************************************}
{ }
{ DUnitX }
{ }
{ Copyright (C) 2016 Vincent Parrett }
{ }
{ vincent@finalbuilder.com }
{ http://www.finalbuilder.com }
{ }
{ }
{***************************************************************************}
{ }
{ 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 DUnitX.ComparableFormat;

interface

{$I DUnitX.inc}

type
TDUnitXComparableFormat = class abstract(TObject);
TDUnitXComparableFormatClass = class of TDUnitXComparableFormat;

implementation

end.
Loading