// bsls_bsltestutil.h -*-C++-*- #ifndef INCLUDED_BSLS_BSLTESTUTIL #define INCLUDED_BSLS_BSLTESTUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide test utilities for 'bsl' that do not use <iostream>. // //@CLASSES: // bsls::BslTestUtil: utilities to aid writing 'bsl' test drivers // //@MACROS: // BSLS_BSLTESTUTIL_ASSERT(X): record and print error if '!X' // BSLS_BSLTESTUTIL_LOOP_ASSERT(I, X): print args if '!X' // BSLS_BSLTESTUTIL_LOOP2_ASSERT(I, J, X): print args if '!X' // BSLS_BSLTESTUTIL_LOOP3_ASSERT(I, J, K, X): print args if '!X' // BSLS_BSLTESTUTIL_LOOP4_ASSERT(I, J, K, L, X): print args if '!X' // BSLS_BSLTESTUTIL_LOOP5_ASSERT(I, J, K, L, M, X): print args if '!X' // BSLS_BSLTESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, X): print args if '!X' // BSLS_BSLTESTUTIL_LOOP7_ASSERT(I, J, K, L, M, N, O, X): print args if '!X' // BSLS_BSLTESTUTIL_LOOP8_ASSERT(I, J, K, L, M, N, O,V, X): print args if '!X' // // BSLS_BSLTESTUTIL_Q(X) : quote identifier literally // BSLS_BSLTESTUTIL_P(X) : print identifier and value // BSLS_BSLTESTUTIL_P_(X): print identifier and value without '\n' // BSLS_BSLTESTUTIL_L_ : current line number // BSLS_BSLTESTUTIL_T_ : print tab without '\n' // // BSLS_BSLTESTUTIL_FORMAT_ZU : 'printf' format for 'size_t' // BSLS_BSLTESTUTIL_FORMAT_TD : 'printf' format for 'ptrdiff_t' // BSLS_BSLTESTUTIL_FORMAT_I64: 'printf' format for unsigned 64-bit integers // BSLS_BSLTESTUTIL_FORMAT_U64: 'printf' format for signed 64-bit integers // BSLS_BSLTESTUTIL_FORMAT_PTR: 'printf' format for 'uintptr_t' // //@DESCRIPTION: This component provides standard facilities for components in // the 'bsl' package group to produce test driver output, including the // standard printing macros used in BDE-style test drivers ('ASSERT', // 'LOOP_ASSERT', 'ASSERTV', 'P', 'Q', 'L', and 'T'), and a suite of // cross-platform format strings for printing C++ or BDE-specific types with // 'printf'. // // Many components in the 'bsl' package group reside below the standard // library; therefore, hierarchical design dictates that the test driver for // these components shall not use 'iostream' (which is part of the standard // library), and instead they shall only rely on the 'printf' function to print // objects' values. Using 'printf' over 'iostream' has the following // disadvantages: // //: o The 'printf' function requires a format string to specify the way to //: print an object; so, unlike 'iostream', printing different types of //: objects using 'printf' requires different syntaxes due to the need for //: different format strings. //: //: o While the format strings for built-in types can be included as part of //: the standard boiler plate code of the test driver, printing a //: user-defined type often requires additional code that is not part of the //: standard boilerplate. // // This component provides solutions to these issues by (1) encapsulating all // the standard printing macros in a single place, (2) providing a way to // extend the supplied macros to support user-defined types, and (3) providing // macros that resolve the correct 'printf' format strings for types that do // not have standard, cross-platform format strings of their own. // // The macros in this component use a class method template, // 'BslTestUtil::callDebugprint', to print the value of an object of the // parameterized type, along with an optional leading string and an optional // trailing string, to the console. The value of the object of the // parameterized type will be printed using a free function named 'debugprint'. // // The macros defined in this component natively support built-in types through // the 'debugprint' function overloads for these types defined in this // component. The macros can be extended support additional user-defined types // by defining function overloads for 'debugprint' that takes a single // parameter of each user-defined type, in the same namespace in which the // user-defined type is defined. See the second usage example for more // details. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Writing a Test Driver /// - - - - - - - - - - - - - - - - // First, we write a component to test, which provides a utility class: //.. // namespace bslabc { // // struct BslExampleUtil { // // This utility class provides sample functionality to demonstrate how // // a test driver might be written validating its only method. // // static int fortyTwo(); // // Return the integer value '42'. // }; // // inline // int BslExampleUtil::fortyTwo() // { // return 42; // } // // } // close package namespace //.. // Then, we can write a test driver for this component. We start by providing // the standard BDE assert test macro: //.. // // ======================================================================== // // STANDARD BDE ASSERT TEST MACRO // // ------------------------------------------------------------------------ // static int testStatus = 0; // // static void aSsErT(bool b, const char *s, int i) // { // if (b) { // printf("Error " __FILE__ "(%d): %s (failed)\n", i, s); // if (testStatus >= 0 && testStatus <= 100) ++testStatus; // } // } // // # define ASSERT(X) { aSsErT(!(X), #X, __LINE__); } //.. // Next, we define the standard print and 'LOOP_ASSERT' macros, as aliases to // the macros defined by this component: //.. // // ======================================================================== // // STANDARD BDE TEST DRIVER MACROS // // ------------------------------------------------------------------------ // #define LOOP_ASSERT BSLS_BSLTESTUTIL_LOOP_ASSERT // #define LOOP2_ASSERT BSLS_BSLTESTUTIL_LOOP2_ASSERT // #define LOOP3_ASSERT BSLS_BSLTESTUTIL_LOOP3_ASSERT // #define LOOP4_ASSERT BSLS_BSLTESTUTIL_LOOP4_ASSERT // #define LOOP5_ASSERT BSLS_BSLTESTUTIL_LOOP5_ASSERT // #define LOOP6_ASSERT BSLS_BSLTESTUTIL_LOOP6_ASSERT // #define LOOP7_ASSERT BSLS_BSLTESTUTIL_LOOP7_ASSERT // #define LOOP8_ASSERT BSLS_BSLTESTUTIL_LOOP8_ASSERT // // #define Q BSLS_BSLTESTUTIL_Q // Quote identifier literally. // #define P BSLS_BSLTESTUTIL_P // Print identifier and value. // #define P_ BSLS_BSLTESTUTIL_P_ // 'P(X)' without '\n'. // #define T_ BSLS_BSLTESTUTIL_T_ // Print a tab (w/o newline). // #define L_ BSLS_BSLTESTUTIL_L_ // current Line number //.. // Now, using the (standard) abbreviated macro names we have just defined, we // write a test function for the 'static' 'fortyTwo' method, to be called from // a test case in a test driver. //.. // void testFortyTwo(bool verbose) // { // const int value = bslabc::BslExampleUtil::fortyTwo(); // if (verbose) P(value); // LOOP_ASSERT(value, 42 == value); // } //.. // Finally, when 'testFortyTwo' is called from a test case in verbose mode we // observe the console output: //.. // value = 42 //.. // ///Example 2: Adding Support For A New User-Defined Type ///- - - - - - - - - - - - - - - - - - - - - - - - - - - // First, we define a new user-defined type, 'MyType': //.. // namespace xyza { // // class MyType { // // This elided class provides a type intended to show how the macros in // // 'bsls_bsltestutil' can be extended to support a new user-defined // // type. // // private: // // DATA // int d_value; // the value of MyType // // // ... // // public: // // CREATORS // // // ... // // explicit MyType(int value); // // Create a 'MyType' object with 'd_value' set to the specified // // 'value'. // // // ACCESSORS // // // ... // // int value() const; // // Return the value of 'd_value'. // // // ... // }; // // // ... // // inline // MyType::MyType(int value) // : d_value(value) // { // } // // // ... // // inline // int MyType::value() const // { // return d_value; // } //.. // Then, in the same namespace in which 'MyType' is defined, we define a // function 'debugprint' that prints the value of a 'MyType' object to the // console. (In this case, we will simply print a string literal for // simplicity): //.. // void debugprint(const MyType& obj) // { // printf("MyType<%d>", obj.value()); // } // // } // close namespace xyza //.. // Now, using the (standard) abbreviated macro names previously defined, we // write a test function for the 'MyType' constructor, to be called from a test // case in a test driver. //.. // void testMyTypeSetValue(bool verbose) { // xyza::MyType obj(9); // if (verbose) P(obj); // LOOP_ASSERT(obj.value(), obj.value() == 9); // } //.. // Finally, when 'testMyTypeSetValue' is called from a test case in verbose // mode we observe the console output: //.. // obj = MyType<9> //.. // ///Example 3: Printing Unusual Types with 'printf' ///- - - - - - - - - - - - - - - - - - - - - - - - // Suppose we are writing a test driver that needs to print out the contents of // a complex data structure in 'veryVeryVerbose' mode. The complex data // structure contains, among other values, an array of block sizes, expressed // as 'size_t'. It would be very cumbersome, and visually confusing, to print // each member of the array with either the 'P_' or 'Q_' standard output // macros, so we elect to print out the array as a single string, following the // pattern of '[ A, B, C, D, E, ... ]'. This could be easily accomplished with // multiple calls to 'printf', except that 'printf' has no cross-platform // standard formatting string for 'size_t'. We can use the // 'BSLS_BSLTESTUTIL_FORMAT_ZU' macro to resolve the appropriate format string // for us on each platform. // // First, we write a component to test, which provides an a utility that // operates on a list of memory blocks. Each block is a structure containing a // base address, a block size, and a pointer to the next block in the list. //.. // namespace xyza { // struct Block { // // DATA // char *d_address; // size_t d_size; // Block *d_next; // // // ... // }; // // class BlockList { // // ... // // // DATA // Block *d_head; // // // ... // // public: // // CREATORS // BlockList(); // ~BlockList(); // // // MANIPULATORS // // Block *begin(); // Block *end(); // // void addBlock(size_t size); // // // ... // // // ACCESSORS // int length(); // // // ... // }; // // } // close namespace xyza //.. // Then, we write a test driver for this component. //.. // // ... // // // ======================================================================== // // STANDARD BDE TEST DRIVER MACROS // // ------------------------------------------------------------------------ // // // ... //.. // Here, after defining the standard BDE test macros, we define a macro, 'ZU' // for the platform-specific 'printf' format string for 'size_t': //.. // // ======================================================================== // // PRINTF FORMAT MACROS // // ------------------------------------------------------------------------ // #define ZU BSLS_BSLTESTUTIL_FORMAT_ZU //.. // Note that, we could use 'BSLS_BSLTESTUTIL_FORMAT_ZU' as is, but it is more // convenient to define 'ZU' locally as an abbreviation. // // Next, we write the test apparatus for the test driver, which includes a // support function that prints the list of blocks in a 'BlockList' in a // visually succinct form: //.. // void printBlockList(xyza::BlockList &list) // { // xyza::Block *blockPtr = list.begin(); // // printf("{\n"); // while (blockPtr != list.end()) { //.. // Here, we use 'ZU' as the format specifier for the 'size_t' in the 'printf' // invocation. 'ZU' is the appropriate format specifier for 'size_t' on each // supported platform. //.. // printf("\t{ address: %p,\tsize: " ZU " }", // blockPtr->d_address, // blockPtr->d_size); // blockPtr = blockPtr->d_next; // // if (blockPtr) { // printf(",\n"); // } else { // printf("\n"); // } // } // printf("}\n"); // } //.. // Note that because we are looping through a number of blocks, formatting the // output directly with 'printf' produces more readable output than we would // get from callling the standard output macros. // // Calling 'printf' directly will yield output similar to: //.. // { // { address: 0x012345600, size: 32 }, // ... // } //.. // while the standard output macros would have produced: //.. // { // { blockPtr->d_address = 0x012345600, blockPtr->d_size: 32 }, // ... // } //.. // Now, we write a test function for one of our test cases, which provides a // detailed trace of 'BlockList' contents: //.. // void testBlockListConstruction(bool veryVeryVerbose) // { // // ... // // { // xyza::BlockList bl; // // bl.addBlock(42); // bl.addBlock(19); // bl.addBlock(1024); // // if (veryVeryVerbose) { // printBlockList(bl); // } // // ASSERT(3 == bl.length()); // // // ... // } // // // ... // } //.. // Finally, when 'testBlockListConstruction' is called from a test case in // 'veryVeryVerbose' mode, we observe console output similar to: //.. // { // { address: 0x012345600, size: 42 }, // { address: 0x012345610, size: 19 }, // { address: 0x012345620, size: 1024 } // } //.. #include <bsls_platform.h> #if defined(BSLS_PLATFORM_CMP_MSVC) # include <stddef.h> #else # include <stdint.h> #endif // ================= // Macro Definitions // ================= #define BSLS_BSLTESTUTIL_ASSERT(X) \ do { aSsErT(!(X), #X, __LINE__); } while (false) #define BSLS_BSLTESTUTIL_LOOP0_ASSERT \ BSLS_BSLTESTUTIL_ASSERT #define BSLS_BSLTESTUTIL_LOOP_ASSERT(I,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) #define BSLS_BSLTESTUTIL_LOOP1_ASSERT \ BSLS_BSLTESTUTIL_LOOP_ASSERT #define BSLS_BSLTESTUTIL_LOOP2_ASSERT(I,J,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(J, #J ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) #define BSLS_BSLTESTUTIL_LOOP3_ASSERT(I,J,K,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(J, #J ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(K, #K ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) #define BSLS_BSLTESTUTIL_LOOP4_ASSERT(I,J,K,L,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(J, #J ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(K, #K ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(L, #L ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) #define BSLS_BSLTESTUTIL_LOOP5_ASSERT(I,J,K,L,M,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(J, #J ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(K, #K ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(L, #L ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(M, #M ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) #define BSLS_BSLTESTUTIL_LOOP6_ASSERT(I,J,K,L,M,N,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(J, #J ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(K, #K ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(L, #L ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(M, #M ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(N, #N ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) #define BSLS_BSLTESTUTIL_LOOP7_ASSERT(I,J,K,L,M,N,O,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(J, #J ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(K, #K ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(L, #L ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(M, #M ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(N, #N ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(O, #O ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) #define BSLS_BSLTESTUTIL_LOOP8_ASSERT(I,J,K,L,M,N,O,V,X) do { \ if (!(X)) { BloombergLP::bsls:: \ BslTestUtil::callDebugprint(I, #I ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(J, #J ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(K, #K ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(L, #L ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(M, #M ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(N, #N ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(O, #O ": ", "\t"); \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(V, #V ": ", "\n"); \ aSsErT(true, #X, __LINE__); } } while (false) // The 'BSLS_BSLTESTUTIL_EXPAND' macro is required to workaround a // pre-processor issue on windows that prevents __VA_ARGS__ to be expanded in // the definition of 'BSLS_BSLTESTUTIL_NUM_ARGS' #define BSLS_BSLTESTUTIL_EXPAND(X) \ X #define BSLS_BSLTESTUTIL_NUM_ARGS_IMPL(X8, X7, X6, X5, X4, X3, X2, X1, X0, \ N, ...) \ N #define BSLS_BSLTESTUTIL_NUM_ARGS(...) \ BSLS_BSLTESTUTIL_EXPAND(BSLS_BSLTESTUTIL_NUM_ARGS_IMPL( \ __VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0, "")) #define BSLS_BSLTESTUTIL_LOOPN_ASSERT_IMPL(N, ...) \ BSLS_BSLTESTUTIL_EXPAND(BSLS_BSLTESTUTIL_LOOP ## N ## _ASSERT(__VA_ARGS__)) #define BSLS_BSLTESTUTIL_LOOPN_ASSERT(N, ...) \ BSLS_BSLTESTUTIL_LOOPN_ASSERT_IMPL(N, __VA_ARGS__) #define BSLS_BSLTESTUTIL_ASSERTV(...) \ BSLS_BSLTESTUTIL_LOOPN_ASSERT( \ BSLS_BSLTESTUTIL_NUM_ARGS(__VA_ARGS__), __VA_ARGS__) // STANDARD TEST DRIVER OUTPUT MACROS #define BSLS_BSLTESTUTIL_Q(X) \ BloombergLP::bsls:: \ BslTestUtil::printStringNoFlush("<| " #X " |>\n"); // Quote identifier literally. #define BSLS_BSLTESTUTIL_P(X) \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(X, #X " = ", "\n"); // Print identifier and its value. #define BSLS_BSLTESTUTIL_P_(X) \ BloombergLP::bsls:: \ BslTestUtil::callDebugprint(X, #X " = ", ", "); // P(X) without '\n'. #define BSLS_BSLTESTUTIL_L_ __LINE__ // Current line number. #define BSLS_BSLTESTUTIL_T_ BloombergLP::bsls::BslTestUtil::printTab(); // Print a tab (w/o newline). // PRINTF FORMAT MACROS #if defined(BSLS_PLATFORM_CMP_MSVC) # define BSLS_BSLTESTUTIL_FORMAT_ZU "%Iu" #else # define BSLS_BSLTESTUTIL_FORMAT_ZU "%zu" #endif // Provide a platform-independent way to specify a 'size_t' format for // 'printf'. #if defined(BSLS_PLATFORM_CMP_MSVC) # define BSLS_BSLTESTUTIL_FORMAT_TD "%Id" #else # define BSLS_BSLTESTUTIL_FORMAT_TD "%td" #endif // Provide a platform-independent way to specify a 'ptrdiff_t' format for // 'printf'. #if defined(BSLS_PLATFORM_CMP_MSVC) # define BSLS_BSLTESTUTIL_FORMAT_I64 "%I64d" #else # define BSLS_BSLTESTUTIL_FORMAT_I64 "%lld" #endif // Provide a platform-independent way to specify a signed 64-bit integer // format for 'printf'. #if defined(BSLS_PLATFORM_CMP_MSVC) # define BSLS_BSLTESTUTIL_FORMAT_U64 "%I64u" #else # define BSLS_BSLTESTUTIL_FORMAT_U64 "%llu" #endif // Provide a platform-independent way to specify an unsigned 64-bit integer // format for 'printf'. #if defined(BSLS_PLATFORM_CPU_64_BIT) # if defined(BSLS_PLATFORM_CMP_MSVC) # define BSLS_BSLTESTUTIL_FORMAT_PTR "%llX" # else # define BSLS_BSLTESTUTIL_FORMAT_PTR "%lX" # endif #else # define BSLS_BSLTESTUTIL_FORMAT_PTR "%X" #endif // Provide a platform-independent way to specify a 'uintptr_t' integer // format for 'printf'. namespace BloombergLP { namespace bsls { // ================== // struct BslTestUtil // ================== struct BslTestUtil { // This class provides a namespace for utilities that are useful when // writing a test driver that is not permitted to use the standard C++ // iostream facilities, which is typical of test drivers in the 'bsl' // package group. private: // PRIVATE CLASS METHODS static void *identityPtr(void *ptr); // Return 'ptr' without modification. Note that this is NOT an inline // function, so that if the caller is not in the same module, the // compiler has no way of knowing that it's an identity transform. public: // CLASS METHODS static void flush(); // Write any unwritten text in the output buffer to 'stdout'. static void printStringNoFlush(const char *s); // Print to the console the specified string, 's'. Note that the // underlying stream is *not* flushed. static void printTab(); // Print to the console a tab character, and then 'flush' the // underlying stream to ensure the text is written. template <class TYPE> static void callDebugprint(const TYPE& object, const char *leadingString = 0, const char *trailingString = 0); // Print the value of the specified 'object' of the parameterized // 'TYPE' to the console. Optionally specify a 'leadingString', which // will be printed before 'object', and a 'trailingString', which will // be printed after 'object'. If 'leadingString' is 0, then nothing // will be printed before 'object'. If 'trailingString' is 0, then // nothing will be printed after 'object'. template <class FUNCTION_PTR> static FUNCTION_PTR makeFunctionCallNonInline(FUNCTION_PTR functionPtr); // Return the specified 'functionPtr' (expected to be a static function // pointer) without modification. The value of 'functionPtr' is // transformed through 'identityPtr' so that if the caller is in a // different module, the compiler will have no way of knowing that this // is an identity transform and thus no way of inlining the call. // // Note: the Windows optimizer is still able to inline the call, it may // be comparing the result of this function with the argument and // branching to inline on equality and call on inequality, so the // Windows optimizer has to be turned off with // '# pragma optimize("", off)'. // // Also note that even with an optimizer that can't figure out that // this is an identity transform, there is still the possibility of // chaining the call. }; // FREE FUNCTIONS void debugprint(bool v); // Print to the console the string "true" if the specified 'v' is true, and // the string "false" otherwise. void debugprint(char v); // Print to the console the specified character, 'v', enclosed by // single-quote characters ('). void debugprint(signed char v); void debugprint(unsigned char v); void debugprint(short v); void debugprint(unsigned short v); void debugprint(int v); void debugprint(unsigned int v); void debugprint(long v); void debugprint(unsigned long v); void debugprint(long long v); void debugprint(unsigned long long v); // Print to the console the specified integer value, 'v', formatted as a // string. void debugprint(float v); void debugprint(double v); void debugprint(long double v); // Print to the console the specified value, 'v', formatted as a string // enclosed by single-quote characters ('). void debugprint(const char * v); void debugprint(char * v); void debugprint(const volatile char *v); void debugprint(volatile char *v); // Print to the console the specified string, 'v', enclosed by quote // characters ("), unless 'v' is null, in which case print '(null)' // (without quotes of any kind). void debugprint(void * v); void debugprint(volatile void * v); void debugprint(const void * v); void debugprint(const volatile void *v); // Print to the console the specified memory address, 'v', formatted as a // hexadecimal integer. template <class RESULT> void debugprint(RESULT (*v)()); // Print to the console the specified function pointer, 'v', formatted as a // hexadecimal integer. On some platforms (notably Windows), a function // pointer is treated differently from an object pointer, and the compiler // will not be able to determine which 'void *' overload of 'debugprint' // should be used for a function pointer. Therefore an overload of // 'debugprint' is provided specifically for function pointers. Because // the type signature of a function pointer varies with its return type as // well as with its argument list, a template function is used, to provide // matches for all return types. // ============================================================================ // TEMPLATE AND INLINE FUNCTION DEFINITIONS // ============================================================================ // ------------------ // struct BslTestUtil // ------------------ // CLASS METHODS template <class TYPE> void BslTestUtil::callDebugprint(const TYPE& obj, const char *leadingString, const char *trailingString) { if (leadingString) { BloombergLP::bsls::BslTestUtil::printStringNoFlush(leadingString); } debugprint(obj); if (trailingString) { BloombergLP::bsls::BslTestUtil::printStringNoFlush(trailingString); } flush(); } template <class FUNCTION_PTR> inline FUNCTION_PTR BslTestUtil::makeFunctionCallNonInline(FUNCTION_PTR function) { // 'static_assert' isn't available pre-C++11, and 'BSLMF_ASSERT' is not // accessible from here in bsls, so we divide by the boolean expression // under test -- if the boolean expression is 'false', it will be a // divide-by-zero in an enum and fail to compile, thus providing us with a // "poor man's" compile-time assert. // // The cast to 'int' is necessary because dividing by 'bool' gives a // compiler warning on Windows. enum { k_STATIC_ASSERT = 1 / static_cast<int>(sizeof(FUNCTION_PTR) == sizeof(void *)) }; return reinterpret_cast<FUNCTION_PTR>(identityPtr(reinterpret_cast<void *>( function))); } } // close package namespace // FREE FUNCTIONS template <class RESULT> void bsls::debugprint(RESULT (*v)()) { uintptr_t address = reinterpret_cast<uintptr_t>(v); debugprint(reinterpret_cast<void *>(address)); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------