From fff39797c077571c873fb4d24280bceabfb9a923 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 21 Oct 2012 20:04:25 -0700 Subject: [PATCH] UT: Lots of improvements and fixes. - Parse negative amounts. - Make Amount.negate() return a new value. - Add Amount.equals(). - Rename Remote.trace() to set_trace(). - Fix request_ripple_balnce. - Add more tests to send-test.js. - Add more tests to amount-test.js. - Add helper functions create_accounts and credit_limits to testutils.js. --- js/amount.js | 60 +++++++++++++++++------ js/remote.js | 33 ++++++++----- test/amount-test.js | 27 +++++++++- test/offer-test.js | 50 +++++++++---------- test/send-test.js | 117 +++++++++++++++++++++++++++++++++++++++++++- test/testutils.js | 46 +++++++++++++++++ 6 files changed, 275 insertions(+), 58 deletions(-) diff --git a/js/amount.js b/js/amount.js index ea8d24095a..d791e8c983 100644 --- a/js/amount.js +++ b/js/amount.js @@ -38,6 +38,10 @@ UInt160.prototype.copyTo = function(d) { return d; }; +UInt160.prototype.equals = function(d) { + return this.value === d.value; +}; + // value = NaN on error. UInt160.prototype.parse_json = function (j) { // Canonicalize and validate @@ -166,6 +170,12 @@ var Amount = function () { this.issuer = new UInt160(); }; +// Given "100/USD/mtgox" return the a string with mtgox remapped. +Amount.text_full_rewrite = function (j) { + return Amount.from_json(j).to_text_full(); +} + +// Given "100/USD/mtgox" return the json. Amount.json_rewrite = function(j) { return Amount.from_json(j).to_json(); }; @@ -174,15 +184,18 @@ Amount.from_json = function(j) { return (new Amount()).parse_json(j); }; -Amount.prototype.clone = function() { - return this.copyTo(new Amount()); +Amount.prototype.clone = function(negate) { + return this.copyTo(new Amount(), negate); }; // Returns copy. -Amount.prototype.copyTo = function(d) { +Amount.prototype.copyTo = function(d, negate) { if ('object' === typeof this.value) { - this.value.copyTo(d.value); + if (this.is_native && negate) + this.value.negate.copyTo(d.value); + else + this.value.copyTo(d.value); } else { @@ -191,7 +204,7 @@ Amount.prototype.copyTo = function(d) { d.offset = this.offset; d.is_native = this.is_native; - d.is_negative = this.is_negative; + d.is_negative = this.is_negative ? undefined : !this.is_negative; this.currency.copyTo(d.currency); this.issuer.copyTo(d.issuer); @@ -266,15 +279,13 @@ Amount.prototype.canonicalize = function() { this.offset += 1; } } + + return this; }; +// Return a new value. Amount.prototype.negate = function () { - if (this.is_native) { - this.value.negate(); - } - else { - this.is_negative = !this.is_negative; - } + return this.clone('NEGATE'); }; Amount.prototype.to_json = function() { @@ -307,23 +318,26 @@ Amount.prototype.parse_native = function(j) { var m; if ('string' === typeof j) - m = j.match(/^(\d+)(\.\d{1,6})?$/); + m = j.match(/^(-?)(\d+)(\.\d{1,6})?$/); if (m) { - if (undefined === m[2]) { + if (undefined === m[3]) { // Integer notation - this.value = new BigInteger(m[1]); + this.value = new BigInteger(m[2]); } else { // Decimal notation - var int_part = (new BigInteger(m[1])).multiply(exports.consts.bi_xns_unit); - var fraction_part = (new BigInteger(m[2])).multiply(new BigInteger(String(Math.pow(10, 1+exports.consts.xns_precision-m[2].length)))); + var int_part = (new BigInteger(m[2])).multiply(exports.consts.bi_xns_unit); + var fraction_part = (new BigInteger(m[3])).multiply(new BigInteger(String(Math.pow(10, 1+exports.consts.xns_precision-m[3].length)))); this.value = int_part.add(fraction_part); } + if (m[1]) + this.value = this.value.negate(); + this.is_native = true; this.offset = undefined; this.is_negative = undefined; @@ -442,6 +456,20 @@ Amount.prototype.parse_issuer = function (issuer) { return this; }; +// Check BigInteger NaN +Amount.prototype.equals = function (d) { + return 'string' === typeof (d) + ? this.equals(Amount.from_json(d)) + : this === d + || (d.constructor === Amount + && this.is_native === d.is_native + && (this.is_native + ? this.value.equals(d.value) + : this.is_negative === d.is_negative + ? this.value.equals(d.value) + : this.value.equals(BigInteger.ZERO) && d.value.equals(BigInteger.ZERO))); +}; + exports.Amount = Amount; exports.Currency = Currency; exports.UInt160 = UInt160; diff --git a/js/remote.js b/js/remote.js index f3393d9a8b..554411fc6e 100644 --- a/js/remote.js +++ b/js/remote.js @@ -244,8 +244,8 @@ Remote.prototype._set_state = function (state) { } }; -Remote.prototype.trace = function () { - this.trace = true; +Remote.prototype.set_trace = function (trace) { + this.trace = undefined === trace || trace; return this; }; @@ -731,6 +731,8 @@ Remote.prototype.dirty_account_root = function (account) { // --> issuer: String // --> currency: String // --> current: bool : true = current ledger +// +// If does not exist: emit('error', 'error' : 'remoteError', 'remote' : { 'error' : 'entryNotFound' }) Remote.prototype.request_ripple_balance = function (account, issuer, currency, current) { var request = this.request_ledger_entry('ripple_state'); // YYY Could be cached per ledger. @@ -739,20 +741,25 @@ Remote.prototype.request_ripple_balance = function (account, issuer, currency, c .ledger_choose(current) .on('success', function (message) { var node = message.node; + var lowLimit = Amount.from_json(node.LowLimit); var highLimit = Amount.from_json(node.HighLimit); + // The amount account holds of issuer (after negation if needed). var balance = Amount.from_json(node.Balance); - var flip = UInt160.from_json(account) == highLimit.issuer; - var issuerLimit = flip ? lowLimit : highLimit; - var accountLimit = flip ? highLimit : lowLimit; - var issuerBalance = (flip ? balance.negate() : balance).parse_issuer(issuer); - var accountBalance = issuerBalance.clone().parse_issuer(issuer); + // accountHigh implies: for account: balance is negated, highLimit is the limit set by account. + var accountHigh = UInt160.from_json(account).equals(highLimit.issuer); + // The limit set by issuer. + var issuerLimit = (accountHigh ? lowLimit : highLimit).parse_issuer(issuer); + // The limit set by account. + var accountLimit = (accountHigh ? highLimit : lowLimit).parse_issuer(account); + var issuerBalance = (accountHigh ? balance.negate() : balance).parse_issuer(issuer); + var accountBalance = issuerBalance.clone().negate().parse_issuer(account); request.emit('ripple_state', { - 'issuer_balance' : issuerBalance, // Balance with dst as issuer. - 'account_balance' : accountBalance, // Balance with account as issuer. - 'issuer_limit' : issuerLimit.clone().parse_issuer(account), // Limit set by issuer with src as issuer. - 'account_limit' : accountLimit.clone().parse_issuer(issuer) // Limit set by account with dst as issuer. + 'issuer_balance' : issuerBalance, // Balance with dst as issuer. + 'account_balance' : accountBalance, // Balance with account as issuer. + 'issuer_limit' : issuerLimit, // Limit set by issuer with src as issuer. + 'account_limit' : accountLimit // Limit set by account with dst as issuer. }); }); } @@ -774,7 +781,7 @@ Remote.prototype.transaction = function () { // Events: // 'success' : Transaction submitted without error. // 'error' : Error submitting transaction. -// 'proposed: Advisory proposed status transaction. +// 'proposed' : Advisory proposed status transaction. // - A client should expect 0 to multiple results. // - Might not get back. The remote might just forward the transaction. // - A success could be reverted in final. @@ -1115,7 +1122,7 @@ Transaction.prototype.ripple_line_set = function (src, limit, quality_in, qualit // Allow limit of 0 through. if (undefined !== limit) - this.transaction.LimitAmount = limit.to_json(); + this.transaction.LimitAmount = Amount.json_rewrite(limit); if (quality_in) this.transaction.QualityIn = quality_in; diff --git a/test/amount-test.js b/test/amount-test.js index 3ddd400745..9b10dad5a8 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -10,12 +10,29 @@ buster.testCase("Amount", { "Parse 0 export" : function () { buster.assert.equals(amount.consts.hex_xns, amount.UInt160.from_json("0").to_json()); }, - "Parse native 123" : function () { - buster.assert.equals("123/XNS", amount.Amount.from_json("123").to_text_full()); + }, + "Amount" : { + "Parse native 0" : function () { + buster.assert.equals("0/XNS", amount.Amount.from_json("0").to_text_full()); + }, + "Parse native 0.0" : function () { + buster.assert.equals("0/XNS", amount.Amount.from_json("0.0").to_text_full()); + }, + "Parse native -0" : function () { + buster.assert.equals("0/XNS", amount.Amount.from_json("-0").to_text_full()); + }, + "Parse native -0.0" : function () { + buster.assert.equals("0/XNS", amount.Amount.from_json("-0.0").to_text_full()); + }, + "Parse native 1000" : function () { + buster.assert.equals("1000/XNS", amount.Amount.from_json("1000").to_text_full()); }, "Parse native 12.3" : function () { buster.assert.equals("12300000/XNS", amount.Amount.from_json("12.3").to_text_full()); }, + "Parse native -12.3" : function () { + buster.assert.equals("-12300000/XNS", amount.Amount.from_json("-12.3").to_text_full()); + }, "Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); }, @@ -28,6 +45,12 @@ buster.testCase("Amount", { "Parse 1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { buster.assert.equals("1.23/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); }, + "Parse -0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { + buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("-0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + }, + "Parse -0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { + buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("-0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + }, } }); diff --git a/test/offer-test.js b/test/offer-test.js index 18867ea25f..590d3f262b 100644 --- a/test/offer-test.js +++ b/test/offer-test.js @@ -23,11 +23,11 @@ buster.testCase("Offer tests", { function (callback) { self.remote.transaction() .offer_create("root", "500", "100/USD/root") - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_create: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS', m); }) - .on("final", function (m) { + .on('final', function (m) { // console.log("FINAL: offer_create: %s", JSON.stringify(m)); buster.assert.equals('tesSUCCESS', m.metadata.TransactionResult); @@ -39,11 +39,11 @@ buster.testCase("Offer tests", { function (m, callback) { self.remote.transaction() .offer_cancel("root", m.transaction.Sequence) - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_cancel: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS', m); }) - .on("final", function (m) { + .on('final', function (m) { // console.log("FINAL: offer_cancel: %s", JSON.stringify(m)); buster.assert.equals('tesSUCCESS', m.metadata.TransactionResult); @@ -54,7 +54,7 @@ buster.testCase("Offer tests", { }, function (m, callback) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: %d: %s", ledger_closed_index, ledger_closed); }) .ledger_accept(); @@ -77,14 +77,14 @@ buster.testCase("Offer tests", { function (callback) { self.remote.transaction() .offer_create("root", "500", "100/USD/root") - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_create: %s", JSON.stringify(m)); offer_seq = m.transaction.Sequence; callback(m.result != 'tesSUCCESS'); }) - .on("final", function (m) { + .on('final', function (m) { // console.log("FINAL: offer_create: %s", JSON.stringify(m)); buster.assert.equals('tesSUCCESS', m.metadata.TransactionResult); @@ -98,7 +98,7 @@ buster.testCase("Offer tests", { function (callback) { if (!final_create) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: %d: %s", ledger_closed_index, ledger_closed); }) @@ -113,11 +113,11 @@ buster.testCase("Offer tests", { self.remote.transaction() .offer_cancel("root", offer_seq) - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_cancel: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS'); }) - .on("final", function (m) { + .on('final', function (m) { // console.log("FINAL: offer_cancel: %s", JSON.stringify(m)); buster.assert.equals('tesSUCCESS', m.metadata.TransactionResult); @@ -130,7 +130,7 @@ buster.testCase("Offer tests", { // See if ledger_accept will crash. function (callback) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: A: %d: %s", ledger_closed_index, ledger_closed); callback(); }) @@ -138,7 +138,7 @@ buster.testCase("Offer tests", { }, function (callback) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: B: %d: %s", ledger_closed_index, ledger_closed); callback(); }) @@ -174,14 +174,14 @@ buster.testCase("Offer tests", { function (callback) { self.remote.transaction() .offer_create("alice", "500", "100/USD/alice") - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_create: %s", JSON.stringify(m)); offer_seq = m.transaction.Sequence; callback(m.result != 'tesSUCCESS'); }) - .on("final", function (m) { + .on('final', function (m) { // console.log("FINAL: offer_create: %s", JSON.stringify(m)); buster.assert.equals('tesSUCCESS', m.metadata.TransactionResult); @@ -195,7 +195,7 @@ buster.testCase("Offer tests", { function (callback) { if (!final_create) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: %d: %s", ledger_closed_index, ledger_closed); }) @@ -210,11 +210,11 @@ buster.testCase("Offer tests", { self.remote.transaction() .offer_cancel("alice", offer_seq) - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_cancel: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS'); }) - .on("final", function (m) { + .on('final', function (m) { // console.log("FINAL: offer_cancel: %s", JSON.stringify(m)); buster.assert.equals('tesSUCCESS', m.metadata.TransactionResult); @@ -227,7 +227,7 @@ buster.testCase("Offer tests", { // See if ledger_accept will crash. function (callback) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: A: %d: %s", ledger_closed_index, ledger_closed); callback(); }) @@ -235,7 +235,7 @@ buster.testCase("Offer tests", { }, function (callback) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: B: %d: %s", ledger_closed_index, ledger_closed); callback(); }) @@ -258,7 +258,7 @@ buster.testCase("Offer tests", { self.remote.transaction() .payment('root', 'alice', Amount.from_json("10000")) .set_flags('CreateAccount') - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: CreateAccount: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS', m); }) @@ -274,7 +274,7 @@ buster.testCase("Offer tests", { function (m, callback) { self.remote.transaction() .offer_cancel("root", m.transaction.Sequence) - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_cancel past: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS', m); }) @@ -284,7 +284,7 @@ buster.testCase("Offer tests", { function (m, callback) { self.remote.transaction() .offer_cancel("root", m.transaction.Sequence+1) - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("PROPOSED: offer_cancel same: %s", JSON.stringify(m)); callback(m.result != 'temBAD_SEQUENCE', m); }) @@ -297,7 +297,7 @@ buster.testCase("Offer tests", { self.remote.transaction() .offer_cancel("root", m.transaction.Sequence+2) - .on("proposed", function (m) { + .on('proposed', function (m) { // console.log("ERROR: offer_cancel future: %s", JSON.stringify(m)); callback(m.result != 'temBAD_SEQUENCE'); }) @@ -306,7 +306,7 @@ buster.testCase("Offer tests", { // See if ledger_accept will crash. function (callback) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: A: %d: %s", ledger_closed_index, ledger_closed); callback(); }) @@ -314,7 +314,7 @@ buster.testCase("Offer tests", { }, function (callback) { self.remote - .once("ledger_closed", function (ledger_closed, ledger_closed_index) { + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { // console.log("LEDGER_CLOSED: B: %d: %s", ledger_closed_index, ledger_closed); callback(); }) diff --git a/test/send-test.js b/test/send-test.js index 2376b4f42e..9d66ad030c 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -1,3 +1,4 @@ +var async = require("async"); var buster = require("buster"); var Amount = require("../js/amount.js").Amount; @@ -9,13 +10,13 @@ var testutils = require("./testutils.js"); // How long to wait for server to start. var serverDelay = 1500; -buster.testRunner.timeout = 5000; +buster.testRunner.timeout = 2000; buster.testCase("Sending", { 'setUp' : testutils.test_setup, 'tearDown' : testutils.test_teardown, - "send to non-existant account without create." : + "send XNS to non-existant account without create." : function (done) { var self = this; var ledgers = 20; @@ -71,6 +72,118 @@ buster.testCase("Sending", { }) .submit(); }, + + // Also test transaction becomes lost after terNO_DST. + "credit_limit to non-existant account = terNO_DST" : + function (done) { + this.remote.transaction() + .ripple_line_set("root", "100/USD/alice") + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + buster.assert.equals(m.result, 'terNO_DST'); + + done(); + }) + .submit(); + }, + + "credit_limit" : + function (done) { + var self = this; + //this.remote.set_trace(); + + async.waterfall([ + function (callback) { + this.what = "Create account."; + + testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback); + }, + function (callback) { + this.what = "Check a non-existant credit limit."; + self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT') + .on('ripple_state', function (m) { + buster.assert(false); + + callback(); + }) + .on('error', function(m) { + // console.log("error: %s", JSON.stringify(m)); + + buster.assert.equals('remoteError', m.error); + buster.assert.equals('entryNotFound', m.remote.error); + callback(); + }) + .request(); + }, + function (callback) { + this.what = "Create a credit limit."; + testutils.credit_limit(self.remote, "alice", "800/USD/mtgox", callback); + }, + function (callback) { + self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT') + .on('ripple_state', function (m) { +// console.log("BALANCE: %s", JSON.stringify(m)); +// console.log("account_balance: %s", m.account_balance.to_text_full()); +// console.log("account_limit: %s", m.account_limit.to_text_full()); +// console.log("issuer_balance: %s", m.issuer_balance.to_text_full()); +// console.log("issuer_limit: %s", m.issuer_limit.to_text_full()); + buster.assert(m.account_balance.equals("0/USD/alice")); + buster.assert(m.account_limit.equals("800/USD/alice")); + buster.assert(m.issuer_balance.equals("0/USD/mtgox")); + buster.assert(m.issuer_limit.equals("0/USD/mtgox")); + + callback(); + }) + .request(); + }, + function (callback) { + this.what = "Modify a credit limit."; + + testutils.credit_limit(self.remote, "alice", "700/USD/mtgox", callback); + }, + function (callback) { + self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT') + .on('ripple_state', function (m) { + buster.assert(m.account_balance.equals("0/USD/alice")); + buster.assert(m.account_limit.equals("700/USD/alice")); + buster.assert(m.issuer_balance.equals("0/USD/mtgox")); + buster.assert(m.issuer_limit.equals("0/USD/mtgox")); + + callback(); + }) + .request(); + }, + function (callback) { + this.what = "Zero a credit limit."; + + testutils.credit_limit(self.remote, "alice", "0/USD/mtgox", callback); + }, + function (callback) { + this.what = "Make sure still exists."; + + self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT') + .on('ripple_state', function (m) { + buster.assert(m.account_balance.equals("0/USD/alice")); + buster.assert(m.account_limit.equals("0/USD/alice")); + buster.assert(m.issuer_balance.equals("0/USD/mtgox")); + buster.assert(m.issuer_limit.equals("0/USD/mtgox")); + + callback(); + }) + .request(); + }, + // Check in both owner books. + // Set limit on other side. + // Set negative limit. + //function (callback) { + // testutils.credit_limit(self.remote, "alice", "-1/USD/mtgox", callback); + //}, + ], function (error) { + buster.refute(error, this.what); + done(); + }); + } }); // vim:sw=2:sts=2:ts=8 diff --git a/test/testutils.js b/test/testutils.js index f2f0111275..605f8e27d1 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -1,3 +1,6 @@ +var async = require("async"); +// var buster = require("buster"); + var Remote = require("../js/remote.js").Remote; var Server = require("./server.js").Server; @@ -28,6 +31,49 @@ var test_teardown = function (done, host) { .connect(false); }; +var create_accounts = function (remote, src, amount, accounts, callback) { + assert(5 === arguments.length); + + async.forEachSeries(accounts, function (account, callback) { + remote.transaction() + .payment(src, account, amount) + .set_flags('CreateAccount') + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + callback(m.result != 'tesSUCCESS'); + }) + .on('error', function (m) { + // console.log("error: %s", JSON.stringify(m)); + + callback(m); + }) + .submit(); + }, callback); +}; + +var credit_limit = function (remote, src, amount, callback) { + assert(4 === arguments.length); + + remote.transaction() + .ripple_line_set(src, amount) + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + // buster.assert.equals(m.result, 'tesSUCCESS'); + + callback(m.result != 'tesSUCCESS'); + }) + .on('error', function (m) { + // console.log("error: %s", JSON.stringify(m)); + + callback(m); + }) + .submit(); +}; + +exports.create_accounts = create_accounts; +exports.credit_limit = credit_limit; exports.test_setup = test_setup; exports.test_teardown = test_teardown;