Sunday, 24 February 2013

Using Delphi code coverage

I couldn't find a good self-explanatory example for the usage of Delphi-code-coverage tool so here you will find a simple example from top to bottom. The idea is really simple; I have a set of units which I want to know whether they are covered by my unit tests or not. Even though there is a lot of information about the project, I couldn't find a really good example explaining all the details about How to properly set up the project, folders, flags, etc. I have used the Delphi-code-coverage-wizard which is great to generate the initial structure (batch file + list of paths + units) but I went manual from there as I couldn't get any output.
I must say that both projects are really good and that's why I'm giving them an opportunity as I want to test the coverage of my projects under Delphi XE.
First step is to correctly identify where your source code is and your unit tests are. This step is really important as to correctly set-up the code coverage project. All my testing code is under my repository and available here: Delphi-repositoty. For this example I'm using a very simple example where I have a unique unit test which tries to cover two units (thundax.AbstractFactory.pas and thundax.Prototype.pas).

My unit test project is called thundax.DesignPatternsTest.exe which has 2 tests:
Now I want to know if those two unit tests cover my previously defined units (thundax.AbstractFactory.pas and thundax.Prototype.pas).

Download Delphi-Code-Coverage and leave it under your bin\ folder or where your test.exe application is (in my case thundax.DesignPatternsTest.exe).
Create two text files called dcov_paths.lst and dcov_units.lst. You can use Delphi-code-coverage-wizard to set up the initial structure, but I would rather go manual as I have more control of the execution.

- The first file (dcov_paths.lst) will contain the path to your source code:
C:\ThundaxDelphiRepository\thundax-delphi-personal-repository\src\Design Patterns\

- The second file (dcov_units.lst) will contain the list of unit tests you want to check whether they cover your code or not.
thundax.Prototype
thundax.AbstractFactory

Your projects needs to have debug information generating a detailed Map file:

Now we can create a small batch file (dcov_execute.bat) or run the following command from the command line tool:
CodeCoverage.exe -e "thundax.DesignPatternsTest.exe" -m "thundax.DesignPatternsTest.map" -ife -uf dcov_units.lst -spf dcov_paths.lst -od ".\" -lt -html -xml -emma

This is the configuration that works for me, where:
  • -e identifies the executable to run (in this case the Unit test framework).
  • -m identifies the map file (the map file contains all the debugging symbols).
  • -ife include file extension (if you are using generics.collections use this option).
  • -uf list of your units (source code, not your unit tests code).
  • -spf list of source directories.
  • -od Output directory (".\" gets  the current).
  • -lt generates log file. (Delphi-Code-Coverage-Debug.txt).
  • -html Html output
  • -xml Xml output
  • -emma EMMA output
Once the line has been run, you should get the correct output files:
  • CodeCoverage_summary.html (Html output)
  • CodeCoverage_summary.xml (xml output)
  • coverage.es (EMMA output)
  • Delphi-Code-Coverage-Debug.txt 
  • thundax.AbstractFactory(thundax.AbstractFactory.pas).html (Your report)
  • thundax.Prototype(thundax.Prototype.pas).html (Your report)

If you open the summary you will see the total of lines and %age covered by your test:

And you can inspect the files by doing click on the links:
As you can see, one of the units is only 69% covered. Once we inspect the file we can see that there are lines (highlighted in blue) which are not covered by my unit tests and the green ones which are.
I hope you find this useful and start using it.
Jordi

Sunday, 3 February 2013

Macro actions (mouse and keyboard) with Delphi

I know this could be an old topic, but I find really useful to know how to send the key strokes or how to simulate the mouse click using our favourite language: Delphi. It's for this, that I have create a small open source project where you can find one of my latest tools "thundax macro actions". In here you will be able to add a sequence of actions e.g move the mouse to a particular position, perform right click or left click and type any kind of message or just press a special key like CONTROL or F1, etc. to automate repetitive tasks or actions that you usually perform and that you need to do as quick as possible. As I always automate everything, it was a really nice idea to come up with this solution and it is quite pleasant to see it working for you. All the source code is available and it is free for anybody to inspect, comment and give suggestions to improve this little tool. I have used the tool to perform a series of operations without me interacting and it saved me loads of time.

Imagine that you need to go through a text where you need to add an extra character or something which would be really tedious to perform manually. With this stand-alone tool, you will be able to perform the same operation with just defining the list of actions to execute and off you go.

The code is really easy to understand and the way to send the key strokes or to perform the left/right click of the mouse are really easy to do. You'll find hundreds of examples on the net:

Here is the tool:

Download it from the following link:
There are still loads of things to do to complete the tool, but at least there is a working solution which can now be used.

Related links:

Monday, 14 January 2013

Using Quick Sequence Diagram Editor (sdedit) in your Delphi applications

My first article of the year is about Quick Sequence Diagram Editor (sdedit), a tool for creating UML sequence diagrams from textual descriptions of objects and messages that follow a really easy syntax. The ones who follow my blog will realise that I love logging details for my applications and with this component you will be able to create a nice sequence diagram from any of your real business scenarios. I have been dealing lately with loads of different multi-threaded applications and it was when doing some of my homework for Uni when I found this marvellous gem.
I have written a small and quite straight-forward wrapper in Delphi which will help you to generate the ".sdx" file and run the converter calling the library via java command. All the source code and examples can be found in my personal repository on Google code: thundax-delphi-personal-repository where I keep all my tests and things I want to try out.
With few easy callings, you can instantiate the TUML class and use "start" and "call" methods to generate things like this:

More complex example:


It is really useful when doing reports or to display any of your business scenarios in a nice way. One of my tasks was to create a small application which would send messages across different instances in a supercomputer and this is the best way I found to really present what was going on in there. You can generate huge diagrams and sdedit will cope with it.

Here is the piece of code for the wrapper:
type
  TUML = class(TObject)
  private
    FFormat: string;
    FOutFile: TLog;
    FUmlFileName: string;
  public
    property Format: string read FFormat write FFormat;
    constructor Create(umlFileName: string);
    class function Start(umlFileName: string): TUML;
    procedure Define(name : String; kind : String); overload;
    procedure Define(); overload;
    procedure Call(caller: string; callee: string; method: string; params: string); overload;
    procedure Call(caller: string; callee: string; method: string; params: string; result: string); overload;
    procedure Convert();
  end;

const
  DefaultFormat = 'jpg';
  DefaultLocationLibrary = '..\..\thirdpartylibs\sdedit\sdedit.jar';

implementation

uses
  ShellAPI, Windows;

{ TUML }

procedure TUML.Call(caller, callee, method, params: string);
begin
  FOutFile.print(caller + ':' + callee + '.' + method + '(' + params + ')');
end;

procedure TUML.Call(caller, callee, method, params, result: string);
begin
  FOutFile.print(caller + ':' + result + '=' + callee + '.' + method + '(' + params + ')');
end;

procedure TUML.Convert();
var
  params: string;
  FileINFormat: string;
  FileOutFormat: string;
begin
  FileINFormat := FUmlFileName + '.sdx';
  FileOutFormat := FUmlFileName + '.' + FFormat;
  params := '-jar ' + DefaultLocationLibrary + ' -o ' + FileOutFormat + ' -t ' + FFormat + ' -r landscape ' + FileINFormat;
  ShellExecute(0, nil, 'java.exe', PChar(params), nil, SW_HIDE);
end;

constructor TUML.Create(umlFileName: string);
begin
  FOutFile := TLog.Start(umlFileName + '.sdx');
  FFormat := DefaultFormat;
  FUmlFileName := umlFileName;
end;

procedure TUML.Define;
begin
  FOutFile.print('');
end;

procedure TUML.Define(name, kind: String);
begin
  FOutFile.print(name + ':' + kind);
end;

class function TUML.Start(umlFileName: string): TUML;
begin
  result := Create(umlFileName);
end;
And this is a more realistic approach, where we can have for example 3 different threads which will perform different operations at a different times. All of them are asynchronous and they use the TUML class to show how long every thread took to finish its processing.

Example:
procedure TestTUML.TestUMLDiagramAsynchronous;
var
  lock: TCriticalSection;
  thread1, thread2, thread3: TThread;
  sw : TStopWatch;
begin
  if fileExists(FUmlFileName + '.sdx') then
    DeleteFile(PChar(FUmlFileName + '.sdx'));

  if fileExists(FUmlFileName + '.jpg') then
    DeleteFile(PChar(FUmlFileName + '.jpg'));

  lock := TCriticalSection.Create;
  FUML.Define('Application', 'TApplication');
  FUML.Define('MainThread', 'TThread');
  FUML.Define('thread1', 'TThread');
  FUML.Define('thread2', 'TThread');
  FUML.Define('thread3', 'TThread');
  FUML.Define();

  FUML.Call('Application','MainThread','Start','');

  thread1 := TThread.CreateAnonymousThread( procedure
  var
    b : Boolean;
    i : integer;
    j : Integer;
  begin
    thread1.NameThreadForDebugging('thread1a');
    b := True;
    i := 0;
    lock.Acquire;
    sw := TStopWatch.StartNew;
    j := 10 + Random(300);
    while b do
    begin
      inc(i);
      b:= (i < j);
      sleep(10);
    end;
    FUML.Call('MainThread','thread1','CreateAnonymousThread',IntToStr(j), 'DONE(' + IntToStr(sw.ElapsedMilliseconds) + 'ms)');
    lock.Release;
  end);
  thread1.FreeOnTerminate := false;
  thread1.Start;

  thread2 := TThread.CreateAnonymousThread( procedure
  var
    b : Boolean;
    i : integer;
    j : Integer;
  begin
    thread2.NameThreadForDebugging('thread2a');
    b := True;
    i := 0;
    lock.Acquire;
    sw := TStopWatch.StartNew;
    j := 10 + Random(300);
    while b do
    begin
      inc(i);
      b:= (i < j);
      sleep(10);
    end;
    FUML.Call('MainThread','thread2','CreateAnonymousThread',IntToStr(j), 'DONE(' + IntToStr(sw.ElapsedMilliseconds) + 'ms)');
    lock.Release;
  end);
  thread2.FreeOnTerminate := false;
  thread2.Start;

  thread3 := TThread.CreateAnonymousThread( procedure
  var
    b : Boolean;
    i : integer;
    j : Integer;
  begin
    thread3.NameThreadForDebugging('thread3a');
    b := True;
    i := 0;
    lock.Acquire;
    sw := TStopWatch.StartNew;
    j := 10 + Random(300);
    while b do
    begin
      inc(i);
      b:= (i < j);
      sleep(10);
    end;
    FUML.Call('MainThread','thread3','CreateAnonymousThread',IntToStr(j), 'DONE(' + IntToStr(sw.ElapsedMilliseconds) + 'ms)');
    lock.Release;
  end);

  thread3.FreeOnTerminate := false;
  thread3.Start;

  thread1.WaitFor;
  thread2.WaitFor;
  thread3.WaitFor;
  thread1.Terminate;
  thread1.Free;
  thread2.Terminate;
  thread2.Free;
  thread3.Terminate;
  thread3.Free;

  FUML.Convert;
  Sleep(2000); 
  CheckTrue(FileExists(FUmlFileName + '.jpg'), 'Error, File was not created');
end;

A more realistic approach (Output):

I hope you find this article interesting enough to catch you attention as it is always good when finding tools like this an that are easy enough to integrate with any language and with great results.

Don't forget to leave your comment.

Jordi Corbilla