Skip to content

Commit 9559db7

Browse files
committed
Fixed: crash when restoring certain backups with poorly formatted amount strings
Added some GncXmlHelper tests
1 parent 5783b87 commit 9559db7

4 files changed

Lines changed: 61 additions & 43 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
Change Log
22
===============================================================================
3+
Version 1.6.4 *(2015-08-xx)*
4+
----------------------------
5+
* Fixed: Isolated crash during backup restoration
6+
37
Version 1.6.3 *(2015-08-09)*
48
----------------------------
59
* Fixed: Transfer account ignored when saving transaction with one split (after opening split editor)

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ apply plugin: 'crashlytics'
55

66
def versionMajor = 1
77
def versionMinor = 6
8-
def versionPatch = 3
8+
def versionPatch = 4
99
def versionBuild = 0
1010

1111
def buildTime() {

app/src/main/java/org/gnucash/android/export/xml/GncXmlHelper.java

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919

2020
import android.support.annotation.NonNull;
2121

22-
import org.gnucash.android.model.Money;
23-
import org.gnucash.android.model.Split;
24-
import org.gnucash.android.model.TransactionType;
22+
import org.gnucash.android.ui.transaction.TransactionFormFragment;
2523

2624
import java.math.BigDecimal;
2725
import java.math.BigInteger;
@@ -162,41 +160,8 @@ public static long parseDate(String dateString) throws ParseException {
162160
}
163161

164162
/**
165-
* Parses the amounts in template transaction splits.
166-
* <p>GnuCash desktop formats the amounts based on the locale of the computer. That poses a problem here as the input can vary per user.<br/>
167-
* The solution is to parse the string irrespective of comma or thousands separators as follows:
168-
* <ol>
169-
* <li>Find the last non-numeric character and split the string at that point</li>
170-
* <li>If the length of the 2nd part is &gt;= 2, then it is a thousands separator, else it is decimal</li>
171-
* <li>Append the two parts again together accordingly</li>
172-
* <li>If no non-numeric character was found, then just return a new {@link BigDecimal}</li>
173-
* </ol>
174-
* </p>
175-
* @param amountString String value of the amount.
176-
* @return BigDecimal representation of the amount
177-
* @see #formatTemplateSplitAmount(BigDecimal)
178-
*/
179-
public static BigDecimal parseTemplateSplitAmount(@NonNull String amountString){
180-
Pattern pattern = Pattern.compile(".*\\D");
181-
Matcher matcher = pattern.matcher(amountString);
182-
if (matcher.find()){
183-
int index = matcher.end();
184-
String wholeNum = amountString.substring(0, index).replaceAll("\\D", "");
185-
String decimal = amountString.substring(index);
186-
String parsedAmountString;
187-
if (decimal.length() > 2){ //then it is just another thousands separator, just add it back
188-
parsedAmountString = wholeNum + decimal;
189-
} else { //add it as a decimal
190-
parsedAmountString = wholeNum + "." + decimal;
191-
}
192-
return new BigDecimal(parsedAmountString);
193-
} else {//an amount string with no commas or periods
194-
return new BigDecimal(amountString);
195-
}
196-
}
197-
198-
/**
199-
* Parses amount strings from GnuCash XML into {@link java.math.BigDecimal}s
163+
* Parses amount strings from GnuCash XML into {@link java.math.BigDecimal}s.
164+
* The amounts are formatted as 12345/4100
200165
* @param amountString String containing the amount
201166
* @return BigDecimal with numerical value
202167
* @throws ParseException if the amount could not be parsed
@@ -207,9 +172,11 @@ public static BigDecimal parseSplitAmount(String amountString) throws ParseExcep
207172
{
208173
throw new ParseException("Cannot parse money string : " + amountString, 0);
209174
}
210-
BigInteger numerator = new BigInteger(amountString.substring(0, pos));
211-
int scale = amountString.length() - pos - 2;
212-
return new BigDecimal(numerator, scale);
175+
176+
int scale = amountString.length() - pos - 2; //do this before, because we could modify the string
177+
String numerator = TransactionFormFragment.stripCurrencyFormatting(amountString.substring(0, pos));
178+
BigInteger numeratorInt = new BigInteger(numerator);
179+
return new BigDecimal(numeratorInt, scale);
213180
}
214181

215182
/**
@@ -224,7 +191,8 @@ public static String formatSplitAmount(BigDecimal amount, Currency trxCurrency){
224191
BigDecimal denom = new BigDecimal(denomInt);
225192
String denomString = Integer.toString(denomInt);
226193

227-
return amount.multiply(denom).stripTrailingZeros().toPlainString() + "/" + denomString;
194+
String numerator = TransactionFormFragment.stripCurrencyFormatting(amount.multiply(denom).stripTrailingZeros().toPlainString());
195+
return numerator + "/" + denomString;
228196
}
229197

230198
/**
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.gnucash.android.test.unit.export;
2+
3+
import org.gnucash.android.export.xml.GncXmlHelper;
4+
import org.junit.Test;
5+
6+
import java.math.BigDecimal;
7+
import java.text.ParseException;
8+
import java.util.Currency;
9+
10+
import static org.assertj.core.api.Assertions.assertThat;
11+
12+
/**
13+
* Test the helper methods used for generating GnuCash XML
14+
*/
15+
public class GncXmlHelperTest {
16+
17+
/**
18+
* Tests the parsing of split amounts
19+
*/
20+
@Test
21+
public void testParseSplitAmount() throws ParseException {
22+
String splitAmount = "12345/100";
23+
BigDecimal amount = GncXmlHelper.parseSplitAmount(splitAmount);
24+
assertThat(amount.toPlainString()).isEqualTo("123.45");
25+
26+
amount = GncXmlHelper.parseSplitAmount("1.234,50/100");
27+
assertThat(amount.toPlainString()).isEqualTo("1234.50");
28+
}
29+
30+
@Test(expected = ParseException.class)
31+
public void shouldFailToParseWronglyFormattedInput() throws ParseException {
32+
GncXmlHelper.parseSplitAmount("123.45");
33+
}
34+
35+
@Test
36+
public void testFormatSplitAmount(){
37+
BigDecimal bigDecimal = new BigDecimal("45.90");
38+
String amount = GncXmlHelper.formatSplitAmount(bigDecimal, Currency.getInstance("USD"));
39+
assertThat(amount).isEqualTo("4590/100");
40+
41+
42+
bigDecimal = new BigDecimal("350");
43+
amount = GncXmlHelper.formatSplitAmount(bigDecimal, Currency.getInstance("EUR"));
44+
assertThat(amount).isEqualTo("35000/100");
45+
}
46+
}

0 commit comments

Comments
 (0)