Модульный тест на невозможность копирования класса и другие свойства времени компиляции

Есть ли способ проверить ошибки времени компиляции, но без фактического создания ошибки? Например, если я создаю некопируемый класс, я хотел бы проверить тот факт, что попытка его копирования вызовет ошибку компилятора, но я все же хотел бы выполнить другие тесты времени выполнения.

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.

Я предполагаю, что это не может быть сделано так просто, но есть ли идиоматический способ сделать это, или я должен свернуть свое собственное решение (может быть, используя скрипты, компилирующие отдельные файлы тестов и проверяющие результаты?)?

N.B.: Я взял non-copyable только для того, чтобы проиллюстрировать свою точку зрения, поэтому меня не интересуют ответы об использовании boost::noncopyable и тому подобное.


person Luc Touraille    schedule 03.03.2009    source источник
comment
Я предполагаю, что static_assert тоже выходит за рамки: P (boost .org/doc/libs/1_38_0/doc/html/boost_staticassert.html)   -  person dirkgently    schedule 03.03.2009
comment
static_assert не будет работать. Он хочет иметь возможность утверждать, что static_assert на самом деле действительно вызывает ошибку компиляции. (или что-то еще, что предположительно вызывает ошибку компиляции, на самом деле делает это)   -  person jalf    schedule 03.03.2009
comment
только что опубликовал глупую идею, которая может помочь вам создать своего рода структуру...   -  person Robert Gould    schedule 03.03.2009


Ответы (3)


Вы можете сделать это с помощью make. Каждый тест будет фрагментом кода. Вот рабочий пример с двумя тестами для VC++. (Я использовал 2 пакетных файла для прохождения теста и теста на отказ). Я использую GNU make здесь.

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

фейлтест.бат


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

Обратите внимание, что cl.exe (то есть компилятор Visual Studio) должен быть на вашем пути, чтобы это «просто работало»

Веселиться!

P.S. Хотя сомневаюсь, что это сделало бы меня знаменитым :-)

person Dushara    schedule 04.03.2009
comment
Этот редактор вырезает половину Makefile, и я не знаю, почему. В нем должны быть еще 2 строки: test2: must_pass_but_fails.cpp @$(PASSTEST) $ - person Dushara; 04.03.2009

Кстати, единственная известная мне система сборки, которая позволяет проводить такой тест «из коробки», — это Boost.Build:

Проверьте здесь" http://beta.boost.org/boost-build2/doc/html/bbv2/builtins/testing.html

Например,

# in your Jamfile
compile-fail crappy.cpp ;

.

int main()
{
  my crappy cpp file
}

Для получения дополнительных примеров просто grep -R compile-fail в вашем каталоге BOOST_TOP_DIR\libs.

person Alexander Poluektov    schedule 18.02.2010
comment
CMake имеет try_compile, который также можно использовать для этой цели. - person Luc Touraille; 31.10.2017

К сожалению, нет простого способа проверить ошибку компиляции так, как вы хотите, я тоже хотел сделать это раньше.

В любом случае, если ваши тесты достаточно малы, вы можете написать короткий некомпилируемый код, такой как ваш образец, и проверить с помощью скрипта, верны ли сгенерированные ошибки (опять же, вы только что это сказали).

Примером такого рода вещей могут быть сценарии настройки Unix, в более чем нескольких сценариях, которые я видел, они пытались скомпилировать небольшие образцы, чтобы проверить версию/возможности компилятора, чтобы правильно настроить makefile.

Так, по крайней мере, вы можете знать, что вы не одиноки. Теперь, если бы вы написали успешную тестовую среду для такого рода вещей, вы, вероятно, стали бы знаменитыми :)

Редактировать: вы также можете использовать #define, который либо пытается, либо не компилирует некомпилируемый код, примерно так:

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

Обратите внимание, что это то, о чем я только что подумал, и, вероятно, с этим шаблоном много проблем, но он может послужить основой для некоторых лучших идей.

person Robert Gould    schedule 03.03.2009
comment
Ну, этого я и опасался... по крайней мере, у меня есть новый проект, над которым я могу работать в свое (скудное) свободное время :p! - person Luc Touraille; 03.03.2009
comment
Да, несчастный. Но помните, вы можете стать знаменитым ;) - person Robert Gould; 03.03.2009
comment
На данный момент я использую что-то похожее на ваше редактирование: у меня есть файл cpp, который включает либо test_compile.h, либо test_runtime.cpp, в зависимости от константы компилятора. - person Luc Touraille; 03.03.2009
comment
Проблема с методом определения заключается в том, что если какой-то пользователь запускает ваши тесты, ему сначала нужно подумать о запуске двух версий, что делает его автоматическим тестированием, а во-вторых, они увидят, что он не компилируется, но как они могут проверить что все места, которые не должны компилироваться, действительно не компилировались? - person ; 06.11.2010
comment
@ufotds хорошие моменты. Я полагал, что люди будут хранить сборки в автоматическом инструменте, который выполняет все комбинации сборки. Если вы работаете без такой настройки, это становится связующим звеном. - person Robert Gould; 10.11.2010