Life, Teams, and Software Engineering

Category: C

C++ C Function Wrappers – Introducing CFunctionWrapperGenerator

Dependency-injection in C++ is not convenient, especially when you bring “Free” C functions into the mix. There are several approaches you can use to isolate these functions, but the one I’ve had the most success with is to create C++ classes whose sole purpose is to wrap calls to C functions. This approach works quite well, both in minimizing the impact to the production code, and simplifying unit testing, particularly when paired with the googlemock C++ Mocking framework.

I’ve been doing this for some time and have started to feel some pain in the maintenance area. Wrapper functions are starting to be duplicated between wrapper modules, and classes depending on wrappers are importing functions that they’ll never call. But most of all, building out and maintaining these wrapper classes takes time and is extremely tedious. So being the lazy developer that I am, I wrote C Function Wrapper Generator (CFWG) to do the heavy lifting for me.

Basically it’s a collection of Python scripts that generate C++ classes whose sole responsibility are to provide interfaces to C Functions.  They provide a transparent API to the C functions so you don’t have to change how you’re calling them (much), but the main advantage they provide is during unit testing: you now have a seam to control side-effects and return values of C functions that you would otherwise have had to deal with by hand.

The main interface is a YAML configuration file that looks like this:

  1. Functions:
  2.     – name         CreateFileA
  3.       real_header  winbase.h
  4.       include_headerwindows.h
  5.     – name         CloseHandle
  6.       real_header  winbase.h
  7.       include_headerwindows.h
  8.     – name         WriteFile
  9.       real_header  winbase.h
  10.       include_headerwindows.h
  11.     – name         CreateEnvironmentBlock
  12.       real_header  userenv.h
  13.       include_headeruserenv.h
  14. Aggregators:
  15.     – nameFileExists
  16.       functions:
  17.          – CreateFileA
  18.          – CloseHandle

This basically tells CFWG what functions you want to wrap, where it can find them, and what header should be included in real code that calls it.  You can also specify custom aggregators if you want.  This allows you to pull in just the functions you need.  In the case of shared libraries this will prevent callers from getting linkage they don’t actually use.

CFWG generates three files:

  1. ICWrappers.h – Contains an interface for each C function in the form ICFunction (e.g. ICreateFileA).  This also contains an IMasterCWrapper (which multiply inherits from the individual ICFunctions) which comes in handy for unit testing (and my examples) and an interface for each aggregator specified in the configuration.  You want your production code to depend on these interfaces.
  2. Component/CWrappers.h – Contains the implementation for each interface listed in ICWrappers.h.  These actually call the real C function, simply passing the arguments down.  You pass an instance of one of these to any production code that needs the function (or functions in the case of an aggregator).
  3. Mock/CWrappers.h – Contains GMock implementations for IMasterCWrapper in ICWrappers.h and one for each Aggregate interface specified in the configuration file.
  1. /* Unit class (has dependencies) */
  2. class Unit::Foo
  3. {
  4. public:
  5.     Foo(ICreateFileA &createFileA, IWriteFile &writeFile, ICloseHandle &closeHandle)
  6.         : m_createFileA(createFileA), m_writeFile(writeFile), m_closeHandle(closeHandle)
  7.     {}
  8.     void bar();
  9. private:
  10.     ICreateFileA &m_createFileA;
  11.     IWriteFile &m_writeFile;
  12.     ICloseHandle &m_closeHandle;
  13. };
  14. void
  15. Unit::Foo::Bar()
  16. {
  17.     HANDLE handle = m_createFileA.myCreateFileA(
  18.         “testFile.txt”,
  19.         GENERIC_WRITE,
  20.         0,
  21.         0,
  22.         CREATE_NEW,
  24.         0);
  25.     if (INVALID_HANDLE_VALUE == handle)
  26.     {
  27.         throw std::exception(“CreateFileA failed!”);
  28.     }
  29.     const char *toWrite = “yay!!”;
  30.     DWORD numBytesWritten = 0;
  31.     if (!m_writeFile.myWriteFile(
  32.         handle,
  33.         toWrite,
  34.         strlen(toWrite),
  35.         &numBytesWritten,
  36.         0) || numBytesWritten != strlen(toWrite))
  37.     {
  38.         m_closeHandle.myCloseHandle(handle);
  39.         throw std::exception(“WriteFile failed!”);
  40.     }
  41.     m_closeHandle.myCloseHandle(handle);
  42. }
  43. int
  44. main()
  45. {
  46.     Component::MasterCWrapper wrapper;
  47.     Unit::Foo foo(wrapper, wrapper, wrapper);
  48.     foo.Bar();
  49. }

Now you can write unit tests for Foo and easily test all these conditions.  Well, you could before too, now you just don’t have to maintain all those boilerplate wrappers anymore.

Check it out on Github and let me know what you think!

P.S. This depends heavily on the cppclean C++ AST generator, so props to those guys for providing a great tool.

Autotest for Compiled Languages (C#, C++) using Watchr

When I was learning Rails I set up Autotest on Ubuntu with Growl notifications, which I thought was a pretty slick idea. On Ruby this whole technique is super easy and efficient because Ruby is an interpreted language; there’s no compile time to slow you down, and no other files to pollute your directory tree. Compiled languages don’t have that advantage, but I think we deserve some continuous feedback too. Here I’ll describe how to configure Watchr, a generic Autotest utility, to run compiled tests whenever a source file in the path is updated. This tutorial will use a C# example, but it’s trivial to have it trigger on different file types.

Getting Started

First, we’ll need to install Ruby and Watchr.  Because I’m using Windows I just downloaded RubyInstaller.  Make sure you put the Ruby/bin directory in your PATH.

Next, download Watchr from Github, extract the archive and navigate to that directory.  Or you can just download the gem directly, but some people might want to run the tests locally first. The following command will install the gem from the local directory:

C:\mynyml-watchr-17fa9bf\>gem install Watchr

Configuring Watchr

Now that we have all the dependencies installed, we need to configure Watchr. This process is easiest if you already have a single point of entry for your continuous build process, but if you don’t it’s not that bad and you’ll probably want one anyway. Now, at the same level as the directory(ies) containing your source code, create a text file. I usually call this autotest.watchr, but you could call it autotest.unit or autotest.integration if you’re into that sort of thing. For now, just put in the following line in:

  1. watch(‘./.*/(.*)\.cs$’) {system “cd build && buildAndRunTests.bat && cd ..\\}

Yes, it’s that easy. What this is doing is telling Watchr to monitor any files that match the regular expression (in this case a recursive directory search for .cs files) inside the watch() call, and then execute the command on the right. I also have it configured to return to the same directory when it’s finished, but I don’t know if that’s actually necessary. The watch() pattern is what you would modify for different environments. For example, you could use watch('./.*/(.*)\.[h|cpp|hpp|c]$') for a Mixed C/C++ system, or watch('./.*/(.*)\.[cs|vb|cpp|h]$') for a .NET project with components built in different languages. An important thing to note is the $ at the end of the regex. Because it’s likely that there will be a lot of intermediary files generated during the build process, we don’t want a file which happens to match this pattern that’s generated at build time to trigger an infinite loop of build & test (like happened to me). The heavy lifting is done here, but the stuff specific to your project happens in build/buildAndRunTests.bat. Let’s take a look at that:

  1. pushd ..\
  2. echo Building tests
  3. “C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\” Tests.Unit\Tests.Unit.csproj /rebuild Release
  4. popd
  5. pushd ..\Tests.Unit\bin\Release
  6. echo Running tests through nunit-console
  7. nunit-console.exe Tests.Unit.dll /run=Tests.Unit
  8. popd

You’ll obviously want to customize this to the specifics of your project, but right now it’s hard-coded to call Visual Studio 2008’s (on a 64-bit OS) and build a project called Tests.Unit. For brevity it also assumes that nunit-console.exe is available on the PATH. Not terribly interesting, but that’s the rest of the work.

Now to have all the magic happen. Run the following command in a new console window from your project directory:

C:\Projects\MyProject>Watchr autotest.watchr

That’s it! Watchr is now monitoring for changes to files that match your pattern. Simply modify any file matching the pattern and watch the whole process set off. Once it finishes, you can hopefully see the results and it will wait for the next change.

Now there’s one less thing you have to do during your heavy refactoring sessions, or just with day-to-day development.

Copyright © 2017 Life, Teams, and Software Engineering

Theme by Anders NorenUp ↑