mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-24 23:50:22 +00:00
Fix
This commit is contained in:
@@ -52,13 +52,13 @@ public:
|
||||
% if field.get('mpt_support'):
|
||||
* MPT Support: ${field['mpt_support']}
|
||||
% endif
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'SoeRequired' or field['requirement'] == 'SoeDefault':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
% endif
|
||||
*/
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'SoeRequired' or field['requirement'] == 'SoeDefault':
|
||||
[[nodiscard]]
|
||||
${field['typeData']['return_type']}
|
||||
get${field['name'][2:]}() const
|
||||
@@ -94,13 +94,13 @@ public:
|
||||
* MPT Support: ${field['mpt_support']}
|
||||
% endif
|
||||
* @note This is an untyped field (${field.get('cppType', 'unknown')}).
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'SoeRequired' or field['requirement'] == 'SoeDefault':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
% endif
|
||||
*/
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'SoeRequired' or field['requirement'] == 'SoeDefault':
|
||||
[[nodiscard]]
|
||||
${field['typeData']['return_type']}
|
||||
get${field['name'][2:]}() const
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
// Auto-generated unit tests for ledger entry ${name}
|
||||
<%! from itertools import chain %>\
|
||||
<%
|
||||
default_fields = [f for f in fields if f["requirement"] == "SoeDefault"]
|
||||
required_fields = [f for f in fields if f["requirement"] == "SoeRequired"]
|
||||
optional_fields = [f for f in fields if f["requirement"] != "SoeRequired"]
|
||||
optional_fields = [f for f in fields if f["requirement"] == "SoeOptional"]
|
||||
|
||||
def canonical_expr(field):
|
||||
return f"canonical_{field['stiSuffix']}()"
|
||||
|
||||
def default_expr(field):
|
||||
# The value a SoeDefault field's getter returns when the field is unset.
|
||||
if field["typed"]:
|
||||
return f"{field['typeData']['return_type']}{{}}"
|
||||
sti = field.get("stiSuffix")
|
||||
if sti == "ARRAY":
|
||||
return "STArray{}"
|
||||
if sti == "PATHSET":
|
||||
return "STPathSet{}"
|
||||
return "STObject{sfGeneric}"
|
||||
|
||||
# Pick a wrong ledger entry to test type mismatch
|
||||
# Use Ticket as it has minimal required fields (just Account)
|
||||
if name != "Ticket":
|
||||
wrong_le_include = "Ticket"
|
||||
else:
|
||||
wrong_le_include = "Check"
|
||||
%>
|
||||
|
||||
%>\
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <protocol_autogen/TestHelpers.h>
|
||||
@@ -46,6 +58,9 @@ TEST(${name}Tests, BuilderSettersRoundTrip)
|
||||
% for field in optional_fields:
|
||||
builder.set${field["name"][2:]}(${field["paramName"]}Value);
|
||||
% endfor
|
||||
% for field in default_fields:
|
||||
builder.set${field["name"][2:]}(${field["paramName"]}Value);
|
||||
% endfor
|
||||
|
||||
builder.setLedgerIndex(index);
|
||||
builder.setFlags(0x1u);
|
||||
@@ -56,7 +71,7 @@ TEST(${name}Tests, BuilderSettersRoundTrip)
|
||||
|
||||
EXPECT_TRUE(entry.validate());
|
||||
|
||||
% for field in required_fields:
|
||||
% for field in chain(required_fields, default_fields):
|
||||
{
|
||||
auto const& expected = ${field["paramName"]}Value;
|
||||
auto const actual = entry.get${field["name"][2:]}();
|
||||
@@ -112,7 +127,7 @@ TEST(${name}Tests, BuilderFromSleRoundTrip)
|
||||
EXPECT_TRUE(entryFromBuilder.validate());
|
||||
EXPECT_TRUE(entryFromSle.validate());
|
||||
|
||||
% for field in required_fields:
|
||||
% for field in chain(required_fields, default_fields):
|
||||
{
|
||||
auto const& expected = ${field["paramName"]}Value;
|
||||
|
||||
@@ -228,4 +243,48 @@ TEST(${name}Tests, OptionalFieldsReturnNullopt)
|
||||
% endfor
|
||||
}
|
||||
% endif
|
||||
|
||||
% if default_fields:
|
||||
// 6) Default fields return the type default when unset, and the assigned value
|
||||
// after being set.
|
||||
TEST(${name}Tests, DefaultFieldsRoundTrip)
|
||||
{
|
||||
uint256 const index{4u};
|
||||
|
||||
% for field in required_fields:
|
||||
auto const ${field["paramName"]}Value = ${canonical_expr(field)};
|
||||
% endfor
|
||||
|
||||
// Unset: default fields return the type default.
|
||||
${name}Builder defaultBuilder{
|
||||
% for i, field in enumerate(required_fields):
|
||||
${field["paramName"]}Value${"," if i < len(required_fields) - 1 else ""}
|
||||
% endfor
|
||||
};
|
||||
auto const defaultEntry = defaultBuilder.build(index);
|
||||
% for field in default_fields:
|
||||
{
|
||||
auto const expected = ${default_expr(field)};
|
||||
expectEqualField(expected, defaultEntry.get${field["name"][2:]}(), "${field["name"]}");
|
||||
}
|
||||
% endfor
|
||||
|
||||
// Set: default fields return the assigned value.
|
||||
${name}Builder setBuilder{
|
||||
% for i, field in enumerate(required_fields):
|
||||
${field["paramName"]}Value${"," if i < len(required_fields) - 1 else ""}
|
||||
% endfor
|
||||
};
|
||||
% for field in default_fields:
|
||||
setBuilder.set${field["name"][2:]}(${canonical_expr(field)});
|
||||
% endfor
|
||||
auto const setEntry = setBuilder.build(index);
|
||||
% for field in default_fields:
|
||||
{
|
||||
auto const expected = ${canonical_expr(field)};
|
||||
expectEqualField(expected, setEntry.get${field["name"][2:]}(), "${field["name"]}");
|
||||
}
|
||||
% endfor
|
||||
}
|
||||
% endif
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
% if field.get('supports_mpt'):
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
% endif
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'SoeRequired' or field['requirement'] == 'SoeDefault':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
@@ -97,13 +97,13 @@ public:
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
% endif
|
||||
* @note This is an untyped field.
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'SoeRequired' or field['requirement'] == 'SoeDefault':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
% endif
|
||||
*/
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'SoeRequired' or field['requirement'] == 'SoeDefault':
|
||||
[[nodiscard]]
|
||||
${field['typeData']['return_type']}
|
||||
get${field['name'][2:]}() const
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
// Auto-generated unit tests for transaction ${name}
|
||||
<%! from itertools import chain %>\
|
||||
<%
|
||||
default_fields = [f for f in fields if f["requirement"] == "SoeDefault"]
|
||||
required_fields = [f for f in fields if f["requirement"] == "SoeRequired"]
|
||||
optional_fields = [f for f in fields if f["requirement"] != "SoeRequired"]
|
||||
optional_fields = [f for f in fields if f["requirement"] == "SoeOptional"]
|
||||
|
||||
def canonical_expr(field):
|
||||
return f"canonical_{field['stiSuffix']}()"
|
||||
|
||||
def default_expr(field):
|
||||
# The value a SoeDefault field's getter returns when the field is unset.
|
||||
if field["typed"]:
|
||||
return f"{field['typeData']['return_type']}{{}}"
|
||||
sti = field.get("stiSuffix")
|
||||
if sti == "ARRAY":
|
||||
return "STArray{}"
|
||||
if sti == "PATHSET":
|
||||
return "STPathSet{}"
|
||||
return "STObject{sfGeneric}"
|
||||
|
||||
# Pick a wrong transaction to test type mismatch
|
||||
if name != "AccountSet":
|
||||
wrong_tx_include = "AccountSet"
|
||||
else:
|
||||
wrong_tx_include = "OfferCancel"
|
||||
%>
|
||||
|
||||
%>\
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <protocol_autogen/TestHelpers.h>
|
||||
@@ -58,6 +70,10 @@ TEST(Transactions${name}Tests, BuilderSettersRoundTrip)
|
||||
% for field in optional_fields:
|
||||
builder.set${field["name"][2:]}(${field["paramName"]}Value);
|
||||
% endfor
|
||||
// Set default fields
|
||||
% for field in default_fields:
|
||||
builder.set${field["name"][2:]}(${field["paramName"]}Value);
|
||||
% endfor
|
||||
|
||||
auto tx = builder.build(publicKey, secretKey);
|
||||
|
||||
@@ -73,8 +89,8 @@ TEST(Transactions${name}Tests, BuilderSettersRoundTrip)
|
||||
EXPECT_EQ(tx.getSequence(), sequenceValue);
|
||||
EXPECT_EQ(tx.getFee(), feeValue);
|
||||
|
||||
// Verify required fields
|
||||
% for field in required_fields:
|
||||
// Verify required and default fields
|
||||
% for field in chain(required_fields, default_fields):
|
||||
{
|
||||
auto const& expected = ${field["paramName"]}Value;
|
||||
auto const actual = tx.get${field["name"][2:]}();
|
||||
@@ -126,6 +142,9 @@ TEST(Transactions${name}Tests, BuilderFromStTxRoundTrip)
|
||||
% for field in optional_fields:
|
||||
initialBuilder.set${field["name"][2:]}(${field["paramName"]}Value);
|
||||
% endfor
|
||||
% for field in default_fields:
|
||||
initialBuilder.set${field["name"][2:]}(${field["paramName"]}Value);
|
||||
% endfor
|
||||
|
||||
auto initialTx = initialBuilder.build(publicKey, secretKey);
|
||||
|
||||
@@ -142,8 +161,8 @@ TEST(Transactions${name}Tests, BuilderFromStTxRoundTrip)
|
||||
EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue);
|
||||
EXPECT_EQ(rebuiltTx.getFee(), feeValue);
|
||||
|
||||
// Verify required fields
|
||||
% for field in required_fields:
|
||||
// Verify required and default fields
|
||||
% for field in chain(required_fields, default_fields):
|
||||
{
|
||||
auto const& expected = ${field["paramName"]}Value;
|
||||
auto const actual = rebuiltTx.get${field["name"][2:]}();
|
||||
@@ -238,4 +257,62 @@ TEST(Transactions${name}Tests, OptionalFieldsReturnNullopt)
|
||||
}
|
||||
% endif
|
||||
|
||||
% if default_fields:
|
||||
// 6) Default fields return the type default when unset, and the assigned value
|
||||
// after being set.
|
||||
TEST(Transactions${name}Tests, DefaultFieldsRoundTrip)
|
||||
{
|
||||
// Generate a deterministic keypair for signing
|
||||
auto const [publicKey, secretKey] =
|
||||
generateKeyPair(KeyType::Secp256k1, generateSeed("test${name}Default"));
|
||||
|
||||
// Common transaction fields
|
||||
auto const accountValue = calcAccountID(publicKey);
|
||||
std::uint32_t const sequenceValue = 4;
|
||||
auto const feeValue = canonical_AMOUNT();
|
||||
|
||||
// Transaction-specific required field values
|
||||
% for field in required_fields:
|
||||
auto const ${field["paramName"]}Value = ${canonical_expr(field)};
|
||||
% endfor
|
||||
|
||||
// Unset: default fields return the type default.
|
||||
${name}Builder defaultBuilder{
|
||||
accountValue,
|
||||
% for field in required_fields:
|
||||
${field["paramName"]}Value,
|
||||
% endfor
|
||||
sequenceValue,
|
||||
feeValue
|
||||
};
|
||||
auto const defaultTx = defaultBuilder.build(publicKey, secretKey);
|
||||
% for field in default_fields:
|
||||
{
|
||||
auto const expected = ${default_expr(field)};
|
||||
expectEqualField(expected, defaultTx.get${field["name"][2:]}(), "${field["name"]}");
|
||||
}
|
||||
% endfor
|
||||
|
||||
// Set: default fields return the assigned value.
|
||||
${name}Builder setBuilder{
|
||||
accountValue,
|
||||
% for field in required_fields:
|
||||
${field["paramName"]}Value,
|
||||
% endfor
|
||||
sequenceValue,
|
||||
feeValue
|
||||
};
|
||||
% for field in default_fields:
|
||||
setBuilder.set${field["name"][2:]}(${canonical_expr(field)});
|
||||
% endfor
|
||||
auto const setTx = setBuilder.build(publicKey, secretKey);
|
||||
% for field in default_fields:
|
||||
{
|
||||
auto const expected = ${canonical_expr(field)};
|
||||
expectEqualField(expected, setTx.get${field["name"][2:]}(), "${field["name"]}");
|
||||
}
|
||||
% endfor
|
||||
}
|
||||
% endif
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user