rippled
Loading...
Searching...
No Matches
AccountCurrencies_test.cpp
1#include <test/jtx.h>
2
3#include <xrpl/beast/unit_test.h>
4#include <xrpl/protocol/jss.h>
5
6namespace xrpl {
7
9{
10 void
12 {
13 testcase("Bad input to account_currencies");
14
15 using namespace test::jtx;
16 Env env{*this};
17
18 auto const alice = Account{"alice"};
19 env.fund(XRP(10000), alice);
20 env.close();
21
22 { // invalid ledger (hash)
23 Json::Value params;
24 params[jss::account] = Account{"bob"}.human();
25 params[jss::ledger_hash] = 1;
26 auto const result =
27 env.rpc("json", "account_currencies", to_string(params))[jss::result];
28 BEAST_EXPECT(result[jss::error] == "invalidParams");
29 BEAST_EXPECT(
30 result[jss::error_message] == "Invalid field 'ledger_hash', not hex string.");
31 }
32
33 { // missing account field
34 auto const result = env.rpc("json", "account_currencies", "{}")[jss::result];
35 BEAST_EXPECT(result[jss::error] == "invalidParams");
36 BEAST_EXPECT(result[jss::error_message] == "Missing field 'account'.");
37 }
38
39 {
40 // test account non-string
41 auto testInvalidAccountParam = [&](auto const& param) {
42 Json::Value params;
43 params[jss::account] = param;
44 auto jrr = env.rpc("json", "account_currencies", to_string(params))[jss::result];
45 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
46 BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'.");
47 };
48
49 testInvalidAccountParam(1);
50 testInvalidAccountParam(1.1);
51 testInvalidAccountParam(true);
52 testInvalidAccountParam(Json::Value(Json::nullValue));
53 testInvalidAccountParam(Json::Value(Json::objectValue));
54 testInvalidAccountParam(Json::Value(Json::arrayValue));
55 }
56
57 {
58 // test ident non-string
59 auto testInvalidIdentParam = [&](auto const& param) {
60 Json::Value params;
61 params[jss::ident] = param;
62 auto jrr = env.rpc("json", "account_currencies", to_string(params))[jss::result];
63 BEAST_EXPECT(jrr[jss::error] == "invalidParams");
64 BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'ident'.");
65 };
66
67 testInvalidIdentParam(1);
68 testInvalidIdentParam(1.1);
69 testInvalidIdentParam(true);
70 testInvalidIdentParam(Json::Value(Json::nullValue));
71 testInvalidIdentParam(Json::Value(Json::objectValue));
72 testInvalidIdentParam(Json::Value(Json::arrayValue));
73 }
74
75 {
76 Json::Value params;
77 params[jss::account] = "llIIOO"; // these are invalid in bitcoin alphabet
78 auto const result =
79 env.rpc("json", "account_currencies", to_string(params))[jss::result];
80 BEAST_EXPECT(result[jss::error] == "actMalformed");
81 BEAST_EXPECT(result[jss::error_message] == "Account malformed.");
82 }
83
84 {
85 // Cannot use a seed as account
86 Json::Value params;
87 params[jss::account] = "Bob";
88 auto const result =
89 env.rpc("json", "account_currencies", to_string(params))[jss::result];
90 BEAST_EXPECT(result[jss::error] == "actMalformed");
91 BEAST_EXPECT(result[jss::error_message] == "Account malformed.");
92 }
93
94 { // ask for nonexistent account
95 Json::Value params;
96 params[jss::account] = Account{"bob"}.human();
97 auto const result =
98 env.rpc("json", "account_currencies", to_string(params))[jss::result];
99 BEAST_EXPECT(result[jss::error] == "actNotFound");
100 BEAST_EXPECT(result[jss::error_message] == "Account not found.");
101 }
102 }
103
104 void
106 {
107 testcase("Basic request for account_currencies");
108
109 using namespace test::jtx;
110 Env env{*this};
111
112 auto const alice = Account{"alice"};
113 auto const gw = Account{"gateway"};
114 env.fund(XRP(10000), alice, gw);
115 char currencySuffix{'A'};
116 std::vector<std::optional<IOU>> gwCurrencies(26); // A - Z
117 std::generate(gwCurrencies.begin(), gwCurrencies.end(), [&]() {
118 auto gwc = gw[std::string("US") + currencySuffix++];
119 env(trust(alice, gwc(100)));
120 return gwc;
121 });
122 env.close();
123
124 Json::Value params;
125 params[jss::account] = alice.human();
126 auto result = env.rpc("json", "account_currencies", to_string(params))[jss::result];
127
128 auto arrayCheck = [&result](
129 Json::StaticString const& fld,
130 std::vector<std::optional<IOU>> const& expected) -> bool {
131 bool stat = result.isMember(fld) && result[fld].isArray() &&
132 result[fld].size() == expected.size();
133 for (size_t i = 0; stat && i < expected.size(); ++i)
134 {
135 stat &= (to_string(expected[i].value().currency) == result[fld][i].asString());
136 }
137 return stat;
138 };
139
140 BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies));
141 BEAST_EXPECT(arrayCheck(jss::send_currencies, {}));
142
143 // now form a payment for each currency
144 for (auto const& c : gwCurrencies)
145 env(pay(gw, alice, c.value()(50))); // NOLINT(bugprone-unchecked-optional-access)
146
147 // send_currencies should be populated now
148 result = env.rpc("json", "account_currencies", to_string(params))[jss::result];
149 BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies));
150 BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies));
151
152 // freeze the USD trust line and verify that the receive currencies
153 // does not change
154 env(trust(alice, gw["USD"](100), tfSetFreeze));
155 result = env.rpc("account_lines", alice.human());
156 for (auto const& l : result[jss::lines])
157 BEAST_EXPECT(l[jss::freeze].asBool() == (l[jss::currency] == "USD"));
158 result = env.rpc("json", "account_currencies", to_string(params))[jss::result];
159 BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies));
160 BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies));
161 // clear the freeze
162 env(trust(alice, gw["USD"](100), tfClearFreeze));
163
164 // make a payment that exhausts the trustline from alice to gw for USA
165 env(pay(gw, alice, gw["USA"](50)));
166 // USA should now be missing from receive_currencies
167 result = env.rpc("json", "account_currencies", to_string(params))[jss::result];
168 decltype(gwCurrencies)
169 const gwCurrenciesNoUSA(gwCurrencies.begin() + 1, gwCurrencies.end());
170 BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrenciesNoUSA));
171 BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies));
172
173 // add trust from gw to alice and then exhaust that trust line
174 // so that send_currencies for alice will now omit USA
175 env(trust(gw, alice["USA"](100)));
176 env(pay(alice, gw, alice["USA"](200)));
177 result = env.rpc("json", "account_currencies", to_string(params))[jss::result];
178 BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies));
179 BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrenciesNoUSA));
180 }
181
182public:
183 void
184 run() override
185 {
186 testBadInput();
187 testBasic();
188 }
189};
190
191BEAST_DEFINE_TESTSUITE(AccountCurrencies, rpc, xrpl);
192
193} // namespace xrpl
T begin(T... args)
Lightweight wrapper to tag static string.
Definition json_value.h:44
Represents a JSON value.
Definition json_value.h:130
bool isMember(char const *key) const
Return true if the object has a member named key.
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
void run() override
Runs the suite.
T end(T... args)
T generate(T... args)
@ nullValue
'null' value
Definition json_value.h:19
@ arrayValue
array value (ordered list)
Definition json_value.h:25
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:26
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602