BDE 4.39.x Production Release
Loading...
Searching...
No Matches
ball_testobserver.h
Go to the documentation of this file.
1/// @file ball_testobserver.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// ball_testobserver.h -*-C++-*-
8#ifndef INCLUDED_BALL_TESTOBSERVER
9#define INCLUDED_BALL_TESTOBSERVER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup ball_testobserver ball_testobserver
15/// @brief Provide an instrumented observer for testing.
16/// @addtogroup bal
17/// @{
18/// @addtogroup ball
19/// @{
20/// @addtogroup ball_testobserver
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#ball_testobserver-purpose"> Purpose</a>
25/// * <a href="#ball_testobserver-classes"> Classes </a>
26/// * <a href="#ball_testobserver-description"> Description </a>
27/// * <a href="#ball_testobserver-thread-safety"> Thread Safety </a>
28/// * <a href="#ball_testobserver-verbose-mode"> Verbose Mode </a>
29/// * <a href="#ball_testobserver-usage"> Usage </a>
30/// * <a href="#ball_testobserver-example-1-basic-usage"> Example 1: Basic Usage </a>
31///
32/// # Purpose {#ball_testobserver-purpose}
33/// Provide an instrumented observer for testing.
34///
35/// # Classes {#ball_testobserver-classes}
36///
37/// - ball::TestObserver: instrumented observer for testing
38///
39/// @see ball_record, ball_context, ball_observer
40///
41/// # Description {#ball_testobserver-description}
42/// This component provides a concrete implementation of the
43/// `ball::Observer` protocol, `ball::TestObserver`, that is instrumented for
44/// testing systems that use `ball::Observer` objects.
45/// @code
46/// ( ball::TestObserver )
47/// | static numInstances
48/// | ctor
49/// | setVerbose
50/// | id
51/// | lastPublishedContext
52/// | lastPublishedRecord
53/// | numPublishedRecords
54/// | numReleases
55/// V
56/// ( ball::Observer )
57/// dtor
58/// publish
59/// releaseRecords
60/// @endcode
61/// `ball::TestObserver` ascribes to each instance (within a process) a unique
62/// integer identifier (accessible via the `id` method), and each instance keeps
63/// a count of the total number of records that it has published (accessible via
64/// the `numPublishedRecords` method). In addition, the test observer maintains
65/// a copy of the record and context data from the most recent call to
66/// `publish`; that information is available via the accessors
67/// `lastPublishedRecord` and `lastPublishedContext`.
68///
69/// ## Thread Safety {#ball_testobserver-thread-safety}
70///
71///
72/// The `ball::TestObserver` provides a `publish` method that is *thread-safe*,
73/// meaning that the test observer may be used to log records from multiple
74/// threads. However, the `ball::TestObserver` accessors `lastPublished` method
75/// and `lastPublishedContext` provide references to internal data structures
76/// (for backwards compatibility) and are therefore *not* *thread-safe*.
77///
78/// ## Verbose Mode {#ball_testobserver-verbose-mode}
79///
80///
81/// The `publish` method, in addition to making a local copy of the published
82/// data for future inspection, is capable of printing an appropriate diagnostic
83/// message to the `ostream` held by the test observer instance. By default,
84/// this printing is suppressed, but the behavior can be altered by calling the
85/// `setVerbose` method. A call to `setVerbose` with a non-zero argument (e.g.,
86/// `setVerbose(1)`) places the object in verbose mode, which enables diagnostic
87/// printing. A subsequent call of `setVerbose(0)` restores the default "quiet"
88/// behavior.
89///
90/// ## Usage {#ball_testobserver-usage}
91///
92///
93/// This section illustrates intended use of this component.
94///
95/// ### Example 1: Basic Usage {#ball_testobserver-example-1-basic-usage}
96///
97///
98/// The following snippets of code illustrate the basic usage of testing
99/// observer objects. The example focuses on the individual features that are
100/// useful for testing larger systems (not shown) that use observers derived
101/// from `ball::Observer`.
102///
103/// First create a `ball::Record` object `record` and a `ball::Context` object
104/// `context`. Note that the default values for these objects (or their
105/// contained objects) are perfectly suitable for testing purposes, since the
106/// testing observer's purpose is simply to report what has been presented to
107/// its `publish` method.
108/// @code
109/// ball::RecordAttributes attributes;
110/// ball::UserFields fieldValues;
111/// ball::Context context;
112///
113/// bslma::Allocator *ga = bslma::Default::globalAllocator(0);
114/// const bsl::shared_ptr<const ball::Record>
115/// record(new (*ga) ball::Record(attributes, fieldValues, ga), ga);
116/// @endcode
117/// Next, create three test observers `to1`, to2', and `to3`, each with
118/// `bsl::cout` as the held stream. Note that each instance will be given a
119/// unique integer identifier by the constructor.
120/// @code
121/// assert(0 == ball::TestObserver::numInstances());
122///
123/// ball::TestObserver to1(&bsl::cout);
124/// assert(1 == to1.id());
125/// assert(1 == ball::TestObserver::numInstances());
126///
127/// ball::TestObserver to2(&bsl::cout);
128/// assert(2 == to2.id());
129/// assert(2 == ball::TestObserver::numInstances());
130///
131/// ball::TestObserver to3(&bsl::cout);
132/// assert(3 == to3.id());
133/// assert(3 == ball::TestObserver::numInstances());
134///
135/// assert(0 == to1.numPublishedRecords());
136/// assert(0 == to2.numPublishedRecords());
137/// assert(0 == to3.numPublishedRecords());
138/// @endcode
139/// Finally, set `to1` to "verbose mode" and publish `record` and `context` to
140/// `to1` and also to `to2`, but not to `to3`.
141/// @code
142/// to1.setVerbose(1);
143/// to1.publish(record, context);
144/// assert(1 == to1.numPublishedRecords());
145///
146/// to2.publish(record, context);
147/// assert(1 == to2.numPublishedRecords());
148/// assert(0 == to3.numPublishedRecords());
149/// @endcode
150/// This will produce the following output on `stdout`:
151/// @code
152/// Test Observer ID 1 publishing record number 1
153/// Context: cause = PASSTHROUGH
154/// count = 1 of an expected 1 total records.
155/// @endcode
156/// Note that `to2` produces no output, although its `publish` method executed
157/// (as verified by the `numPublishedRecords` method); only `to1` produces a
158/// printed output, because it has been set to verbose mode.
159/// @}
160/** @} */
161/** @} */
162
163/** @addtogroup bal
164 * @{
165 */
166/** @addtogroup ball
167 * @{
168 */
169/** @addtogroup ball_testobserver
170 * @{
171 */
172
173#include <balscm_version.h>
174
175#include <ball_context.h>
176#include <ball_observer.h>
177#include <ball_record.h>
178
179#include <bslma_allocator.h>
181
183
184#include <bslmt_lockguard.h>
185#include <bslmt_mutex.h>
186
187#include <bsls_assert.h>
188#include <bsls_atomic.h>
190#include <bsls_keyword.h>
191#include <bsls_review.h>
192
193#include <bsl_iosfwd.h>
194#include <bsl_memory.h>
195
196
197namespace ball {
198
199 // ==================
200 // class TestObserver
201 // ==================
202
203/// This class provides an instrumented implementation of the `Observer`
204/// protocol suitable for testing systems that use `Observer`. Each
205/// instance receives a unique (per process) integer identifier at
206/// construction, and keeps count of the number of records that it has
207/// published, as well as the contents of the most recently published record
208/// and context.
209///
210/// By default, the `publish` method prints no diagnostic information to the
211/// `bsl::ostream` supplied at construction. This diagnostic information
212/// can be enabled by a call to `setVerbose` with a non-zero argument. A
213/// subsequent call to `setVerbose` with a zero argument will restore the
214/// default behavior of `publish`.
215///
216/// See @ref ball_testobserver
217class TestObserver : public Observer {
218
219 // TYPES
221 typedef bsls::AtomicOperations::AtomicTypes::Int AtomicInt;
222
223 // CLASS DATA
224 static AtomicInt s_count; // number of instances created
225
226 // DATA
227 bsl::ostream *d_stream_p; // target of `publish` method
228 // diagnostic information
229
230 Record d_record; // most-recently-published record
231
232 Context d_context; // most-recently-published context
233
234 int d_id; // unique (per process) id
235
236 int d_verboseFlag; // "verbosity" mode on `publish`
237
238 int d_numRecords; // total number of published records
239
240 int d_numReleases; // total number of calls to
241 // `releaseRecords`
242
243 mutable bslmt::Mutex d_mutex; // serializes concurrent calls to
244 // `publish` and protects concurrent
245 // access to other class members
246
247 private:
248 // NOT IMPLEMENTED
250 TestObserver& operator=(const TestObserver&);
251
252 public:
253 // TRAITS
255
256 // CLASS METHODS
257
258 /// Return the total number of instances of this class that have been
259 /// created since this process has begun.
260 static int numInstances();
261
262 // CREATORS
263
264 /// Create a test observer having a unique integer identifier, whose
265 /// `publish` method will print diagnostic information (if any) to the
266 /// specified `stream`. Optionally specify a `basicAllocator` used to
267 /// supply memory. If `basicAllocator` is 0, the currently installed
268 /// default allocator is used. By default, this observer prints nothing to `stream`.
269 ///
270 /// \note Note that the `setVerbose` method can affect this
271 /// default behavior.
272 explicit
273 TestObserver(bsl::ostream *stream, bslma::Allocator *basicAllocator = 0);
274
275#ifndef BDE_OMIT_INTERNAL_DEPRECATED
276 /// Create a test observer having a unique integer identifier, whose
277 /// `publish` method will print diagnostic information (if any) to the
278 /// specified `stream`. Optionally specify a `basicAllocator` used to
279 /// supply memory. If `basicAllocator` is 0, the currently installed
280 /// default allocator is used. By default, this observer prints nothing to `stream`.
281 ///
282 /// \note Note that the `setVerbose` method can affect this
283 /// default behavior.
284 ///
285 /// @deprecated Use the constructor taking `bsl::ostream *` instead.
286 explicit
287 TestObserver(bsl::ostream& stream, bslma::Allocator *basicAllocator = 0);
288#endif // BDE_OMIT_INTERNAL_DEPRECATED
289
290 /// Destroy this test observer.
292
293 // MANIPULATORS
294
295 /// Store as the most recently published data the specified log `record`
296 /// and publishing `context`. If this test observer is in verbose mode,
297 /// print an appropriate diagnostic message to the stream specified at construction.
298 ///
299 /// \note Note that at construction test observers are not in
300 /// verbose mode, but that the `setVerbose` method can affect this mode,
301 /// and thus the behavior of this method.
302 ///
303 /// @deprecated Use the alternative `publish` overload instead.
304 void publish(const Record& record,
305 const Context& context) BSLS_KEYWORD_OVERRIDE;
306
307 /// Store as the most recently published data the specified log `record`
308 /// and publishing `context`. If this test observer is in verbose mode,
309 /// print an appropriate diagnostic message to the stream specified at construction.
310 ///
311 /// \note Note that at construction test observers are not in
312 /// verbose mode, but that the `setVerbose` method can affect this mode,
313 /// and thus the behavior of this method.
314 void publish(const bsl::shared_ptr<const Record>& record,
315 const Context& context)
317
318 /// Discard any shared reference to a `Record` object that was supplied
319 /// to the `publish` method, and is held by this observer.
320 ///
321 /// \note Note that this operation should be called if resources underlying the
322 /// previously provided shared-pointers must be released.
324
325 /// Set the internal verbose mode of this test observer to the specified
326 /// (boolean) `flagValue`. The default mode is *not* verbose. If
327 /// `flagValue` is non-zero, calls to `publish` will print appropriate
328 /// diagnostics to the `bsl::ostream` associated with this test
329 /// observer. This printing is suppressed if `flagValue` is 0.
330 void setVerbose(int flagValue);
331
332 // ACCESSORS
333
334 /// Return the unique (per process) integer identifier of this test
335 /// observer.
336 int id() const;
337
338 /// Return a reference to the context most recently published by this test observer.
339 ///
340 /// \pre The behavior is undefined unless `publish` has been
341 /// called at least once, and no other thread is manipulating this
342 /// object concurrently (i.e., this function is *not* thread safe).
343 const Context& lastPublishedContext() const;
344
345 /// Return a reference to the record most recently published by this test observer.
346 ///
347 /// \pre The behavior is undefined unless `publish` has been
348 /// called at least once, and no other thread is manipulating this
349 /// object concurrently (i.e., this function is *not* thread safe).
350 const Record& lastPublishedRecord() const;
351
352 /// Return the total number of records that this test observer has
353 /// published.
354 int numPublishedRecords() const;
355
356 /// Return the total number of times that `releaseRecords` has been
357 /// called on this test observer.
358 int numReleases() const;
359};
360
361// ============================================================================
362// INLINE DEFINITIONS
363// ============================================================================
364
365 // ------------------
366 // class TestObserver
367 // ------------------
368
369// CLASS METHODS
370inline
372{
373 return AtomicOps::getIntRelaxed(&s_count);
374}
375
376// CREATORS
377inline
378TestObserver::TestObserver(bsl::ostream *stream,
379 bslma::Allocator *basicAllocator)
380: d_stream_p(stream)
381, d_record(basicAllocator)
382, d_context(basicAllocator)
383, d_id(AtomicOps::incrementIntNvAcqRel(&s_count))
384, d_verboseFlag(0)
385, d_numRecords(0)
386, d_numReleases(0)
387{
388 BSLS_ASSERT(d_stream_p);
389}
390
391#ifndef BDE_OMIT_INTERNAL_DEPRECATED
392inline
393TestObserver::TestObserver(bsl::ostream& stream,
394 bslma::Allocator *basicAllocator)
395: d_stream_p(&stream)
396, d_record(basicAllocator)
397, d_context(basicAllocator)
398, d_id(AtomicOps::incrementIntNvAcqRel(&s_count))
399, d_verboseFlag(0)
400, d_numRecords(0)
401, d_numReleases(0)
402{
403}
404#endif // BDE_OMIT_INTERNAL_DEPRECATED
405
406// MANIPULATORS
407inline
409{
410 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
411 ++d_numReleases;
412}
413
414inline
415void TestObserver::setVerbose(int flagValue)
416{
417 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
418 d_verboseFlag = flagValue;
419}
420
421// ACCESSORS
422inline
424{
425 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
426 return d_id;
427}
428
429inline
431{
432 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
433 return d_context;
434}
435
436inline
438{
439 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
440 return d_record;
441}
442
443inline
445{
446 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
447 return d_numRecords;
448}
449
450inline
452{
453 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
454 return d_numReleases;
455}
456
457} // close package namespace
458
459
460#endif
461
462// ----------------------------------------------------------------------------
463// Copyright 2015 Bloomberg Finance L.P.
464//
465// Licensed under the Apache License, Version 2.0 (the "License");
466// you may not use this file except in compliance with the License.
467// You may obtain a copy of the License at
468//
469// http://www.apache.org/licenses/LICENSE-2.0
470//
471// Unless required by applicable law or agreed to in writing, software
472// distributed under the License is distributed on an "AS IS" BASIS,
473// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
474// See the License for the specific language governing permissions and
475// limitations under the License.
476// ----------------------------- END-OF-FILE ----------------------------------
477
478/** @} */
479/** @} */
480/** @} */
Definition ball_context.h:297
Definition ball_observer.h:235
Definition ball_record.h:176
Definition ball_testobserver.h:217
const Context & lastPublishedContext() const
Definition ball_testobserver.h:430
~TestObserver() BSLS_KEYWORD_OVERRIDE
Destroy this test observer.
int numPublishedRecords() const
Definition ball_testobserver.h:444
BSLMF_NESTED_TRAIT_DECLARATION(TestObserver, bslma::UsesBslmaAllocator)
void releaseRecords() BSLS_KEYWORD_OVERRIDE
Definition ball_testobserver.h:408
const Record & lastPublishedRecord() const
Definition ball_testobserver.h:437
int id() const
Definition ball_testobserver.h:423
void setVerbose(int flagValue)
Definition ball_testobserver.h:415
int numReleases() const
Definition ball_testobserver.h:451
void publish(const Record &record, const Context &context) BSLS_KEYWORD_OVERRIDE
static int numInstances()
Definition ball_testobserver.h:371
Definition bslma_allocator.h:545
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:317
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition ball_administration.h:214
Definition bdlat_valuetypefunctions.h:939
Definition bslma_usesbslmaallocator.h:344
Definition bsls_atomicoperations.h:836
static int getIntRelaxed(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1536