post

Simple C++ DSL using Macros

Recently at ST Electronics I was asked to help the C++ client application development team for the Future School Project. At a late stage in development they needed a database, and a data layer, and quickly.

The data layer should support an ADO data source like MS Access now, and potentially an embedded database like SQLite later.

When approached, given the time and budget constraints, I wanted to provide something which made it easy for developers to use, yet was flexible enough they could plug in support for other databases later. This flexibility was important because it meant I could concentrate on addressing their immediate needs (MS Access) without investing time in what they may or may not need later (SQLite ) – obeying the YAGNI principle via the GRASP Protected Variation pattern.

Being an advocate of declarative programming, convention over configuration, and code generation I was looking for a simple mechanism that allowed the developers to declare what they wanted.

In C# I would typically solve this problem via attributes and reflection but in C++ the runtime type information is limited. C++ Template meta-programming is something I have only just begun investigating, so that wasn’t an option for me. In the end I settled for good old fashioned Macros – I know, most developers have relegated them to the sidelines along with the goto statement…

In this scenario, macros fitted like a glove.

Along with CRUD operations, I provided support for queries and other extensions via this mechanism. Here is a simple example of declaring entity information using this macro based DSL:

class AvatarInventoryItem:public ClientDatabase::DataEntity{
public:
    __int(Id)
    __int(ObjectId)
    __int(ActionId)
    __bool(IsActive)
    __float(XPosition)
    __float(YPosition)
    __float(ZPosition)
    __float(XRotation)
    __float(YRotation)
    __float(ZRotation)
    __int(UserId)
    __datetime(LastChangeTime)

    __table(AvatarInventory)
    __key(Id,int,true)
};

class AvatarInventory:public ClientDatabase::Table<AvatarInventoryItem>{
public:
    __selectall(AvatarInventory)
};

Here is an example of reading data from the table:

auto_ptr<AvatarInventory> inventory(AvatarInventory::SelectAll());

while(inventory->HasData()){
    auto_ptr<AvatarInventoryItem> item(inventory->PopBack());
    cout << ” Id:” << item->GetId() << endl;
}

Another example, using a different class, saving data:

Application * application=new Application();
application->SetName(L”Test Application”);
application->SetOfflineAccess(true);
application->Save();

The factory and dataservice interface provided the indirection I needed to support other databases:

IDataService * service=DataServiceFactory::Create("access","C:\\data\\MsAccess.mdb");
Database.Initialize(service);

All in all, I’m pretty happy with, yes you guessed it, macros – perhaps I need to revisit the goto statement now, after all most conditions compile down to a jump statement :)

post

Doxygen

Doxygen is a cross platform open source code documentation tool which I’ve used for both Visual C++ and C# .NET projects. It produces awesome documentation and is very easy to use. Configuration is straight forward using the DoxyWizard application.

Doxygen can be configured to use Graphviz to produce graphs. After installing Graphiz you’ll need to configure it’s path in DoxyWizard.

It supports multiple documentation conventions, the one I use most frequently is the Xml Comments found in .NET, for example:

/// <summary>
/// Creates a Command which will get the last auto-generated Id in a table.
/// Note: Client is responsible for deleting the command.
/// <summary>
/// <param name="table">The name of the database table.</param>
/// <returns>A pointer to a Command.</returns>
/// <exception cref="DataException">Thrown if the table is empty.</exception>
Command * CreateGetLastIdCommand(const std::string & table);

Produces this documentation:

doxygen

For more information on the .NET Xml Comments, see this excellent cheat sheet.

post

Testing unmanged c++ with NUnit

Unit Testing, especially Test Driven Design, is a discipline of the Agile Development Methodology which you can find more about here. Generally, I find it difficult to follow the text book approach in the trenches, but I do try to make the effort to develop unit tests where possible, typically after I have written a class. Having developed in C# for a number of years I became addicted to the visual affirmation provided by NUnit – those green lines are so encouraging :)

To cut a long story short, I had recently been assigned to work on a native Win32 Visual C++ project and Unit Testing wasn’t in the pipeline. Missing NUnit so much, I created a Visual C++/CLI Class Library. I added my unmanaged DLL to the solution, wrote my unit tests in C++/CLI and was able to drive them using the NUnit console.

Unit Testing C++

Unit Testing Native Win32 C++

One of the issues with using Native C++ in CLI/C++ is the marshaling of strings, such as between std::wstring and System^. To address this I created a base class which provided functions to marshal the strings, and wrappers around the NUnit StringAssert class:

static std::string AsString(String ^s){
    std::string os;
    MarshalString(s,os);
    return os;
}
static std::string AsWString(String ^s){
    std::string os;
    MarshalString(s,os);
    return os;
}
static void MarshalString(String^ s, std::string& os){
    using namespace Runtime::InteropServices;
    const char* chars=(const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
    os=chars;
    Marshal::FreeHGlobal(IntPtr((void*)chars));
}
static void MarshalString(String^ s, std::wstring& os){
    using namespace Runtime::InteropServices;
    const wchar_t* chars=(const wchar_t*)(Marshal::StringToHGlobalUni(s)).ToPointer();
    os=chars;
    Marshal::FreeHGlobal(IntPtr((void*)chars));
}
static void StringAssertContains(String^ expected, const std::string & actual){
    String^ a=gcnew String(actual.c_str());
    StringAssert::Contains(expected,a);
}
etc….

To simplify testing, I decided to create a test database and between tests attach and detach the database, ensuring I was always testing from a known baseline. This required two things, first batch and sql commands to do the attaching/detaching:

AttachDatabase.cmd
copy /Y c:\db\TestBase.mdf c:\db\Test.mdf
sqlcmd -S STFERDINAND\SqlExpress -U sa -P p@ssw0rd -i c:\db\AttachDatabase.sql
AttachDatabase.sql
USE [master]
GO
CREATE DATABASE [TestDatabase] ON
( FILENAME = N’C:\db\Test.mdf’ ) FOR ATTACH ;
GO
DetachDatabase.cmd
sqlcmd -S STFERDINAND\SqlExpress -U sa -P p@ssw0rd -i c:\db\DetachDatabase.sql
del c:\db\Test.mdf
DetachDatabase.sql
USE [master]
GO
DROP DATABASE [TestDatabase]
GO

And secondly, a base test fixture to execute these commands:

[SetUp]
void TestSetup(void){

    InitializeDatabase();
}
[TearDown]
void TestTeardown(void){

    FinalizeDatabase();
}
void InitializeDatabase(void){
    system(AsString(CreateDatabaseScript).c_str());
    Domain.Initialize();
}
void FinalizeDatabase(void){
    Domain.Finalize();
    system(AsString(DeleteDatabaseScript).c_str());
}

And finally, with the infrastructure in place, it’s on to creating test fixtures:

[TestFixture]
public ref class AvatarServiceFixture:BaseFixture{

public:
    [Test]
    void LoadAvatarTest(void){
        CallResult<Avatar> avatarResult=AvatarService::GetAvatar(PLAYER1_ID);
        Assert::IsTrue(avatarResult.IsSuccess());

        Avatar & avatar=avatarResult.Value;

        vector<AvatarObject> avatarObjects=AvatarObject::GetByAvatarId(avatar.GetId());
        AvatarObjectFilter aoFilter(avatarObjects);
        AvatarObjectFilter activeObjects=aoFilter.WhereIsActive(true);

        CheckTransientActive(activeObjects,avatar.GetTop());
        CheckTransientActive(activeObjects,avatar.GetAccessory());
        CheckTransientActive(activeObjects,avatar.GetBottom());
        CheckTransientActive(activeObjects,avatar.GetShoe());
        CheckTransientActive(activeObjects,avatar.GetHeadGear());
        CheckTransientActive(activeObjects,avatar.GetFace());
}

And that’s pretty much it in a nutshell.

You can find more out about nunit here.

Follow

Get every new post delivered to your Inbox.