Sunday, September 23, 2012

Protest -- unit testing in C++ made slick

I've tried so many unit testing framework in C++, yet nothing really impressed me. Most are bad clones of JUnit, others are just silly (macros are not always bad). A few get close to what I'd like to have, but all frameworks really fall short on how fixtures are handled.

So, this weekend I decided to see if I could come up with something better. Here's what I got so far. I call it Protest, and it's a unit testing framework that a simple, powerful and slick. Here's an example:
#include <protest.hh>
suite("my first suite of tests.") {
  test("my first test") {
    int i = 2;
    expect(1 != i - 1) << "Intentionally wrong";
  }
}
which will print the following when run:
example.cc:4: expectation '1 != i - 1' (1 != 1) failed [my first suite][my first test][Intentionally wrong].

Fixtures are handled differently in Protest than in most other framework. There is no need to create a separate class or declare any extra stuff:
#include <protest.hh>
suite("tests with fixture 1") {
  int i = 2; // Can be used in all tests.
  test("test 1") {
    expect(i != 1);
  }
  test("test 2") {
    expect(i != 3);
  }
  // If needed, any tear-down code goes here.
}

However, sometimes there is a need for a more traditional approach to fixture (that is, inheriting from a base class). This is also supported in Protest:
#include <protest.hh> 
struct Fixture {
  int two() { return 2; }
}
suite("tests with fixture 2") {
  int i = two();
  test("test 1") {
    expect(two() == i);
  }
}

In addition, Protest supports ignoring test-cases, expected failures, and logging parts of expressions (not yet implemented: will only be logged if test-case fails). It also handles when test-cases crashed (SIGSEGV) and reports the last known line that was executed (usually the last expect that was executed).

Note that I've used lower-case for suite, test, etc, which are macros. These are just development names, and I intend that to be configurable.

Wednesday, September 19, 2012

Infer return type for templated function in C++

When I recently played around with ways of implementing generator in a test framework in C++, I had the need to have the compiler infer the return type of a template function. Something long the lines:
template<typename T>
T generate() {
  // generate a value of type T.
}
void test() {
  int integer = generate();
  std:::string str = generate();
}
Unfortunately, this code does not compile as the compiler cannot infer the return type required for the call to generate. There is, however, a way around this -- by using a casting operator.

Casting operator are functions that are used when the compiler tries to convert one type to another. An example of this is follows here:
struct Object {
  operator int() { return 0; }
};
int foo() {
  Object obj;
  return obj;  // 'obj' is implicitly converted to an 'int'.
}
Here, foo will return 0 because that's what Object's casting operator returns.

So, without further ado, here's an example how to emulate return type inference on a template function:
template<typename T>
struct ReturnValue { };

// Specialization for type int. Implements 'T generate()'
// for T == int.
template<>
struct ReturnValue<int> {
  static int value() { return 17; }
};

// Specialization for type std::string. Implements
// 'T generate()' for T == std::string.
template<>
struct ReturnValue<std::string> {
  static std::string value() { return "foo"; }
};

struct ReturnType {
  template<typename T>
  operator T() {
    return ReturnValue<T>::value();
  }
};
ReturnType generate() {
  return ReturnType();
}

void test() {
  int integer = generate(); // = 17
  std::string str = generate(); // = "foo"
}
It's a bit of extra complexity but it works nicely and it makes it possible to separate the implementations of T generate() for different values of T, which is pretty neat.

I wouldn't call this pattern useful in normal application code, but might be useful for APIs or parts of DSLs.