The story:
Pushing for more quality and stability we integrate google test into our existing projects or extend test coverage. One of such cases was the creation of tests to document and verify a bugfix. They called a single function and checked the fields of the returned cv::Scalar.
TEST(ScalarTest, SingleValue) { ... cv::Scalar actual = target.compute(); ASSERT_DOUBLE_EQ(90, actual[0]); ASSERT_DOUBLE_EQ(0, actual[1]); ASSERT_DOUBLE_EQ(0, actual[2]); ASSERT_DOUBLE_EQ(0, actual[3]); }
Because this was the first test using OpenCV, the CMakeLists.txt also had to be modified:
target_link_libraries( ... ${OpenCV_LIBS} ... )
Unfortunately, the test didn’t run through: it ended either with a core dump or a segmentation fault. The analysis of the called function showed that it used no pointers and all variables were referenced while still in scope. What did gdb say to the segmentation fault?
(gdb) bt #0 0x00007ffff426bd25 in raise () from /lib64/libc.so.6 #1 0x00007ffff426d1a8 in abort () from /lib64/libc.so.6 #2 0x00007ffff42a9fbb in __libc_message () from /lib64/libc.so.6 #3 0x00007ffff42afb56 in malloc_printerr () from /lib64/libc.so.6 #4 0x00007ffff54d5135 in void std::_Destroy_aux<false>::__destroy<testing::internal::String*>(testing::internal::String*, testing::internal::String*) () from /usr/lib64/libopencv_ts.so.2.4 #5 0x00007ffff54d5168 in std::vector<testing::internal::String, std::allocator<testing::internal::String> >::~vector() () from /usr/lib64/libopencv_ts.so.2.4 #6 0x00007ffff426ec4f in __cxa_finalize () from /lib64/libc.so.6 #7 0x00007ffff54a6a33 in ?? () from /usr/lib64/libopencv_ts.so.2.4 #8 0x00007fffffffe110 in ?? () #9 0x00007ffff7de9ddf in _dl_fini () from /lib64/ld-linux-x86-64.so.2 Backtrace stopped: frame did not save the PC
Apparently my test had problems at the end of the test, at the time of object destruction. So I started to eliminate every statement until the problem vanished or no statements were left. The result:
#include "gtest/gtest.h" TEST(DemoTest, FailsBadly) { ASSERT_EQ(1, 0); }
And it still crashed! So the code under test wasn’t the culprit. Another change introduced previously was the addition of OpenCV libs to the linker call. An incompatibility between OpenCV and google test? A quick search spitted out posts from users experiencing the same problems, eventually leading to the entry in OpenCVs bug tracker: http://code.opencv.org/issues/1608 or http://code.opencv.org/issues/3225. The opencv_ts library which appeared in the stack trace, exports symbols that conflict with google test version we link against. Since we didn’t need opencv_ts library, the solution was to clean up our linker dependencies:
Before:
find_package(OpenCV)
/usr/bin/c++ CMakeFiles/demo_tests.dir/DemoTests.cpp.o -o demo_tests -rdynamic ../gtest-1.7.0/libgtest_main.a -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_nonfree -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_ts -lopencv_video -lopencv_videostab ../gtest-1.7.0/libgtest.a -lpthread -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_nonfree -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_ts -lopencv_video -lopencv_videostab
After:
find_package(OpenCV REQUIRED core highgui)
/usr/bin/c++ CMakeFiles/demo_tests.dir/DemoTests.cpp.o -o demo_tests -rdynamic ../gtest-1.7.0/libgtest_main.a -lopencv_highgui -lopencv_core ../gtest-1.7.0/libgtest.a -lpthread
Lessons learned:
Know what you really want to depend on and explicitly name it. Ignorance or trust in build tools’ black magic is a recipe for blog posts.