How do I test that a function won't produce a segmentation fault?
Here what I know right now, I can do:
EXPECT_DEATH(foo(nullParameter))
In side the function, a segmentation fault is produce which is the behavior that I want to make fail. The snippet above will make the test pass because that is what is expected, the death of the process.
Now, how can I make it fail?
Here's a function that will segfault if passed a null pointer argument and otherwise not:
int deref(int * pint)
{
return *pint;
}
And here is a googletest program that tests that behaviour:
main.cpp
#include <gtest/gtest.h>
int deref(int * pint)
{
return *pint;
}
TEST(test_deref_1,will_segfault)
{
ASSERT_EXIT((deref(nullptr),exit(0)),::testing::KilledBySignal(SIGSEGV),".*");
}
TEST(test_dref_2,will_not_segfault)
{
int i = 42;
ASSERT_EXIT((deref(&i),exit(0)),::testing::ExitedWithCode(0),".*");
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Compile and link:
$ g++ -Wall -Wextra -pedantic -o tester main.cpp -pthread -lgtest
Run:
$ ./tester
[==========] Running 2 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 1 test from test_deref_1
[ RUN ] test_deref_1.will_segfault
[ OK ] test_deref_1.will_segfault (168 ms)
[----------] 1 test from test_deref_1 (168 ms total)
[----------] 1 test from test_dref_2
[ RUN ] test_dref_2.will_not_segfault
[ OK ] test_dref_2.will_not_segfault (1 ms)
[----------] 1 test from test_dref_2 (1 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 2 test cases ran. (169 ms total)
[ PASSED ] 2 tests.
As far as I can imagine, TEST(test_deref_1,will_segfault)
is a pointless test,
because I cannot think of any circumstances in which I would want to assure
myself that a program will segfault as a result of making a certain call to a
function I have written.
TEST(test_dref_2,will_not_segfault)
is possibly a useful kind of test. In effect,
it is a test that the program:
int main()
{
int i = 42;
defref(&i);
exit(0);
}
will terminate by exit(0)
rather than in any premature abnormal way. A better name for
this test would probably be TEST(test_dref,does_not_crash)
, or similar.
It is a possibly useful kind of test because there could be a significant risk of it
failing, if defref
was some sufficiently complicated code, and the test suite
could report that failure without crashing itself. We can force a failure by rewriting
it:
TEST(test_dref_2,will_not_segfault)
{
ASSERT_EXIT((deref(nullptr),exit(0)),::testing::ExitedWithCode(0),".*");
}
and then test test report is:
$ ./tester
[==========] Running 2 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 1 test from test_deref_1
[ RUN ] test_deref_1.will_segfault
[ OK ] test_deref_1.will_segfault (147 ms)
[----------] 1 test from test_deref_1 (147 ms total)
[----------] 1 test from test_dref_2
[ RUN ] test_dref_2.will_not_segfault
main.cpp:25: Failure
Death test: (deref(nullptr),exit(0))
Result: died but not with expected exit code:
Terminated by signal 11 (core dumped)
Actual msg:
[ DEATH ]
[ FAILED ] test_dref_2.will_not_segfault (90 ms)
[----------] 1 test from test_dref_2 (90 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 2 test cases ran. (237 ms total)
[ PASSED ] 1 test.
[ FAILED ] 1 test, listed below:
[ FAILED ] test_dref_2.will_not_segfault
1 FAILED TEST
See the documentation of {ASSERT|EXPECT}_EXIT
to understand these macros.
Tests which crash are already failures (presumably you don't want any of your code to segfault). Just test for the behavior you expect, as with any other test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With