BDD your C

A couple of weeks ago I found my self writing some C code. Dropping down to a lower level language like C can always be painful when you have been spending too much time in the land of dynamic languages. Interestingly enough, it was not Ruby's Enumerable that was causing the most withdrawal pain but in fact the aspect I was missing most about my Ruby environment was rSpec. If you have not checked out rSpec or any other BDD testing suite I would highly recommend it. rSpec has helped me learn what TDD is suppose to really be about and has changed the way I code. Anyways, I had remembered seeing a post about how you could now use rSpec to spec out your Java code and began wondering if the same could be done with C.

Well, it turns out with that with little of help from SWIG it is quite easy to BDD your C with rSpec. For those late to the party, SWIG is a really cool tool that generates wrappers for C/C++ code that other languages (generally scripting languages) can use. All that you need to do is create an interface file for swig to parse that correlates with the C/C++ that you wish to generate wrappers for.

To illustrate how to use SWIG in conjunction with rSpec lets take a look at what seems to of become the canonical rSpec example, Bowling. This looks slightly different because of the C twist to it:

# bowling_spec.rb
require 'bowling'

describe Bowling do

  #Note, I am not creating a new Bowling object...
  # But rather I am testing the functional C code as stand alone module.

  it "should score 0 for gutter game" do
    20.times { Bowling.hit(0) }
    Bowling.score.should == 0
  end
end

Now, the corresponding C code that will put our spec in the green:

//bowling.c

void hit(int pins)
{
}

int score()
{
  return 0;
}

The interface file required by SWIG to generate the wrappers is as follows:

%module bowling

void hit(int pins);
int score();

Once those are in place you run SWIG to generate the wrappers, use 'mkmf' to generate the Makefile (just like a you were making a C extension for Ruby), make, and then spec. This one-off ruby script shows the steps:

# bdd_c.rb
require 'mkmf'

c_program = ARGV.first

`swig -ruby #{c_program}.i`  # Have SWIG generate the wrappers...
create_makefile(c_program)   # Create the Makefile that will incorporate our wrappers...
`make`
puts `spec -f s -c #{c_program}_spec.rb`  # Watch as the green goes by

So in our example:

./bdd_c.rb bowling

creating Makefile
/usr/bin/ld: warning multiple definitions of symbol _setregid
/usr/local/lib/libruby.dylib(process.o) definition of _setregid
/usr/lib/gcc/i686-apple-darwin8/4.0.1/../../../libpthread.dylib(setregid.So) definition of _setregid
/usr/bin/ld: warning multiple definitions of symbol _setreuid
/usr/local/lib/libruby.dylib(process.o) definition of _setreuid
/usr/lib/gcc/i686-apple-darwin8/4.0.1/../../../libpthread.dylib(setreuid.So) definition of _setreuid

Bowling
- should score 0 for gutter game

Finished in 0.060227 seconds

1 example, 0 failures

Like I said this is a very simple example. I was only using rSpec to BDD some simple C functions so the above steps worked perfectly for me. As you need to spec more complicated C code I would suggest looking at the SWIG and Ruby reference. This page covers how to deal with variable linking, pointers, etc... One thing that I did run into that I should point out is that module names will not be camel case as seen in idiomatic Ruby.. So 'bowling_pin.c" after SWIG got through with it would be used in your specs like Bowling_pin and not BowingPin. You might be able so change this easily with a SWIG flag or setting in the interface file but I didn't bother finding out.

I hope this helps someone and if you find this useful and end up taking/automating this process further please let me know.


About this entry