Skip to content

Commit

Permalink
Better Output for Expect<That::FuncReturns> and Expect<That::FuncThrows>
Browse files Browse the repository at this point in the history
Summary: Created a new class `FuncOutcome` for Expect<That::FuncReturns> and Expect<That::FuncThrows>

Test Plan: N/A

Reviewers: jcmcdonald, tfu, memateo

Reviewed By: jcmcdonald

Subscribers: memateo, tfu, jcmcdonald

Tags: #goldilocks_project, #programming_dept

Maniphest Tasks: T1386

Revert Plan: N/A

Differential Revision: https://phab.mousepawmedia.com/D444
  • Loading branch information
Gerar Almonte committed Sep 1, 2021
1 parent 2860f84 commit 64a8273
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 42 deletions.
22 changes: 21 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,27 @@
"unordered_set": "cpp",
"ranges": "cpp",
"valarray": "cpp",
"variant": "cpp"
"variant": "cpp",
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"iomanip": "cpp",
"ostream": "cpp"
},
"cSpell.words": [
"cmake",
Expand Down
159 changes: 133 additions & 26 deletions goldilocks-source/include/goldilocks/expect/outcomes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
#define GOLDILOCKS_OUTCOMES_HPP

#include <stdexcept> // std::domain_error
#include <iostream> // std::string
#include <string> // std::to_string
#include <tuple> // std::tuple

#include "goldilocks/expect/should.hpp"
#include "goldilocks/types.hpp"
Expand Down Expand Up @@ -85,6 +88,41 @@ class AbstractOutcome
}
}

/** Assign appropriate outcome representation string.
* \param should: how success should be interpreted.
* \return a string stating if the test past or failed.
*/
virtual testdoc_t compose_outcome(const Should& should) const final {
switch (should) {
case Should::Pass_Silent:
if (this->pass) {
return "";
}
[[fallthrough]];
case Should::Pass:
if (this->pass) {
return " [PASS]";
} else {
return " [FAIL]";
}
break;
case Should::Fail_Silent:
if (!this->pass) {
return "";
}
[[fallthrough]];
case Should::Fail:
if (!this->pass) {
return " [PASS: Failed]";
} else {
return " [FAIL: Passed]";
}
break;
default:
throw std::domain_error("Unknown Should:: value in Expect.");
}
}

/// Create the string representation of the outcome. (Abstract)
virtual testdoc_t compose(const Should&,
const testdoc_t comparison) const = 0;
Expand Down Expand Up @@ -130,32 +168,10 @@ class Outcome : public AbstractOutcome
// TODO: Potentially drop in favor of more robust formatting elsewhere

// Create the appropriate outcome representation string.
testdoc_t outcome = "";
switch (should) {
case Should::Pass_Silent:
if (this->pass) {
return "";
}
[[fallthrough]];
case Should::Pass:
if (this->pass) {
outcome = " [PASS]";
} else {
outcome = " [FAIL]";
}
break;
case Should::Fail_Silent:
if (!this->pass) {
return "";
}
[[fallthrough]];
case Should::Fail:
if (!this->pass) {
outcome = " [PASS: Failed]";
} else {
outcome = " [FAIL: Passed]";
}
break;
testdoc_t outcome = compose_outcome(should);

if (outcome == "") {
return "";
}

// Compose a string from the value, comparison, and outcome strings.
Expand All @@ -179,4 +195,95 @@ inline OutcomePtr build_outcome(const bool& passed,
return std::make_shared<Outcome<X, R>>(passed, returned, expected);
}

typedef std::shared_ptr<AbstractOutcome> FuncOutcomePtr;

/// Outcomes of evaluation for Expect<That::FuncReturns> and Expect<That::FuncThrows>.
template<typename X, typename R, typename... Args>
class FuncOutcome : public AbstractOutcome
{
protected:
/// The actual value.
R returned;
/// The expected value.
X expected;
// The name of the function as a string.
const char* name_hint;
// The arguments to passed to the function.
std::tuple <Args...> args;
// String of args.
std::string strOfArgs;

// Method to iterate through a tuple and convert the arguments to string.
template <size_t I = 0>
void convertTupleValToStr(std::tuple <Args...> tupArgs)
{
// Appends last element to strOfArgs and stops recursion when I reaches the lenght of the tuple.
if constexpr(I == sizeof...(Args) - 1) {
this->strOfArgs += std::to_string(std::get<I>(tupArgs));
} else {
// Get value from tuple and append it to strOfArgs.
this->strOfArgs += std::to_string(std::get<I>(tupArgs)) + ",";
// Goes to the next element to the tuple by calling itself.
convertTupleValToStr<I + 1>(args);
}
}

public:
/** Create a new outcome.
* \param passed: the raw outcome of the comparison as a boolean
* \param expected: the expected value (or right-hand operand)
* \param returned: the actual value (or left-hand operand)
* \param name_hint: the name of the of the function as a string
* \param args: The arguments to pass to the function
* \return an outcome object
*/
FuncOutcome<X, R, Args...>(const bool& passed, const R& returned, const X& expected,
const char* name_hint, Args... args) : AbstractOutcome(passed), returned(returned),
expected(expected), name_hint(name_hint), args(std::make_tuple(args...))
{
//Convert args to strOfArgs.
convertTupleValToStr(this->args);
}

/** Create the string representation of the outcome.
* \param should: how success should be interpreted.
* \param comparison: the string representing the comparison operation
*/
testdoc_t compose(const Should& should,
const testdoc_t comparison) const override
{
// TODO: Potentially drop in favor of more robust formatting elsewhere

// Create the appropriate outcome representation string.
testdoc_t outcome = compose_outcome(should);

if (outcome == "") {
return "";
}

// Compose a string from the value, comparison, and outcome strings.
return stringify(name_hint) + "(" + this->strOfArgs + ")" + comparison + stringify(this->returned) + " == " + stringify(this->expected) + outcome;
}

~FuncOutcome() = default;
};

/** Build an outcome.
* \param passed: the raw outcome of the comparison as a boolean
* \param expected: the expected value
* \param returned: the actual value
* \param name_hint: the name of the of the function as a string
* \param args: The arguments to pass to the function
* \return a shared pointer to the outcome.
*/
template<typename X, typename R, typename... Args>
inline FuncOutcomePtr build_funcoutcome(const bool& passed,
const R& returned,
const X& expected,
const char* name_hint,
const Args... args)
{
return std::make_shared<FuncOutcome<X, R, Args...>>(passed, returned, expected, name_hint, args...);
}

#endif
22 changes: 11 additions & 11 deletions goldilocks-source/include/goldilocks/expect/that.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,15 +554,15 @@ struct FuncReturns {
* \return the outcome
*/
template<typename T, typename U, typename... Args>
static OutcomePtr eval(const T& target,
static FuncOutcomePtr eval(const T& target,
const char* name_hint,
const U func,
const Args... args)
{
(void)name_hint; // TODO: Process name hint
// (void)name_hint; // TODO: Process name hint
auto ret = func(args...);
// TODO: Store function call data in outcome!
return build_outcome(ret == target, ret, target);
return build_funcoutcome(ret == target, target, ret, name_hint, args...);
}
};

Expand All @@ -580,7 +580,7 @@ struct FuncThrows {
* \return the outcome
*/
template<typename T, typename U, typename... Args>
static OutcomePtr eval(const T& target,
static FuncOutcomePtr eval(const T& target,
const char* name_hint,
const U func,
const Args... args)
Expand All @@ -590,19 +590,19 @@ struct FuncThrows {
func(args...);
} catch (const T& e) {
// TODO: Store function call data in outcome!
return build_outcome(true, target, e);
return build_funcoutcome(true, target, e, name_hint, args...);
} catch (const std::exception& e) {
return build_outcome(false, target, e);
return build_funcoutcome(false, target, e, name_hint, args...);
} catch (...) {
return build_outcome(false, target, Nothing());
return build_funcoutcome(false, target, Nothing(), name_hint, args...);
}

return build_outcome(false, target, Nothing());
return build_funcoutcome(false, target, Nothing(), name_hint, args...);
}

// "Throw Nothing" version of eval()
template<typename U, typename... Args>
static OutcomePtr eval(const Nothing& target,
static FuncOutcomePtr eval(const Nothing& target,
const char* name_hint,
const U func,
const Args... args)
Expand All @@ -611,10 +611,10 @@ struct FuncThrows {
try {
func(args...);
} catch (...) {
return build_outcome(false, Nothing(), target);
return build_funcoutcome(false, Nothing(), target, name_hint, args...);
}

return build_outcome(true, target, Nothing());
return build_funcoutcome(true, target, Nothing(), name_hint, args...);
}
};

Expand Down
10 changes: 6 additions & 4 deletions goldilocks-tester/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ void black_hole(int) { return; }
* All test code that is needed long term should be
* moved to a dedicated Goldilocks Test and Suite.
*/

int add (int a, int b) {
return a + b;
}

void test_code()
{
std::cout << Expect<That::IsInRange>(2, 1, 5) << std::endl;
std::cout << Expect<That::IsInRange>(0.5f, 1, 2.5f) << std::endl;
std::cout << Expect<That::IsNotInRange>(1, 2, 3) << std::endl;
std::cout << Expect<That::IsNotInRange>(3.5f, 2, 6) << std::endl;
std::cout << Expect<That::FuncReturns>(2, "add", add, 2, 3) << std::endl;
}

/////// WARNING: DO NOT ALTER BELOW THIS POINT! ///////
Expand Down

0 comments on commit 64a8273

Please sign in to comment.