rippled
OwnerInfo_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2017 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 #include <test/jtx.h>
20 
21 #include <ripple/beast/unit_test.h>
22 #include <ripple/protocol/AccountID.h>
23 #include <ripple/protocol/STAmount.h>
24 #include <ripple/protocol/jss.h>
25 
26 namespace ripple {
27 
28 class OwnerInfo_test : public beast::unit_test::suite
29 {
30  void
32  {
33  testcase("Bad input to owner_info");
34 
35  using namespace test::jtx;
36  Env env{*this};
37 
38  auto const alice = Account{"alice"};
39  env.fund(XRP(10000), alice);
40  env.close();
41 
42  { // missing account field
43  auto const result =
44  env.rpc("json", "owner_info", "{}")[jss::result];
45  BEAST_EXPECT(result[jss::error] == "invalidParams");
46  BEAST_EXPECT(
47  result[jss::error_message] == "Missing field 'account'.");
48  }
49 
50  { // ask for empty account
51  Json::Value params;
52  params[jss::account] = "";
53  auto const result =
54  env.rpc("json", "owner_info", to_string(params))[jss::result];
55  if (BEAST_EXPECT(
56  result.isMember(jss::accepted) &&
57  result.isMember(jss::current)))
58  {
59  BEAST_EXPECT(result[jss::accepted][jss::error] == "badSeed");
60  BEAST_EXPECT(
61  result[jss::accepted][jss::error_message] ==
62  "Disallowed seed.");
63  BEAST_EXPECT(result[jss::current][jss::error] == "badSeed");
64  BEAST_EXPECT(
65  result[jss::current][jss::error_message] ==
66  "Disallowed seed.");
67  }
68  }
69 
70  { // ask for nonexistent account
71  // this seems like it should be an error, but current impl
72  // (deprecated) does not return an error, just empty fields.
73  Json::Value params;
74  params[jss::account] = Account{"bob"}.human();
75  auto const result =
76  env.rpc("json", "owner_info", to_string(params))[jss::result];
77  BEAST_EXPECT(result[jss::accepted] == Json::objectValue);
78  BEAST_EXPECT(result[jss::current] == Json::objectValue);
79  BEAST_EXPECT(result[jss::status] == "success");
80  }
81  }
82 
83  void
85  {
86  testcase("Basic request for owner_info");
87 
88  using namespace test::jtx;
89  Env env{*this};
90 
91  auto const alice = Account{"alice"};
92  auto const gw = Account{"gateway"};
93  env.fund(XRP(10000), alice, gw);
94  auto const USD = gw["USD"];
95  auto const CNY = gw["CNY"];
96  env(trust(alice, USD(1000)));
97  env(trust(alice, CNY(1000)));
98  env(offer(alice, USD(1), XRP(1000)));
99  env.close();
100 
101  env(pay(gw, alice, USD(50)));
102  env(pay(gw, alice, CNY(50)));
103  env(offer(alice, CNY(2), XRP(1000)));
104 
105  Json::Value params;
106  params[jss::account] = alice.human();
107  auto const result =
108  env.rpc("json", "owner_info", to_string(params))[jss::result];
109  if (!BEAST_EXPECT(
110  result.isMember(jss::accepted) &&
111  result.isMember(jss::current)))
112  {
113  return;
114  }
115 
116  // accepted ledger entry
117  if (!BEAST_EXPECT(result[jss::accepted].isMember(jss::ripple_lines)))
118  return;
119  auto lines = result[jss::accepted][jss::ripple_lines];
120  if (!BEAST_EXPECT(lines.isArray() && lines.size() == 2))
121  return;
122 
123  BEAST_EXPECT(
124  lines[0u][sfBalance.fieldName] ==
125  (STAmount{Issue{to_currency("CNY"), noAccount()}, 0}
126  .value()
128  BEAST_EXPECT(
129  lines[0u][sfHighLimit.fieldName] ==
130  alice["CNY"](1000).value().getJson(JsonOptions::none));
131  BEAST_EXPECT(
132  lines[0u][sfLowLimit.fieldName] ==
133  gw["CNY"](0).value().getJson(JsonOptions::none));
134 
135  BEAST_EXPECT(
136  lines[1u][sfBalance.fieldName] ==
137  (STAmount{Issue{to_currency("USD"), noAccount()}, 0}
138  .value()
140  BEAST_EXPECT(
141  lines[1u][sfHighLimit.fieldName] ==
142  alice["USD"](1000).value().getJson(JsonOptions::none));
143  BEAST_EXPECT(
144  lines[1u][sfLowLimit.fieldName] ==
145  USD(0).value().getJson(JsonOptions::none));
146 
147  if (!BEAST_EXPECT(result[jss::accepted].isMember(jss::offers)))
148  return;
149  auto offers = result[jss::accepted][jss::offers];
150  if (!BEAST_EXPECT(offers.isArray() && offers.size() == 1))
151  return;
152 
153  BEAST_EXPECT(offers[0u][jss::Account] == alice.human());
154  BEAST_EXPECT(
155  offers[0u][sfTakerGets.fieldName] ==
156  XRP(1000).value().getJson(JsonOptions::none));
157  BEAST_EXPECT(
158  offers[0u][sfTakerPays.fieldName] ==
159  USD(1).value().getJson(JsonOptions::none));
160 
161  // current ledger entry
162  if (!BEAST_EXPECT(result[jss::current].isMember(jss::ripple_lines)))
163  return;
164  lines = result[jss::current][jss::ripple_lines];
165  if (!BEAST_EXPECT(lines.isArray() && lines.size() == 2))
166  return;
167 
168  BEAST_EXPECT(
169  lines[0u][sfBalance.fieldName] ==
170  (STAmount{Issue{to_currency("CNY"), noAccount()}, -50}
171  .value()
173  BEAST_EXPECT(
174  lines[0u][sfHighLimit.fieldName] ==
175  alice["CNY"](1000).value().getJson(JsonOptions::none));
176  BEAST_EXPECT(
177  lines[0u][sfLowLimit.fieldName] ==
178  gw["CNY"](0).value().getJson(JsonOptions::none));
179 
180  BEAST_EXPECT(
181  lines[1u][sfBalance.fieldName] ==
182  (STAmount{Issue{to_currency("USD"), noAccount()}, -50}
183  .value()
185  BEAST_EXPECT(
186  lines[1u][sfHighLimit.fieldName] ==
187  alice["USD"](1000).value().getJson(JsonOptions::none));
188  BEAST_EXPECT(
189  lines[1u][sfLowLimit.fieldName] ==
190  gw["USD"](0).value().getJson(JsonOptions::none));
191 
192  if (!BEAST_EXPECT(result[jss::current].isMember(jss::offers)))
193  return;
194  offers = result[jss::current][jss::offers];
195  // 1 additional offer in current, (2 total)
196  if (!BEAST_EXPECT(offers.isArray() && offers.size() == 2))
197  return;
198 
199  BEAST_EXPECT(offers[1u] == result[jss::accepted][jss::offers][0u]);
200  BEAST_EXPECT(offers[0u][jss::Account] == alice.human());
201  BEAST_EXPECT(
202  offers[0u][sfTakerGets.fieldName] ==
203  XRP(1000).value().getJson(JsonOptions::none));
204  BEAST_EXPECT(
205  offers[0u][sfTakerPays.fieldName] ==
206  CNY(2).value().getJson(JsonOptions::none));
207  }
208 
209 public:
210  void
211  run() override
212  {
213  testBadInput();
214  testBasic();
215  }
216 };
217 
218 BEAST_DEFINE_TESTSUITE(OwnerInfo, app, ripple);
219 
220 } // namespace ripple
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:129
ripple::OwnerInfo_test
Definition: OwnerInfo_test.cpp:28
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:45
ripple::OwnerInfo_test::testBadInput
void testBadInput()
Definition: OwnerInfo_test.cpp:31
ripple::sfTakerPays
const SF_AMOUNT sfTakerPays
ripple::sfLowLimit
const SF_AMOUNT sfLowLimit
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::JsonOptions::none
@ none
ripple::STAmount
Definition: STAmount.h:42
ripple::sfTakerGets
const SF_AMOUNT sfTakerGets
ripple::test::jtx::offers
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
Definition: owners.h:89
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::OwnerInfo_test::run
void run() override
Definition: OwnerInfo_test.cpp:211
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:293
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::STAmount::value
STAmount const & value() const noexcept
Definition: STAmount.h:231
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::OwnerInfo_test::testBasic
void testBasic()
Definition: OwnerInfo_test.cpp:84
Json::Value
Represents a JSON value.
Definition: json_value.h:145