Search code examples
c++unit-testingcompiler-errors

Unit test that a class is non copyable, and other compile-time properties


Is there a way to test compile-time errors, but without actually generating the error? For example, if I create a class which is non-copyable, I'd like to test the fact that trying to copy it will generate a compiler error, but I'd still like to execute the other runtime tests.

struct Foo {
    int value_;
    Foo(int value) : value_(value) {}
  private:
    Foo(const Foo&);
    const Foo& operator=(const Foo&);
};

int main()
{
    Foo f(12);
    assert(f.value_ == 12);
    assert(IS_COMPILER_ERROR(Foo copy(f);));
} // Would like this to compile and run fine.

I guess this can't be done as simply as that, but is there an idiomatic way to do this, or should I roll my own solution (maybe using scripts compiling separate tests files and testing the results?)?

N.B.: I took non-copyable only to illustrate my point, so I'm not interested in answers about using boost::noncopyable and such.


Solution

  • You can do it using make. Each test will be a code snippet. Here's a working example with 2 tests for VC++. (I've used 2 batch files for pass test and fail test). I'm using GNU make here.

    Makefile:

    
    FAILTEST = .\failtest.bat
    PASSTEST = .\passtest.bat
    
    tests: must_fail_but_passes \
        must_pass_but_fails
    
    must_fail_but_passes:
        @$(FAILTEST) [email protected]
    
    must_pass_but_fails:
        @$(PASSTEST) [email protected]
    
    

    must_pass_but_fails.cpp

    
    struct Foo {
        int value_;
        Foo(void) : value_(0) {}
      private:
        Foo(const Foo&);
        const Foo& operator=(const Foo&);
    };

    int main() { Foo f(12); return 0; }

    must_fail_but_passes.cpp

    
    struct Foo {
        int value_;
        Foo(int value) : value_(value) {}
      private:
        Foo(const Foo&);
        const Foo& operator=(const Foo&);
    };

    int main() { Foo f(12); return 0; }

    passtest.bat

    
    @echo off
    cl /nologo %1 >NUL
    if %errorlevel% == 0 goto pass
    @echo %1 FAILED
    :pass
    

    failtest.bat

    
    @echo off
    cl /nologo %1 >NUL
    if not %errorlevel% == 0 goto pass
    @echo %1 FAILED
    :pass
    

    Note that cl.exe (i.e. Visual Studio compiler) need to be in your path for this to "just work"

    Have fun!

    P.S. I doubt that this would make me famous though :-)