make TER changes

This commit is contained in:
Mayukha Vadari
2026-07-22 17:07:18 -04:00
parent 3122de86bf
commit 0621841912
3 changed files with 160 additions and 15 deletions

View File

@@ -643,44 +643,149 @@ class CanCvtToTER<NotTEC> : public std::true_type
{
};
// TER allows all of the subsets.
using TER = TERSubset<CanCvtToTER>;
// TERRaw allows all of the subsets (the plain numeric code, no reason string).
using TERRaw = TERSubset<CanCvtToTER>;
//------------------------------------------------------------------------------
// Forward declaration required by TER constructors below (TER.cpp provides the
// definition). The full public declaration is repeated after the struct.
std::string
transHuman(TERRaw code);
//------------------------------------------------------------------------------
// TER: a transaction result code paired with a human-readable reason string.
//
// When no reason is supplied the standard description from transHuman() is used
// automatically, so existing "return tesSUCCESS;" and "return tecNO_DST;"
// call sites continue to compile and gain a default reason for free.
//
// To attach a more specific reason at a particular return site write:
// return {tecNO_DST, "destination account has been deleted"};
//
struct TER
{
TERRaw code;
std::string reason;
// Default-construct to tesSUCCESS with its standard description.
TER() : code(tesSUCCESS), reason(transHuman(TERRaw{tesSUCCESS}))
{
}
TER(TER const&) = default;
TER(TER&&) = default;
TER&
operator=(TER const&) = default;
TER&
operator=(TER&&) = default;
// --- construction from TERRaw ---
// Without explicit reason: populate from transHuman.
TER(TERRaw c) : code(c), reason(transHuman(c)) // NOLINT(google-explicit-constructor)
{
}
// With explicit reason.
TER(TERRaw c, std::string r) : code(c), reason(std::move(r))
{
}
// --- construction from any TE*codes enum or NotTEC ---
// Without explicit reason: populate from transHuman.
template <typename T>
TER(T c) // NOLINT(google-explicit-constructor)
requires(CanCvtToTER<std::remove_cv_t<std::remove_reference_t<T>>>::value)
: code(c), reason(transHuman(TERRaw{c}))
{
}
// With explicit reason.
template <typename T>
TER(T c, std::string r)
requires(CanCvtToTER<std::remove_cv_t<std::remove_reference_t<T>>>::value)
: code(c), reason(std::move(r))
{
}
// Build from a raw integer (used by transCode).
static TER
fromInt(int from)
{
return TER(TERRaw::fromInt(from));
}
// True when the code is anything other than tesSUCCESS.
explicit
operator bool() const
{
return static_cast<bool>(code);
}
// Allow assignment to json::Objects without casting.
operator json::Value() const // NOLINT(google-explicit-constructor)
{
return json::Value{TERtoInt(code)};
}
// Allow implicit conversion to TERRaw for backward compatibility with
// functions that now take TERRaw (like transResultInfo, transToken, etc).
operator TERRaw() const // NOLINT(google-explicit-constructor)
{
return code;
}
friend std::ostream&
operator<<(std::ostream& os, TER const& rhs)
{
return os << TERtoInt(rhs.code);
}
};
// Expose the underlying integer so the existing template comparison operators
// (operator==, !=, <, <=, >, >=) continue to work with TER values.
inline TERUnderlyingType
TERtoInt(TER const& v)
{
return TERtoInt(v.code);
}
//------------------------------------------------------------------------------
inline bool
isTelLocal(TER x) noexcept
isTelLocal(TER const& x) noexcept
{
return (x >= telLOCAL_ERROR && x < temMALFORMED);
}
inline bool
isTemMalformed(TER x) noexcept
isTemMalformed(TER const& x) noexcept
{
return (x >= temMALFORMED && x < tefFAILURE);
}
inline bool
isTefFailure(TER x) noexcept
isTefFailure(TER const& x) noexcept
{
return (x >= tefFAILURE && x < terRETRY);
}
inline bool
isTerRetry(TER x) noexcept
isTerRetry(TER const& x) noexcept
{
return (x >= terRETRY && x < tesSUCCESS);
}
inline bool
isTesSuccess(TER x) noexcept
isTesSuccess(TER const& x) noexcept
{
// Makes use of TERSubset::operator bool()
// Makes use of TER::operator bool()
return !x;
}
inline bool
isTecClaim(TER x) noexcept
isTecClaim(TER const& x) noexcept
{
return (x >= tecCLAIM);
}
@@ -689,13 +794,13 @@ std::unordered_map<TERUnderlyingType, std::pair<char const* const, char const* c
transResults();
bool
transResultInfo(TER code, std::string& token, std::string& text);
transResultInfo(TERRaw code, std::string& token, std::string& text);
std::string
transToken(TER code);
transToken(TERRaw code);
std::string
transHuman(TER code);
transHuman(TERRaw code);
std::optional<TER>
transCode(std::string const& token);

View File

@@ -233,7 +233,7 @@ transResults()
}
bool
transResultInfo(TER code, std::string& token, std::string& text)
transResultInfo(TERRaw code, std::string& token, std::string& text)
{
auto& results = transResults();
@@ -248,7 +248,7 @@ transResultInfo(TER code, std::string& token, std::string& text)
}
std::string
transToken(TER code)
transToken(TERRaw code)
{
std::string token;
std::string text;
@@ -257,7 +257,7 @@ transToken(TER code)
}
std::string
transHuman(TER code)
transHuman(TERRaw code)
{
std::string token;
std::string text;

View File

@@ -235,12 +235,52 @@ struct TER_test : public beast::unit_test::Suite
testIterate<kHiIndex, kHiIndex, CheckComparable>(kTers, *this);
}
void
testReason()
{
testcase("Reason");
// 1. Implicit conversion from enum uses transHuman
{
TER t = tecNO_DST;
BEAST_EXPECT(t.code == tecNO_DST);
BEAST_EXPECT(t.reason == transHuman(TERRaw{tecNO_DST}));
}
// 2. Explicit reason
{
TER t = {tecNO_DST, "custom reason"};
BEAST_EXPECT(t.code == tecNO_DST);
BEAST_EXPECT(t.reason == "custom reason");
}
// 3. Default constructor uses tesSUCCESS description
{
TER t;
BEAST_EXPECT(t.code == tesSUCCESS);
BEAST_EXPECT(t.reason == transHuman(TERRaw{tesSUCCESS}));
}
// 4. Copy and move
{
TER t1 = {tecPATH_DRY, "reason 1"};
TER t2 = t1;
BEAST_EXPECT(t2.code == tecPATH_DRY);
BEAST_EXPECT(t2.reason == "reason 1");
TER t3 = std::move(t1);
BEAST_EXPECT(t3.code == tecPATH_DRY);
BEAST_EXPECT(t3.reason == "reason 1");
}
}
void
run() override
{
testTransResultInfo();
testConversion();
testComparison();
testReason();
}
};