GTest 可以 ASSERT_DOES_NOT_COMPILE 吗?

Is it possible to ASSERT_DOES_NOT_COMPILE with GTest?

假设一个模板class,我们在编译时断言整数模板参数必须大于零:

template<int N>
class A
{
public:

    A() {
        static_assert(N > 0, "N needs to be greater 0.");
    }

};

是否可以创建一个 googletest 单元测试编译,但在运行时报告错误?例如:

TEST(TestA, ConstructionNotAllowedWithZero)
{
    ASSERT_DOES_NOT_COMPILE( 
        {
            A< 0 > a;
        }
    );
}

有一种方法,但遗憾的是它可能不是您想要的方式。

我的第一个想法是尝试让 SFINAE 通过在未计算的上下文中扩展无效的 lambda 来减少过载。不幸的是(在你的情况下),这是明确不允许的...

#define CODE { \
 utter garbage \
}
struct test
{
    template<class T>
    static std::false_type try_compile(...) { return{}; }
    template<class T>
    static auto try_compile(int)
    -> decltype([]() CODE, void(), std::true_type());
    { return {}; }
};
struct tag {};
using does_compile = decltype(test::try_compile<tag>(0));

输出:

./maybe_compile.cpp:88:17: error: lambda expression in an unevaluated operand
    -> decltype([]() CODE, void(), std::true_type());

所以它又回到了绘图板和一个很好的旧系统调用来调出编译器...

#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>
#include <sstream>

struct temp_file {
    temp_file()
    : filename(std::tmpnam(nullptr))
    {}

    ~temp_file() {
        std::remove(filename.c_str());
    }

    std::string filename;
};

bool compiles(const std::string code, std::ostream& reasons)
{
    using namespace std::string_literals;

    temp_file capture_file;
    temp_file cpp_file;

    std::ofstream of(cpp_file.filename);
    std::copy(std::begin(code), std::end(code), std::ostream_iterator<char>(of));
    of.flush();
    of.close();
    const auto cmd_line = "c++ -x c++ -o /dev/null "s + cpp_file.filename + " 2> " + capture_file.filename;
    auto val = system(cmd_line.c_str());

    std::ifstream ifs(capture_file.filename);
    reasons << ifs.rdbuf();
    ifs.close();

    return val == 0;
}

auto main() -> int
{
    std::stringstream reasons1;
    const auto code1 =
R"code(
    #include <iostream>
    int main() {
        return 0;
    }
)code";
    std::cout << "compiles: " << compiles(code1, reasons1) << std::endl;

    std::stringstream reasons2;
    const auto code2 =
R"code(
    #include <iostream>
    int main() {
        FOO!!!!XC@£$%^&*()VBNMYGHH
        return 0;
    }
)code";
    std::cout << "compiles: " << compiles(code2, reasons2) << std::endl;
    std::cout << "\nAnd here's why...\n";
    std::cout << reasons2.str() << std::endl;

    return 0;
}

在我的例子中给出了以下示例输出:

compiles: 1
compiles: 0

And here's why...
/var/tmp/tmp.3.2dADZ7:4:9: error: use of undeclared identifier 'FOO'
        FOO!!!!XC@£$%^&*()VBNMYGHH
        ^
/var/tmp/tmp.3.2dADZ7:4:19: error: non-ASCII characters are not allowed outside of literals and identifiers
        FOO!!!!XC@£$%^&*()VBNMYGHH
                  ^
2 errors generated.

当然,您可以在对 compiles() 的调用周围添加所有必要的宏,以便对其进行 GTESTify。您当然必须在 c 编译器调用上设置命令行选项以设置正确的路径和定义。