As I'm a bit of a fan of Phil Nash's Catch test framework I decided to convert the code in Jeff Langr's book to use Catch. This post describes the changes that were required for the first tests, i.e. chapter 2.
Catch is header only so is much simpler to incorporate than Google Mock/Test so the CMakeLists.txt can be much simpler. For the start of the chapter, this is sufficient:
After I adapted some existing code that used MSTest so that I was able to use Catch, I started to look at whether it was possible to do better; specifically I wanted to share source code between VS and Catch written for a console app and I wanted to retain the ability to generate standard VS TestResults files (*.trx).
The results were better than I expected; I found it was possible, with a little adaptation, to change the Catch internals so that I could do all that; so much so that I was able to reimplement the Catch self tests as Managed C++ test projects for VS2010 and VS2012 as well as Native C++ test projects.
You can find a fork of Catch here that implements this; hopefully Phil and I will be able to integrate this into the Catch mainline soon but until that is done I will do my best to keep the fork in sync with the code here.
Visual Studio 2010 has an option for creating C++ unit tests, but these tests are 'managed' C++. There are a number of problems with such tests:
The tests are slow to compile and slow to load/run.
Tests tend to be more complicated than needed - the Managed C++ compiler does not allow C++ value types as member variables for example, so these have to be kept as pointers and new/delete used.
The debugger doesn't understand C++ types very well, so when in managed code it is often not possible to view object values. Whilst it could be argued that using TDD should avoid most uses of the debugger, sometimes it's inevitable.
Sometimes the Managed C++ debugger gets a 'mind of its own' and decides to run a test to completion part way through debugging. This can be frustrating!
In the absence of Native C++ unit tests (note: VS2012 has these - see later) I wanted to be able to share the code base between MSTest managed tests and native tests so that the build system could happily run MSTest on its managed build and I could run native tests using Catch. This article describes my experiment to do this…
Differences in test philosophy
To persuade MSTest to look like Catch, we have to think about how the test needs to run. MSTest requires a class, but Catch does not. Catch allows multiple runs by using SECTIONs, but this doesn't figure in MSTest. So my first attempt used a TEST_CASE as a 'class' wrapper and a SECTION for each test method. This worked pretty well, except that it wasn't possible to specify individual tests to run (SECTIONs don't support tags).
Looking at the tests that I wanted convert, they tended to follow a pattern:
namespaceManagedTestProject{[TestClass]publicrefclassClassNameForTest{// some data that needs to be initialized...Stuff*m_data;//Use TestInitialize to run code before running each test[TestInitialize()]voidMyTestInitialize(){m_data=newStuff(...);}//Use TestCleanup to run code after each test has run[TestCleanup()]voidMyTestCleanup(){deletem_data;m_data=NULL;}public:[TestMethod]voidMethod1(){}[TestMethod]voidMethod2(){}};}
So you have Mingw (or gdb on Linux) and you'd like to use Phil Nash's CATCH testing framework. This article will go through some simple tests that we can construct and how to use it in that environment.
Throughout this document I use a test project that I've setup in C:\Projects\catch_gdb_example - I'll use the Mingw directory /c/Projects/catch_gdb_example to access it.
For testing, I was using the latest CATCH with Mingw32:
12
$ uname -a
MINGW32_NT-6.1 machine 1.0.18(0.48/3/2) 2012-11-21 22:34 i686 Msys
and Git:
12
$ git --version
git version 1.8.3.msysgit.0
First, CATCH your framework
There are two easy ways to get CATCH, and one that is slightly harder, so guess which one I chose? The easy way is download the source zip file, available from https://github.com/philsquared/Catch and unpack it - you can either use the full include headers (from catch/include) or the single header (from catch/single_include).
The alternative that I chose was to first download and install git for windows (http://msysgit.github.com/).
Several years ago Adam Peterson published an article on how to implement FizzBuzz at cmpile time in C++. The code was clever, but had a dependency on Boost and didn't go into great detail on how it worked, so I thought I'd write it again from scratch and try to explain my workings. In this article I'm only going to show examples that would work for very small FizzBuzz sequences because, well, this is a learning exercise not a typing exercise!
At the end of this article you'll find the source that I used to run the examples below - up to 16 items in the sequence. Much of what follows is a variation on the code in chapter 5 of C++ Template Metaprogramming, in particular the use of mpl::vector and the 'tiny' sequence.
First, get an error message
To make this work, we first have persuade the compiler to print an error message to the console when we build the program, something like this:
This article follows three posts describing how to install Ruby 1.9.3 to use Octopress with redcarpet and github-linguist in a native MingW environment; using what I learnt in that process I've figured out how to use the Ruby Installer for Windows to do the same thing - this post describes how to do that. I plan to leave the original posts (starting here) in case they may provide inspiration for someone else with similar ambitions.
I wanted to use redcarpet/github-linguist for markdown in Octopress, however there's a dependency on the charlock_holmes Gem that requires native code libraries (file, ICU), some of which it needs to build. It turns out that we can do this with Ruby Installer
First, install Ruby…
Install and install ruby 1.9.3 (from rubyinstaller.org)
Download the devkit (current version here)
Unpack dev kit, e.g. into C:\Ruby193\devkit
Setup the Ruby installation to work with the devkit:
12
ruby dk.rb init
ruby dk.rb install
All of this follows the regular instructions for installing Ruby and the devkit.
<!– more –>
Install Python 2.7
Next, install Python 2.7, if you havn't already - this is required for pygments.rb. Make sure Python is in your path. Check in a Mingw window:
1
python --version
Additional tools for devkit
For some reason, the devkit doesn't come with tar, zip & patch so install these from MingW downloads. I used 7-zip to unpack the wget and xz and then used the binaries of those tools to get the rest; if you want you can just download the missing tools and unpack them with 7-zip, then copy the binaries manually.
If you want to use MingW, first you need to download and unpack xz, wget and dlls for openssl and liblzma; download wget from here , xz from here, openssl dlls from here and liblzma dlls from here. Unpack them all with 7-zip (unpack the tar files as well) and copy the binaries to the bin, etc and lib directories of your devkit (copying with Windows Explorer is fine).
Start the devkit using the msys.bat file located in the devkit root and check that they installed:
123456
$ wget --version
GNU Wget 1.12 built on msys.
...
$ xz --version
xz (XZ Utils) 5.0.3
liblzma 5.0.3
Now you should be able to use MingW/MSYS to download and install the missing tools; create a temporary directory to unpack the files into and copy the files:
Now we're ready to install the dependencies for the charlock_holmes Gem…
Build native libraries
We need some additional libraries for the Ruby Gem charlock_holmes. I've built them both with static linking here so that we don't need to worry about where the DLLs might have gone.
Download Octopress (see also Octopress setup instructions). The easiest way to do this is to first install Git for Windows. Start Git Bash, and then (note: this example uses ~/build32 but you can put octopress where you like…):
12
cd /c/Ruby193/devkit/home/[user]/build32/
git clone git://github.com/imathis/octopress.git octopress
At this stage (back in MingW build environment):
1234567891011
cd ~/build32/octopress
$ gem list
*** LOCAL GEMS ***
bigdecimal (1.1.0)
io-console (0.3)
json (1.5.5)
minitest (2.5.1)
rake (0.9.2.2)
rdoc (3.9.5)
You should get the site built in octopress/public. Check that index.html is generated properly (size > 0).
At this point we have the default Octopress installed using rdiscount for markdown generation and we've setup the required libraries for redcarpet. Now we need to install charlock_holmes manually:
Install some updates required for github-linguist
Update the Gemfile to install pygments 0.3.7 - this is required so that we have the updated lexer Augeas (part contents of Gemfile):
This is the third of three posts describing how to install Ruby 1.9.3 native MingW environment. It's much simpler to use Ruby Installer to do this but if you want all the details of how to do it natively, read on…
If you're wondering why I did this, I wanted to use redcarpet/github-linguist for markdown in Octopress; there's a dependency on the charlock_holmes Gem that requires native code libraries (file, ICU), some of which it needs to build. I couldn't figure out how to make the Ruby Installer do this and I wanted to understand the process, so I did the whole thing from scratch. The first part is here and the second part is here.
Setup ruby.
In the build location (/build32 if following the instructions)…
First, install Python 2.7, if you havn't already - this is required for pygments.rb. Make sure Python is in your path. Check in a Mingw window:
1
python --version
We need some additional libraries for the Ruby Gem charlock_holmes. I've built them both with static linking here so that we don't need to worry about where the DLLs might have gone.
<!– more –>
Download Octopress (see also Octopress setup instructions). The easiest way to do this is to first install Git for Windows. Start Git Bash, and then (note: this example uses /build32 but you can put octopress where you like…):
12
cd /c/mingw/build32
git clone git://github.com/imathis/octopress.git octopress
At this stage (back in MingW build environment):
1234567891011
cd /build32/octopress
$ gem list
*** LOCAL GEMS ***
bigdecimal (1.1.0)
io-console (0.3)
json (1.5.5)
minitest (2.5.1)
rake (0.9.2.2)
rdoc (3.9.5)
#!C:/mingw/local32/bin/ruby
#--
# Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#++
begin
require 'rubygems'
rescue LoadError
end
require 'rake'
Rake.application.run
END
Install the default Octopress theme, create a new test page and generate the site:
You should get the site built in octopress/public. Check that index.html is generated properly (size > 0).
At this point we have the default Octopress installed using rdiscount for markdown generation and we've setup the required libraries for redcarpet. Now we need to install charlock_holmes manually:
This is the second of three posts describing how to install Ruby 1.9.3 native MingW environment. It's much simpler to use Ruby Installer to do this but if you want all the details of how to do it natively, read on…
If you 're wondering why I did this, I wanted to use redcarpet/github-linguist for markdown in Octopress; there's a dependency on the charlock_holmes Gem that requires native code libraries (file, ICU), some of which it needs to build. I couldn't figure out how to make the Ruby Installer do this and I wanted to understand the process, so I did the whole thing from scratch. The first part is here and the final part is here.
Download and build libyaml. Yaml requires a built DLL and needs it to be available so we build that manually (instructions for hacking a ruby gem very useful knowledge for this). Not sure if the first part to build and install the static libraries is required. We're hard coding the target location, but just need to get it to work…:
Download and install ruby (note: dbm, pty and syslog will fail to configure, this is ok on Windows…no others should fail). For some reason we need the drive/path to the install location or it doesn't install any files…:
This is the first of three posts describing how to install Ruby 1.9.3 native MingW environment. It's much simpler to use Ruby Installer to do this but if you want all the details of how to do it natively, read on…
If you 're wondering why I did this, I wanted to use redcarpet/github-linguist for markdown in Octopress; there's a dependency on the charlock_holmes Gem that requires native code libraries (file, ICU), some of which it needs to build. I couldn't figure out how to make the Ruby Installer do this and I wanted to understand the process, so I did the whole thing from scratch. The second part is here and the final part is here.
This is a prerequisite for installing Ruby 1.9.3 in a native Mingw environment on Windows.
Download and run mingw installer: mingw-get-setup.exe
Select 'mingw-developer-toolkit' and apply changes. This installs a default msys and default packages.
Start msys.bat (usually in C:\MinGW\msys\1.0).
'exit' from all msys shells and restart. You should see the following mounts:
123456
$ mount
...
c:\mingw\build32 on /build32 type user (binmode)
c:\mingw\local32 on /local32 type user (binmode)
c:\mingw on /mingw type user (binmode)
...