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(
60  result[jss::accepted][jss::error] == "actMalformed");
61  BEAST_EXPECT(
62  result[jss::accepted][jss::error_message] ==
63  "Account malformed.");
64  BEAST_EXPECT(
65  result[jss::current][jss::error] == "actMalformed");
66  BEAST_EXPECT(
67  result[jss::current][jss::error_message] ==
68  "Account malformed.");
69  }
70  }
71 
72  { // ask for nonexistent account
73  // this seems like it should be an error, but current impl
74  // (deprecated) does not return an error, just empty fields.
75  Json::Value params;
76  params[jss::account] = Account{"bob"}.human();
77  auto const result =
78  env.rpc("json", "owner_info", to_string(params))[jss::result];
79  BEAST_EXPECT(result[jss::accepted] == Json::objectValue);
80  BEAST_EXPECT(result[jss::current] == Json::objectValue);
81  BEAST_EXPECT(result[jss::status] == "success");
82  }
83  }
84 
85  void
87  {
88  testcase("Basic request for owner_info");
89 
90  using namespace test::jtx;
91  Env env{*this};
92 
93  auto const alice = Account{"alice"};
94  auto const gw = Account{"gateway"};
95  env.fund(XRP(10000), alice, gw);
96  auto const USD = gw["USD"];
97  auto const CNY = gw["CNY"];
98  env(trust(alice, USD(1000)));
99  env(trust(alice, CNY(1000)));
100  env(offer(alice, USD(1), XRP(1000)));
101  env.close();
102 
103  env(pay(gw, alice, USD(50)));
104  env(pay(gw, alice, CNY(50)));
105  env(offer(alice, CNY(2), XRP(1000)));
106 
107  Json::Value params;
108  params[jss::account] = alice.human();
109  auto const result =
110  env.rpc("json", "owner_info", to_string(params))[jss::result];
111  if (!BEAST_EXPECT(
112  result.isMember(jss::accepted) &&
113  result.isMember(jss::current)))
114  {
115  return;
116  }
117 
118  // accepted ledger entry
119  if (!BEAST_EXPECT(result[jss::accepted].isMember(jss::ripple_lines)))
120  return;
121  auto lines = result[jss::accepted][jss::ripple_lines];
122  if (!BEAST_EXPECT(lines.isArray() && lines.size() == 2))
123  return;
124 
125  BEAST_EXPECT(
126  lines[0u][sfBalance.fieldName] ==
127  (STAmount{Issue{to_currency("CNY"), noAccount()}, 0}
128  .value()
130  BEAST_EXPECT(
131  lines[0u][sfHighLimit.fieldName] ==
132  alice["CNY"](1000).value().getJson(JsonOptions::none));
133  BEAST_EXPECT(
134  lines[0u][sfLowLimit.fieldName] ==
135  gw["CNY"](0).value().getJson(JsonOptions::none));
136 
137  BEAST_EXPECT(
138  lines[1u][sfBalance.fieldName] ==
139  (STAmount{Issue{to_currency("USD"), noAccount()}, 0}
140  .value()
142  BEAST_EXPECT(
143  lines[1u][sfHighLimit.fieldName] ==
144  alice["USD"](1000).value().getJson(JsonOptions::none));
145  BEAST_EXPECT(
146  lines[1u][sfLowLimit.fieldName] ==
147  USD(0).value().getJson(JsonOptions::none));
148 
149  if (!BEAST_EXPECT(result[jss::accepted].isMember(jss::offers)))
150  return;
151  auto offers = result[jss::accepted][jss::offers];
152  if (!BEAST_EXPECT(offers.isArray() && offers.size() == 1))
153  return;
154 
155  BEAST_EXPECT(offers[0u][jss::Account] == alice.human());
156  BEAST_EXPECT(
157  offers[0u][sfTakerGets.fieldName] ==
158  XRP(1000).value().getJson(JsonOptions::none));
159  BEAST_EXPECT(
160  offers[0u][sfTakerPays.fieldName] ==
161  USD(1).value().getJson(JsonOptions::none));
162 
163  // current ledger entry
164  if (!BEAST_EXPECT(result[jss::current].isMember(jss::ripple_lines)))
165  return;
166  lines = result[jss::current][jss::ripple_lines];
167  if (!BEAST_EXPECT(lines.isArray() && lines.size() == 2))
168  return;
169 
170  BEAST_EXPECT(
171  lines[0u][sfBalance.fieldName] ==
172  (STAmount{Issue{to_currency("CNY"), noAccount()}, -50}
173  .value()
175  BEAST_EXPECT(
176  lines[0u][sfHighLimit.fieldName] ==
177  alice["CNY"](1000).value().getJson(JsonOptions::none));
178  BEAST_EXPECT(
179  lines[0u][sfLowLimit.fieldName] ==
180  gw["CNY"](0).value().getJson(JsonOptions::none));
181 
182  BEAST_EXPECT(
183  lines[1u][sfBalance.fieldName] ==
184  (STAmount{Issue{to_currency("USD"), noAccount()}, -50}
185  .value()
187  BEAST_EXPECT(
188  lines[1u][sfHighLimit.fieldName] ==
189  alice["USD"](1000).value().getJson(JsonOptions::none));
190  BEAST_EXPECT(
191  lines[1u][sfLowLimit.fieldName] ==
192  gw["USD"](0).value().getJson(JsonOptions::none));
193 
194  if (!BEAST_EXPECT(result[jss::current].isMember(jss::offers)))
195  return;
196  offers = result[jss::current][jss::offers];
197  // 1 additional offer in current, (2 total)
198  if (!BEAST_EXPECT(offers.isArray() && offers.size() == 2))
199  return;
200 
201  BEAST_EXPECT(offers[1u] == result[jss::accepted][jss::offers][0u]);
202  BEAST_EXPECT(offers[0u][jss::Account] == alice.human());
203  BEAST_EXPECT(
204  offers[0u][sfTakerGets.fieldName] ==
205  XRP(1000).value().getJson(JsonOptions::none));
206  BEAST_EXPECT(
207  offers[0u][sfTakerPays.fieldName] ==
208  CNY(2).value().getJson(JsonOptions::none));
209  }
210 
211 public:
212  void
213  run() override
214  {
215  testBadInput();
216  testBasic();
217  }
218 };
219 
220 BEAST_DEFINE_TESTSUITE(OwnerInfo, app, ripple);
221 
222 } // 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:132
ripple::OwnerInfo_test
Definition: OwnerInfo_test.cpp:28
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::value
STAmount const & value() const noexcept
Definition: STAmount.h:440
ripple::STAmount
Definition: STAmount.h:45
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:213
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:296
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::OwnerInfo_test::testBasic
void testBasic()
Definition: OwnerInfo_test.cpp:86
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
Json::Value
Represents a JSON value.
Definition: json_value.h:145