Unit test that a class is non copyable, and other

2019-01-12 03:17发布

问题:

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.

回答1:

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) $@.cpp

must_pass_but_fails:
    @$(PASSTEST) $@.cpp

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 :-)



回答2:

BTW the only build system I know that allows such test out-of-the-box is Boost.Build:

Check here" http://beta.boost.org/boost-build2/doc/html/bbv2/builtins/testing.html

For example,

# in your Jamfile
compile-fail crappy.cpp ;

.

int main()
{
  my crappy cpp file
}

For more examples just grep -R compile-fail in your BOOST_TOP_DIR\libs directory.



回答3:

Unfortunately there is no easy way to test a compile error in the way you want to, I've also wanted to do this before.

Anyways if your tests are small enough you can write short uncompilable code, like your sample, and verify with a script if the errors generated are correct or not (again you just said it).

An example of this sort of thing would be Unix's configure scripts, in more than a few scripts I've seen them try to compile little samples to verify the version/abilities of the compiler, to configure the makefile correctly.

So at least you can know you're not alone. Now if you wrote a successful test framework for this sort of thing you'd probably become famous :)

Edit: You could possibly also use a #define that either tries or not compile uncompilable code something like this:

#ifdef _COMPILETEST
#define TRY_COMPILE(...) (__VA_ARG__)
#else
#define TRY_COMPILE(...)
#end

Note that this is something I just though about and there are probably many problems with this pattern, but it might serve as a seed for some better ideas.



回答4:

This article I wrote a while back may be of interest http://petebarber.blogspot.co.uk/2012/04/unit-testing-when-success-case-is.html



回答5:

boost.type_traits seems to have what you are looking for.