BDE 4.14.0 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 // NOT IMPLEMENTED
249 TestObserver& operator=(const TestObserver&);
250
251 public:
252 // TRAITS
254
255 // CLASS METHODS
256
257 /// Return the total number of instances of this class that have been
258 /// created since this process has begun.
259 static int numInstances();
260
261 // CREATORS
262
263 /// Create a test observer having a unique integer identifier, whose
264 /// `publish` method will print diagnostic information (if any) to the
265 /// specified `stream`. Optionally specify a `basicAllocator` used to
266 /// supply memory. If `basicAllocator` is 0, the currently installed
267 /// default allocator is used. By default, this observer prints nothing
268 /// to `stream`. Note that the `setVerbose` method can affect this
269 /// default behavior.
270 explicit
271 TestObserver(bsl::ostream *stream, bslma::Allocator *basicAllocator = 0);
272
273#ifndef BDE_OMIT_INTERNAL_DEPRECATED
274 /// Create a test observer having a unique integer identifier, whose
275 /// `publish` method will print diagnostic information (if any) to the
276 /// specified `stream`. Optionally specify a `basicAllocator` used to
277 /// supply memory. If `basicAllocator` is 0, the currently installed
278 /// default allocator is used. By default, this observer prints nothing
279 /// to `stream`. Note that the `setVerbose` method can affect this
280 /// default behavior.
281 ///
282 /// @deprecated Use the constructor taking `bsl::ostream *` instead.
283 explicit
284 TestObserver(bsl::ostream& stream, bslma::Allocator *basicAllocator = 0);
285#endif // BDE_OMIT_INTERNAL_DEPRECATED
286
287 /// Destroy this test observer.
289
290 // MANIPULATORS
291
292 /// Store as the most recently published data the specified log `record`
293 /// and publishing `context`. If this test observer is in verbose mode,
294 /// print an appropriate diagnostic message to the stream specified at
295 /// construction. Note that at construction test observers are not in
296 /// verbose mode, but that the `setVerbose` method can affect this mode,
297 /// and thus the behavior of this method.
298 ///
299 /// @deprecated Use the alternative `publish` overload instead.
300 void publish(const Record& record,
301 const Context& context) BSLS_KEYWORD_OVERRIDE;
302
303 /// Store as the most recently published data the specified log `record`
304 /// and publishing `context`. If this test observer is in verbose mode,
305 /// print an appropriate diagnostic message to the stream specified at
306 /// construction. Note that at construction test observers are not in
307 /// verbose mode, but that the `setVerbose` method can affect this mode,
308 /// and thus the behavior of this method.
309 void publish(const bsl::shared_ptr<const Record>& record,
310 const Context& context)
312
313 /// Discard any shared reference to a `Record` object that was supplied
314 /// to the `publish` method, and is held by this observer. Note that
315 /// this operation should be called if resources underlying the
316 /// previously provided shared-pointers must be released.
318
319 /// Set the internal verbose mode of this test observer to the specified
320 /// (boolean) `flagValue`. The default mode is *not* verbose. If
321 /// `flagValue` is non-zero, calls to `publish` will print appropriate
322 /// diagnostics to the `bsl::ostream` associated with this test
323 /// observer. This printing is suppressed if `flagValue` is 0.
324 void setVerbose(int flagValue);
325
326 // ACCESSORS
327
328 /// Return the unique (per process) integer identifier of this test
329 /// observer.
330 int id() const;
331
332 /// Return a reference to the context most recently published by this
333 /// test observer. The behavior is undefined unless `publish` has been
334 /// called at least once, and no other thread is manipulating this
335 /// object concurrently (i.e., this function is *not* thread safe).
336 const Context& lastPublishedContext() const;
337
338 /// Return a reference to the record most recently published by this
339 /// test observer. The behavior is undefined unless `publish` has been
340 /// called at least once, and no other thread is manipulating this
341 /// object concurrently (i.e., this function is *not* thread safe).
342 const Record& lastPublishedRecord() const;
343
344 /// Return the total number of records that this test observer has
345 /// published.
346 int numPublishedRecords() const;
347
348 /// Return the total number of times that `releaseRecords` has been
349 /// called on this test observer.
350 int numReleases() const;
351};
352
353// ============================================================================
354// INLINE DEFINITIONS
355// ============================================================================
356
357 // ------------------
358 // class TestObserver
359 // ------------------
360
361// CLASS METHODS
362inline
364{
365 return AtomicOps::getIntRelaxed(&s_count);
366}
367
368// CREATORS
369inline
370TestObserver::TestObserver(bsl::ostream *stream,
371 bslma::Allocator *basicAllocator)
372: d_stream_p(stream)
373, d_record(basicAllocator)
374, d_context(basicAllocator)
375, d_id(AtomicOps::incrementIntNvAcqRel(&s_count))
376, d_verboseFlag(0)
377, d_numRecords(0)
378, d_numReleases(0)
379{
380 BSLS_ASSERT(d_stream_p);
381}
382
383#ifndef BDE_OMIT_INTERNAL_DEPRECATED
384inline
385TestObserver::TestObserver(bsl::ostream& stream,
386 bslma::Allocator *basicAllocator)
387: d_stream_p(&stream)
388, d_record(basicAllocator)
389, d_context(basicAllocator)
390, d_id(AtomicOps::incrementIntNvAcqRel(&s_count))
391, d_verboseFlag(0)
392, d_numRecords(0)
393, d_numReleases(0)
394{
395}
396#endif // BDE_OMIT_INTERNAL_DEPRECATED
397
398// MANIPULATORS
399inline
401{
402 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
403 ++d_numReleases;
404}
405
406inline
407void TestObserver::setVerbose(int flagValue)
408{
409 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
410 d_verboseFlag = flagValue;
411}
412
413// ACCESSORS
414inline
416{
417 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
418 return d_id;
419}
420
421inline
423{
424 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
425 return d_context;
426}
427
428inline
430{
431 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
432 return d_record;
433}
434
435inline
437{
438 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
439 return d_numRecords;
440}
441
442inline
444{
445 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
446 return d_numReleases;
447}
448
449} // close package namespace
450
451
452#endif
453
454// ----------------------------------------------------------------------------
455// Copyright 2015 Bloomberg Finance L.P.
456//
457// Licensed under the Apache License, Version 2.0 (the "License");
458// you may not use this file except in compliance with the License.
459// You may obtain a copy of the License at
460//
461// http://www.apache.org/licenses/LICENSE-2.0
462//
463// Unless required by applicable law or agreed to in writing, software
464// distributed under the License is distributed on an "AS IS" BASIS,
465// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
466// See the License for the specific language governing permissions and
467// limitations under the License.
468// ----------------------------- END-OF-FILE ----------------------------------
469
470/** @} */
471/** @} */
472/** @} */
Definition ball_context.h:295
Definition ball_observer.h:235
Definition ball_record.h:178
Definition ball_testobserver.h:217
const Context & lastPublishedContext() const
Definition ball_testobserver.h:422
~TestObserver() BSLS_KEYWORD_OVERRIDE
Destroy this test observer.
int numPublishedRecords() const
Definition ball_testobserver.h:436
BSLMF_NESTED_TRAIT_DECLARATION(TestObserver, bslma::UsesBslmaAllocator)
void releaseRecords() BSLS_KEYWORD_OVERRIDE
Definition ball_testobserver.h:400
const Record & lastPublishedRecord() const
Definition ball_testobserver.h:429
int id() const
Definition ball_testobserver.h:415
void setVerbose(int flagValue)
Definition ball_testobserver.h:407
int numReleases() const
Definition ball_testobserver.h:443
void publish(const Record &record, const Context &context) BSLS_KEYWORD_OVERRIDE
static int numInstances()
Definition ball_testobserver.h:363
Definition bslma_allocator.h:457
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:315
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition ball_administration.h:214
Definition bdlb_printmethods.h:283
Definition bslma_usesbslmaallocator.h:343
Definition bsls_atomicoperations.h:834
static int getIntRelaxed(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1534