<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Object Mentor Blog: Tag RSpec</title>
    <link>http://blog.objectmentor.com/articles/tag/rspec</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>Unit Testing C and C++ ... with Ruby and RSpec!</title>
      <description>&lt;p&gt;If you&amp;#8217;re writing C/C&amp;#043;&amp;#043; code, it&amp;#8217;s natural to write your unit tests in the same language (or use C&amp;#043;&amp;#043; for your C test code). All the well-known unit testing tools take this approach.&lt;/p&gt;


	&lt;p&gt;I think we can agree that neither language offers the best developer productivity among all the language choices out there. Most of us use either language because of perceived performance requirements, institutional and industry tradition, &lt;em&gt;etc.&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;There&amp;#8217;s growing interest, however, in mixing languages, tools, and &lt;em&gt;paradigms&lt;/em&gt; to get the best tool for a particular job. &amp;lt;shameless-plug&amp;gt;I&amp;#8217;m giving a talk March 7&lt;sup&gt;th&lt;/sup&gt; at &lt;a href="https://www.cmpevents.com/SDw8/a.asp?option=C&amp;#38;V=11&amp;#38;SessID=6102"&gt;SD West&lt;/a&gt; on this very topic, called &lt;a href="https://www.cmpevents.com/SDw8/a.asp?option=C&amp;#38;V=11&amp;#38;SessID=6102"&gt;Polyglot and Poly-Paradigm Programming&lt;/a&gt; &amp;lt;/shameless-plug&amp;gt;.&lt;/p&gt;


	&lt;p&gt;So, why not use a more productive language for your C or C&amp;#043;&amp;#043; unit tests? You have more freedom in your development chores than what&amp;#8217;s required for production. Why not use Ruby&amp;#8217;s &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;, a &lt;a href="http://behaviour-driven.org/"&gt;Behavior-Driven Development&lt;/a&gt; tool for acceptance and unit testing? Or, you could use Ruby&amp;#8217;s version of &lt;a href="http://www.junit.org"&gt;JUnit&lt;/a&gt;, called &lt;a href="http://ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;Test::Unit&lt;/a&gt;. The hard part is integrating Ruby and C/C&amp;#043;&amp;#043;. If you&amp;#8217;ve been looking for an excuse to bring Ruby (or Tcl or Python or Java or&amp;#8230;) into your C/C&amp;#043;&amp;#043; environment, starting with development tasks is usually the path of least resistance.&lt;/p&gt;


	&lt;p&gt;I did some experimenting over the last few days to integrate &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;  using &lt;a href="http://www.swig.org"&gt;&lt;span class="caps"&gt;SWIG&lt;/span&gt;&lt;/a&gt; (Simplified Wrapper and Interface Generator), a tool for bridging libraries written in C and C&amp;#043;&amp;#043; to other languages, like Ruby. The &lt;a href="http://www.swig.org/Doc1.3/Ruby.html"&gt;Ruby section&lt;/a&gt; of the &lt;span class="caps"&gt;SWIG&lt;/span&gt; manual was very helpful.&lt;/p&gt;


	&lt;h2&gt;My Proof-of-Concept Code&lt;/h2&gt;


	&lt;p&gt;Here is a zip file of my experiment: &lt;a href="http://blog.objectmentor.com/files/rspec_for_cpp.zip" title="rspec_for_cpp.zip"&gt;rspec_for_cpp.zip&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;This is far from a complete and working solution, but I think it shows promise. See the &lt;strong&gt;Current Limitations&lt;/strong&gt; section below for details.&lt;/p&gt;


	&lt;p&gt;Unzip the file into a directory. I&amp;#8217;ll assume you named it &lt;code&gt;rspec_for_cpp&lt;/code&gt;. You need to have &lt;code&gt;gmake&lt;/code&gt;, &lt;code&gt;gcc&lt;/code&gt;, &lt;span class="caps"&gt;SWIG&lt;/span&gt; and Ruby installed, along with the RSpec &amp;#8220;gem&amp;#8221;. Right now, it only builds on &lt;span class="caps"&gt;OS X&lt;/span&gt; and Linux (at least the configurations on my machines running those OS&amp;#8217;s &amp;#8211; see the discussion below). To run the build, use the following commands:&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        $ cd rspec_for_cpp/cpp
        $ make 
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;You should see it finish with the lines&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        ( cd ../spec; spec *_spec.rb )
        .........

        Finished in 0.0***** seconds

        9 examples, 0 failures
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Congratulations, you&amp;#8217;ve just tested some C and C&amp;#043;&amp;#043; code with RSpec! (Or, if you didn&amp;#8217;t succeed, see the notes in the &lt;code&gt;Makefile&lt;/code&gt; and the discussion below.)&lt;/p&gt;


	&lt;h2&gt;The Details&lt;/h2&gt;


	&lt;p&gt;I&amp;#8217;ll briefly walk you through the files in the zip and the key steps required to make it all work.&lt;/p&gt;


	&lt;h3&gt;&lt;code&gt;cexample.h&lt;/code&gt;&lt;/h3&gt;


	&lt;p&gt;Here is a simple C header file.&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        /* cexample.h */
        #ifndef CEXAMPLE_H
        #define CEXAMPLE_H
        #ifdef __cplusplus
         extern "C" {
        #endif
        char* returnString(char* input);
        double returnDouble(int input);
        void  doNothing();

        #ifdef __cplusplus
         }
        #endif
        #endif
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Of course, in a pure C shop, you won&amp;#8217;t need the &lt;code&gt;#ifdef __cplusplus&lt;/code&gt; stuff. I found this was essential in my experiment when I mixed C and C&amp;#043;&amp;#043;, as you might expect.&lt;/p&gt;


	&lt;h3&gt;&lt;code&gt;cpp/cexample.c&lt;/code&gt;&lt;/h3&gt;


	&lt;p&gt;Here is the corresponding C source file.&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        /* cexample.h */

        char* returnString(char* input) {
            return input;
        }

        double returnDouble(int input) {
            return (double) input;
        }

        void  doNothing() {}
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;h3&gt;&lt;code&gt;cpp/CppExample.h&lt;/code&gt;&lt;/h3&gt;


	&lt;p&gt;Here is a C&amp;#043;&amp;#043; header file.&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        #ifndef CPPEXAMPLE_H
        #define CPPEXAMPLE_H

        #include &amp;lt;string&amp;gt;

        class CppExample 
        {
        public:
            CppExample();
            CppExample(const CppExample&amp;#38; foo);
            CppExample(const char* title, int flag);
            virtual ~CppExample();

            const char* title() const;
            void        title(const char* title);
            int         flag() const;
            void        flag(int value);

            static int countOfCppExamples();
        private:
            std::string _title;
            int         _flag;
        };

        #endif
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;h3&gt;&lt;code&gt;cpp/CppExample.cpp&lt;/code&gt;&lt;/h3&gt;


	&lt;p&gt;Here is the corresponding C&amp;#043;&amp;#043; source file.&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        #include "CppExample.h" 

        CppExample::CppExample() : _title("") {}
        CppExample::CppExample(const CppExample&amp;#38; foo): _title(foo._title) {}
        CppExample::CppExample(const char* title, int flag) : _title(title), _flag(flag) {}
        CppExample::~CppExample() {}

        const char* CppExample::title() const { return _title.c_str(); }
        void        CppExample::title(const char* name) { _title = name; }

        int  CppExample::flag() const { return _flag; }
        void CppExample::flag(int value) { _flag = value; }

        int CppExample::countOfCppExamples() { return 1; }
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;h3&gt;&lt;code&gt;cpp/example.i&lt;/code&gt;&lt;/h3&gt;


	&lt;p&gt;Typically in &lt;span class="caps"&gt;SWIG&lt;/span&gt;, you specify a &lt;code&gt;.i&lt;/code&gt; file to the &lt;code&gt;swig&lt;/code&gt; command to define the &lt;em&gt;module&lt;/em&gt; that wraps the classes and global functions, which classes and functions to expose to the target language (usually all in our case), and other assorted customization options, which are discussed in the &lt;a href="http://www.swig.org/Doc1.3"&gt;&lt;span class="caps"&gt;SWIG&lt;/span&gt; manual&lt;/a&gt;. I&amp;#8217;ll show the &lt;code&gt;swig&lt;/code&gt; command in a minute. For now, note that I&amp;#8217;m going to generate an &lt;code&gt;example_wrap.cpp&lt;/code&gt; file that will function as the bridge between the languages.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s my &lt;code&gt;example.i&lt;/code&gt;, where I named the module &lt;code&gt;example&lt;/code&gt;.&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        %module example
        %{
            #include "cexample.h" 
            #include "CppExample.h"    
        %}
        %include "cexample.h" 
        %include "CppExample.h" 
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;It looks odd to have header files appear twice. The code inside the &lt;code&gt;%{...%}&lt;/code&gt; (with a &amp;#8217;#&amp;#8217; before each &lt;code&gt;include&lt;/code&gt;) are standard C and C&amp;#043;&amp;#043; statements, &lt;em&gt;etc.&lt;/em&gt; that will be inserted verbatim into the generated &amp;#8220;wrapper&amp;#8221; file, &lt;code&gt;example_wrap.cpp&lt;/code&gt;, so that file will compile when it references anything declared in the header files. The second case, with a &amp;#8217;%&amp;#8217; before the &lt;code&gt;include&lt;/code&gt; statements&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;, tells &lt;span class="caps"&gt;SWIG&lt;/span&gt; to make all the declarations in those header files available to the target language. (You can be more selective, if you prefer&amp;#8230;)&lt;/p&gt;


	&lt;p&gt;Following Ruby conventions, the Ruby plugin for &lt;span class="caps"&gt;SWIG&lt;/span&gt; automatically names the module with an upper case first letter (&lt;code&gt;Example&lt;/code&gt;), but you use &lt;code&gt;require 'example'&lt;/code&gt; to include it, as we&amp;#8217;ll see shortly.&lt;/p&gt;


	&lt;h3&gt;Building&lt;/h3&gt;


	&lt;p&gt;See the &lt;code&gt;cpp/Makefile&lt;/code&gt; for the gory details. In a nutshell, you run the &lt;code&gt;swig&lt;/code&gt; command like this.&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        swig -c++ -ruby -Wall -o example_wrap.cpp example.i
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Next, you create a dynamically-linked library, as appropriate for your platform, so the Ruby interpreter can load the module dynamically when required. The &lt;code&gt;Makefile&lt;/code&gt; can do this for Linux and &lt;span class="caps"&gt;OS X&lt;/span&gt; platforms. See the &lt;a href="http://www.swig.org/Doc1.3/Ruby.html"&gt;Ruby section&lt;/a&gt; of the &lt;span class="caps"&gt;SWIG&lt;/span&gt; manual for Windows specifics.&lt;/p&gt;


	&lt;p&gt;If you test-drive your code, which tends to drive you towards minimally-coupled &amp;#8220;modules&amp;#8221;, then you can keep your libraries and build times small, which will make the build and test cycle very fast!&lt;/p&gt;


	&lt;h3&gt;&lt;code&gt;spec/cexample_spec.rb&lt;/code&gt; and &lt;code&gt;spec/cppexample_spec.rb&lt;/code&gt;&lt;/h3&gt;


	&lt;p&gt;Finally, here are the RSpec files that exercise the C and C&amp;#043;&amp;#043; code. (Disclaimer: these aren&amp;#8217;t the best spec files I&amp;#8217;ve ever written. For one thing, they don&amp;#8217;t exercise all the &lt;code&gt;CppExample&lt;/code&gt; methods! So sue me&amp;#8230; :)&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
        require File.dirname(__FILE__) + '/spec_helper'
        require 'example'

        describe "Example (C functions)" do
          it "should be a constant on Module" do
            Module.constants.should include('Example')
          end
          it "should have the methods defined in the C header file" do
            Example.methods.should include('returnString')
            Example.methods.should include('returnDouble')
            Example.methods.should include('doNothing')
          end
        end

        describe Example, ".returnString" do
          it "should return the input char * string as a Ruby string unchanged" do
            Example.returnString("bar!").should == "bar!" 
          end  
        end

        describe Example, ".returnDouble" do
          it "should return the input integer as a double" do
            Example.returnDouble(10).should == 10.0
          end
        end

        describe Example, ".doNothing" do
          it "should exist, but do nothing" do
            lambda { Example.doNothing }.should_not raise_error
          end
        end
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;and&lt;/p&gt;


&lt;pre&gt;
    &lt;code&gt;
    require File.dirname(__FILE__) + '/spec_helper'
    require 'example'

    describe Example::CppExample do
      it "should be a constant on module Example" do
        Example.constants.should include('CppExample')
      end
    end

    describe Example::CppExample, ".new" do
      it "should create a new object of type CppExample" do
        example = Example::CppExample.new("example1", 1)
        example.title.should == "example1" 
        example.flag.should  == 1
      end
    end

    describe Example::CppExample, "#title(value)" do
      it "should set the title" do
        example = Example::CppExample.new("example1", 1)
        example.title("title2")
        example.title.should == "title2" 
      end
    end

    describe Example::CppExample, "#flag(value)" do
      it "should set the flag" do
        example = Example::CppExample.new("example1", 1)
        example.flag(2)
        example.flag.should == 2
      end
    end
    &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;If you love RSpec like I do, this is a very compelling thing to see!&lt;/p&gt;


	&lt;p&gt;And now for the small print:&lt;/p&gt;


	&lt;h2&gt;Current Limitations&lt;/h2&gt;


	&lt;p&gt;As I said, this is just an experiment at this point. Volunteers to make this &lt;em&gt;battle-ready&lt;/em&gt; would be most welcome!&lt;/p&gt;


	&lt;h3&gt;General&lt;/h3&gt;


	&lt;h4&gt;The Example &lt;code&gt;Makefile&lt;/code&gt; File&lt;/h4&gt;


	&lt;p&gt;&lt;strong&gt;It Must Be Hand Edited for Each New or Renamed Source File&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;You&amp;#8217;ve probably already solved this problem for your own make files. Just merge in the example &lt;code&gt;Makefile&lt;/code&gt; to pick up the &lt;span class="caps"&gt;SWIG&lt;/span&gt;- and RSpec-related targets and rules.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;It Only Knows How to Build Shared Libraries for Mac &lt;span class="caps"&gt;OS X&lt;/span&gt; and Linux (and Not Very Well)&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;Some definitions are probably unique to my &lt;span class="caps"&gt;OS X&lt;/span&gt; and Linux machines. Windows is not supported at all. However, this is also easy rectify. Start with the notes in the &lt;code&gt;Makefile&lt;/code&gt; itself.&lt;/p&gt;


	&lt;h4&gt;The &lt;code&gt;module.i&lt;/code&gt; File Must Be Hand Edited for Each File Change&lt;/h4&gt;


	&lt;p&gt;Since the format is simple, a make task could fill a template file with the changed list of source files during the build.&lt;/p&gt;


	&lt;h4&gt;Better Automation&lt;/h4&gt;


	&lt;p&gt;It should be straightforward to provide scripts, &lt;span class="caps"&gt;IDE&lt;/span&gt;/Editor shortcuts, &lt;em&gt;etc&lt;/em&gt;. that automate some of the tasks of adding new methods and classes to your C and C&amp;#043;&amp;#043; code when you introduce them  &lt;i&gt;first&lt;/i&gt; in your &amp;#8220;spec&amp;#8221; files. (The true &lt;span class="caps"&gt;TDD&lt;/span&gt; way, of course.)&lt;/p&gt;


	&lt;h3&gt;Specific Issues for C Code Testing&lt;/h3&gt;


	&lt;p&gt;I don&amp;#8217;t know of any other C-specific issues, so unit testing with Ruby is most viable today for C code. Although I haven&amp;#8217;t experimented extensively, C functions and variables are easily mapped by &lt;span class="caps"&gt;SWIG&lt;/span&gt; to a Ruby module. The &lt;a href="http://www.swig.org/Doc1.3/Ruby.html"&gt;Ruby section&lt;/a&gt; of the &lt;span class="caps"&gt;SWIG&lt;/span&gt; manual discusses this mapping in some detail.&lt;/p&gt;


	&lt;h3&gt;Specific Issues for C&amp;#043;&amp;#043; Code Testing&lt;/h3&gt;


	&lt;p&gt;More work will be required to make this viable. It&amp;#8217;s important to note that &lt;span class="caps"&gt;SWIG&lt;/span&gt; cannot handle all C&amp;#043;&amp;#043; constructs (although there are workarounds for most issues, if you&amp;#8217;re committed to this approach&amp;#8230;). For example, namespaces, nested classes, some template and some method overloading scenarios are not supported. The &lt;a href="http://www.swig.org/Doc1.3"&gt;&lt;span class="caps"&gt;SWIG&lt;/span&gt; manual&lt;/a&gt; has details.&lt;/p&gt;


	&lt;p&gt;Also, during my experiment, &lt;span class="caps"&gt;SWIG&lt;/span&gt; didn&amp;#8217;t seem to map &lt;code&gt;const std::string&amp;#38;&lt;/code&gt; objects in C&amp;#043;&amp;#043; method signatures to Ruby strings, as I would have expected (&lt;code&gt;char*&lt;/code&gt; worked fine).&lt;/p&gt;


	&lt;h2&gt;Is It a Viable Approach?&lt;/h2&gt;


	&lt;p&gt;Once the &lt;strong&gt;General&lt;/strong&gt; issues listed above are handled, I think this approach would work very well for C code. For C&amp;#043;&amp;#043; code, there are more issues that need to be addressed, and programmers who are committed to this strategy will need to tolerate some issues (or just use C&amp;#043;&amp;#043;-language tools for some scenarios).&lt;/p&gt;


	&lt;h2&gt;Conclusions: Making It Development-Team Ready&lt;/h2&gt;


	&lt;p&gt;I&amp;#8217;d like to see this approach pushed to its logical limit. I think it has the potential to really improve the productivity of C and C&amp;#043;&amp;#043; developers and the quality of their test coverage, by leveraging the productivity and power of dynamically-typed languages like Ruby. If you prefer, you could use Tcl, Python, even Java instead.&lt;/p&gt;


	&lt;h3&gt;License&lt;/h3&gt;


	&lt;p&gt;This code is complete open and free to use. Of course, use it at your own risk; I offer it without warranty, &lt;em&gt;etc.&lt;/em&gt;, &lt;em&gt;etc&lt;/em&gt;. When I polish it to the point of making it an &amp;#8220;official&amp;#8221; project, I will probably release under the Apache license.&lt;/p&gt;


	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; I spent a lot of time debugging problems because I had a &amp;#8217;#&amp;#8217; where I should have had a &amp;#8217;%&amp;#8217;! &lt;em&gt;Caveat emptor&lt;/em&gt;!&lt;/p&gt;</description>
      <pubDate>Mon, 04 Feb 2008 22:08:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:cba4dc23-cbce-4173-be6f-14c7847dcfea</guid>
      <author>Dean Wampler</author>
      <link>http://blog.objectmentor.com/articles/2008/02/04/unit-testing-c-and-c-with-ruby-and-rspec</link>
      <category>Embedded</category>
      <category>Dean's Deprecations</category>
      <category>Dynamic Languages</category>
      <category>Agile Methods</category>
      <category>c</category>
      <category>RSpec</category>
      <category>Ruby</category>
      <category>TDD</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
