• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *             Copyright Andrey Semashev 2018.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   abi_test_tools.hpp
9  * \author Andrey Semashev
10  * \date   09.03.2018
11  *
12  * \brief  This file contains a set of ABI testing tools
13  */
14 
15 #ifndef BOOST_WINAPI_TEST_RUN_ABI_TEST_TOOLS_HPP_INCLUDED_
16 #define BOOST_WINAPI_TEST_RUN_ABI_TEST_TOOLS_HPP_INCLUDED_
17 
18 #include <boost/winapi/config.hpp>
19 #include <boost/config.hpp>
20 #include <boost/current_function.hpp>
21 #include <boost/core/is_same.hpp>
22 #include <boost/core/lightweight_test.hpp>
23 #include <boost/core/lightweight_test_trait.hpp>
24 #include <boost/preprocessor/seq/for_each.hpp>
25 #include <boost/preprocessor/tuple/elem.hpp>
26 #include <cstddef> // offsetof
27 
28 //! The macro produces Boost.WinAPI equivalent for a Windows SDK constant or type name
29 #define BOOST_WINAPI_NAME(name)\
30     boost::winapi::name
31 
32 //! The macro tests that the given constant has the same value in Boost.WinAPI and Windows SDK
33 #define BOOST_WINAPI_TEST_CONSTANT(name)\
34     BOOST_TEST_EQ(name, BOOST_WINAPI_NAME(name ## _))
35 
36 //! The macro tests that the given type is the same in Boost.WinAPI and Windows SDK
37 #define BOOST_WINAPI_TEST_TYPE_SAME(name)\
38     BOOST_TEST_TRAIT_TRUE((boost::core::is_same< name, BOOST_WINAPI_NAME(name ## _) >))
39 
40 //! The macro tests that the given type has the same size in Boost.WinAPI and Windows SDK
41 #define BOOST_WINAPI_TEST_TYPE_SIZE(name)\
42     BOOST_TEST_EQ(sizeof(name), sizeof(BOOST_WINAPI_NAME(name ## _)))
43 
44 #define BOOST_WINAPI_TEST_STRUCT_FIELD(r, names, field)\
45     BOOST_TEST_EQ(sizeof(BOOST_PP_TUPLE_ELEM(2, 0, names)().field), sizeof(BOOST_PP_TUPLE_ELEM(2, 1, names)().field));\
46     BOOST_TEST_EQ(offsetof(BOOST_PP_TUPLE_ELEM(2, 0, names), field), offsetof(BOOST_PP_TUPLE_ELEM(2, 1, names), field));
47 
48 //! The macro tests that the structure has the same size, and its fields have the same size and offsets in Boost.WinAPI and Windows SDK
49 #define BOOST_WINAPI_TEST_STRUCT(name, fields)\
50     BOOST_PP_SEQ_FOR_EACH(BOOST_WINAPI_TEST_STRUCT_FIELD, (name, BOOST_WINAPI_NAME(name ## _)), fields)\
51     BOOST_TEST_EQ(sizeof(name), sizeof(BOOST_WINAPI_NAME(name ## _)))
52 
53 #if defined(BOOST_MSVC)
54 #pragma warning(push, 3)
55 // conditional expression is constant
56 #pragma warning(disable: 4127)
57 #endif
58 
59 template< typename Windows_SDK_Signature, typename BoostWinAPI_Signature >
test_equal_signatures(Windows_SDK_Signature *,BoostWinAPI_Signature *,const char * test_name,const char * file,int line)60 inline void test_equal_signatures(Windows_SDK_Signature*, BoostWinAPI_Signature*, const char* test_name, const char* file, int line)
61 {
62     // pass BOOST_CURRENT_FUNCTION here to include signature types in the error message
63     boost::detail::test_impl(test_name, file, line, BOOST_CURRENT_FUNCTION,
64         boost::core::is_same< Windows_SDK_Signature, BoostWinAPI_Signature >::value);
65 }
66 
67 #if defined(BOOST_MSVC)
68 #pragma warning(pop)
69 #endif
70 
71 /*!
72  * \brief The macro tests that the given function signature is the same in Boost.WinAPI and Windows SDK
73  *
74  * If the signatures don't match, the test may fail to compile instead of failing at runtime. Depending on the compiler,
75  * the error message may say that either there are multiple different declarations of an extern "C" function, or that
76  * \c test_equal_signatures cannot be instantiated because of an unresolved overloaded function. This is because we currently
77  * have forward declarations of Windows functions in the global namespace, so technically the declaration from Boost.WinAPI
78  * and from Windows SDK are either two declarations of the same function (if they match) or declarations of two overloaded
79  * functions (which is an error because both of them are extern "C"). Anyway, the test will fail if there's an error and
80  * will pass if everything's fine, which is what we want.
81  *
82  * \note Do not use this macro to compare function signatures where we use our own structures binary-compatible with Windows SDK.
83  *       Such functions are defined as inline wrappers in Boost.WinAPI headers and the wrappers will obviously not compare equal
84  *       to the functions in Windows SDK. Currently, there's no way to test those function declarations because Boost.WinAPI
85  *       declares Windows functions in the global namespace. They are implicitly tested by the compiler though, which should fail
86  *       to compile if the declarations don't match.
87  */
88 #if !defined(BOOST_NO_CXX11_DECLTYPE)
89 #define BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(name)\
90     test_equal_signatures((decltype(&name))0, (decltype(&BOOST_WINAPI_NAME(name)))0, "BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(" #name ")", __FILE__, __LINE__)
91 #else
92 #define BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(name)\
93     test_equal_signatures(&name, &BOOST_WINAPI_NAME(name), "BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(" #name ")", __FILE__, __LINE__)
94 #endif
95 
96 #endif // BOOST_WINAPI_TEST_RUN_ABI_TEST_TOOLS_HPP_INCLUDED_
97