Ocean
ValidationPrecision.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_TEST_VALIDATION_PRECISION_H
9 #define META_OCEAN_TEST_VALIDATION_PRECISION_H
10 
11 #include "ocean/test/Test.h"
12 #include "ocean/test/Validation.h"
13 
15 
16 namespace Ocean
17 {
18 
19 namespace Test
20 {
21 
22 /**
23  * This class implements a helper class to validate the accuracy of tests.
24  * @see Validation.
25  * @ingroup test
26  */
28 {
29  public:
30 
31  /**
32  * Creates a new scoped iteration.
33  * By default the iteration is accurate enough.<br>
34  * Call setInaccurate() for an iteration which is not precise enough.
35  */
37  {
38  public:
39 
40  /**
41  * Creates a new scoped iteration associated with a validation object.
42  */
44 
45  /**
46  * Destructs this scoped object and forwards the information to the owning validation.
47  */
48  inline ~ScopedIteration();
49 
50  /**
51  * Sets this iteration to be not precise enough.
52  */
53  inline void setInaccurate();
54 
55  /**
56  * Sets this iteration to be not precise enough.
57  * This function will also write a message to the error log.
58  * @param expected The expected value
59  * @param actual The actual value
60  * @param file The source file in which the function call happens, e.g., __FILE__, must be valid
61  * @param line The line in the source file in which the function call happens, e.g., __LINE__, must be valid
62  * @tparam T The data type of the expected and actual value
63  */
64  template <typename T>
65  inline void setInaccurate(const T& expected, const T& actual, const char* file, const int line);
66 
67  protected:
68 
69  /**
70  * Disabled default constructor.
71  */
72  ScopedIteration() = delete;
73 
74  /**
75  * Disabled copy constructor.
76  */
77  ScopedIteration(const ScopedIteration&) = delete;
78 
79  /**
80  * Disabled move constructor.
81  */
82  ScopedIteration(const ScopedIteration&&) = delete;
83 
84  protected:
85 
86  /// True, if the iteration is accurate; False, if the iteration was not accurate enough.
87  bool accurate_ = true;
88 
89  /// The owner of this scoped object.
91  };
92 
93  public:
94 
95  /**
96  * Creates a new precision-based validation object with specified threshold.
97  * @param threshold The necessary percent of accurate iterations necessary for a successful verification, with range (0, 1]
98  */
99  explicit inline ValidationPrecision(const double threshold);
100 
101  /**
102  * Creates a new validation object associated with a random generator, by default the verified has succeeded.
103  * @param threshold The necessary percent of accurate iterations necessary for a successful verification, with range (0, 1]
104  * @param randomGenerator The random generator which will be used during verification
105  */
106  inline ValidationPrecision(const double threshold, RandomGenerator& randomGenerator);
107 
108  /**
109  * Destructs this validation object.
110  */
111  inline ~ValidationPrecision();
112 
113  /**
114  * Explicitly adds a new iteration which is either accurate or not.
115  * @param accurate True, if the iteration was precise enough; False, if the iteration was not precise enough
116  * @see ScopedIteration.
117  */
118  inline void addIteration(const bool accurate);
119 
120  /**
121  * Explicitly adds new iterations for which the amount of accurate iterations is known.
122  * @param accurateIterations The number of accurate iterations, with range [0, iterations]
123  * @param iterations The number of new iterations, with range [1, infinity)
124  * @see ScopedIteration.
125  */
126  inline void addIterations(const size_t accurateIterations, const size_t iterations);
127 
128  /**
129  * Explicitly sets the validation to be failed.
130  * Setting this validation to be failed will result in a failed validation even if all iteration were precise enough.
131  * @see succeeded().
132  */
133  inline void setFailed();
134 
135  /**
136  * Explicitly sets the validation to be failed.
137  * Setting this validation to be failed will result in a failed validation even if all iteration were precise enough.
138  * @param file The source file in which the function call happens, e.g., __FILE__, must be valid
139  * @param line The line in the source file in which the function call happens, e.g., __LINE__, must be valid
140  * @see succeeded().
141  */
142  inline void setFailed(const char* file, const int line);
143 
144  /**
145  * Returns the number of iterations in which the precision has been determined.
146  * @return The number of iterations, with range [0, infinity)
147  */
148  inline uint64_t iterations() const;
149 
150  /**
151  * Returns the necessary iterations to allow determining success or failure based on the specified success threshold.
152  * @return The number of necessary iterations, with range [1, infinity)
153  */
154  inline uint64_t necessaryIterations() const;
155 
156  /**
157  * Returns whether the number of iterations is not yet sufficient to determine a success or failure.
158  * @return True, if more iterations are required
159  */
160  inline bool needMoreIterations() const;
161 
162  /**
163  * Returns if this validation has succeeded.
164  * @return True, if so; False, if the validation has failed
165  */
166  [[nodiscard]] inline bool succeeded() const;
167 
168  /**
169  * Returns the accuracy of all iterations.
170  * Beware: Ensure that at least one iteration has been added.
171  * @return The validation's accuracy, in percent, with range [0, 1]
172  */
173  [[nodiscard]] inline double accuracy() const;
174 
175  /**
176  * Returns the defined threshold.
177  * @return The validation object's precision threshold, with range [0, 1]
178  */
179  inline double threshold() const;
180 
181  /**
182  * Returns whether this validation object has been set to failed explicitly.
183  * This function is intended for internal use only, use succeeded() instead.
184  * @return True, if so
185  * @see succeeded().
186  */
187  [[nodiscard]] inline bool hasSetFailed() const;
188 
189  /**
190  * Returns a string containing the random generator's initial seed, if any
191  * @return The string with initial seed test, empty if no random generator is associated with this validation object
192  */
193  inline std::string randomGeneratorOutput() const;
194 
195  protected:
196 
197  /**
198  * Disabled copy constructor.
199  */
201 
202  /**
203  * Sets the succeeded state to false.
204  */
205  inline void setSucceededFalse();
206 
207  protected:
208 
209  /// The necessary percent of accurate iterations necessary for a successful verification, with range (0, 1]
210  double threshold_ = 1.0;
211 
212  /// True, if the validation has succeeded; False, if the validation has failed.
213  bool succeeded_ = true;
214 
215  /// The number of iterations needed to determine success or failure.
216  uint64_t necessaryIterations_ = 0ull;
217 
218  /// The overall number of iterations which have been added.
219  uint64_t iterations_ = 0ull;
220 
221  /// The number of iterations which were precise enough, with range [0, iterations_]
222  uint64_t accurateIterations_ = 0ull;
223 
224  /// Optional random generator object which will be used during validation.
226 
227 #ifdef OCEAN_DEBUG
228  /// True, if the success state of this validation has been checked.
229  mutable bool succeededChecked_ = false;
230 #endif // OCEAN_DEBUG
231 };
232 
233 #ifndef OCEAN_SET_INACCURATE
234  #define OCEAN_SET_INACCURATE(scopedIteration, expected, actual) scopedIteration.setInaccurate(expected, actual, __FILE__, __LINE__);
235 #endif
236 
238  validationPrecision_(ValidationPrecision)
239 {
240  // nothing to do here
241 }
242 
244 {
245  validationPrecision_.addIteration(accurate_);
246 }
247 
249 {
250  accurate_ = false;
251 }
252 
253 template <typename T>
254 inline void ValidationPrecision::ScopedIteration::setInaccurate(const T& expected, const T& actual, const char* file, const int line)
255 {
256  accurate_ = false;
257 
258  ocean_assert(file != nullptr);
259  if (file != nullptr)
260  {
261  Log::error() << "ScopedIteration::setInaccurate() in '" << file << "', in line " << line << ": expected " << expected << ", got " << actual << validationPrecision_.randomGeneratorOutput();
262  }
263 }
264 
266 {
267  ocean_assert(threshold > 0.0 && threshold <= 1.0);
268 
269  if (threshold > 0.0 && threshold <= 1.0)
270  {
272 
273  const double failureRate = 1.0 - threshold_;
274  ocean_assert(failureRate > 0.0);
275 
276  const double idealIterations = 1.0 / failureRate;
277 
278  ocean_assert(idealIterations <= 1000000000u);
279  necessaryIterations_ = std::max(1u, (unsigned int)(std::ceil(idealIterations) * 2.0));
280  }
281  else
282  {
284  }
285 }
286 
289 {
290  randomGenerator_ = &randomGenerator;
291 }
292 
294 {
295 #ifdef OCEAN_DEBUG
296  ocean_assert(succeededChecked_ && "The verifier has not been check for success");
297 #endif
298 }
299 
300 inline void ValidationPrecision::addIteration(const bool accurate)
301 {
302  ++iterations_;
303 
304  if (accurate)
305  {
307  }
308 }
309 
310 inline void ValidationPrecision::addIterations(const size_t accurateIterations, const size_t iterations)
311 {
312  ocean_assert(accurateIterations <= iterations);
313  ocean_assert(iterations >= 1);
314 
315  if (accurateIterations > iterations)
316  {
318  }
319 
320  accurateIterations_ += accurateIterations;
322 }
323 
325 {
327 }
328 
329 inline void ValidationPrecision::setFailed(const char* file, const int line)
330 {
332 
333  ocean_assert(file != nullptr);
334  if (file != nullptr)
335  {
336 #ifdef OCEAN_USE_GTEST
337  std::cerr << "\nValidationPrecision::setFailed() in '" << file << "', in line " << line << randomGeneratorOutput() << "\n" << std::endl;
338 #else
339  Log::error() << "ValidationPrecision::setFailed() in '" << file << "', in line " << line << randomGeneratorOutput();
340 #endif
341  }
342 }
343 
344 inline uint64_t ValidationPrecision::iterations() const
345 {
346  return iterations_;
347 }
348 
350 {
351  ocean_assert(necessaryIterations_ >= 1ull);
352 
353  return necessaryIterations_;
354 }
355 
357 {
358  ocean_assert(necessaryIterations_ >= 1ull);
359 
361 }
362 
364 {
365 #ifdef OCEAN_DEBUG
366  succeededChecked_ = true;
367 #endif
368 
369  ocean_assert(threshold_ > 0.0 && threshold_ <= 1.0);
370 
371  if (threshold_ <= 0.0 || threshold_ > 1.0)
372  {
373  return false;
374  }
375 
376  const double percent = accuracy();
377 
378  if (percent < threshold_)
379  {
380 #ifdef OCEAN_USE_GTEST
381 
382  std::ostream& stream = std::cerr << "\nFAILED with only " << String::toAString(accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(threshold() * 100.0, 1u) << "%" << randomGeneratorOutput() << "\n";
383 
384  if (needMoreIterations())
385  {
386  stream << "Not enough iterations for the specified success threshold (executed " << iterations_ << " of " << necessaryIterations_ << " necessary iterations)\n";
387  }
388 
389  stream << std::endl;
390 #endif
391  return false;
392  }
393 
394  return succeeded_;
395 }
396 
397 [[nodiscard]] inline double ValidationPrecision::accuracy() const
398 {
399  ocean_assert(iterations_ != 0ull);
400 
401  if (iterations_ == 0u)
402  {
403  return -1.0;
404  }
405 
406  ocean_assert(accurateIterations_ <= iterations_);
407 
408  const double percent = double(accurateIterations_) / double(iterations_);
409  ocean_assert(percent >= 0.0 && percent <= 1.0);
410 
411  return percent;
412 }
413 
414 inline double ValidationPrecision::threshold() const
415 {
416  return threshold_;
417 }
418 
419 [[nodiscard]] inline bool ValidationPrecision::hasSetFailed() const
420 {
421  return succeeded_ == false;
422 }
423 
425 {
426  if (randomGenerator_ != nullptr)
427  {
428  return ", with random generator initial seed '" + String::toAString(randomGenerator_->initialSeed()) + "'";
429  }
430 
431  return std::string();
432 }
433 
435 {
436  succeeded_ = false;
437 }
438 
439 inline std::ostream& operator<<(std::ostream& stream, const ValidationPrecision& validation)
440 {
441  if (validation.hasSetFailed())
442  {
443  stream << "FAILED!" << validation.randomGeneratorOutput();
444  }
445  else
446  {
447  if (validation.accuracy() < validation.threshold())
448  {
449  stream << "FAILED with only " << String::toAString(validation.accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(validation.threshold() * 100.0, 1u) << "%" << validation.randomGeneratorOutput();
450  }
451  else
452  {
453  stream << String::toAString(validation.accuracy() * 100.0, 1u) << "% succeeded.";
454  }
455  }
456 
457  return stream;
458 }
459 
460 template <bool tActive>
461 MessageObject<tActive>& operator<<(MessageObject<tActive>& messageObject, const ValidationPrecision& validation)
462 {
463  if (validation.hasSetFailed())
464  {
465  messageObject << "FAILED!" << validation.randomGeneratorOutput();
466  }
467  else
468  {
469  if (validation.accuracy() < validation.threshold())
470  {
471  messageObject << "FAILED with only " << String::toAString(validation.accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(validation.threshold() * 100.0, 1u) << "%" << validation.randomGeneratorOutput();
472  }
473  else
474  {
475  messageObject << String::toAString(validation.accuracy() * 100.0, 1u) << "% succeeded.";
476  }
477  }
478 
479  return messageObject;
480 }
481 
482 template <bool tActive>
483 MessageObject<tActive>& operator<<(MessageObject<tActive>&& messageObject, const ValidationPrecision& validation)
484 {
485  if (validation.hasSetFailed())
486  {
487  messageObject << "FAILED!" << validation.randomGeneratorOutput();
488  }
489  else
490  {
491  if (validation.accuracy() < validation.threshold())
492  {
493  messageObject << "FAILED with only " << String::toAString(validation.accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(validation.threshold() * 100.0, 1u) << "%" << validation.randomGeneratorOutput();
494  }
495  else
496  {
497  messageObject << String::toAString(validation.accuracy() * 100.0, 1u) << "% succeeded.";
498  }
499  }
500 
501  return messageObject;
502 }
503 
504 }
505 
506 }
507 
508 #endif // META_OCEAN_TEST_VALIDATION_PRECISION_H
static MessageObject error()
Returns the message for error messages.
Definition: Messenger.h:1074
Messenger object, one object for each message.
Definition: Messenger.h:427
This class implements a generator for random numbers.
Definition: RandomGenerator.h:42
unsigned int initialSeed() const
Returns the initial seed value which was used to initialize this random generator.
Definition: RandomGenerator.h:178
static std::string toAString(const char value)
Converts a value to a string with 8bit character.
Creates a new scoped iteration.
Definition: ValidationPrecision.h:37
ScopedIteration(const ScopedIteration &&)=delete
Disabled move constructor.
void setInaccurate()
Sets this iteration to be not precise enough.
Definition: ValidationPrecision.h:248
ValidationPrecision & validationPrecision_
The owner of this scoped object.
Definition: ValidationPrecision.h:90
ScopedIteration(const ScopedIteration &)=delete
Disabled copy constructor.
bool accurate_
True, if the iteration is accurate; False, if the iteration was not accurate enough.
Definition: ValidationPrecision.h:87
~ScopedIteration()
Destructs this scoped object and forwards the information to the owning validation.
Definition: ValidationPrecision.h:243
ScopedIteration()=delete
Disabled default constructor.
This class implements a helper class to validate the accuracy of tests.
Definition: ValidationPrecision.h:28
double threshold() const
Returns the defined threshold.
Definition: ValidationPrecision.h:414
void addIterations(const size_t accurateIterations, const size_t iterations)
Explicitly adds new iterations for which the amount of accurate iterations is known.
Definition: ValidationPrecision.h:310
uint64_t iterations_
The overall number of iterations which have been added.
Definition: ValidationPrecision.h:219
RandomGenerator * randomGenerator_
Optional random generator object which will be used during validation.
Definition: ValidationPrecision.h:225
uint64_t accurateIterations_
The number of iterations which were precise enough, with range [0, iterations_].
Definition: ValidationPrecision.h:222
ValidationPrecision(const double threshold)
Creates a new precision-based validation object with specified threshold.
Definition: ValidationPrecision.h:265
std::string randomGeneratorOutput() const
Returns a string containing the random generator's initial seed, if any.
Definition: ValidationPrecision.h:424
bool needMoreIterations() const
Returns whether the number of iterations is not yet sufficient to determine a success or failure.
Definition: ValidationPrecision.h:356
bool succeeded_
True, if the validation has succeeded; False, if the validation has failed.
Definition: ValidationPrecision.h:213
double accuracy() const
Returns the accuracy of all iterations.
Definition: ValidationPrecision.h:397
void setSucceededFalse()
Sets the succeeded state to false.
Definition: ValidationPrecision.h:434
void addIteration(const bool accurate)
Explicitly adds a new iteration which is either accurate or not.
Definition: ValidationPrecision.h:300
~ValidationPrecision()
Destructs this validation object.
Definition: ValidationPrecision.h:293
ValidationPrecision(const ValidationPrecision &)=delete
Disabled copy constructor.
uint64_t necessaryIterations() const
Returns the necessary iterations to allow determining success or failure based on the specified succe...
Definition: ValidationPrecision.h:349
bool succeeded() const
Returns if this validation has succeeded.
Definition: ValidationPrecision.h:363
double threshold_
The necessary percent of accurate iterations necessary for a successful verification,...
Definition: ValidationPrecision.h:210
uint64_t iterations() const
Returns the number of iterations in which the precision has been determined.
Definition: ValidationPrecision.h:344
bool succeededChecked_
True, if the success state of this validation has been checked.
Definition: ValidationPrecision.h:229
uint64_t necessaryIterations_
The number of iterations needed to determine success or failure.
Definition: ValidationPrecision.h:216
bool hasSetFailed() const
Returns whether this validation object has been set to failed explicitly.
Definition: ValidationPrecision.h:419
void setFailed()
Explicitly sets the validation to be failed.
Definition: ValidationPrecision.h:324
std::ostream & operator<<(std::ostream &stream, const Validation &validation)
Definition: Validation.h:824
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15