From 8393afbed101daf5e2dee30535033b1232b9a762 Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 27 Jun 2021 14:47:34 +0200 Subject: [PATCH] Fix of #891 - New lines are replaced with spaces for description and memo lines of the QIF export. Empty memos are no longer exported (field is optional in QIF). Also fixed export test and added new test for no new lines export. Increased Robolectric version from 4.3.1 to 4.5.1 because of failing build (see https://github.com/robolectric/robolectric/issues/5456). --- app/build.gradle | 4 +-- .../android/export/qif/QifExporter.java | 19 +++++----- .../gnucash/android/export/qif/QifHelper.java | 7 ++++ .../test/unit/export/QifExporterTest.java | 35 ++++++++++++++++--- 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b4483fbfe..fe038326e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -229,14 +229,14 @@ dependencies { } - testImplementation 'org.robolectric:robolectric:4.3.1' + testImplementation 'org.robolectric:robolectric:4.5.1' testImplementation( 'junit:junit:4.12', 'joda-time:joda-time:2.9.4', 'org.assertj:assertj-core:3.14.0' ) - testImplementation 'org.robolectric:shadows-multidex:4.3.1' + testImplementation 'org.robolectric:shadows-multidex:4.5.1' androidTestImplementation ( 'com.android.support:support-annotations:' + androidSupportVersion, diff --git a/app/src/main/java/org/gnucash/android/export/qif/QifExporter.java b/app/src/main/java/org/gnucash/android/export/qif/QifExporter.java index 9f1478df8..3ce8597eb 100644 --- a/app/src/main/java/org/gnucash/android/export/qif/QifExporter.java +++ b/app/src/main/java/org/gnucash/android/export/qif/QifExporter.java @@ -145,7 +145,7 @@ public List generateExport() throws ExporterException { currentAccountUID = accountUID; writer.append(QifHelper.ACCOUNT_HEADER).append(newLine); writer.append(QifHelper.ACCOUNT_NAME_PREFIX) - .append(cursor.getString(cursor.getColumnIndexOrThrow("acct1_full_name"))) + .append(QifHelper.sanitizeQifLine(cursor.getString(cursor.getColumnIndexOrThrow("acct1_full_name")))) .append(newLine); writer.append(QifHelper.ENTRY_TERMINATOR).append(newLine); writer.append(QifHelper.getQifHeader(cursor.getString(cursor.getColumnIndexOrThrow("acct1_type")))) @@ -158,12 +158,15 @@ public List generateExport() throws ExporterException { .append(newLine); // Payee / description writer.append(QifHelper.PAYEE_PREFIX) - .append(cursor.getString(cursor.getColumnIndexOrThrow("trans_desc"))) + .append(QifHelper.sanitizeQifLine(cursor.getString(cursor.getColumnIndexOrThrow("trans_desc")))) .append(newLine); // Notes, memo - writer.append(QifHelper.MEMO_PREFIX) - .append(cursor.getString(cursor.getColumnIndexOrThrow("trans_notes"))) - .append(newLine); + String memo = QifHelper.sanitizeQifLine(cursor.getString(cursor.getColumnIndexOrThrow("trans_notes"))); + if (!memo.isEmpty()) { + writer.append(QifHelper.MEMO_PREFIX) + .append(memo) + .append(newLine); + } // deal with imbalance first double imbalance = cursor.getDouble(cursor.getColumnIndexOrThrow("trans_acct_balance")); BigDecimal decimalImbalance = BigDecimal.valueOf(imbalance).setScale(2, BigDecimal.ROUND_HALF_UP); @@ -186,10 +189,10 @@ public List generateExport() throws ExporterException { // amount associated with the header account will not be exported. // It can be auto balanced when importing to GnuCash writer.append(QifHelper.SPLIT_CATEGORY_PREFIX) - .append(cursor.getString(cursor.getColumnIndexOrThrow("acct2_full_name"))) + .append(QifHelper.sanitizeQifLine(cursor.getString(cursor.getColumnIndexOrThrow("acct2_full_name")))) .append(newLine); - String splitMemo = cursor.getString(cursor.getColumnIndexOrThrow("split_memo")); - if (splitMemo != null && splitMemo.length() > 0) { + String splitMemo = QifHelper.sanitizeQifLine(cursor.getString(cursor.getColumnIndexOrThrow("split_memo"))); + if (!splitMemo.isEmpty()) { writer.append(QifHelper.SPLIT_MEMO_PREFIX) .append(splitMemo) .append(newLine); diff --git a/app/src/main/java/org/gnucash/android/export/qif/QifHelper.java b/app/src/main/java/org/gnucash/android/export/qif/QifHelper.java index 0f9450be8..96275296e 100644 --- a/app/src/main/java/org/gnucash/android/export/qif/QifHelper.java +++ b/app/src/main/java/org/gnucash/android/export/qif/QifHelper.java @@ -83,4 +83,11 @@ public static String getQifHeader(AccountType accountType){ public static String getQifHeader(String accountType) { return getQifHeader(AccountType.valueOf(accountType)); } + + static String sanitizeQifLine(String line) { + if (line == null) { + return ""; + } + return line.replaceAll("\\r?\\n", " "); + } } diff --git a/app/src/test/java/org/gnucash/android/test/unit/export/QifExporterTest.java b/app/src/test/java/org/gnucash/android/test/unit/export/QifExporterTest.java index 689e69b33..2e84349cd 100644 --- a/app/src/test/java/org/gnucash/android/test/unit/export/QifExporterTest.java +++ b/app/src/test/java/org/gnucash/android/test/unit/export/QifExporterTest.java @@ -26,6 +26,7 @@ import org.gnucash.android.export.ExportFormat; import org.gnucash.android.export.ExportParams; import org.gnucash.android.export.qif.QifExporter; +import org.gnucash.android.export.qif.QifHelper; import org.gnucash.android.model.Account; import org.gnucash.android.model.Book; import org.gnucash.android.model.Commodity; @@ -156,13 +157,39 @@ public void memoAndDescription_shouldBeExported() throws IOException { String expectedDescription = "my description"; String expectedMemo = "my memo"; + checkGivenMemoAndDescription(expectedDescription,expectedDescription,expectedMemo,expectedMemo); + } + + /** + * Test that new lines in the memo and description fields of transactions are not exported. + */ + @Test + public void memoAndDescription_doNotExportNewLines() throws IOException { + final String lineBreak = "\r\n"; + final String expectedLineBreakReplacement = " "; + + final String descriptionFirstLine = "Test description"; + final String descriptionSecondLine = "with 2 lines"; + final String originalDescription = descriptionFirstLine + lineBreak + descriptionSecondLine; + final String expectedDescription = descriptionFirstLine + expectedLineBreakReplacement + descriptionSecondLine; + + final String memoFirstLine = "My memo has multiply lines"; + final String memoSecondLine = "This is the second line"; + final String memoThirdLine = "This is the third line"; + final String originalMemo = memoFirstLine + lineBreak + memoSecondLine + lineBreak + memoThirdLine; + final String expectedMemo = memoFirstLine + expectedLineBreakReplacement + memoSecondLine + expectedLineBreakReplacement + memoThirdLine; + + checkGivenMemoAndDescription(originalDescription,expectedDescription,originalMemo,expectedMemo); + } + + private void checkGivenMemoAndDescription(final String originalDescription, final String expectedDescription, final String originalMemo, final String expectedMemo) throws IOException { AccountsDbAdapter accountsDbAdapter = new AccountsDbAdapter(mDb); Account account = new Account("Basic Account"); Transaction transaction = new Transaction("One transaction"); transaction.addSplit(new Split(Money.createZeroInstance("EUR"), account.getUID())); - transaction.setDescription(expectedDescription); - transaction.setNote(expectedMemo); + transaction.setDescription(originalDescription); + transaction.setNote(originalMemo); account.addTransaction(transaction); accountsDbAdapter.addRecord(account); @@ -179,8 +206,8 @@ public void memoAndDescription_shouldBeExported() throws IOException { File file = new File(exportedFiles.get(0)); String fileContent = readFileContent(file); assertThat(file).exists().hasExtension("qif"); - assertThat(fileContent.contains(expectedDescription)); - assertThat(fileContent.contains(expectedMemo)); + assertThat(fileContent).contains(QifHelper.PAYEE_PREFIX + expectedDescription); + assertThat(fileContent).contains(QifHelper.MEMO_PREFIX + expectedMemo); } @NonNull