From 7e73fa323cfeb19911d646d79342442f1c358559 Mon Sep 17 00:00:00 2001
From: Imdad Sardharwalla <imdad.sardharwalla@autodesk.com>
Date: Tue, 19 Oct 2021 11:29:35 +0100
Subject: [PATCH] REFORM-1168 Create additional test macros and rename existing
 ones (#66)

---
 Test/TestArgs.cc              |   3 +-
 Test/TestChecksumCondition.cc |   2 +-
 Test/TestChecksumCondition.hh |   8 +--
 Test/TestOutcome.cc           |  68 ++++++++++++--------
 Test/TestOutcome.hh           | 116 ++++++++++++++++++++--------------
 5 files changed, 120 insertions(+), 77 deletions(-)

diff --git a/Test/TestArgs.cc b/Test/TestArgs.cc
index 0ccdcbe..9ee435b 100755
--- a/Test/TestArgs.cc
+++ b/Test/TestArgs.cc
@@ -63,7 +63,8 @@ int collect(const int _argc, const char* const* _argv)
   int framework_argc = _argc;
 
   // The first argument is the process name
-  process_name_ = _argv[0];
+  if (_argc > 0)
+    process_name_ = _argv[0];
 
   for (int i = 1; i < _argc; i++)
   {
diff --git a/Test/TestChecksumCondition.cc b/Test/TestChecksumCondition.cc
index 0fa8905..b22c749 100644
--- a/Test/TestChecksumCondition.cc
+++ b/Test/TestChecksumCondition.cc
@@ -72,7 +72,7 @@ Condition condition;
 
 }//Checksum
 
-void check_condition(
+void record_condition(
     const char* const _cndt, const Base::CodeLink& _lnk, const bool _rslt)
 {
   TEST(condition, record(_cndt, _lnk, _rslt));
diff --git a/Test/TestChecksumCondition.hh b/Test/TestChecksumCondition.hh
index 2ef2177..64e911e 100644
--- a/Test/TestChecksumCondition.hh
+++ b/Test/TestChecksumCondition.hh
@@ -43,18 +43,18 @@ extern Condition condition;
 
 } // namespace Checksum
 
-void check_condition(
+void record_condition(
     const char* const _cndt, const Base::CodeLink& _lnk, const bool _rslt);
 
 } // namespace Test
 
 // Write a Condition checksum to record the outcome of CONDITION.
-#define CHECK_CONDITION(CONDITION) \
-  ::Test::check_condition(#CONDITION, BASE_CODELINK, CONDITION)
+#define TEST_CONDITION_RECORD(CONDITION) \
+  ::Test::record_condition(#CONDITION, BASE_CODELINK, CONDITION)
 
 #else // defined(TEST_ON)
 
-#define CHECK_CONDITION(CONDITION)
+#define TEST_CONDITION_RECORD(CONDITION)
 
 #endif // defined(TEST_ON)
 
diff --git a/Test/TestOutcome.cc b/Test/TestOutcome.cc
index 41f2ee9..5f38b50 100755
--- a/Test/TestOutcome.cc
+++ b/Test/TestOutcome.cc
@@ -26,61 +26,79 @@ void record_and_handle_unexpected(
   TEST(outcome, record(_call, _oc.ok(), _oc.error_description().c_str()));
 
   if (_unexpected)
-    _oc.handle_unexpected();
+    _oc.unexpected_handler();
 }
 } // namespace
 
-Outcome::Outcome(bool _ok, const std::string& _error_code,
-    const std::string& _error_message,
-    const UnexpectedHandler& _unexpected_handler)
-    : ok_(_ok), error_code_(_error_code), error_message_(_error_message),
-      unexpected_handler_(_unexpected_handler)
+Outcome::Outcome() : ok_(true), error_code_("0"), error_message_("Success") {}
+
+Outcome::Outcome(
+    bool _ok, const std::string& _error_code, const std::string& _error_message)
+    : ok_(_ok), error_code_(_error_code), error_message_(_error_message)
 {
 }
 
-Outcome::Outcome(bool _ok, const int _error_code,
-    const std::string& _error_message,
-    const UnexpectedHandler& _unexpected_handler)
+Outcome::Outcome(
+    bool _ok, const int _error_code, const std::string& _error_message)
     : ok_(_ok), error_code_(std::to_string(_error_code)),
-      error_message_(_error_message), unexpected_handler_(_unexpected_handler)
+      error_message_(_error_message)
+{
+}
+
+const std::string Outcome::error_description() const
 {
+  return ok() ? error_message() : "[" + error_code() + "] " + error_message();
 }
 
-void ignore_unstable_outcome(const char* const _call)
+Outcome::UnexpectedHandler Outcome::unexpected_handler = []
+{
+  TEST_THROW_ERROR(TEST_OUTCOME_UNEXPECTED);
+};
+
+const Outcome& record_outcome(const char* const _call, const Outcome& _oc)
 {
-  std::cout
-      << "-----------------------\n"
-         "Info: Unstable outcome from the following call has been ignored:"
-         "\n\n  " << _call << "\n\n"
-         "Replace IGNORE_UNSTABLE_OUTCOME() with CHECK_OUTCOME() once "
-         "the functionality is stable.\n"
-         "-----------------------"
-      << std::endl;
+  // Never call unexpected-outcome handler
+  record_and_handle_unexpected(_call, _oc, false);
+  return _oc;
 }
 
-void check_outcome(const char* const _call, const Outcome& _oc)
+void expect_success(const char* const _call, const Outcome& _oc)
 {
   // Call unexpected-outcome handler if the call *failed*
   record_and_handle_unexpected(_call, _oc, !_oc.ok());
 }
 
-void expect_failed_outcome(
+void expect_outcome(
     const char* const _call, const Outcome& _oc, const char* const _error_code)
 {
   // Call unexpected-outcome handler if the error code is not correct
   record_and_handle_unexpected(_call, _oc, _oc.error_code() != _error_code);
 }
 
+void expect_outcome(
+    const char* const _call, const Outcome& _oc, const int _error_code)
+{
+  expect_outcome(_call, _oc, std::to_string(_error_code).c_str());
+}
+
 void expect_failure(const char* const _call, const Outcome& _oc)
 {
+  // If _oc represents a failure, replace it with a generic failure outcome
+  auto oc = _oc.ok() ? _oc : Outcome(_oc.ok(), "FAILURE", "Failure");
+
   // Call unexpected-outcome handler if the call *succeeds*
-  record_and_handle_unexpected(_call, _oc, _oc.ok());
+  record_and_handle_unexpected(_call, oc, oc.ok());
 }
 
-const Outcome::UnexpectedHandler Outcome::default_unexpected_handler = []
+void ignore_outcome(const char* const _call, const char* const _reason)
 {
-  TEST_THROW_ERROR(TEST_OUTCOME_UNEXPECTED);
-};
+  // Write an "Ignored Outcome" checksum to the report
+  const auto message = std::string("[IGNORED] ") + _reason;
+  record_outcome(_call, Outcome(true, "", message.c_str()));
+}
+
+// Pass-through function for Test::Outcome
+TEST_OUTCOME_ADD_TYPE(Test::Outcome) { return _oc; }
 
 } // namespace Test
 
diff --git a/Test/TestOutcome.hh b/Test/TestOutcome.hh
index a01dbed..bc7628f 100755
--- a/Test/TestOutcome.hh
+++ b/Test/TestOutcome.hh
@@ -10,32 +10,55 @@
 #include <functional>
 #include <string>
 
-// If CALL is unstable on different platforms/architectures (it fails on some
-// platforms/architectures but not others), use IGNORE_UNSTABLE_OUTCOME(CALL)
-// instead of CHECK_OUTCOME(CALL). This will prevent an unstable checksum being
-// written for CALL and will write to stdout to note that this is happening.
-#define IGNORE_UNSTABLE_OUTCOME(CALL) \
-  (CALL); \
-  ::Test::ignore_unstable_outcome(#CALL)
+// Write an Outcome checksum to record the outcome of CALL. Returns the outcome.
+#define TEST_OUTCOME_RECORD(CALL) \
+  ::Test::record_outcome(#CALL, ::Test::Outcome::make(CALL))
+
+// If CALL *fails*, exit the current function and return the outcome.
+#define TEST_OUTCOME_RETURN(CALL) \
+  { \
+    const auto oc = ::Test::Outcome::make(CALL); \
+    if (!oc.ok()) \
+      return oc; \
+  }
+
+// Write an Outcome checksum to record the outcome of CALL. If CALL *fails*,
+// exit the current function and return the outcome.
+#define TEST_OUTCOME_RECORD_AND_RETURN(CALL) \
+  { \
+    const auto oc = TEST_OUTCOME_RECORD(CALL); \
+    if (!oc.ok()) \
+      return oc; \
+  }
 
 // Write an Outcome checksum to record the outcome of CALL. An
 // unexpected-outcome handler is called if CALL *fails*.
-#define CHECK_OUTCOME(CALL) \
-  ::Test::check_outcome(#CALL, ::Test::Outcome::make(CALL))
+#define TEST_OUTCOME_SUCCESS(CALL) \
+  ::Test::expect_success(#CALL, ::Test::Outcome::make(CALL))
 
 // Write an Outcome checksum to record the outcome of CALL. An
 // unexpected-outcome handler is called if the error code associated with the
-// outcome is not equal to ERROR_CODE. This is intended to be used for failures
-// that occur by design.
-#define EXPECT_FAILED_OUTCOME(ERROR_CODE, CALL) \
-  ::Test::expect_failed_outcome(#CALL, ::Test::Outcome::make(CALL), #ERROR_CODE)
+// outcome is not equal to ERROR_CODE.
+#define TEST_OUTCOME_EXPECT(CALL, ERROR_CODE) \
+  ::Test::expect_outcome(#CALL, ::Test::Outcome::make(CALL), ERROR_CODE)
 
-// Write an Outcome checksum to record the outcome of CALL. An
-// unexpected-outcome handler is called if CALL *succeeds*. This is intended to
-// be used for failures that are caused by a known (but unresolved) bug.
-#define EXPECT_FAILURE(CALL) \
+// Write a success/failure Outcome checksum to record the outcome of CALL. An
+// unexpected-outcome handler is called if CALL *succeeds*.
+#define TEST_OUTCOME_FAILURE(CALL) \
   ::Test::expect_failure(#CALL, ::Test::Outcome::make(CALL))
 
+// Write an Outcome checksum to record that the outcome of CALL was ignored and
+// the REASON why.
+#define TEST_OUTCOME_IGNORE(CALL, REASON) \
+  (CALL); \
+  ::Test::ignore_outcome(#CALL, REASON)
+
+// Write an Outcome checksum to record that the outcome of CALL was ignored and
+// that it is unstable (i.e. gives different outcomes on different
+// platforms/architectures).
+#define TEST_OUTCOME_IGNORE_UNSTABLE(CALL) \
+  TEST_OUTCOME_IGNORE(CALL, "Unstable outcome")
+
 /* Use the following macro to add a new outcome type. It defines a
  * specialisation for Test::Outcome::make<TYPE>(const TYPE& _oc), and must
  * return a Test::Outcome object.
@@ -57,7 +80,7 @@
  * expected.
  */
 #define TEST_OUTCOME_ADD_TYPE(TYPE) \
-  template <> ::Test::Outcome Test::Outcome::make<TYPE>(const TYPE& _oc)
+  template <>::Test::Outcome Test::Outcome::make<TYPE>(const TYPE& _oc)
 
 namespace Test
 {
@@ -65,36 +88,37 @@ namespace Test
 /* A generic outcome class that is intended to be a wrapper for all other
  * outcome classes. It has the following member functions:
  *
- *  - make<T>():           Creates an Outcome object from an object of type T. A
- *                         template specialisation should be added for each T
- *                         that is required by the consuming project (see
- *                         TEST_OUTCOME_ADD_TYPE() macro).
+ *  - constructor:          Calling the constructor with no arguments creates a
+ *                          successful outcome.
  *
- *  - ok():                Returns whether the outcome was a success;
+ *  - make<T>():            Creates an Outcome object from an object of type T.
+ *                          A template specialisation should be added for each T
+ *                          that is required by the consuming project (see
+ *                          TEST_OUTCOME_ADD_TYPE() macro).
  *
- *  - error_code():        Returns the associated error code as a std::string&;
+ *  - ok():                 Returns whether the outcome was a success.
  *
- *  - error_message():     Returns the associated error message;
+ *  - error_code():         Returns the associated error code as a std::string&.
  *
- *  - error_description(): Returns a concatenation of the error code and error
- *                         message;
+ *  - error_message():      Returns the associated error message.
  *
- *  - handle_unexpected(): A function that can be called if the outcome is not
- *                         what was expected.
+ *  - error_description():  Returns a concatenation of the error code and error
+ *                          message.
+ *
+ * It also contains the static variable unexpected_handler, a std::function that
+ * can be called if the outcome is not what was expected.
  */
 class Outcome
 {
 public:
   typedef std::function<void()> UnexpectedHandler;
 
+  Outcome(); // Construct successful outcome
+
   Outcome(bool _ok, const std::string& _error_code,
-      const std::string& _error_message,
-      const UnexpectedHandler& _unexpected_handler =
-          default_unexpected_handler);
+      const std::string& _error_message);
 
-  Outcome(bool _ok, const int _error_code, const std::string& _error_message,
-      const UnexpectedHandler& _unexpected_handler =
-          default_unexpected_handler);
+  Outcome(bool _ok, const int _error_code, const std::string& _error_message);
 
   template <class T> static Outcome make(const T& _oc);
 
@@ -104,31 +128,31 @@ public:
 
   const std::string& error_message() const { return error_message_; }
 
-  const std::string error_description() const
-  {
-    return ok() ? error_message() : "[" + error_code() + "] " + error_message();
-  }
-
-  void handle_unexpected() const { unexpected_handler_(); }
+  const std::string error_description() const;
 
-  static const UnexpectedHandler default_unexpected_handler;
+  static UnexpectedHandler unexpected_handler;
 
 private:
   bool ok_;
   std::string error_code_;
   std::string error_message_;
-  UnexpectedHandler unexpected_handler_;
+
 };
 
-void ignore_unstable_outcome(const char* const _call);
+const Outcome& record_outcome(const char* const _call, const Outcome& _oc);
 
-void check_outcome(const char* const _call, const Outcome& _oc);
+void expect_success(const char* const _call, const Outcome& _oc);
 
-void expect_failed_outcome(
+void expect_outcome(
     const char* const _call, const Outcome& _oc, const char* const _error_code);
 
+void expect_outcome(
+    const char* const _call, const Outcome& _oc, const int _error_code);
+
 void expect_failure(const char* const _call, const Outcome& _oc);
 
+void ignore_outcome(const char* const _call, const char* const _reason);
+
 } // namespace Test
 
 #endif // TEST_ON
-- 
GitLab