Testing C++ in Ruby with Automake and RSpec
Since I’m a C++ newbie, I felt I needed more confidence in my code. As I’ve been programming in Ruby for almost 2 years now, I decided to look for a way to test my C++ code in Ruby. I found an excellent post by Dean Wampler that deals with just this topic. Please take the time to read this fascinating article before continuing. I happened to have been playing with autotools for a different C++ project last week, so I decided to use them for this one too. I decided not to put the SWIG stuff into the Makefile, but rather use a shell script. Automake will make sure the modules get built the way they need to be built, and I can put everything described in Dean’s article in a little shell script which builds the wrapper object for Ruby. I’m using a file src/units.i which loads some module headers for SWIG to wrap. This code is now irrelevant. I’ve found a way to generate this by using mkmf
#!/bin/sh
CXX=/usr/bin/g++
SRC_DIR=src
CFLAGS="-fPIC -fno-strict-aliasing -g -O2"
BIN_DIR=bin
RUBY_LIBS=/usr/lib/ruby/1.8/i486-linux
SWIG=/usr/bin/swig
cd $SRC_DIR
SRCS=`ls *.cpp | sed "s/.*_wrap\.cpp//"`
OBJS=`ls *.o`
`${CXX} -I. -I${RUBY_LIBS} ${CFLAGS} -c ${SRCS}`
`${SWIG} -c++ -ruby -Wall -o units_wrap.cpp units.i`
`${CXX} -I. -I${RUBY_LIBS} ${CFLAGS} -c units_wrap.cpp`
`${CXX} -shared -L. -rdynamic -Wl,-export-dynamic -L/usr/local/lib -o units.so ${OBJS} -lruby1.8 -lpthread -ldl -lcrypt -lm -lc`You could extend it to take options for which module to build. As in my previous autotools example I have a ‘src’ dir containing my C++ code, and a new ‘spec’ dir containing my RSpec specifications in Ruby. The spec_helper.rb in the spec dir is taken from Dean’s example. Here’s an example of a spec for a FileReader class
require File.dirname(__FILE__) + '/spec_helper'
require 'units'
describe Units::FileReader do
it "should be a constant on module Units" do
Units.constants.should include('FileReader')
end
end
describe Units::FileReader, ".new" do
it "should create a new object of the type FileReader" do
fr = Units::FileReader.new("file.txt")
fr.filename.should_be "file.txt"
end
end
describe Units::FileReader, "#openFile" do
it "should open a file" do
fr = Units::FileReader.new
fr.openFile("file.txt").should_be true
fr.filename.should_be "file.txt"
end
end
describe Units::FileReader, "#closeFile" do
it "should close a file" do
fr = Units::FileReader.new
fr.closeFile.should_be true
fr.filename.should_be ""
end
end
describe Units::FileReader, "#readChar" do
it "should read a char" do
fr = Units::FileReader.new("file.txt")
char = fr.readChar
char.should_be fr.ch
char.is_a?(String).should_be true
char.length.should_be 1
end
end
describe Units::FileReader, "#readLine" do
it "should read a line from the file" do
fr = Units::FileReader.new("file.txt")
line = fr.readLine
line.is_a?(String).should_be true
line.match(/^.*\n$/).should_not be_nil
end
endOne little caveat I ran into: you have to expose the private variables of you C++ class with public accessors to be able to use them. Dean’s example shows these two little methods that do this, but it wasn’t obvious to me as my brain is cooked by programming in Ruby for too long. Hope this was helpful for anyone who wants to get started on testing their C++ code in Ruby easily.
Trackbacks
Use the following link to trackback from your own site:
http://blog.aczid.nl/trackbacks?article_id=9










