From b4497bcb089ad9c8d93eb8049fb87ec9cf52e16c Mon Sep 17 00:00:00 2001 From: Geert Weening Date: Thu, 26 Jun 2014 15:34:29 -0700 Subject: [PATCH] [FIX] amount human parsing for hex with amount There were cases where the currency and integer were incorrectly matched. By separating out the regex for hex formatted Amount makes it easier to deal with these cases and fixes the issue. --- src/js/ripple/amount.js | 40 ++++++++++++++++++++++++++++------------ test/amount-test.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/js/ripple/amount.js b/src/js/ripple/amount.js index f3b9f697..1e959c9d 100644 --- a/src/js/ripple/amount.js +++ b/src/js/ripple/amount.js @@ -598,30 +598,48 @@ Amount.prototype.invert = function() { * The regular expression below matches above cases, broken down for better understanding: * * ^\s* // start with any amount of whitespace - * ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217 + * ([A-z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217 * \s* // any amount of whitespace * (-)? // optional dash * (\d+) // 1 or more digits * (?:\.(\d*))? // optional . character with any amount of digits * \s* // any amount of whitespace - * ([a-f0-9]{40}|[a-z0-9]{3})? // optional 40 character hex string OR 3 letters + * ([A-z]{3}|[0-9]{3})? // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217 * \s* // any amount of whitespace * $ // end of string * */ -Amount.human_RE = /^\s*([a-z]{3}|[0-9]{3})?\s*(-)?(\d+)(?:\.(\d*))?\s*([a-f0-9]{40}|[a-z0-9]{3})?\s*$/i; +Amount.human_RE_hex = /^\s*(-)?(\d+)(?:\.(\d*))?\s*([a-fA-F0-9]{40})\s*$/; +Amount.human_RE = /^\s*([A-z]{3}|[0-9]{3})?\s*(-)?(\d+)(?:\.(\d*))?\s*([A-z]{3}|[0-9]{3})?\s*$/; Amount.prototype.parse_human = function(j, opts) { opts = opts || {}; - var m = String(j).match(Amount.human_RE); + var integer; + var fraction; + var currency; + var precision = null; - if (m) { - var currency = m[5] || m[1] || 'XRP'; - var integer = m[5] && m[1] ? m[1] + '' + m[3] : (m[3] || '0'); - var fraction = m[4] || ''; - var precision = null; + // first check if it's a hex formatted currency + var matches = String(j).match(Amount.human_RE_hex); + if (matches && matches.length === 5 && matches[4]) { + integer = matches[2]; + fraction = matches[3] || ''; + currency = matches[4]; + this._is_negative = Boolean(matches[1]); + } + if (integer === void(0) && currency === void(0)) { + var m = String(j).match(Amount.human_RE); + if (m) { + currency = m[5] || m[1] || 'XRP'; + integer = m[5] && m[1] ? m[1] + '' + m[3] : (m[3] || '0'); + fraction = m[4] || ''; + this._is_negative = Boolean(m[2]); + } + } + + if (integer) { currency = currency.toUpperCase(); this._value = new BigInteger(integer); @@ -648,8 +666,6 @@ Amount.prototype.parse_human = function(j, opts) { this.canonicalize(); } - this._is_negative = !!m[2]; - // Apply interest/demurrage if (opts.reference_date && this._currency.has_interest()) { var interest = this._currency.get_interest_at(opts.reference_date); @@ -1155,7 +1171,7 @@ Amount.prototype.to_json = function() { } else { var amount_json = { value : this.to_text(), - currency : this._currency.to_json() + currency : this._currency.has_interest() ? this._currency.to_hex() : this._currency.to_json() }; if (this._issuer.is_valid()) { amount_json.issuer = this._issuer.to_json(); diff --git a/test/amount-test.js b/test/amount-test.js index 9d5c040a..94f9db19 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -35,6 +35,30 @@ describe('Amount', function() { it('12345.6789 XAU', function() { assert.strictEqual(Amount.from_human("12345.6789 XAU").to_text_full(), '12345.6789/XAU/NaN'); }); + it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() { + assert.strictEqual(Amount.from_human("12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_text_full(), '12345.6789/XAU (-0.5%pa)/NaN'); + }); + it('12345.6789 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("12345.6789 0000000000000000000000005553440000000000").to_text_full(), '12345.6789/USD/NaN'); + }); + it('10 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("10 0000000000000000000000005553440000000000").to_text_full(), '10/USD/NaN'); + }); + it('100 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("100 0000000000000000000000005553440000000000").to_text_full(), '100/USD/NaN'); + }); + it('1000 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("1000 0000000000000000000000005553440000000000").to_text_full(), '1000/USD/NaN'); + }); + it('-100 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("-100 0000000000000000000000005553440000000000").to_text_full(), '-100/USD/NaN'); + }); + it('-1000 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("-1000 0000000000000000000000005553440000000000").to_text_full(), '-1000/USD/NaN'); + }); + it('-1000.001 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("-1000.001 0000000000000000000000005553440000000000").to_text_full(), '-1000.001/USD/NaN'); + }); it('XAU 12345.6789', function() { assert.strictEqual(Amount.from_human("XAU 12345.6789").to_text_full(), '12345.6789/XAU/NaN'); }); @@ -190,6 +214,23 @@ describe('Amount', function() { assert.strictEqual('0/XRP/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full()); }); }); + describe('Amount to_json', function() { + it('10 USD', function() { + var amount = Amount.from_human("10 USD").to_json(); + assert.strictEqual("10", amount.value); + assert.strictEqual("USD", amount.currency); + }); + it('10 0000000000000000000000005553440000000000', function() { + var amount = Amount.from_human("10 0000000000000000000000005553440000000000").to_json(); + assert.strictEqual("10", amount.value); + assert.strictEqual("USD", amount.currency); + }); + it('10 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() { + var amount = Amount.from_human("10 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_json(); + assert.strictEqual("10", amount.value); + assert.strictEqual("015841551A748AD2C1F76FF6ECB0CCCD00000000", amount.currency); + }); + }); describe('Amount operations', function() { it('Negate native 123', function () { assert.strictEqual('-0.000123/XRP', Amount.from_json('123').negate().to_text_full());