BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_protocoltest.h
Go to the documentation of this file.
1/// @file bsls_protocoltest.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_protocoltest.h -*-C++-*-
8#ifndef INCLUDED_BSLS_PROTOCOLTEST
9#define INCLUDED_BSLS_PROTOCOLTEST
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_protocoltest bsls_protocoltest
15/// @brief Provide classes and macros for testing abstract protocols.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_protocoltest
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_protocoltest-purpose"> Purpose</a>
25/// * <a href="#bsls_protocoltest-classes"> Classes </a>
26/// * <a href="#bsls_protocoltest-macros"> Macros </a>
27/// * <a href="#bsls_protocoltest-description"> Description </a>
28/// * <a href="#bsls_protocoltest-usage"> Usage </a>
29/// * <a href="#bsls_protocoltest-example-1-testing-a-protocol-class"> Example 1: Testing a Protocol Class </a>
30/// * <a href="#bsls_protocoltest-example-2-testing-a-method-overloaded-on-constness"> Example 2: Testing a Method Overloaded on constness </a>
31/// * <a href="#bsls_protocoltest-implementation-note"> Implementation Note </a>
32///
33/// # Purpose {#bsls_protocoltest-purpose}
34/// Provide classes and macros for testing abstract protocols.
35///
36/// # Classes {#bsls_protocoltest-classes}
37///
38/// - bsls::ProtocolTestImp: provides a framework for testing protocol classes
39/// - bsls::ProtocolTest: provides tests for protocol class concerns
40///
41/// # Macros {#bsls_protocoltest-macros}
42///
43/// - BSLS_PROTOCOLTEST_ASSERT: macro for testing protocol methods
44///
45/// # Description {#bsls_protocoltest-description}
46/// This component provides classes and macros that simplify the
47/// creation of test drivers for protocol (i.e., pure abstract interface)
48/// classes.
49///
50/// The purpose of a test driver for a protocol class is to verify concerns for
51/// that protocol's definition. Although each protocol is different and
52/// requires its own test driver, there is a common set of concerns that apply
53/// to all protocol classes. This component allows us to verify those concerns
54/// in a generic manner.
55///
56/// Each protocol class has to satisfy the following set of requirements
57/// (concerns):
58/// * The protocol is abstract: no objects of it can be created.
59/// * The protocol has no data members.
60/// * The protocol has a virtual destructor.
61/// * All methods of the protocol are pure virtual.
62/// * All methods of the protocol are publicly accessible.
63///
64/// There are two main exceptions to the above requirements:
65/// * Adaptor classes that adapt one protocol to another will have non-pure
66/// virtual functions that invoke pure virtual functions. Test drivers for
67/// such adaptors should test that the appropriate pure virtual function is
68/// called when the adapted function is invoked.
69/// * Protocol classes that copy or extend those from the C++ Standard Library
70/// may have *pass-through* non-virtual functions that call private or
71/// protected virtual functions. For example, non-virtual
72/// `bsl::memory_resource::allocate` calls private virtual `do_allocate`. In
73/// this case test drivers using this component should reference the
74/// non-virtual function as a proxy for the virtual function.
75///
76/// This protocol test component is intended to verify conformance to these
77/// requirements; however, it is not possible to verify all protocol
78/// requirements fully within the framework of the C++ language. The following
79/// aspects of the above requirements are not verified by this component:
80/// * Non-creator methods of the protocol are *pure* virtual.
81/// * There are no methods in the protocol other than the ones being tested.
82///
83/// Additionally some coding guidelines related to protocols are also not
84/// verified:
85/// * The destructor is not pure virtual.
86/// * The destructor is not implemented inline.
87///
88/// ## Usage {#bsls_protocoltest-usage}
89///
90///
91/// This section illustrates intended use of this component.
92///
93/// ### Example 1: Testing a Protocol Class {#bsls_protocoltest-example-1-testing-a-protocol-class}
94///
95///
96/// This example demonstrates how to test a protocol class, `ProtocolClass`,
97/// using this protocol test component. Our `ProtocolClass` provides two of
98/// pure virtual methods (`foo` and `bar`), along with a virtual destructor:
99/// @code
100/// struct ProtocolClass {
101/// virtual ~ProtocolClass();
102/// virtual const char *bar(char const *, char const *) = 0;
103/// virtual int foo(int) const = 0;
104/// };
105///
106/// ProtocolClass::~ProtocolClass()
107/// {
108/// }
109/// @endcode
110/// First, we define a test class derived from this protocol, and implement its
111/// virtual methods. Rather than deriving the test class from `ProtocolClass`
112/// directly, the test class is derived from
113/// `bsls::ProtocolTestImp<ProtocolClass>` (which, in turn, is derived
114/// automatically from `ProtocolClass`). This special base class implements
115/// boilerplate code and provides useful functionality for testing of protocols.
116/// @code
117/// // ========================================================================
118/// // GLOBAL CLASSES/TYPEDEFS FOR TESTING
119/// // ------------------------------------------------------------------------
120///
121/// struct ProtocolClassTestImp : bsls::ProtocolTestImp<ProtocolClass> {
122/// const char *bar(char const *, char const *) { return markDone(); }
123/// int foo(int) const { return markDone(); }
124/// };
125/// @endcode
126/// Notice that in `ProtocolClassTestImp` we must provide an implementation for
127/// every protocol method except for the destructor. The implementation of each
128/// method calls the (protected) `markDone` which is provided by the base class
129/// for the purpose of verifying that the method from which it's called is
130/// declared as virtual in the protocol class.
131///
132/// Then, in our protocol test case we describe the concerns we have for the
133/// protocol class and the plan to test those concerns:
134/// @code
135/// // ------------------------------------------------------------------------
136/// // PROTOCOL TEST:
137/// // Ensure this class is a properly defined protocol.
138/// //
139/// // Concerns:
140/// //: 1 The protocol is abstract: no objects of it can be created.
141/// //:
142/// //: 2 The protocol has no data members.
143/// //:
144/// //: 3 The protocol has a virtual destructor.
145/// //:
146/// //: 4 All methods of the protocol are pure virtual.
147/// //:
148/// //: 5 All methods of the protocol are publicly accessible.
149/// //
150/// // Plan:
151/// //: 1 Define a concrete derived implementation, 'ProtocolClassTestImp',
152/// //: of the protocol.
153/// //:
154/// //: 2 Create an object of the 'bsls::ProtocolTest' class template
155/// //: parameterized by 'ProtocolClassTestImp', and use it to verify
156/// //: that:
157/// //:
158/// //: 1 The protocol is abstract. (C-1)
159/// //:
160/// //: 2 The protocol has no data members. (C-2)
161/// //:
162/// //: 3 The protocol has a virtual destructor. (C-3)
163/// //:
164/// //: 3 Use the 'BSLS_PROTOCOLTEST_ASSERT' macro to verify that
165/// //: non-creator methods of the protocol are:
166/// //:
167/// //: 1 virtual, (C-4)
168/// //:
169/// //: 2 publicly accessible. (C-5)
170/// //
171/// // Testing:
172/// // virtual ~ProtocolClass();
173/// // virtual const char *bar(char const *, char const *) = 0;
174/// // virtual int foo(int) const = 0;
175/// // ------------------------------------------------------------------------
176/// @endcode
177/// Next we print the banner for this test case:
178/// @code
179/// if (verbose) puts("\nPROTOCOL TEST"
180/// "\n=============");
181/// @endcode
182/// Then, we create an object of type
183/// `bsls::ProtocolTest<ProtocolClassTestImp>`, `testObj`:
184/// @code
185/// if (verbose) puts("\n\tCreate a test object.");
186///
187/// bsls::ProtocolTest<ProtocolClassTestImp> testObj(veryVerbose);
188/// @endcode
189/// Now we use the `testObj` to test some general concerns about the protocol
190/// class.
191/// @code
192/// if (verbose) puts("\tVerify that the protocol is abstract.");
193///
194/// ASSERT(testObj.testAbstract());
195///
196/// if (verbose) puts("\tVerify that there are no data members.");
197///
198/// ASSERT(testObj.testNoDataMembers());
199///
200/// if (verbose) puts("\tVerify that the destructor is virtual.");
201///
202/// ASSERT(testObj.testVirtualDestructor());
203/// @endcode
204/// Finally we use the `testObj` to test concerns for each individual method of
205/// the protocol class. To test a protocol method we need to call it from
206/// inside the `BSLS_PROTOCOLTEST_ASSERT` macro, and also pass the `testObj`:
207/// @code
208/// if (verbose) puts("\tVerify that methods are public and virtual.");
209///
210/// BSLS_PROTOCOLTEST_ASSERT(testObj, foo(77));
211/// BSLS_PROTOCOLTEST_ASSERT(testObj, bar("", ""));
212/// @endcode
213/// These steps conclude the protocol testing. If there are any failures, they
214/// will be reported via standard test driver assertions (i.e., the standard
215/// `ASSERT` macro).
216///
217/// ### Example 2: Testing a Method Overloaded on constness {#bsls_protocoltest-example-2-testing-a-method-overloaded-on-constness}
218///
219///
220/// Suppose we have a protocol that represent a sequence of integers. Such a
221/// protocol will have an overloaded `at()` method of both the `const` and the
222/// "mutable" variation. In verification of such methods we need to ensure that
223/// we verify *both* overloads of the `virtual` function.
224///
225/// First let's define the interesting parts of our imaginary sequence, the
226/// overloaded `at()` methods, and a virtual destructor to avoid warnings:
227/// @code
228/// struct IntSeqExample {
229/// // CREATORS
230/// virtual ~IntSeqExample();
231///
232/// // MANIPULATORS
233/// virtual int& at(bsl::size_t index) = 0;
234///
235/// // ACCESSORS
236/// virtual int at(bsl::size_t index) const = 0;
237/// };
238///
239/// IntSeqExample::~IntSeqExample()
240/// {
241/// }
242/// @endcode
243/// Next, we define the test implementation as usual:
244/// @code
245/// struct IntSeqExampleTestImp : bsls::ProtocolTestImp<IntSeqExample> {
246/// static int s_int;
247///
248/// int& at(size_t) { s_int = 4; markDone(); return s_int; }
249/// int at(size_t) const { s_int = 2; return markDone(); }
250/// };
251///
252/// int IntSeqExampleTestImp::s_int = 0;
253/// @endcode
254/// Note the use of a dummy variable to return a reference. We also use that
255/// variable, by giving it different values in the two overloads, to demonstrate
256/// that we have called the overload we have intended.
257///
258/// Then, we test the non-`const` overload as usual:
259/// @code
260/// bsls::ProtocolTest<IntSeqExampleTestImp> testObj(veryVerbose);
261/// BSLS_PROTOCOLTEST_ASSERT(testObj, at(0));
262/// @endcode
263/// Now, we can verify that we have indeed tested the non-`const` overload:
264/// @code
265/// assert(4 == IntSeqExampleTestImp::s_int);
266/// @endcode
267/// Finally, we test `at(size_t) const` and also verify that we indeed called
268/// the intended overload. Notice that we "force" the `const` variant of the
269/// method to be picked by specifying a `const Implementation` type argument to
270/// `bsls::ProtocolTest`:
271/// @code
272/// bsls::ProtocolTest<const IntSeqExampleTestImp> test_OBJ(veryVerbose);
273/// BSLS_PROTOCOLTEST_ASSERT(test_OBJ, at(0));
274///
275/// assert(2 == IntSeqExampleTestImp::s_int);
276/// @endcode
277/// Note that the assertion that verifies that the intended overload was called
278/// is not strictly necessary, it is included for demonstration purposes.
279///
280/// ### Implementation Note {#bsls_protocoltest-implementation-note}
281///
282///
283/// This component has a number of private meta-functions on some platforms,
284/// e.g., `ProtocolTest_EnableIf`, `ProtocolTest_IsClass`, and
285/// `ProtocolTest_IsAbstract`. These mimic, to a limited extent, standard
286/// library meta-functions in the namespace `std` that are not available on all
287/// platforms. For general use, see the {`bslmf`} package and the {`bsl`}
288/// namespace for portable implementations of some of these meta-functions.
289/// @}
290/** @} */
291/** @} */
292
293/** @addtogroup bsl
294 * @{
295 */
296/** @addtogroup bsls
297 * @{
298 */
299/** @addtogroup bsls_protocoltest
300 * @{
301 */
302
303#include <bsls_compilerfeatures.h>
304#include <bsls_libraryfeatures.h>
305#include <bsls_platform.h>
306
307#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
308#include <type_traits>
309#endif
310
311#include <cstddef>
312#include <cstdio>
313
314
315namespace bsls {
316
317 // =============================
318 // class ProtocolTest_IsAbstract
319 // =============================
320
321/// This class template is a compile-time meta-function, parameterized with
322/// type `T`, the output of which is `value`, which will be `true` if `T` is
323/// abstract and `false` otherwise. On some platforms, the `IsAbstract`
324/// test makes use of the fact that a type 'an array of objects of an abstract type' (e.g., `T[1]`) cannot exist.
325///
326/// \note Note that it is only an
327/// approximation, because this is also true for an incomplete type. But,
328/// this approximation is good enough for the purpose of testing protocol
329/// classes. On certain other platforms, the `IsAbstract` test will make
330/// use of the fact that abstract types cannot be returned. This
331/// approximation also has issues, noted below, but is also good enough for
332/// the purpose of testing protocol classes.
333template <class T>
334struct ProtocolTest_IsAbstract;
335
336#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
337
338template <class T>
339struct ProtocolTest_IsAbstract {
340 enum { value = std::is_abstract<T>::value };
341};
342
343#elif defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION >= 110000
344
345///Implementation Note
346///-------------------
347// GCC 11 and later adhere to the core language changes resulting from the
348// paper P0929, which was approved as a defect report and applied to C++03 and
349// later. One effect of this paper is that it became well-formed to name the
350// type 'T[1]' where 'T' is an abstract class type. As a result, platforms
351// that apply P0929 require a different implementation of an abstractness test
352// in C++03 mode.
353
354template <class T>
355struct ProtocolTest_VoidType {
356 // This component-private, meta-function 'struct' template provides a
357 // single-parameter type trait that behaves like the 'bslmf::VoidType'
358 // meta-function for use in the implementation of the
359 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
360 // compilers that apply P0929 to that mode. Note that this component is in
361 // the 'bsls' package, which is levelized below 'bslmf', and so cannot
362 // depend on 'bslmf::VoidType'.
363
364 typedef void Type;
365};
366
367template <class VOID_TYPE, class T>
368struct ProtocolTest_IsClassTypeImp {
369 // This component-private, meta-function (primary) 'struct' template
370 // provides part of the implementation of a type trait that behaves like
371 // 'std::is_class' for use in the implementation of the
372 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
373 // compilers that apply P0929 to that mode. Note that in this mode,
374 // 'std::is_class' is not available.
375
376 enum { value = false };
377};
378
379template <class T>
380struct ProtocolTest_IsClassTypeImp<
381 typename ProtocolTest_VoidType<int T::*>::Type,
382 T> {
383 // This component-private, meta-function 'struct' template (partial
384 // specialization) provides part of the implementation of a type trait that
385 // behaves like 'std::is_class' for use in the implementation of the
386 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
387 // compilers that apply P0929 to that mode. Note that in this mode,
388 // 'std::is_class' is not available.
389
390 enum { value = true };
391};
392
393template <class T>
394struct ProtocolTest_IsClassType {
395 // This component-private, meta-function 'struct' template provides the
396 // implementation of a type trait that behaves like 'std::is_class' for use
397 // in the implementation of the 'ProtocolTest_IsAbstract' meta-function
398 // when compiling in C++03 mode on compilers that apply P0929 to that mode.
399 // Note that in this mode, 'std::is_class' is not available.
400
401 enum {
402 value = ProtocolTest_IsClassTypeImp<void, T>::value
403 };
404};
405
406template <bool CONDITION, class T = void>
407struct ProtocolTest_EnableIf {
408 // This component-private, meta-function (primary) 'struct' template
409 // provides part of the implementation of a type trait that behaves like
410 // 'std::enable_if' for use in the implementation of the
411 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
412 // compilers that apply P0929 to that mode. Note that in this mode,
413 // 'std::enable_if' is not available.
414};
415
416template <class T>
417struct ProtocolTest_EnableIf<true, T> {
418 // This component-private, meta-function 'struct' template (partial
419 // specialization) provides part of the implementation of a type trait that
420 // behaves like 'std::enable_if' for use in the implementation of the
421 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
422 // compilers that apply P0929 to that mode. Note that in this mode,
423 // 'std::enable_if' is not available.
424
425 typedef T Type;
426};
427
428struct ProtocolTest_NoType {
429 // this component-private 'struct' provides a type having a size that is
430 // guaranteed to be different than the size of 'ProtocolTest_YesType', and
431 // is used in the implementation of the 'ProtocolTest_IsAbstract'
432 // meta-function when compiling in C++03 mode on compilers that apply P0929
433 // to that mode.
434
435 char d_padding;
436};
437
438struct ProtocolTest_YesType {
439 // this component-private 'struct' provides a type having a size that is
440 // guaranteed to be different than the size of 'ProtocolTest_NoType', and
441 // is used in the implementation of the 'ProtocolTest_IsAbstract'
442 // meta-function when compiling in C++03 mode on compilers that apply P0929
443 // to that mode.
444
445 char d_padding[17];
446};
447
448struct ProtocolTest_IsReturnableImpUtil {
449 // This component-private 'struct' provides a namespace for a 'test'
450 // overload set used to determine if a specified type can be returned from
451 // a function-call expression or not. This 'struct' is used in the
452 // implementation of the 'ProtocolTest_IsAbstract' meta-function when
453 // compiling in C++03 mode on compilers that apply P0929 to that mode.
454
455 private:
456 // PRIVATE CLASS METHODS
457 template <class T>
458 static T returnThe();
459 // Return a prvalue of the specified 'T' type. Note that this function
460 // is declared but not defined. It is similar in nature to
461 // 'std::declval', with the important distinction that return type of
462 // 'std::declval' is a reference type, and the return type of this
463 // function is not (necessarily) a reference type.
464
465 public:
466 // CLASS METHODS
467 template <class T>
468 static ProtocolTest_NoType test(...);
469 template <class T>
470 static ProtocolTest_YesType
471 test(typename ProtocolTest_EnableIf<static_cast<bool>(
472 sizeof(static_cast<void>(returnThe<T>()), 0))>::Type *);
473 // Return a 'ProtocolTest_YesType' prvalue if the specified 'T' type
474 // can be returned from a function-call expression, and return a
475 // 'ProtocolTest_NoType' prvalue otherwise. The behavior is undefined
476 // unless this function is invoked with a single argument that is
477 // convertible to a 'void *'. Note that this function is declared but
478 // not defined.
479};
480
481template <class T>
482struct ProtocolTest_IsReturnable {
483 // This component-private, meta-function 'struct' template provides a
484 // compile-time constant 'value' class member with the value 'true' if the
485 // supplied 'T' type can be returned from a function-call expression, and
486 // provides a 'value' class member with the value 'false' otherwise. This
487 // meta-function is used in the implementation of the
488 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
489 // compilers that apply P0929 to that mode.
490
491 enum {
492 value = sizeof(ProtocolTest_YesType) ==
493 sizeof(ProtocolTest_IsReturnableImpUtil::test<T>(0))
494 };
495};
496
497
498template <class T>
499struct ProtocolTest_IsAbstract {
500 // This component-private, meta-function 'struct' template provides a
501 // compile-time constant 'value' class member with the value 'true' if the
502 // supplied 'T' type is an abstract class type (or, and this is a defect,
503 // if 'T' is a class type with a private destructor), and provides a
504 // 'value' class member with the value 'false' otherwise. This
505 // meta-function matches the behavior 'std::is_abstract' would have if it
506 // were available except for non-abstract types with a private destructor,
507 // and is for use when compiling in C++03 mode on compilers that apply
508 // P0929 to that mode.
509
510 enum {
511 value = ProtocolTest_IsClassType<T>::value &&
512 !ProtocolTest_IsReturnable<T>::value
513 };
514};
515
516#else
517
518/// This component-private, meta-function `struct` template provides a
519/// compile-time constant `value` class member with the value `true` if the
520/// supplied `T` type is an abstract class type, and provides a `value`
521/// class member with the value `false` otherwise. This meta-function
522/// matches the behavior `std::is_abstract` would have if it were
523/// available on C++03 platforms.
524///
525/// See @ref bsls_protocoltest
526template <class T>
528
529 typedef char YesType;
530 typedef struct { char a[2]; } NoType;
531
532 template <class U>
533 static NoType test(U (*)[1]);
534
535 template <class U>
536 static YesType test(...);
537
538 enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
539};
540
541#endif
542
543 // ===================================
544 // class ProtocolTest_MethodReturnType
545 // ===================================
546
547/// This class is a proxy for a return type designed to simplify testing
548/// implementations of protocol methods.
549/// `ProtocolTest_MethodReturnType` can be converted to any
550/// non-reference type (i.e., the type can be either a value or pointer
551/// type, but not a reference type). When an object of this class is
552/// returned from a test implementation of a protocol method, it is
553/// implicitly converted to the return type of the protocol method.
554///
555/// See @ref bsls_protocoltest
557
558 // ACCESSORS
559
560 /// Return a temporary value of type `T`. The returned object is valid
561 /// but it does not have any meaningful value so it should not be used.
562 /// Type `T` is required to be default-constructible.
563 template <class T>
564 operator T() const;
565};
566
567 // ======================================
568 // class ProtocolTest_MethodReturnRefType
569 // ======================================
570
571/// This class is a proxy for a return type designed to simplify testing
572/// implementations of protocol methods.
573/// `ProtocolTest_MethodReturnRefType` can be converted to any
574/// reference type. When an object of this class is returned from a test
575/// implementation of a protocol method, it is implicitly converted to
576/// the return type of the protocol method.
577///
578/// See @ref bsls_protocoltest
580
581 // ACCESSORS
582
583 /// Return a `T&` reference to an invalid object. The returned value
584 /// should not be used and should be immediately discarded.
585 template <class T>
586 operator T&() const;
587};
588
589 // =======================
590 // class ProtocolTest_Dtor
591 // =======================
592
593/// This class template is a helper protocol-test implementation class that
594/// tests that a protocol destructor is declared `virtual`, which it does by
595/// calling the `markDone` function from its destructor. The destructor
596/// will be executed if the protocol's destructor is declared `virtual` and not executed otherwise.
597///
598/// \note Note that the `BSLS_TESTIMP` template parameter
599/// is required to be a type derived from `ProtocolTestImp` class.
600template <class BSLS_TESTIMP>
601struct ProtocolTest_Dtor : BSLS_TESTIMP {
602
603 // CREATORS
604
605 /// Destroy this object and call the `markDone` method, indicating that
606 /// the base class's destructor was declared `virtual`.
608};
609
610 // =========================
611 // class ProtocolTest_Status
612 // =========================
613
614/// This class keeps track of the test status, which includes the status of
615/// the last test and the number of failures across all tests.
616///
617/// See @ref bsls_protocoltest
619
620 private:
621 // DATA
622 int d_failures; // number of test failures encountered so far
623 bool d_last; // result of the last test ('true' indicates success)
624
625 public:
626 // CREATORS
627
628 /// Create an object of the `ProtocolTest_Status` class with the
629 /// default state in which `failures() == 0` and `last() == true`.
631
632 // MANIPULATORS
633
634 /// Reset the status of the last test to `true`.
635 void resetLast();
636
637 /// Record a test failure by increasing the number of `failures` and
638 /// setting the status of the last test to `false`.
639 void fail();
640
641 // ACCESSORS
642
643 /// Return the number of failures encountered during testing of a
644 /// protocol class, which is 0 if all tests succeeded or if no tests
645 /// ran.
646 int failures() const;
647
648 /// Return `true` if the last test completed successfully (or no test
649 /// has yet completed), and `false` if it failed.
650 bool last() const;
651};
652
653 // ===========================
654 // class ProtocolTest_AsBigAsT
655 // ===========================
656
657/// This auxiliary structure has a size no less than the size of (template
658/// parameter) `T`.
659///
660/// See @ref bsls_protocoltest
661template <class T>
663
664#if defined (BSLS_LIBRARYFEATURES_HAS_CPP11_MISCELLANEOUS_UTILITIES)
665 // DATA
666 std::max_align_t d_dummy[sizeof(T) / sizeof(std::max_align_t) + 1];
667#else
668 // PRIVATE TYPES
669 union MaxAlignType {
670 void *d_v_p;
671 unsigned long long d_ull;
672 long double d_ul;
673 };
674
675 // DATA
676 MaxAlignType d_dummy[sizeof(T) / sizeof(MaxAlignType) + 1];
677#endif
678};
679
680 // =====================
681 // class ProtocolTestImp
682 // =====================
683
684/// This mechanism class template is a base class for a test implementation
685/// of a protocol class defined by the `BSLS_PROTOCOL` template parameter.
686/// Its purpose is to reduce the boilerplate test code required to verify
687/// that derived virtual methods are called. It provides `markDone` member
688/// functions one of which should be called from each method of the protocol
689/// class test implementation to indicate that the virtual method is
690/// correctly overridden. It also overloads `operator->` to serve as a
691/// proxy to `BSLS_PROTOCOL` and detect when `BSLS_PROTOCOL` methods are
692/// called.
693///
694/// See @ref bsls_protocoltest
695template <class BSLS_PROTOCOL>
696class ProtocolTestImp : public BSLS_PROTOCOL {
697
698 private:
699 // DATA
700 mutable ProtocolTest_Status *d_status; // test status object for test
701 // failure reporting; mutable, so
702 // it can be set from 'const'
703 // methods in order to be able to
704 // verify 'const' methods.
705
706 mutable bool d_entered; // 'true' if this object entered a
707 // protocol method call; mutable,
708 // so it can be set from 'const'
709 // methods in order to be able to
710 // verify 'const' methods.
711
712 mutable bool d_exited; // 'true' if this object exited a
713 // protocol method in the derived
714 // class; mutable, so it can be
715 // set from 'const' methods in
716 // order to be able to verify
717 // 'const' methods.
718 public:
719 // TYPES
720 typedef BSLS_PROTOCOL ProtocolType;
721
722 // CREATORS
723
724 /// Create an object of the `ProtocolTestImp` class.
726
727 /// Destroy this object and check the status of the test execution
728 /// (success or failure). On test failure, report it to
729 /// `ProtocolTest_Status`.
731
732 // MANIPULATORS
733
734 /// Dereference this object as if it were a pointer to `BSLS_PROTOCOL`
735 /// in order to call a method on `BSLS_PROTOCOL`. Also mark this
736 /// object as `entered` for the purpose of calling a protocol method.
737 BSLS_PROTOCOL *operator->();
738
739 // ACCESSORS
740
741 /// Dereference this object as if it were a `const BSLS_PROTOCOL *s` in
742 /// order to call a `const` method on `BSLS_PROTOCOL`. Also mark this
743 /// object as `entered` for the purpose of calling a protocol method.
744 const BSLS_PROTOCOL *operator->() const;
745
746 /// Return a proxy object convertible to any value or pointer type.
747 /// Derived classed should call this method from their implementations
748 /// of protocol virtual methods to indicate that virtual methods were
749 /// overridden correctly.
751
752 /// Return a proxy object convertible to any reference type. Derived
753 /// classed should call this method from their implementations of
754 /// protocol virtual methods to indicate that virtual methods were
755 /// overridden correctly.
757
758 /// Return the specified `value`. Derived classes should call this
759 /// method from their implementations of protocol virtual methods to
760 /// indicate that virtual methods were overridden correctly.
761 template <class T>
762 T markDoneVal(const T& value) const;
763
764 /// Mark this object as entered for the purpose of calling a protocol
765 /// method. The `entered` property is tested in the destructor to
766 /// check for test failures (i.e., if `entered == false` then the test cannot fail since it never ran).
767 ///
768 /// \note Note that `markEnter` and
769 /// `markDone` calls have to be paired for a protocol-method-call test
770 /// to succeed.
771 void markEnter() const;
772
773 /// Connect this protocol test object with the specified `testStatus`
774 /// object, which will be used for test failure reporting.
775 void setTestStatus(ProtocolTest_Status *testStatus) const;
776};
777
778 // ==================
779 // class ProtocolTest
780 // ==================
781
782/// This mechanism class template provides the implementation of protocol
783/// testing concerns via `test*` methods (for non-method concerns), and via
784/// `operator->` (for method concerns). The `BSLS_TESTIMP` template
785/// parameter is required to be a class derived from `ProtocolTestImp`
786/// that provides test implementations of all protocol methods.
787///
788/// See @ref bsls_protocoltest
789template <class BSLS_TESTIMP>
791
792 private:
793 // TYPES
794 typedef typename BSLS_TESTIMP::ProtocolType ProtocolType;
795
796 // DATA
797 ProtocolTest_Status d_status;
798 bool d_verbose; // print trace messages if 'true'
799
800 private:
801 // PRIVATE MANIPULATORS
802
803 /// Start a new test by resetting this object to the state before the
804 /// test.
805 void startTest();
806
807 /// Print a trace `message` if `d_verbose` is `true`.
808 void trace(char const *message) const;
809
810 public:
811 // CREATORS
812
813 /// Construct a `ProtocolTest` object.
814 explicit
815 ProtocolTest(bool verbose = false);
816
817 // MANIPULATORS
818
819 /// Return a `BSLS_TESTIMP` object to perform testing of a specific
820 /// method which gets called via `operator->()`.
821 ///
822 /// \note Note that `BSLS_TESTIMP` is a proxy to the actual protocol class.
823 BSLS_TESTIMP method(const char *methodDesc = "");
824
825 /// Return `true` (i.e., the test passed) if the protocol class being
826 /// tested is abstract and return `false` (i.e., the test failed)
827 /// otherwise. Increase the count of `failures` and set `lastStatus` to
828 /// `false` on failure.
829 bool testAbstract();
830
831 /// Return `true` (i.e., the test passed) if the protocol class being
832 /// tested contains no data fields and return `false` (i.e., the test
833 /// failed) otherwise. Increase the count of `failures` and set
834 /// `lastStatus` to `false` on failure.
835 bool testNoDataMembers();
836
837 /// Return `true` (i.e., the test passed) if the protocol class being
838 /// tested has a virtual destructor and return `false` (i.e., the test
839 /// failed) otherwise. Increase the `failures` count and set
840 /// `lastStatus` to `false` on failure.
842
843 // ACCESSORS
844
845 /// Return the number of failures encountered during testing of a
846 /// protocol class. The returned value is 0 if all tests succeeded, or
847 /// no tests ran.
848 int failures() const;
849
850 /// Return `true` if the last test completed successfully (or no test
851 /// has yes completed) and `false` otherwise.
852 bool lastStatus() const;
853};
854
855} // close package namespace
856
857 // ========================
858 // BSLS_PROTOCOLTEST_ASSERT
859 // ========================
860
861// This macro provides a test for method-related concerns of a protocol class.
862// It ensures that a method is publicly accessible and declared 'virtual'. It
863// requires that a standard test driver 'ASSERT' macro is defined, which is
864// used to assert the test completion status.
865
866#define BSLS_PROTOCOLTEST_ASSERT(test, methodCall) \
867 do { \
868 (void) test.method( \
869 "inside BSLS_PROTOCOLTEST_ASSERT("#methodCall")")->methodCall;\
870 if (!test.lastStatus()) { \
871 ASSERT(0 && "Not a virtual method: "#methodCall); \
872 } \
873 } while (0)
874
875#define BSLS_PROTOCOLTEST_RV_ASSERT(test, methodCall, returnValue) \
876 do { \
877 returnValue = test.method( \
878 "inside BSLS_PROTOCOLTEST_ASSERT("#methodCall")")->methodCall;\
879 if (!test.lastStatus()) { \
880 ASSERT(0 && "Not a virtual method: "#methodCall); \
881 } \
882 } while (0)
883
884// ============================================================================
885// INLINE FUNCTION DEFINITIONS
886// ============================================================================
887
888namespace bsls {
889
890 // -----------------------------------
891 // class ProtocolTest_MethodReturnType
892 // -----------------------------------
893
894// ACCESSORS
895template <class T>
896inline
897ProtocolTest_MethodReturnType::operator T() const
898{
899 return T();
900}
901
902 // --------------------------------------
903 // class ProtocolTest_MethodReturnRefType
904 // --------------------------------------
905
906// ACCESSORS
907template <class T>
908inline
909ProtocolTest_MethodReturnRefType::operator T&() const
910{
911 static ProtocolTest_AsBigAsT<T> obj;
912 T *pObj = reinterpret_cast<T *>(&obj);
913 return *pObj;
914}
915
916 // -----------------------
917 // class ProtocolTest_Dtor
918 // -----------------------
919
920// CREATORS
921template <class BSLS_TESTIMP>
922inline
927
928 // -------------------------
929 // class ProtocolTest_Status
930 // -------------------------
931
932// CREATORS
933inline
935: d_failures(0)
936, d_last(true)
937{
938}
939
940// MANIPULATORS
941inline
943{
944 d_last = true;
945}
946
947inline
949{
950 ++d_failures;
951 d_last = false;
952}
953
954// ACCESSORS
955inline
957{
958 return d_failures;
959}
960
961inline
963{
964 return d_last;
965}
966
967 // ---------------------
968 // class ProtocolTestImp
969 // ---------------------
970
971// CREATORS
972template <class BSLS_PROTOCOL>
973inline
975: d_status(0)
976, d_entered(false)
977, d_exited(false)
978{
979}
980
981template <class BSLS_PROTOCOL>
982inline
984{
985 if (d_entered && !d_exited) {
986 d_status->fail();
987 }
988}
989
990// MANIPULATORS
991template <class BSLS_PROTOCOL>
992inline
995{
996 markEnter();
997 return static_cast<BSLS_PROTOCOL *>(this);
998}
999
1000// ACCESSORS
1001template <class BSLS_PROTOCOL>
1002inline
1005{
1006 markEnter();
1007 return static_cast<const BSLS_PROTOCOL *>(this);
1008}
1009
1010template <class BSLS_PROTOCOL>
1011inline
1014{
1015 d_exited = true;
1017}
1018
1019template <class BSLS_PROTOCOL>
1020inline
1023{
1024 d_exited = true;
1026}
1027
1028template <class BSLS_PROTOCOL>
1029template <class T>
1030inline
1032{
1033 d_exited = true;
1034 return value;
1035}
1036
1037template <class BSLS_PROTOCOL>
1038inline
1040{
1041 d_entered = true;
1042}
1043
1044template <class BSLS_PROTOCOL>
1045inline
1047 ProtocolTest_Status *testStatus) const
1048{
1049 d_status = testStatus;
1050}
1051
1052 // ------------------
1053 // class ProtocolTest
1054 // ------------------
1055
1056// PRIVATE MANIPULATORS
1057template <class BSLS_TESTIMP>
1058inline
1060{
1061 d_status.resetLast();
1062}
1063
1064template <class BSLS_TESTIMP>
1065inline
1066void ProtocolTest<BSLS_TESTIMP>::trace(char const *message) const
1067{
1068 if (d_verbose) {
1069 std::printf("\t%s\n", message);
1070 }
1071}
1072
1073// CREATORS
1074template <class BSLS_TESTIMP>
1075inline
1077: d_verbose(verbose)
1078{
1079}
1080
1081// MANIPULATORS
1082template <class BSLS_TESTIMP>
1083inline
1084BSLS_TESTIMP ProtocolTest<BSLS_TESTIMP>::method(const char *methodDesc)
1085{
1086 trace(methodDesc);
1087 startTest();
1088
1089 BSLS_TESTIMP impl;
1090 impl.setTestStatus(&d_status);
1091 return impl;
1092}
1093
1094template <class BSLS_TESTIMP>
1095inline
1097{
1098 trace("inside ProtocolTest::testAbstract()");
1099 startTest();
1100
1102 d_status.fail();
1103 }
1104
1105 return lastStatus();
1106}
1107
1108template <class BSLS_TESTIMP>
1109inline
1111{
1112 trace("inside ProtocolTest::testNoDataMembers()");
1113 struct EmptyProtocol
1114 {
1115 virtual ~EmptyProtocol() {}
1116 };
1117
1118 startTest();
1119
1120 if (sizeof(EmptyProtocol) != sizeof(ProtocolType)) {
1121 d_status.fail();
1122 }
1123
1124 return lastStatus();
1125}
1126
1127template <class BSLS_TESTIMP>
1129{
1130 trace("inside ProtocolTest::testVirtualDestructor");
1131 startTest();
1132
1133 // Can't use an automatic buffer and the placement new for an object of
1134 // type ProtocolTest_Dtor<BSLS_TESTIMP> here, because bslma::Allocator
1135 // defines its own placement new, making it impossible to test
1136 // bslma::Allocator protocol this way.
1137
1138 // Prepare a test
1141 BSLS_TESTIMP * base = obj;
1142 obj->setTestStatus(&d_status);
1143
1144 // Run the test.
1145 obj->markEnter();
1146 delete base;
1147
1148 // 'ProtocolTest_Dtor::~ProtocolTest_Dtor' will be called only if
1149 // the destructor was declared 'virtual' in the interface, but
1150 // 'BSLS_TESTIMP::~BSLS_TESTIMP' is always executed to check if the
1151 // derived destructor was called.
1152
1153 return lastStatus();
1154}
1155
1156// ACCESSORS
1157template <class BSLS_TESTIMP>
1158inline
1160{
1161 return d_status.failures();
1162}
1163
1164template <class BSLS_TESTIMP>
1165inline
1167{
1168 return d_status.last();
1169}
1170
1171} // close package namespace
1172
1173#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
1174// ============================================================================
1175// BACKWARD COMPATIBILITY
1176// ============================================================================
1177
1178#ifdef bsls_ProtocolTest
1179#undef bsls_ProtocolTest
1180#endif
1181/// This alias is defined for backward compatibility.
1182#define bsls_ProtocolTest bsls::ProtocolTest
1183
1184#ifdef bsls_ProtocolTestImp
1185#undef bsls_ProtocolTestImp
1186#endif
1187/// This alias is defined for backward compatibility.
1188#define bsls_ProtocolTestImp bsls::ProtocolTestImp
1189#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
1190
1191
1192
1193#endif
1194
1195// ----------------------------------------------------------------------------
1196// Copyright 2013 Bloomberg Finance L.P.
1197//
1198// Licensed under the Apache License, Version 2.0 (the "License");
1199// you may not use this file except in compliance with the License.
1200// You may obtain a copy of the License at
1201//
1202// http://www.apache.org/licenses/LICENSE-2.0
1203//
1204// Unless required by applicable law or agreed to in writing, software
1205// distributed under the License is distributed on an "AS IS" BASIS,
1206// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1207// See the License for the specific language governing permissions and
1208// limitations under the License.
1209// ----------------------------- END-OF-FILE ----------------------------------
1210
1211/** @} */
1212/** @} */
1213/** @} */
Definition bsls_protocoltest.h:696
ProtocolTest_MethodReturnRefType markDoneRef() const
Definition bsls_protocoltest.h:1022
BSLS_PROTOCOL ProtocolType
Definition bsls_protocoltest.h:720
~ProtocolTestImp()
Definition bsls_protocoltest.h:983
void setTestStatus(ProtocolTest_Status *testStatus) const
Definition bsls_protocoltest.h:1046
T markDoneVal(const T &value) const
Definition bsls_protocoltest.h:1031
BSLS_PROTOCOL * operator->()
Definition bsls_protocoltest.h:994
void markEnter() const
Definition bsls_protocoltest.h:1039
ProtocolTest_MethodReturnType markDone() const
Definition bsls_protocoltest.h:1013
ProtocolTestImp()
Create an object of the ProtocolTestImp class.
Definition bsls_protocoltest.h:974
Definition bsls_protocoltest.h:662
Definition bsls_protocoltest.h:618
ProtocolTest_Status()
Definition bsls_protocoltest.h:934
void fail()
Definition bsls_protocoltest.h:948
bool last() const
Definition bsls_protocoltest.h:962
int failures() const
Definition bsls_protocoltest.h:956
void resetLast()
Reset the status of the last test to true.
Definition bsls_protocoltest.h:942
Definition bsls_protocoltest.h:790
BSLS_TESTIMP method(const char *methodDesc="")
Definition bsls_protocoltest.h:1084
bool lastStatus() const
Definition bsls_protocoltest.h:1166
bool testAbstract()
Definition bsls_protocoltest.h:1096
ProtocolTest(bool verbose=false)
Construct a ProtocolTest object.
Definition bsls_protocoltest.h:1076
bool testNoDataMembers()
Definition bsls_protocoltest.h:1110
bool testVirtualDestructor()
Definition bsls_protocoltest.h:1128
int failures() const
Definition bsls_protocoltest.h:1159
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlt_iso8601util.h:707
Definition bsls_protocoltest.h:601
~ProtocolTest_Dtor()
Definition bsls_protocoltest.h:923
Definition bsls_protocoltest.h:530
Definition bsls_protocoltest.h:527
static NoType test(U(*)[1])
@ value
Definition bsls_protocoltest.h:538
static YesType test(...)
char YesType
Definition bsls_protocoltest.h:529
Definition bsls_protocoltest.h:579
Definition bsls_protocoltest.h:556