Skip to content

Commit 8a568e0

Browse files
authored
CXX-2767 Add macro guards tests for bsoncxx and mongocxx (#1043)
* Use static library for catch/main.cpp * Add include/ and lib/ to target include directories * Add macro guard tests * Fix issues preventing standalone header inclusion * Fix missing prelude header include directives * Add macro guards tests to EVG config * Simplify and improve robustness of test library targets * CXX-2769 Document out-of-place BSONCXX_ENUM guards in macro guard headers * CXX-2770 Workaround missing postlude headers via a test macro
1 parent 2e00223 commit 8a568e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+387
-42
lines changed

.evergreen/compile.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ esac
5151

5252
cd build
5353
"${cmake_binary}" -G "$GENERATOR" "-DCMAKE_BUILD_TYPE=${BUILD_TYPE}" -DBUILD_TESTING=ON -DMONGOCXX_ENABLE_SLOW_TESTS=ON -DENABLE_UNINSTALL=ON "$@" ..
54+
55+
if [[ "${COMPILE_MACRO_GUARD_TESTS:-"OFF"}" == "ON" ]]; then
56+
# We only need to compile the macro guard tests.
57+
"${cmake_binary}" -DENABLE_MACRO_GUARD_TESTS=ON ..
58+
"${cmake_binary}" --build . --config $BUILD_TYPE --target test_bsoncxx_macro_guards test_mongocxx_macro_guards -- $CMAKE_BUILD_OPTS
59+
exit # Nothing else to be done.
60+
fi
61+
62+
# Regular build and install routine.
5463
"${cmake_binary}" --build . --config $BUILD_TYPE -- $CMAKE_BUILD_OPTS
5564
"${cmake_binary}" --build . --config $BUILD_TYPE --target install -- $CMAKE_BUILD_OPTS
5665
"${cmake_binary}" --build . --config $BUILD_TYPE --target $CMAKE_EXAMPLES_TARGET -- $CMAKE_BUILD_OPTS

.mci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ functions:
380380
set -o errexit
381381
set -o pipefail
382382
export BUILD_TYPE=${build_type}
383+
export COMPILE_MACRO_GUARD_TESTS=${COMPILE_MACRO_GUARD_TESTS}
383384
export PATH="${extra_path}:$PATH"
384385
export RUN_DISTCHECK=${RUN_DISTCHECK}
385386
@@ -957,6 +958,14 @@ tasks:
957958
vars:
958959
ENABLE_TESTS: OFF
959960

961+
- name: compile_macro_guard_tests
962+
commands:
963+
- func: "setup"
964+
- func: "fetch_c_driver_source"
965+
- func: "compile"
966+
vars:
967+
COMPILE_MACRO_GUARD_TESTS: ON
968+
960969
- name: compile_and_test_auth_with_shared_libs
961970
commands:
962971
- func: "setup"
@@ -1806,6 +1815,7 @@ buildvariants:
18061815
tasks:
18071816
- name: clang-tidy
18081817
- name: compile_without_tests
1818+
- name: compile_macro_guard_tests
18091819
- name: test_atlas_task_group_search_indexes
18101820

18111821
- name: ubuntu2204-debug-gcc
@@ -1820,6 +1830,7 @@ buildvariants:
18201830
- ubuntu2204-small
18211831
tasks:
18221832
- name: compile_without_tests
1833+
- name: compile_macro_guard_tests
18231834

18241835
- name: ubuntu2204-debug-clang
18251836
display_name: "Ubuntu 22.04 Debug (Clang)"
@@ -1833,6 +1844,7 @@ buildvariants:
18331844
- ubuntu2204-small
18341845
tasks:
18351846
- name: compile_without_tests
1847+
- name: compile_macro_guard_tests
18361848

18371849
- name: mongohouse-ubuntu
18381850
display_name: "Mongohouse Test"

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ set(THIRD_PARTY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/third_party)
351351
set(DATA_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)
352352

353353
option(ENABLE_TESTS "Build MongoDB C++ Driver tests." ON)
354+
option(ENABLE_MACRO_GUARD_TESTS "Enable targets for macro guard compile tests." OFF)
354355

355356
if(ENABLE_TESTS)
356357
enable_testing()

cmake/BsoncxxUtil.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ function(bsoncxx_add_library TARGET OUTPUT_NAME LINK_TYPE)
4646
${TARGET}
4747
PUBLIC
4848
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/bsoncxx/v_noabi>
49+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
4950
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib/bsoncxx/v_noabi>
51+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>
5052
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/lib/bsoncxx/v_noabi>
53+
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/lib>
5154
)
5255
target_compile_definitions(${TARGET} PRIVATE ${libbson_definitions})
5356
endfunction(bsoncxx_add_library)

cmake/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_subdirectory(make_dist)
1616

1717
set(cmake_MODULES
1818
ParseVersion.cmake
19+
MacroGuardTest.cmake
1920
BsoncxxUtil.cmake
2021
MongocxxUtil.cmake
2122
)

cmake/MacroGuardTest.cmake

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#[==[
2+
Define a build-time static library target whose compilation asserts that
3+
header files are properly guarding config macros using inclusion of
4+
prelude/postlude headers.
5+
6+
Usage:
7+
8+
add_macro_guard_test(
9+
PROJECT_NAME <name>
10+
PROJECT_TEST_PROPERTIES_TARGET <target>
11+
INCLUDE_PATTERNS [pattern...]
12+
[EXCLUDE_REGEXES [pattern...]]
13+
GUARDED_MACROS [macro...]
14+
)
15+
16+
PROJECT_NAME
17+
Either "bsoncxx" or "mongocxx".
18+
19+
PROJECT_TEST_PROPERTIES_TARGET
20+
Either the bsoncxx_test_properties or mongocxx_test_properties target.
21+
22+
GUARDED_MACROS
23+
List of macros that should be guarded by prelude/postlude headers.
24+
25+
INCLUDE_PATTERNS
26+
List of regex filters for headers to be added to the tests. Must be
27+
relative to PROJECT_SOURCE_DIR.
28+
29+
EXCLUDE_REGEXES
30+
List of regex filters for headers to be excluded. Applied after
31+
INCLUDE_PATTERNS.
32+
]==]
33+
function(add_macro_guard_test)
34+
set(opt_args "")
35+
set(single_args "PROJECT_NAME;PROJECT_TEST_PROPERTIES_TARGET")
36+
set(multi_args "GUARDED_MACROS;INCLUDE_PATTERNS;EXCLUDE_REGEXES")
37+
38+
cmake_parse_arguments(PARSED "${opt_args}" "${single_args}" "${multi_args}" ${ARGN})
39+
40+
if(NOT "${PARSED_UNPARSED_ARGUMENTS}" STREQUAL "")
41+
message(FATAL_ERROR "unrecognized argument: ${PARSED_UNPARSED_ARGUMENTS}")
42+
endif()
43+
44+
foreach(required_arg PROJECT_NAME PROJECT_TEST_PROPERTIES_TARGET GUARDED_MACROS INCLUDE_PATTERNS)
45+
if("${required_arg}" IN_LIST PARSED_KEYWORDS_MISSING_VALUES)
46+
message(FATAL_ERROR "missing value for required argument ${required_arg}")
47+
endif()
48+
endforeach()
49+
50+
list(TRANSFORM PARSED_INCLUDE_PATTERNS PREPEND "${PROJECT_SOURCE_DIR}/")
51+
file(GLOB_RECURSE GUARDED_HEADERS
52+
LIST_DIRECTORIES false
53+
RELATIVE ${PROJECT_SOURCE_DIR}
54+
${PARSED_INCLUDE_PATTERNS}
55+
)
56+
57+
foreach(filter ${PARSED_EXCLUDE_REGEXES})
58+
list(FILTER GUARDED_HEADERS EXCLUDE REGEX "${filter}")
59+
endforeach()
60+
61+
set(MACRO_GUARD_TEST_PRELUDE "")
62+
63+
# Check and set initial state.
64+
foreach(macro ${PARSED_GUARDED_MACROS})
65+
string(APPEND MACRO_GUARD_TEST_PRELUDE
66+
"#if defined(${macro})\n"
67+
"#error \"${macro} is already defined\"\n"
68+
"#endif\n"
69+
"#define ${macro} macro guard test\n"
70+
"\n"
71+
)
72+
endforeach()
73+
74+
# Implement as recursive algorithm for C++11 compatibility.
75+
string(APPEND MACRO_GUARD_TEST_PRELUDE
76+
"static constexpr bool compare_equal(const char* lhs, const char* rhs) {\n"
77+
" return (*lhs == *rhs) && (*lhs == '\\0' || compare_equal(lhs + 1, rhs + 1));\n"
78+
"}\n"
79+
"\n"
80+
"static_assert(compare_equal(\"abc\", \"abc\"), \"compare_equal() sanity check failed\");\n"
81+
"static_assert(!compare_equal(\"abc\", \"def\"), \"compare_equal() sanity check failed\");\n"
82+
"\n"
83+
"#define _TO_STR(x) #x\n"
84+
"#define TO_STR(x) _TO_STR(x)\n"
85+
"\n"
86+
)
87+
88+
add_library(test_${PARSED_PROJECT_NAME}_macro_guards STATIC EXCLUDE_FROM_ALL)
89+
target_link_libraries(test_${PARSED_PROJECT_NAME}_macro_guards PRIVATE ${PARSED_PROJECT_TEST_PROPERTIES_TARGET})
90+
91+
# Test each header individually.
92+
foreach(header ${GUARDED_HEADERS})
93+
set(MACRO_GUARD_TEST "${MACRO_GUARD_TEST_PRELUDE}")
94+
95+
# Strip the subdir.
96+
string(REGEX REPLACE "^(include|lib|test)/(.*)$" "\\1" subdir "${header}")
97+
string(REGEX REPLACE "^(include|lib|test)/(.*)$" "\\2" header ${header})
98+
99+
# Apply include prefix to test headers.
100+
if("${subdir}" STREQUAL "test")
101+
set(relheader "${PARSED_PROJECT_NAME}/test/${header}")
102+
else()
103+
set(relheader "${header}")
104+
endif()
105+
106+
# CXX-2770: workaround missing postlude header includes.
107+
string(TOUPPER "${PARSED_PROJECT_NAME}" project_name_upper)
108+
string(APPEND MACRO_GUARD_TEST "#define ${project_name_upper}_TEST_MACRO_GUARDS_FIX_MISSING_POSTLUDE\n\n")
109+
110+
# The include directive.
111+
string(APPEND MACRO_GUARD_TEST "#include <${relheader}>\n\n")
112+
113+
# Test all guarded macros have been properly restored.
114+
foreach(macro ${PARSED_GUARDED_MACROS})
115+
string(APPEND MACRO_GUARD_TEST
116+
"static_assert(\n"
117+
" compare_equal(TO_STR(${macro}),\"macro guard test\"),\n"
118+
" \"${macro} was not correctly restored by <${relheader}>\"\n"
119+
");\n"
120+
"\n"
121+
)
122+
endforeach()
123+
124+
# e.g. bsoncxx/v_noabi/bsoncxx/document/view.hpp -> bsoncxx-v_noabi-bsoncxx-document-view.cpp
125+
string(REPLACE "/" "-" test_name "${header}")
126+
string(REGEX REPLACE "^(.*)\\.(hh|hpp)$" "\\1" test_name "${test_name}")
127+
128+
# e.g. macro_guards/(include|lib|test)/bsoncxx-v_noabi-bsoncxx-document-view.cpp
129+
configure_file(test_macro_guards.cpp.in macro_guards/${subdir}/${test_name}.cpp)
130+
131+
target_sources(test_${PARSED_PROJECT_NAME}_macro_guards PRIVATE
132+
${CMAKE_CURRENT_BINARY_DIR}/macro_guards/${subdir}/${test_name}.cpp
133+
)
134+
endforeach()
135+
endfunction()

cmake/MongocxxUtil.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ function(mongocxx_add_library TARGET OUTPUT_NAME LINK_TYPE)
3434
${TARGET}
3535
PUBLIC
3636
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/mongocxx/v_noabi>
37+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
3738
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib/mongocxx/v_noabi>
39+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>
3840
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/lib/mongocxx/v_noabi>
41+
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/lib>
3942
)
4043
target_compile_definitions(${TARGET} PRIVATE ${libmongoc_definitions})
4144
endfunction(mongocxx_add_library)

src/bsoncxx/cmake/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ if(1)
5454
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
5555
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime
5656
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev
57-
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bsoncxx/v_noabi
57+
INCLUDES DESTINATION
58+
${CMAKE_INSTALL_INCLUDEDIR}/bsoncxx/v_noabi
59+
${CMAKE_INSTALL_INCLUDEDIR}
5860
)
5961

6062
install(EXPORT bsoncxx_targets
@@ -76,6 +78,7 @@ endif()
7678
if(1)
7779
set(PACKAGE_INCLUDE_INSTALL_DIRS
7880
${CMAKE_INSTALL_INCLUDEDIR}/bsoncxx/v_noabi
81+
${CMAKE_INSTALL_INCLUDEDIR}
7982
${BSONCXX_POLY_MNMLSTC_DEPRECATED_INCLUDE_DIRS}
8083
)
8184
set(PACKAGE_LIBRARY_INSTALL_DIRS ${CMAKE_INSTALL_LIBDIR})

src/bsoncxx/cmake/libbsoncxx-static.pc.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ Description: The MongoDB C++11 BSON Library
2121
URL: http://github.com/mongodb/mongo-cxx-driver
2222
Version: @BSONCXX_VERSION@
2323
Requires: libbson-static-@LIBBSON_REQUIRED_ABI_VERSION@ >= @LIBBSON_REQUIRED_VERSION@
24-
Cflags: @BSONCXX_POLY_MNMLSTC_PKGCONFIG_STATIC_INCLUDE_DIRS@-I${includedir}/bsoncxx/v_noabi -DBSONCXX_STATIC
24+
Cflags: @BSONCXX_POLY_MNMLSTC_PKGCONFIG_STATIC_INCLUDE_DIRS@-I${includedir}/bsoncxx/v_noabi -I${includedir} -DBSONCXX_STATIC
2525
Libs: -L${libdir} -lbsoncxx-static

src/bsoncxx/cmake/libbsoncxx.pc.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ Name: libbsoncxx
2020
Description: The MongoDB C++11 BSON Library
2121
URL: http://github.com/mongodb/mongo-cxx-driver
2222
Version: @BSONCXX_VERSION@
23-
Cflags: @BSONCXX_POLY_MNMLSTC_PKGCONFIG_INCLUDE_DIRS@-I${includedir}/bsoncxx/v_noabi
23+
Cflags: @BSONCXX_POLY_MNMLSTC_PKGCONFIG_INCLUDE_DIRS@-I${includedir}/bsoncxx/v_noabi -I${includedir}
2424
Libs: -L${libdir} -lbsoncxx

src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/builder/list.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,8 @@ class array : public list {
186186
} // namespace builder
187187
} // namespace v_noabi
188188
} // namespace bsoncxx
189+
190+
// CXX-2770: missing include of postlude header.
191+
#if defined(BSONCXX_TEST_MACRO_GUARDS_FIX_MISSING_POSTLUDE)
192+
#include <bsoncxx/config/postlude.hpp>
193+
#endif

src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,6 @@
4545
#undef BSONCXX_VERSION_PATCH
4646
#pragma pop_macro("BSONCXX_VERSION_PATCH")
4747

48-
// bsoncxx/types.hpp
49-
#ifdef BSONCXX_ENUM
50-
static_assert(false, "BSONCXX_ENUM must be undef'ed");
51-
#endif
52-
#pragma pop_macro("BSONCXX_ENUM")
53-
5448
// export.hpp (generated by CMake)
5549
#undef BSONCXX_API_H
5650
#pragma pop_macro("BSONCXX_API_H")
@@ -72,3 +66,9 @@ static_assert(false, "BSONCXX_ENUM must be undef'ed");
7266
// prelude.hpp
7367
#undef BSONCXX_UNREACHABLE
7468
#pragma pop_macro("BSONCXX_UNREACHABLE")
69+
70+
// CXX-2769: out-of-place, but remains for backward compatibility.
71+
#ifdef BSONCXX_ENUM
72+
static_assert(false, "BSONCXX_ENUM must be undef'ed");
73+
#endif
74+
#pragma pop_macro("BSONCXX_ENUM")

src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@
4242
#pragma push_macro("BSONCXX_VERSION_PATCH")
4343
#undef BSONCXX_VERSION_PATCH
4444

45-
// bsoncxx/types.hpp
46-
#pragma push_macro("BSONCXX_ENUM")
47-
#undef BSONCXX_ENUM
48-
4945
// export.hpp (generated by CMake)
5046
#pragma push_macro("BSONCXX_API_H")
5147
#undef BSONCXX_API_H
@@ -73,6 +69,10 @@
7369
#undef BSONCXX_UNREACHABLE
7470
#define BSONCXX_UNREACHABLE std::abort()
7571

72+
// CXX-2769: out-of-place, but remains for backward compatibility.
73+
#pragma push_macro("BSONCXX_ENUM")
74+
#undef BSONCXX_ENUM
75+
7676
// Doxygen does not account for generated header files.
7777
// Document globally applicable macros and namespaces here.
7878

src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/types.hpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@
1313
// limitations under the License.
1414

1515
#pragma once
16-
#if defined(__clang__)
17-
#pragma clang diagnostic push
18-
#pragma clang diagnostic ignored "-Wfloat-equal"
19-
#elif defined(__GNUC__)
20-
#pragma GCC diagnostic push
21-
#pragma GCC diagnostic ignored "-Wfloat-equal"
22-
#endif
2316

2417
#include <chrono>
2518
#include <cstring>
@@ -32,6 +25,17 @@
3225

3326
#include <bsoncxx/config/prelude.hpp>
3427

28+
#pragma push_macro("BSONCXX_ENUM")
29+
#undef BSONCXX_ENUM
30+
31+
#if defined(__clang__)
32+
#pragma clang diagnostic push
33+
#pragma clang diagnostic ignored "-Wfloat-equal"
34+
#elif defined(__GNUC__)
35+
#pragma GCC diagnostic push
36+
#pragma GCC diagnostic ignored "-Wfloat-equal"
37+
#endif
38+
3539
namespace bsoncxx {
3640
inline namespace v_noabi {
3741
///
@@ -683,10 +687,15 @@ BSONCXX_INLINE bool operator==(const b_maxkey&, const b_maxkey&) {
683687
} // namespace v_noabi
684688
} // namespace bsoncxx
685689

686-
#include <bsoncxx/config/postlude.hpp>
687-
688690
#if defined(__clang__)
689691
#pragma clang diagnostic pop
690692
#elif defined(__GNUC__)
691693
#pragma GCC diagnostic pop
692694
#endif
695+
696+
#ifdef BSONCXX_ENUM
697+
static_assert(false, "BSONCXX_ENUM must be undef'ed");
698+
#endif
699+
#pragma pop_macro("BSONCXX_ENUM")
700+
701+
#include <bsoncxx/config/postlude.hpp>

src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/types/private/convert.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,5 @@ BSONCXX_INLINE void convert_from_libbson(bson_value_t* v, bsoncxx::types::b_arra
330330
} // namespace types
331331
} // namespace v_noabi
332332
} // namespace bsoncxx
333+
334+
#include <bsoncxx/config/private/postlude.hh>

0 commit comments

Comments
 (0)