BDE 4.14.0 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
325/// abstract type' (e.g., `T[1]`) cannot exist. Note that it is only an
326/// approximation, because this is also true for an incomplete type. But,
327/// this approximation is good enough for the purpose of testing protocol
328/// classes. On certain other platforms, the `IsAbstract` test will make
329/// use of the fact that abstract types cannot be returned. This
330/// approximation also has issues, noted below, but is also good enough for
331/// the purpose of testing protocol classes.
332template <class T>
333struct ProtocolTest_IsAbstract;
334
335#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
336
337template <class T>
338struct ProtocolTest_IsAbstract {
339 enum { value = std::is_abstract<T>::value };
340};
341
342#elif defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION >= 110000
343
344///Implementation Note
345///-------------------
346// GCC 11 and later adhere to the core language changes resulting from the
347// paper P0929, which was approved as a defect report and applied to C++03 and
348// later. One effect of this paper is that it became well-formed to name the
349// type 'T[1]' where 'T' is an abstract class type. As a result, platforms
350// that apply P0929 require a different implementation of an abstractness test
351// in C++03 mode.
352
353template <class T>
354struct ProtocolTest_VoidType {
355 // This component-private, meta-function 'struct' template provides a
356 // single-parameter type trait that behaves like the 'bslmf::VoidType'
357 // meta-function for use in the implementation of the
358 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
359 // compilers that apply P0929 to that mode. Note that this component is in
360 // the 'bsls' package, which is levelized below 'bslmf', and so cannot
361 // depend on 'bslmf::VoidType'.
362
363 typedef void Type;
364};
365
366template <class VOID_TYPE, class T>
367struct ProtocolTest_IsClassTypeImp {
368 // This component-private, meta-function (primary) 'struct' template
369 // provides part of the implementation of a type trait that behaves like
370 // 'std::is_class' for use in the implementation of the
371 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
372 // compilers that apply P0929 to that mode. Note that in this mode,
373 // 'std::is_class' is not available.
374
375 enum { value = false };
376};
377
378template <class T>
379struct ProtocolTest_IsClassTypeImp<
380 typename ProtocolTest_VoidType<int T::*>::Type,
381 T> {
382 // This component-private, meta-function 'struct' template (partial
383 // specialization) provides part of the implementation of a type trait that
384 // behaves like 'std::is_class' for use in the implementation of the
385 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
386 // compilers that apply P0929 to that mode. Note that in this mode,
387 // 'std::is_class' is not available.
388
389 enum { value = true };
390};
391
392template <class T>
393struct ProtocolTest_IsClassType {
394 // This component-private, meta-function 'struct' template provides the
395 // implementation of a type trait that behaves like 'std::is_class' for use
396 // in the implementation of the 'ProtocolTest_IsAbstract' meta-function
397 // when compiling in C++03 mode on compilers that apply P0929 to that mode.
398 // Note that in this mode, 'std::is_class' is not available.
399
400 enum {
401 value = ProtocolTest_IsClassTypeImp<void, T>::value
402 };
403};
404
405template <bool CONDITION, class T = void>
406struct ProtocolTest_EnableIf {
407 // This component-private, meta-function (primary) 'struct' template
408 // provides part of the implementation of a type trait that behaves like
409 // 'std::enable_if' for use in the implementation of the
410 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
411 // compilers that apply P0929 to that mode. Note that in this mode,
412 // 'std::enable_if' is not available.
413};
414
415template <class T>
416struct ProtocolTest_EnableIf<true, T> {
417 // This component-private, meta-function 'struct' template (partial
418 // specialization) provides part of the implementation of a type trait that
419 // behaves like 'std::enable_if' for use in the implementation of the
420 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
421 // compilers that apply P0929 to that mode. Note that in this mode,
422 // 'std::enable_if' is not available.
423
424 typedef T Type;
425};
426
427struct ProtocolTest_NoType {
428 // this component-private 'struct' provides a type having a size that is
429 // guaranteed to be different than the size of 'ProtocolTest_YesType', and
430 // is used in the implementation of the 'ProtocolTest_IsAbstract'
431 // meta-function when compiling in C++03 mode on compilers that apply P0929
432 // to that mode.
433
434 char d_padding;
435};
436
437struct ProtocolTest_YesType {
438 // this component-private 'struct' provides a type having a size that is
439 // guaranteed to be different than the size of 'ProtocolTest_NoType', and
440 // is used in the implementation of the 'ProtocolTest_IsAbstract'
441 // meta-function when compiling in C++03 mode on compilers that apply P0929
442 // to that mode.
443
444 char d_padding[17];
445};
446
447struct ProtocolTest_IsReturnableImpUtil {
448 // This component-private 'struct' provides a namespace for a 'test'
449 // overload set used to determine if a specified type can be returned from
450 // a function-call expression or not. This 'struct' is used in the
451 // implementation of the 'ProtocolTest_IsAbstract' meta-function when
452 // compiling in C++03 mode on compilers that apply P0929 to that mode.
453
454 private:
455 // PRIVATE CLASS METHODS
456 template <class T>
457 static T returnThe();
458 // Return a prvalue of the specified 'T' type. Note that this function
459 // is declared but not defined. It is similar in nature to
460 // 'std::declval', with the important distinction that return type of
461 // 'std::declval' is a reference type, and the return type of this
462 // function is not (necessarily) a reference type.
463
464 public:
465 // CLASS METHODS
466 template <class T>
467 static ProtocolTest_NoType test(...);
468 template <class T>
469 static ProtocolTest_YesType
470 test(typename ProtocolTest_EnableIf<static_cast<bool>(
471 sizeof(static_cast<void>(returnThe<T>()), 0))>::Type *);
472 // Return a 'ProtocolTest_YesType' prvalue if the specified 'T' type
473 // can be returned from a function-call expression, and return a
474 // 'ProtocolTest_NoType' prvalue otherwise. The behavior is undefined
475 // unless this function is invoked with a single argument that is
476 // convertible to a 'void *'. Note that this function is declared but
477 // not defined.
478};
479
480template <class T>
481struct ProtocolTest_IsReturnable {
482 // This component-private, meta-function 'struct' template provides a
483 // compile-time constant 'value' class member with the value 'true' if the
484 // supplied 'T' type can be returned from a function-call expression, and
485 // provides a 'value' class member with the value 'false' otherwise. This
486 // meta-function is used in the implementation of the
487 // 'ProtocolTest_IsAbstract' meta-function when compiling in C++03 mode on
488 // compilers that apply P0929 to that mode.
489
490 enum {
491 value = sizeof(ProtocolTest_YesType) ==
492 sizeof(ProtocolTest_IsReturnableImpUtil::test<T>(0))
493 };
494};
495
496
497template <class T>
498struct ProtocolTest_IsAbstract {
499 // This component-private, meta-function 'struct' template provides a
500 // compile-time constant 'value' class member with the value 'true' if the
501 // supplied 'T' type is an abstract class type (or, and this is a defect,
502 // if 'T' is a class type with a private destructor), and provides a
503 // 'value' class member with the value 'false' otherwise. This
504 // meta-function matches the behavior 'std::is_abstract' would have if it
505 // were available except for non-abstract types with a private destructor,
506 // and is for use when compiling in C++03 mode on compilers that apply
507 // P0929 to that mode.
508
509 enum {
510 value = ProtocolTest_IsClassType<T>::value &&
511 !ProtocolTest_IsReturnable<T>::value
512 };
513};
514
515#else
516
517/// This component-private, meta-function `struct` template provides a
518/// compile-time constant `value` class member with the value `true` if the
519/// supplied `T` type is an abstract class type, and provides a `value`
520/// class member with the value `false` otherwise. This meta-function
521/// matches the behavior `std::is_abstract` would have if it were
522/// available on C++03 platforms.
523template <class T>
525
526 typedef char YesType;
527 typedef struct { char a[2]; } NoType;
528
529 template <class U>
530 static NoType test(U (*)[1]);
531
532 template <class U>
533 static YesType test(...);
534
535 enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
536};
537
538#endif
539
540 // ===================================
541 // class ProtocolTest_MethodReturnType
542 // ===================================
543
544/// This class is a proxy for a return type designed to simplify testing
545/// implementations of protocol methods.
546/// `ProtocolTest_MethodReturnType` can be converted to any
547/// non-reference type (i.e., the type can be either a value or pointer
548/// type, but not a reference type). When an object of this class is
549/// returned from a test implementation of a protocol method, it is
550/// implicitly converted to the return type of the protocol method.
552
553 // ACCESSORS
554
555 /// Return a temporary value of type `T`. The returned object is valid
556 /// but it does not have any meaningful value so it should not be used.
557 /// Type `T` is required to be default-constructible.
558 template <class T>
559 operator T() const;
560};
561
562 // ======================================
563 // class ProtocolTest_MethodReturnRefType
564 // ======================================
565
566/// This class is a proxy for a return type designed to simplify testing
567/// implementations of protocol methods.
568/// `ProtocolTest_MethodReturnRefType` can be converted to any
569/// reference type. When an object of this class is returned from a test
570/// implementation of a protocol method, it is implicitly converted to
571/// the return type of the protocol method.
573
574 // ACCESSORS
575
576 /// Return a `T&` reference to an invalid object. The returned value
577 /// should not be used and should be immediately discarded.
578 template <class T>
579 operator T&() const;
580};
581
582 // =======================
583 // class ProtocolTest_Dtor
584 // =======================
585
586/// This class template is a helper protocol-test implementation class that
587/// tests that a protocol destructor is declared `virtual`, which it does by
588/// calling the `markDone` function from its destructor. The destructor
589/// will be executed if the protocol's destructor is declared `virtual` and
590/// not executed otherwise. Note that the `BSLS_TESTIMP` template parameter
591/// is required to be a type derived from `ProtocolTestImp` class.
592template <class BSLS_TESTIMP>
593struct ProtocolTest_Dtor : BSLS_TESTIMP {
594
595 // CREATORS
596
597 /// Destroy this object and call the `markDone` method, indicating that
598 /// the base class's destructor was declared `virtual`.
600};
601
602 // =========================
603 // class ProtocolTest_Status
604 // =========================
605
606/// This class keeps track of the test status, which includes the status of
607/// the last test and the number of failures across all tests.
608///
609/// See @ref bsls_protocoltest
611
612 private:
613 // DATA
614 int d_failures; // number of test failures encountered so far
615 bool d_last; // result of the last test ('true' indicates success)
616
617 public:
618 // CREATORS
619
620 /// Create an object of the `ProtocolTest_Status` class with the
621 /// default state in which `failures() == 0` and `last() == true`.
623
624 // MANIPULATORS
625
626 /// Reset the status of the last test to `true`.
627 void resetLast();
628
629 /// Record a test failure by increasing the number of `failures` and
630 /// setting the status of the last test to `false`.
631 void fail();
632
633 // ACCESSORS
634
635 /// Return the number of failures encountered during testing of a
636 /// protocol class, which is 0 if all tests succeeded or if no tests
637 /// ran.
638 int failures() const;
639
640 /// Return `true` if the last test completed successfully (or no test
641 /// has yet completed), and `false` if it failed.
642 bool last() const;
643};
644
645 // ===========================
646 // class ProtocolTest_AsBigAsT
647 // ===========================
648
649/// This auxiliary structure has a size no less than the size of (template
650/// parameter) `T`.
651///
652/// See @ref bsls_protocoltest
653template <class T>
655
656#if defined (BSLS_LIBRARYFEATURES_HAS_CPP11_MISCELLANEOUS_UTILITIES)
657 // DATA
658 std::max_align_t d_dummy[sizeof(T) / sizeof(std::max_align_t) + 1];
659#else
660 // PRIVATE TYPES
661 union MaxAlignType {
662 void *d_v_p;
663 unsigned long long d_ull;
664 long double d_ul;
665 };
666
667 // DATA
668 MaxAlignType d_dummy[sizeof(T) / sizeof(MaxAlignType) + 1];
669#endif
670};
671
672 // =====================
673 // class ProtocolTestImp
674 // =====================
675
676/// This mechanism class template is a base class for a test implementation
677/// of a protocol class defined by the `BSLS_PROTOCOL` template parameter.
678/// Its purpose is to reduce the boilerplate test code required to verify
679/// that derived virtual methods are called. It provides `markDone` member
680/// functions one of which should be called from each method of the protocol
681/// class test implementation to indicate that the virtual method is
682/// correctly overridden. It also overloads `operator->` to serve as a
683/// proxy to `BSLS_PROTOCOL` and detect when `BSLS_PROTOCOL` methods are
684/// called.
685///
686/// See @ref bsls_protocoltest
687template <class BSLS_PROTOCOL>
688class ProtocolTestImp : public BSLS_PROTOCOL {
689
690 private:
691 // DATA
692 mutable ProtocolTest_Status *d_status; // test status object for test
693 // failure reporting; mutable, so
694 // it can be set from 'const'
695 // methods in order to be able to
696 // verify 'const' methods.
697
698 mutable bool d_entered; // 'true' if this object entered a
699 // protocol method call; mutable,
700 // so it can be set from 'const'
701 // methods in order to be able to
702 // verify 'const' methods.
703
704 mutable bool d_exited; // 'true' if this object exited a
705 // protocol method in the derived
706 // class; mutable, so it can be
707 // set from 'const' methods in
708 // order to be able to verify
709 // 'const' methods.
710 public:
711 // TYPES
712 typedef BSLS_PROTOCOL ProtocolType;
713
714 // CREATORS
715
716 /// Create an object of the `ProtocolTestImp` class.
718
719 /// Destroy this object and check the status of the test execution
720 /// (success or failure). On test failure, report it to
721 /// `ProtocolTest_Status`.
723
724 // MANIPULATORS
725
726 /// Dereference this object as if it were a pointer to `BSLS_PROTOCOL`
727 /// in order to call a method on `BSLS_PROTOCOL`. Also mark this
728 /// object as `entered` for the purpose of calling a protocol method.
729 BSLS_PROTOCOL *operator->();
730
731 // ACCESSORS
732
733 /// Dereference this object as if it were a `const BSLS_PROTOCOL *s` in
734 /// order to call a `const` method on `BSLS_PROTOCOL`. Also mark this
735 /// object as `entered` for the purpose of calling a protocol method.
736 const BSLS_PROTOCOL *operator->() const;
737
738 /// Return a proxy object convertible to any value or pointer type.
739 /// Derived classed should call this method from their implementations
740 /// of protocol virtual methods to indicate that virtual methods were
741 /// overridden correctly.
743
744 /// Return a proxy object convertible to any reference type. Derived
745 /// classed should call this method from their implementations of
746 /// protocol virtual methods to indicate that virtual methods were
747 /// overridden correctly.
749
750 /// Return the specified `value`. Derived classes should call this
751 /// method from their implementations of protocol virtual methods to
752 /// indicate that virtual methods were overridden correctly.
753 template <class T>
754 T markDoneVal(const T& value) const;
755
756 /// Mark this object as entered for the purpose of calling a protocol
757 /// method. The `entered` property is tested in the destructor to
758 /// check for test failures (i.e., if `entered == false` then the test
759 /// cannot fail since it never ran). Note that `markEnter` and
760 /// `markDone` calls have to be paired for a protocol-method-call test
761 /// to succeed.
762 void markEnter() const;
763
764 /// Connect this protocol test object with the specified `testStatus`
765 /// object, which will be used for test failure reporting.
766 void setTestStatus(ProtocolTest_Status *testStatus) const;
767};
768
769 // ==================
770 // class ProtocolTest
771 // ==================
772
773/// This mechanism class template provides the implementation of protocol
774/// testing concerns via `test*` methods (for non-method concerns), and via
775/// `operator->` (for method concerns). The `BSLS_TESTIMP` template
776/// parameter is required to be a class derived from `ProtocolTestImp`
777/// that provides test implementations of all protocol methods.
778///
779/// See @ref bsls_protocoltest
780template <class BSLS_TESTIMP>
782
783 private:
784 // TYPES
785 typedef typename BSLS_TESTIMP::ProtocolType ProtocolType;
786
787 // DATA
788 ProtocolTest_Status d_status;
789 bool d_verbose; // print trace messages if 'true'
790
791 private:
792 // PRIVATE MANIPULATORS
793
794 /// Start a new test by resetting this object to the state before the
795 /// test.
796 void startTest();
797
798 /// Print a trace `message` if `d_verbose` is `true`.
799 void trace(char const *message) const;
800
801 public:
802 // CREATORS
803
804 /// Construct a `ProtocolTest` object.
805 explicit
806 ProtocolTest(bool verbose = false);
807
808 // MANIPULATORS
809
810 /// Return a `BSLS_TESTIMP` object to perform testing of a specific
811 /// method which gets called via `operator->()`. Note that
812 /// `BSLS_TESTIMP` is a proxy to the actual protocol class.
813 BSLS_TESTIMP method(const char *methodDesc = "");
814
815 /// Return `true` (i.e., the test passed) if the protocol class being
816 /// tested is abstract and return `false` (i.e., the test failed)
817 /// otherwise. Increase the count of `failures` and set `lastStatus` to
818 /// `false` on failure.
819 bool testAbstract();
820
821 /// Return `true` (i.e., the test passed) if the protocol class being
822 /// tested contains no data fields and return `false` (i.e., the test
823 /// failed) otherwise. Increase the count of `failures` and set
824 /// `lastStatus` to `false` on failure.
825 bool testNoDataMembers();
826
827 /// Return `true` (i.e., the test passed) if the protocol class being
828 /// tested has a virtual destructor and return `false` (i.e., the test
829 /// failed) otherwise. Increase the `failures` count and set
830 /// `lastStatus` to `false` on failure.
832
833 // ACCESSORS
834
835 /// Return the number of failures encountered during testing of a
836 /// protocol class. The returned value is 0 if all tests succeeded, or
837 /// no tests ran.
838 int failures() const;
839
840 /// Return `true` if the last test completed successfully (or no test
841 /// has yes completed) and `false` otherwise.
842 bool lastStatus() const;
843};
844
845} // close package namespace
846
847 // ========================
848 // BSLS_PROTOCOLTEST_ASSERT
849 // ========================
850
851// This macro provides a test for method-related concerns of a protocol class.
852// It ensures that a method is publicly accessible and declared 'virtual'. It
853// requires that a standard test driver 'ASSERT' macro is defined, which is
854// used to assert the test completion status.
855
856#define BSLS_PROTOCOLTEST_ASSERT(test, methodCall) \
857 do { \
858 (void) test.method( \
859 "inside BSLS_PROTOCOLTEST_ASSERT("#methodCall")")->methodCall;\
860 if (!test.lastStatus()) { \
861 ASSERT(0 && "Not a virtual method: "#methodCall); \
862 } \
863 } while (0)
864
865#define BSLS_PROTOCOLTEST_RV_ASSERT(test, methodCall, returnValue) \
866 do { \
867 returnValue = test.method( \
868 "inside BSLS_PROTOCOLTEST_ASSERT("#methodCall")")->methodCall;\
869 if (!test.lastStatus()) { \
870 ASSERT(0 && "Not a virtual method: "#methodCall); \
871 } \
872 } while (0)
873
874// ============================================================================
875// INLINE FUNCTION DEFINITIONS
876// ============================================================================
877
878namespace bsls {
879
880 // -----------------------------------
881 // class ProtocolTest_MethodReturnType
882 // -----------------------------------
883
884// ACCESSORS
885template <class T>
886inline
887ProtocolTest_MethodReturnType::operator T() const
888{
889 return T();
890}
891
892 // --------------------------------------
893 // class ProtocolTest_MethodReturnRefType
894 // --------------------------------------
895
896// ACCESSORS
897template <class T>
898inline
899ProtocolTest_MethodReturnRefType::operator T&() const
900{
901 static ProtocolTest_AsBigAsT<T> obj;
902 T *pObj = reinterpret_cast<T *>(&obj);
903 return *pObj;
904}
905
906 // -----------------------
907 // class ProtocolTest_Dtor
908 // -----------------------
909
910// CREATORS
911template <class BSLS_TESTIMP>
912inline
917
918 // -------------------------
919 // class ProtocolTest_Status
920 // -------------------------
921
922// CREATORS
923inline
925: d_failures(0)
926, d_last(true)
927{
928}
929
930// MANIPULATORS
931inline
933{
934 d_last = true;
935}
936
937inline
939{
940 ++d_failures;
941 d_last = false;
942}
943
944// ACCESSORS
945inline
947{
948 return d_failures;
949}
950
951inline
953{
954 return d_last;
955}
956
957 // ---------------------
958 // class ProtocolTestImp
959 // ---------------------
960
961// CREATORS
962template <class BSLS_PROTOCOL>
963inline
965: d_status(0)
966, d_entered(false)
967, d_exited(false)
968{
969}
970
971template <class BSLS_PROTOCOL>
972inline
974{
975 if (d_entered && !d_exited) {
976 d_status->fail();
977 }
978}
979
980// MANIPULATORS
981template <class BSLS_PROTOCOL>
982inline
985{
986 markEnter();
987 return static_cast<BSLS_PROTOCOL *>(this);
988}
989
990// ACCESSORS
991template <class BSLS_PROTOCOL>
992inline
995{
996 markEnter();
997 return static_cast<const BSLS_PROTOCOL *>(this);
998}
999
1000template <class BSLS_PROTOCOL>
1001inline
1004{
1005 d_exited = true;
1007}
1008
1009template <class BSLS_PROTOCOL>
1010inline
1013{
1014 d_exited = true;
1016}
1017
1018template <class BSLS_PROTOCOL>
1019template <class T>
1020inline
1022{
1023 d_exited = true;
1024 return value;
1025}
1026
1027template <class BSLS_PROTOCOL>
1028inline
1030{
1031 d_entered = true;
1032}
1033
1034template <class BSLS_PROTOCOL>
1035inline
1037 ProtocolTest_Status *testStatus) const
1038{
1039 d_status = testStatus;
1040}
1041
1042 // ------------------
1043 // class ProtocolTest
1044 // ------------------
1045
1046// PRIVATE MANIPULATORS
1047template <class BSLS_TESTIMP>
1048inline
1050{
1051 d_status.resetLast();
1052}
1053
1054template <class BSLS_TESTIMP>
1055inline
1056void ProtocolTest<BSLS_TESTIMP>::trace(char const *message) const
1057{
1058 if (d_verbose) {
1059 std::printf("\t%s\n", message);
1060 }
1061}
1062
1063// CREATORS
1064template <class BSLS_TESTIMP>
1065inline
1067: d_verbose(verbose)
1068{
1069}
1070
1071// MANIPULATORS
1072template <class BSLS_TESTIMP>
1073inline
1074BSLS_TESTIMP ProtocolTest<BSLS_TESTIMP>::method(const char *methodDesc)
1075{
1076 trace(methodDesc);
1077 startTest();
1078
1079 BSLS_TESTIMP impl;
1080 impl.setTestStatus(&d_status);
1081 return impl;
1082}
1083
1084template <class BSLS_TESTIMP>
1085inline
1087{
1088 trace("inside ProtocolTest::testAbstract()");
1089 startTest();
1090
1092 d_status.fail();
1093 }
1094
1095 return lastStatus();
1096}
1097
1098template <class BSLS_TESTIMP>
1099inline
1101{
1102 trace("inside ProtocolTest::testNoDataMembers()");
1103 struct EmptyProtocol
1104 {
1105 virtual ~EmptyProtocol() {}
1106 };
1107
1108 startTest();
1109
1110 if (sizeof(EmptyProtocol) != sizeof(ProtocolType)) {
1111 d_status.fail();
1112 }
1113
1114 return lastStatus();
1115}
1116
1117template <class BSLS_TESTIMP>
1119{
1120 trace("inside ProtocolTest::testVirtualDestructor");
1121 startTest();
1122
1123 // Can't use an automatic buffer and the placement new for an object of
1124 // type ProtocolTest_Dtor<BSLS_TESTIMP> here, because bslma::Allocator
1125 // defines its own placement new, making it impossible to test
1126 // bslma::Allocator protocol this way.
1127
1128 // Prepare a test
1131 BSLS_TESTIMP * base = obj;
1132 obj->setTestStatus(&d_status);
1133
1134 // Run the test.
1135 obj->markEnter();
1136 delete base;
1137
1138 // 'ProtocolTest_Dtor::~ProtocolTest_Dtor' will be called only if
1139 // the destructor was declared 'virtual' in the interface, but
1140 // 'BSLS_TESTIMP::~BSLS_TESTIMP' is always executed to check if the
1141 // derived destructor was called.
1142
1143 return lastStatus();
1144}
1145
1146// ACCESSORS
1147template <class BSLS_TESTIMP>
1148inline
1150{
1151 return d_status.failures();
1152}
1153
1154template <class BSLS_TESTIMP>
1155inline
1157{
1158 return d_status.last();
1159}
1160
1161} // close package namespace
1162
1163#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
1164// ============================================================================
1165// BACKWARD COMPATIBILITY
1166// ============================================================================
1167
1168#ifdef bsls_ProtocolTest
1169#undef bsls_ProtocolTest
1170#endif
1171/// This alias is defined for backward compatibility.
1172#define bsls_ProtocolTest bsls::ProtocolTest
1173
1174#ifdef bsls_ProtocolTestImp
1175#undef bsls_ProtocolTestImp
1176#endif
1177/// This alias is defined for backward compatibility.
1178#define bsls_ProtocolTestImp bsls::ProtocolTestImp
1179#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
1180
1181
1182
1183#endif
1184
1185// ----------------------------------------------------------------------------
1186// Copyright 2013 Bloomberg Finance L.P.
1187//
1188// Licensed under the Apache License, Version 2.0 (the "License");
1189// you may not use this file except in compliance with the License.
1190// You may obtain a copy of the License at
1191//
1192// http://www.apache.org/licenses/LICENSE-2.0
1193//
1194// Unless required by applicable law or agreed to in writing, software
1195// distributed under the License is distributed on an "AS IS" BASIS,
1196// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1197// See the License for the specific language governing permissions and
1198// limitations under the License.
1199// ----------------------------- END-OF-FILE ----------------------------------
1200
1201/** @} */
1202/** @} */
1203/** @} */
Definition bsls_protocoltest.h:688
ProtocolTest_MethodReturnRefType markDoneRef() const
Definition bsls_protocoltest.h:1012
BSLS_PROTOCOL ProtocolType
Definition bsls_protocoltest.h:712
~ProtocolTestImp()
Definition bsls_protocoltest.h:973
void setTestStatus(ProtocolTest_Status *testStatus) const
Definition bsls_protocoltest.h:1036
T markDoneVal(const T &value) const
Definition bsls_protocoltest.h:1021
BSLS_PROTOCOL * operator->()
Definition bsls_protocoltest.h:984
void markEnter() const
Definition bsls_protocoltest.h:1029
ProtocolTest_MethodReturnType markDone() const
Definition bsls_protocoltest.h:1003
ProtocolTestImp()
Create an object of the ProtocolTestImp class.
Definition bsls_protocoltest.h:964
Definition bsls_protocoltest.h:654
Definition bsls_protocoltest.h:610
ProtocolTest_Status()
Definition bsls_protocoltest.h:924
void fail()
Definition bsls_protocoltest.h:938
bool last() const
Definition bsls_protocoltest.h:952
int failures() const
Definition bsls_protocoltest.h:946
void resetLast()
Reset the status of the last test to true.
Definition bsls_protocoltest.h:932
Definition bsls_protocoltest.h:781
BSLS_TESTIMP method(const char *methodDesc="")
Definition bsls_protocoltest.h:1074
bool lastStatus() const
Definition bsls_protocoltest.h:1156
bool testAbstract()
Definition bsls_protocoltest.h:1086
ProtocolTest(bool verbose=false)
Construct a ProtocolTest object.
Definition bsls_protocoltest.h:1066
bool testNoDataMembers()
Definition bsls_protocoltest.h:1100
bool testVirtualDestructor()
Definition bsls_protocoltest.h:1118
int failures() const
Definition bsls_protocoltest.h:1149
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlt_iso8601util.h:691
Definition bsls_protocoltest.h:593
~ProtocolTest_Dtor()
Definition bsls_protocoltest.h:913
Definition bsls_protocoltest.h:527
Definition bsls_protocoltest.h:524
static NoType test(U(*)[1])
static YesType test(...)
@ value
Definition bsls_protocoltest.h:535
char YesType
Definition bsls_protocoltest.h:526
Definition bsls_protocoltest.h:572
Definition bsls_protocoltest.h:551