gnucash master: Multiple changes pushed

Geert Janssens gjanssens at code.gnucash.org
Sat May 12 08:11:13 EDT 2018


Updated	 via  https://github.com/Gnucash/gnucash/commit/61071b9f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/61fe6478 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7f91cb82 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fc963f87 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/836705f9 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/388a4906 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5e1c8e91 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9eedea71 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/66fcaa4f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/bb551af9 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4e851026 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4c55141d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ded88b01 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1df7fb40 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d4cb87fe (commit)
	 via  https://github.com/Gnucash/gnucash/commit/23410ca4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/97ab1b19 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/13f31e06 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5e0fc04f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8ddee964 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c6032ac6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/dda6730c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4a27285e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/44a568bc (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fd028716 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d68ccc33 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ac510d13 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4b9ec663 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f82e5a5b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f89f00f5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4a7bc0b5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2102c55b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/b95fa5ba (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6210b80f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6e78fa1d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2e53d647 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1f3cf845 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/27c1df30 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/682b5cf5 (commit)
	from  https://github.com/Gnucash/gnucash/commit/435b0ace (commit)



commit 61071b9f6d9b912ca6418b1b7018e6a3e6fcc6f2
Merge: 435b0ac 61fe647
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat May 12 14:10:38 2018 +0200

    Merge branch 'maint'


commit 61fe647828e806667659ed63f64be9e16b3b31ed
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat May 12 14:07:26 2018 +0200

    Use lowercase for account type descriptions

diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 26c3529..966246c 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -576,7 +576,7 @@ tags within description, notes or memo. ")
     pagename-filter optname-closing-transactions
     "l" (_ "By default most users should not include closing \
 transactions in a transaction report. Closing transactions are \
-transfers from INCOME and EXPENSE accounts to equity, and must usually \
+transfers from income and expense accounts to equity, and must usually \
 be excluded from periodic reporting.")
     'exclude-closing
     (keylist->vectorlist show-closing-list)))
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d5cfd96..24e50aa 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -461,7 +461,6 @@ gnucash/report/report-system/html-style-sheet.scm
 gnucash/report/report-system/html-table.scm
 gnucash/report/report-system/html-text.scm
 gnucash/report/report-system/html-utilities.scm
-gnucash/report/report-system/list-extras.scm
 gnucash/report/report-system/options-utilities.scm
 gnucash/report/report-system/report-collectors.scm
 gnucash/report/report-system/report.scm

commit 7f91cb82d7ef07177085b714ffa53dc5233fbb8f
Merge: fc963f8 388a490
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat May 12 14:07:59 2018 +0200

    Merge branch 'scheme-progress' of https://github.com/christopherlam/gnucash into maint


commit fc963f877cd725ee4e561530e2deb0f9bba6e515
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Tue May 1 15:11:16 2018 +0100

    Change the right margin setting for reconcile totals
    
    Change the margin setting from the gtk box to the label so it looks
    correct when styled.

diff --git a/gnucash/gnome/window-reconcile.c b/gnucash/gnome/window-reconcile.c
index 5491c48..9ed3dd8 100644
--- a/gnucash/gnome/window-reconcile.c
+++ b/gnucash/gnome/window-reconcile.c
@@ -1186,12 +1186,6 @@ gnc_reconcile_window_create_view_box(Account *account,
     gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
-#if GTK_CHECK_VERSION(3,12,0)
-    gtk_widget_set_margin_end (GTK_WIDGET(hbox), 10);
-#else
-    gtk_widget_set_margin_right (GTK_WIDGET(hbox), 10);
-#endif
-
     label = gtk_label_new(_("Total:"));
     gnc_label_set_alignment(label, 1.0, 0.5);
     gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
@@ -1200,6 +1194,12 @@ gnc_reconcile_window_create_view_box(Account *account,
     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
     *total_save = label;
 
+#if GTK_CHECK_VERSION(3,12,0)
+    gtk_widget_set_margin_end (GTK_WIDGET(label), 10);
+#else
+    gtk_widget_set_margin_right (GTK_WIDGET(label), 10);
+#endif
+
     return vbox;
 }
 
diff --git a/gnucash/gnome/window-reconcile2.c b/gnucash/gnome/window-reconcile2.c
index aa089ae..699f97d 100644
--- a/gnucash/gnome/window-reconcile2.c
+++ b/gnucash/gnome/window-reconcile2.c
@@ -1154,6 +1154,12 @@ gnc_reconcile_window_create_view_box (Account *account,
     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
     *total_save = label;
 
+#if GTK_CHECK_VERSION(3,12,0)
+    gtk_widget_set_margin_end (GTK_WIDGET(label), 10);
+#else
+    gtk_widget_set_margin_right (GTK_WIDGET(label), 10);
+#endif
+
     return vbox;
 }
 

commit 836705f98087ec7bf9418cef71af939fcff6a393
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Tue May 1 15:07:46 2018 +0100

    Bug 795101 - Fix the reconcile window sort order
    
    When the reconcile column was moved, the default sort order was not
    altered for the change so fixed it. Also added enum so model columns
    can be referenced by name which hopefully will make it easier to read.

diff --git a/gnucash/gnome/reconcile-view.c b/gnucash/gnome/reconcile-view.c
index a4e7404..0dfb661 100644
--- a/gnucash/gnome/reconcile-view.c
+++ b/gnucash/gnome/reconcile-view.c
@@ -125,10 +125,10 @@ gnc_reconcile_view_tooltip_cb (GNCQueryView *qview, gint x, gint y,
         g_list_free (cols);
 
         /* If column is not description, do not show tooltip */
-        if (col_pos != 2)
+        if (col_pos != (REC_DESC - 1)) // allow for the pointer model column at 0
             return FALSE;
 
-        gtk_tree_model_get (model, &iter, 3, &desc_text, -1);
+        gtk_tree_model_get (model, &iter, REC_DESC, &desc_text, -1);
 
         if (desc_text)
         {
@@ -259,8 +259,9 @@ gnc_reconcile_view_construct (GNCReconcileView *view, Query *query)
     gnc_query_view_construct (qview, view->column_list, query);
     gnc_query_view_set_numerics (qview, TRUE, inv_sort);
 
-    /* Set the description field to have spare space */
-    col = gtk_tree_view_get_column (GTK_TREE_VIEW (qview), 3);
+    /* Set the description field to have spare space,
+       REC_DESC -1 to allow for the pointer model column at 0 */
+    col = gtk_tree_view_get_column (GTK_TREE_VIEW (qview), (REC_DESC - 1));
     gtk_tree_view_column_set_expand (col, TRUE);
 
     /* Get the renderer of the description column and set ellipsize value */
@@ -411,7 +412,7 @@ gnc_reconcile_view_init (GNCReconcileView *view)
                                     gnc_reconcile_view_is_reconciled, view);
     gnc_search_param_set_title ((GNCSearchParam *) param, _("Reconciled:R") + 11);
     gnc_search_param_set_justify ((GNCSearchParam *) param, GTK_JUSTIFY_CENTER);
-    gnc_search_param_set_passive ((GNCSearchParam *) param, TRUE);
+    gnc_search_param_set_passive ((GNCSearchParam *) param, FALSE);
     gnc_search_param_set_non_resizeable ((GNCSearchParam *) param, TRUE);
     columns = g_list_prepend (columns, param);
 
@@ -540,13 +541,13 @@ gnc_reconcile_view_toggle_children (Account *account, GNCReconcileView *view, Sp
         while (valid)
         {
             // Walk through the list, reading each row
-            gtk_tree_model_get (model, &iter, 0, &pointer, -1);
+            gtk_tree_model_get (model, &iter, REC_POINTER, &pointer, -1);
 
             if(pointer == other_split)
             {
                 gboolean toggled;
-                gtk_tree_model_get (model, &iter, 1, &toggled, -1);
-                gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, !toggled, -1);
+                gtk_tree_model_get (model, &iter, REC_RECN, &toggled, -1);
+                gtk_list_store_set (GTK_LIST_STORE (model), &iter, REC_RECN, !toggled, -1);
                 break;
             }
 
@@ -597,7 +598,7 @@ gnc_reconcile_view_line_toggled (GNCQueryView *qview,
     model = gtk_tree_view_get_model (GTK_TREE_VIEW (qview));
     gtk_tree_model_iter_nth_child (model, &iter, NULL, qview->toggled_row);
     gtk_list_store_set (GTK_LIST_STORE (model), &iter, qview->toggled_column, GPOINTER_TO_INT(item), -1);
-    gtk_tree_model_get (model, &iter, 0, &entry, -1);
+    gtk_tree_model_get (model, &iter, REC_POINTER, &entry, -1);
 
     gnc_reconcile_view_toggle (view, entry);
 }
@@ -659,10 +660,10 @@ gnc_reconcile_view_set_list ( GNCReconcileView  *view, gboolean reconcile)
         if(gtk_tree_model_get_iter(model, &iter, node->data))
         {
             /* now iter is a valid row iterator */
-            gtk_tree_model_get (model, &iter, 0, &entry, -1);
-            gtk_tree_model_get (model, &iter, 1, &toggled, -1);
+            gtk_tree_model_get (model, &iter, REC_POINTER, &entry, -1);
+            gtk_tree_model_get (model, &iter, REC_RECN, &toggled, -1);
 
-            gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, reconcile, -1);
+            gtk_list_store_set (GTK_LIST_STORE (model), &iter, REC_RECN, reconcile, -1);
 
             if(reconcile != toggled)
                 gnc_reconcile_view_toggle (view, entry);
@@ -709,7 +710,7 @@ gnc_reconcile_view_set_toggle (GNCReconcileView  *view)
         if(gtk_tree_model_get_iter(model, &iter, node->data))
         {
             /* now iter is a valid row iterator */
-            gtk_tree_model_get (model, &iter, 1, &toggled, -1);
+            gtk_tree_model_get (model, &iter, REC_RECN, &toggled, -1);
 
             if(toggled)
                 num_toggled++;
@@ -943,7 +944,7 @@ gnc_reconcile_view_postpone (GNCReconcileView *view)
     {
         char recn;
 
-        gtk_tree_model_get (model, &iter, 0, &entry, -1);
+        gtk_tree_model_get (model, &iter, REC_POINTER, &entry, -1);
 
         // Don't change splits past reconciliation date that haven't been
         // set to be reconciled
diff --git a/gnucash/gnome/reconcile-view.h b/gnucash/gnome/reconcile-view.h
index 03f4259..f0d433e 100644
--- a/gnucash/gnome/reconcile-view.h
+++ b/gnucash/gnome/reconcile-view.h
@@ -44,6 +44,16 @@ typedef enum
     RECLIST_CREDIT
 } GNCReconcileViewType;
 
+enum
+{
+    REC_POINTER, //0
+    REC_RECN,    //1
+    REC_DATE,    //2
+    REC_NUM,     //3
+    REC_DESC,    //4
+    REC_AMOUNT   //5
+};
+
 struct GNCReconcileView
 {
     GNCQueryView         qview;
diff --git a/gnucash/gnome/window-reconcile.c b/gnucash/gnome/window-reconcile.c
index 8405a32..5491c48 100644
--- a/gnucash/gnome/window-reconcile.c
+++ b/gnucash/gnome/window-reconcile.c
@@ -1946,8 +1946,8 @@ recnWindowWithBalance (Account *account, gnc_numeric new_ending,
     gnc_window_adjust_for_screen(GTK_WINDOW(recnData->window));
 
     /* Set the sort orders of the debit and credit tree views */
-    gnc_query_sort_order(GNC_QUERY_VIEW(recnData->debit), 1, GTK_SORT_ASCENDING);
-    gnc_query_sort_order(GNC_QUERY_VIEW(recnData->credit), 1, GTK_SORT_ASCENDING);
+    gnc_query_sort_order(GNC_QUERY_VIEW(recnData->debit), REC_DATE, GTK_SORT_ASCENDING);
+    gnc_query_sort_order(GNC_QUERY_VIEW(recnData->credit), REC_DATE, GTK_SORT_ASCENDING);
 
     gtk_widget_grab_focus (recnData->debit);
 
diff --git a/gnucash/gnome/window-reconcile2.c b/gnucash/gnome/window-reconcile2.c
index 4f7cbc9..aa089ae 100644
--- a/gnucash/gnome/window-reconcile2.c
+++ b/gnucash/gnome/window-reconcile2.c
@@ -1886,8 +1886,8 @@ recnWindow2WithBalance (GtkWidget *parent, Account *account,
     gnc_window_adjust_for_screen (GTK_WINDOW (recnData->window));
 
     /* Set the sort orders of the debit and credit tree views */
-    gnc_query_sort_order (GNC_QUERY_VIEW (recnData->debit), 1, GTK_SORT_ASCENDING);
-    gnc_query_sort_order (GNC_QUERY_VIEW (recnData->credit), 1, GTK_SORT_ASCENDING);
+    gnc_query_sort_order (GNC_QUERY_VIEW (recnData->debit), REC_DATE, GTK_SORT_ASCENDING);
+    gnc_query_sort_order (GNC_QUERY_VIEW (recnData->credit), REC_DATE, GTK_SORT_ASCENDING);
 
     gtk_widget_grab_focus (recnData->debit);
 

commit 388a4906b05740b507582b8eda9b264d8a357bfa
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Fri May 11 16:39:00 2018 +0800

    gnc:options->sxml allow alphanumeric in test filename

diff --git a/gnucash/report/report-system/test/test-extras.scm b/gnucash/report/report-system/test/test-extras.scm
index 02bde41..b8a74c2 100644
--- a/gnucash/report/report-system/test/test-extras.scm
+++ b/gnucash/report/report-system/test/test-extras.scm
@@ -104,7 +104,8 @@
          (renderer (gnc:report-template-renderer template))
          (document (renderer report))
          (sanitize-char (lambda (c)
-                          (if (char-alphabetic? c) c #\-)))
+                          (if (or (char-alphabetic? c)
+                                  (char-numeric? c)) c #\-)))
          (fileprefix (string-map sanitize-char prefix))
          (filename (string-map sanitize-char test-title)))
     (gnc:html-document-set-style-sheet! document (gnc:report-stylesheet report))

commit 5e1c8e91321ad07ffc6c2e45823315d44773434c
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu May 10 22:52:43 2018 +0800

    business-reports/*.scm: close tags to make valid XHTML
    
    This will be important for testing.

diff --git a/gnucash/report/business-reports/customer-summary.scm b/gnucash/report/business-reports/customer-summary.scm
index c8bc60b..b0384be 100644
--- a/gnucash/report/business-reports/customer-summary.scm
+++ b/gnucash/report/business-reports/customer-summary.scm
@@ -580,10 +580,10 @@
     (gnc:html-table-append-row!
      table
      (list
-      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br>")))
+      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br/>")))
     (gnc:html-table-append-row!
      table
-     (list "<br>"))
+     (list "<br/>"))
     (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
@@ -625,7 +625,7 @@
     (gnc:html-table-append-row! table (list (if name name "")))
     (gnc:html-table-append-row! table (list (string-expand
                                              (if addy addy "")
-                                             #\newline "<br>")))
+                                             #\newline "<br/>")))
     (gnc:html-table-append-row! table (list
                                        (strftime
                                         date-format
diff --git a/gnucash/report/business-reports/easy-invoice.scm b/gnucash/report/business-reports/easy-invoice.scm
index 6a80711..985b6eb 100644
--- a/gnucash/report/business-reports/easy-invoice.scm
+++ b/gnucash/report/business-reports/easy-invoice.scm
@@ -564,10 +564,10 @@
     (gnc:html-table-append-row!
      table
      (list
-      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br>")))
+      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br/>")))
     (gnc:html-table-append-row!
      table
-     (list "<br>"))
+     (list "<br/>"))
     (for-each
      (lambda (order)
        (let* ((reference (gncOrderGetReference order)))
@@ -780,7 +780,7 @@
                   (gnc:make-html-text
                     (string-append
                       (_ "Billing ID") ": "
-                      (string-expand billing-id #\newline "<br>"))))
+                      (string-expand billing-id #\newline "<br/>"))))
                 (make-break! document)))))
 
         (if (opt-val "Display" "Billing Terms")
@@ -792,7 +792,7 @@
                 (gnc:make-html-text
                   (string-append
                     (_ "Terms") ": "
-                    (string-expand terms #\newline "<br>")))))))
+                    (string-expand terms #\newline "<br/>")))))))
 
         (make-break! document)
 
@@ -814,14 +814,14 @@
               (gnc:html-document-add-object!
                document
                (gnc:make-html-text
-               (string-expand notes #\newline "<br>"))))
+               (string-expand notes #\newline "<br/>"))))
             (make-break! document)
             (make-break! document)))
 
         (gnc:html-document-add-object!
           document
           (gnc:make-html-text
-            (string-expand (opt-val "Text" "Extra Notes") #\newline "<br>")
+            (string-expand (opt-val "Text" "Extra Notes") #\newline "<br/>")
              ))
 
         ; close the framing table
diff --git a/gnucash/report/business-reports/fancy-invoice.scm b/gnucash/report/business-reports/fancy-invoice.scm
index a7c7809..77c2b4e 100644
--- a/gnucash/report/business-reports/fancy-invoice.scm
+++ b/gnucash/report/business-reports/fancy-invoice.scm
@@ -622,7 +622,7 @@
     (gnc:html-table-cell-set-style!
      name-cell "td"
      'font-size "+2")
-    (gnc:html-table-append-row! table (list name-cell "" "")) ;;Bert: had a newline and a "<br>"
+    (gnc:html-table-append-row! table (list name-cell "" "")) ;;Bert: had a newline and a "<br/>"
     (gnc:html-table-append-row!
      table
      (list
@@ -927,7 +927,7 @@
 		(gnc:html-document-add-object!
 		 document
 		 (gnc:make-html-text
-		  (string-expand notes #\newline "<br>")))))
+		  (string-expand notes #\newline "<br/>")))))
 
 	  (make-break! document)
 
diff --git a/gnucash/report/business-reports/invoice.scm b/gnucash/report/business-reports/invoice.scm
index 447d9d1..3434c95 100644
--- a/gnucash/report/business-reports/invoice.scm
+++ b/gnucash/report/business-reports/invoice.scm
@@ -541,10 +541,10 @@
     (gnc:html-table-append-row!
      table
      (list
-      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br>")))
+      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br/>")))
     (gnc:html-table-append-row!
      table
-     (list "<br>"))
+     (list "<br/>"))
     (for-each
      (lambda (order)
        (let* ((reference (gncOrderGetReference order)))
@@ -595,7 +595,7 @@
     (gnc:html-table-append-row! table (list (if name name "")))
     (gnc:html-table-append-row! table (list (string-expand
 					     (if addy addy "")
-					     #\newline "<br>")))
+					     #\newline "<br/>")))
     (gnc:html-table-append-row! table (list
 				       (strftime
 					date-format
@@ -718,7 +718,7 @@
 		       (gnc:make-html-text
 			(string-append
 			 (_ "Reference") ": "
-			 (string-expand billing-id #\newline "<br>"))))
+			 (string-expand billing-id #\newline "<br/>"))))
 		      (make-break! document)))))
 
 	  (if (opt-val "Display" "Billing Terms")
@@ -731,7 +731,7 @@
 		       (gnc:make-html-text
 			(string-append
 			  (_ "Terms") ": "
-			  (string-expand terms #\newline "<br>"))))
+			  (string-expand terms #\newline "<br/>"))))
 		      (make-break! document))
 		)))
 
@@ -746,14 +746,14 @@
 		       (gnc:make-html-text
 			(string-append
 			 (_ "Job number") ": "
-			 (string-expand jobnumber #\newline "<br>"))))
+			 (string-expand jobnumber #\newline "<br/>"))))
        (make-break! document)
        (gnc:html-document-add-object!
 		       document
 		       (gnc:make-html-text
 			(string-append
 			 (_ "Job name") ": "
-			 (string-expand jobname #\newline "<br>"))))
+			 (string-expand jobname #\newline "<br/>"))))
        (make-break! document)
        (make-break! document)
     )))
@@ -768,7 +768,7 @@
 		(gnc:html-document-add-object!
 		 document
 		 (gnc:make-html-text
-		  (string-expand notes #\newline "<br>")))))
+		  (string-expand notes #\newline "<br/>")))))
 
 	  (make-break! document)
 
@@ -776,7 +776,7 @@
 	   document
 	   (gnc:make-html-text
 	    (gnc:html-markup-br)
-	    (string-expand (opt-val "Display" "Extra Notes") #\newline "<br>")
+	    (string-expand (opt-val "Display" "Extra Notes") #\newline "<br/>")
 	    (gnc:html-markup-br))))
 
 	; else
diff --git a/gnucash/report/business-reports/owner-report.scm b/gnucash/report/business-reports/owner-report.scm
index 20d8e28..787c998 100644
--- a/gnucash/report/business-reports/owner-report.scm
+++ b/gnucash/report/business-reports/owner-report.scm
@@ -678,10 +678,10 @@
     (gnc:html-table-append-row!
      table
      (list
-      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br>")))
+      (string-expand (gnc:owner-get-name-and-address-dep owner) #\newline "<br/>")))
     (gnc:html-table-append-row!
      table
-     (list "<br>"))
+     (list "<br/>"))
     (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
@@ -721,7 +721,7 @@
     (gnc:html-table-append-row! table (list (if name name "")))
     (gnc:html-table-append-row! table (list (string-expand
                          (if addy addy "")
-                         #\newline "<br>")))
+                         #\newline "<br/>")))
     (gnc:html-table-append-row! table (list
                        (strftime
                     date-format
diff --git a/gnucash/report/business-reports/receipt.scm b/gnucash/report/business-reports/receipt.scm
index a782783..6ee7250 100644
--- a/gnucash/report/business-reports/receipt.scm
+++ b/gnucash/report/business-reports/receipt.scm
@@ -191,7 +191,7 @@
                 notespage optname-extra-notes "a"
                 (N_ "Notes added at end of invoice -- may contain HTML markup")
                 ""))
-                ;(N_ "(Development version -- don't rely on the numbers on this report without double-checking them.<br>Change the 'Extra Notes' option to get rid of this message)")))
+                ;(N_ "(Development version -- don't rely on the numbers on this report without double-checking them.<br/>Change the 'Extra Notes' option to get rid of this message)")))
 
   (gnc:options-set-default-section
     report-options generalpage)
diff --git a/gnucash/report/business-reports/taxinvoice.scm b/gnucash/report/business-reports/taxinvoice.scm
index d6919c7..054b18f 100644
--- a/gnucash/report/business-reports/taxinvoice.scm
+++ b/gnucash/report/business-reports/taxinvoice.scm
@@ -237,7 +237,7 @@
                 notespage optname-extra-notes "a"
                 (_ "Notes added at end of invoice -- may contain HTML markup.") 
                 (_ "Thank you for your patronage!")))
-                ;(N_ "(Development version -- don't rely on the numbers on this report without double-checking them.<br>Change the 'Extra Notes' option to get rid of this message)")))
+                ;(N_ "(Development version -- don't rely on the numbers on this report without double-checking them.<br/>Change the 'Extra Notes' option to get rid of this message)")))
 
   (add-option (gnc:make-text-option	notespage optname-extra-css "b"
                 (N_ "Embedded CSS.")	"h1.coyname { text-align: left; }"))

commit 9eedea71ea1871fdc8d926fe2376b1105291b06a
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed May 9 20:30:34 2018 +0800

    test-GSTR: implementation testing for GST Report

diff --git a/gnucash/report/standard-reports/test/CMakeLists.txt b/gnucash/report/standard-reports/test/CMakeLists.txt
index 1db6daf..f994b17 100644
--- a/gnucash/report/standard-reports/test/CMakeLists.txt
+++ b/gnucash/report/standard-reports/test/CMakeLists.txt
@@ -8,6 +8,7 @@ set(scm_test_standard_reports_SOURCES
 
 set(scm_test_with_srfi64_SOURCES
   test-transaction.scm
+  test-income-gst.scm
 )
 
 set(scm_test_report_SUPPORT
diff --git a/gnucash/report/standard-reports/test/test-income-gst.scm b/gnucash/report/standard-reports/test/test-income-gst.scm
new file mode 100644
index 0000000..a11bbf8
--- /dev/null
+++ b/gnucash/report/standard-reports/test/test-income-gst.scm
@@ -0,0 +1,213 @@
+(use-modules (gnucash gnc-module))
+(gnc:module-begin-syntax (gnc:module-load "gnucash/app-utils" 0))
+(use-modules (gnucash engine test test-extras))
+(use-modules (gnucash report standard-reports income-gst-statement))
+(use-modules (gnucash report stylesheets))
+(use-modules (gnucash report report-system))
+(use-modules (gnucash report report-system test test-extras))
+(use-modules (srfi srfi-64))
+(use-modules (gnucash engine test srfi64-extras))
+(use-modules (sxml simple))
+(use-modules (sxml xpath))
+
+
+;; This is implementation testing for Income & GST report. This
+;; delegates to the Transaction Report, therefore, only the
+;; GSTR-specific options will be individually tested. Foreign-currency
+;; conversions will NOT be tested, because they require pricedb entries.
+
+;; see transaction.scm for explanatory notes and hints.
+
+;; copied from income-gst-statement.scm
+(define rpt-uuid "5bf27f249a0d11e7abc4cec278b6b50a")
+
+;; Explicitly set locale to make the report output predictable
+(setlocale LC_ALL "C")
+
+(define (run-test)
+  (test-runner-factory gnc:test-runner)
+  (test-begin "income-gst-statement.scm")
+  (null-test)
+  (gstr-tests)
+  (test-end "income-gst-statement.scm"))
+
+(define (options->sxml options test-title)
+  (gnc:options->sxml rpt-uuid options "test-gstr" test-title))
+
+(define (set-option! options section name value)
+  (let ((option (gnc:lookup-option options section name)))
+    (if option
+        (gnc:option-set-value option value)
+        (test-assert (format #f "wrong-option ~a ~a" section name) #f))))
+
+(define structure
+  (list "Root" (list (cons 'type ACCT-TYPE-ASSET))
+        (list "GST"
+              (list "GST on Purchases")
+              (list "GST on Sales" (list (cons 'type ACCT-TYPE-LIABILITY)))
+              (list "Reduced GST on Sales" (list (cons 'type ACCT-TYPE-LIABILITY))))
+        (list "Asset"
+              (list "Bank")
+              (list "A/Receivable" (list (cons 'type ACCT-TYPE-RECEIVABLE))))
+        (list "Liability" (list (cons 'type ACCT-TYPE-PAYABLE))
+              (list "CreditCard")
+              (list "A/Payable"))
+        (list "Income" (list (cons 'type ACCT-TYPE-INCOME)))
+        (list "Expenses" (list (cons 'type ACCT-TYPE-EXPENSE)))
+        ))
+
+(define (null-test)
+  ;; This null-test tests for the presence of report.
+  (let ((options (gnc:make-report-options rpt-uuid)))
+    (test-assert "null-test" (options->sxml options "null-test"))))
+
+(define (gstr-tests)
+  ;; This function will perform implementation testing on the transaction report.
+  (let* ((env (create-test-env))
+         (account-alist (env-create-account-structure-alist env structure))
+         (bank (cdr (assoc "Bank" account-alist)))
+         (income (cdr (assoc "Income" account-alist)))
+         (expense (cdr (assoc "Expenses" account-alist)))
+         (creditcard (cdr (assoc "CreditCard" account-alist)))
+         (payable (cdr (assoc "A/Payable" account-alist)))
+         (receivable (cdr (assoc "A/Receivable" account-alist)))
+         (gst-sales (cdr (assoc "GST on Sales" account-alist)))
+         (reduced-gst-sales (cdr (assoc "Reduced GST on Sales" account-alist)))
+         (gst-purch (cdr (assoc "GST on Purchases" account-alist)))
+         (YEAR (gnc:time64-get-year (gnc:get-today))))
+
+    (define (default-testing-options)
+      ;; To ease testing of transaction report, we will set default
+      ;; options for generating reports. We will elable extra columns
+      ;; for Exporting, disable generation of informational text, and
+      ;; disable indenting. These options will be tested separately as
+      ;; the first test group. By default, we'll select the modern dates.
+      (let ((options (gnc:make-report-options rpt-uuid)))
+        (set-option! options "Accounts" "Accounts" (list income expense payable receivable))
+        (set-option! options "Accounts" "Tax Accounts" (list gst-sales
+                                                             reduced-gst-sales
+                                                             gst-purch))
+        (set-option! options "General" "Add options summary" 'always)
+        (set-option! options "General" "Table for Exporting" #t)
+        (set-option! options "General" "Start Date" (cons 'relative 'start-cal-year))
+        (set-option! options "General" "End Date" (cons 'relative 'end-cal-year))
+        options))
+
+    (define* (create-txn DD MM YY DESC list-of-splits #:optional txn-type)
+      (let ((txn (xaccMallocTransaction (gnc-get-current-book))))
+        (xaccTransBeginEdit txn)
+        (xaccTransSetDescription txn DESC)
+        (xaccTransSetCurrency txn (gnc-default-report-currency))
+        (xaccTransSetDate txn DD MM YY)
+        (for-each
+         (lambda (tfr)
+           (let ((split (xaccMallocSplit (gnc-get-current-book))))
+             (xaccSplitSetParent split txn)
+             (xaccSplitSetAccount split (cdr tfr))
+             (xaccSplitSetValue split (car tfr))
+             (xaccSplitSetAmount split (car tfr))))
+         list-of-splits)
+        (if txn-type
+            (xaccTransSetTxnType txn txn-type))
+        (xaccTransCommitEdit txn)
+        txn))
+
+    ;; This will make all accounts use default currency (I think depends on locale)
+    (for-each
+     (lambda(pair)
+       (xaccAccountSetCommodity (cdr pair) (gnc-default-report-currency)))
+     account-alist)
+
+    (create-txn 1 1 YEAR "invoice charge $100, no GST"
+                (list (cons -100 income)
+                      (cons  100 receivable))
+                TXN-TYPE-INVOICE)
+
+    (create-txn 2 1 YEAR "invoice charge $200+$20GST"
+                (list (cons -200 income)
+                      (cons  -20 gst-sales)
+                      (cons  220 receivable))
+                TXN-TYPE-INVOICE)
+
+    (create-txn 3 1 YEAR "receive $320 for invoices from bank"
+                (list (cons -320 receivable)
+                      (cons  320 bank))
+                TXN-TYPE-PAYMENT)
+
+    (create-txn 4 1 YEAR "cash sales $300+$15GST5%"
+                (list (cons -300 income)
+                      (cons  -15 reduced-gst-sales)
+                      (cons  315 bank)))
+
+    (create-txn 5 1 YEAR "cash spend $50, no GST"
+                (list (cons -50 bank)
+                      (cons  50 expense)))
+
+    (create-txn 6 1 YEAR "purchase on credit $80+$8GST"
+                (list (cons -88 payable)
+                      (cons  80 expense)
+                      (cons   8 gst-purch))
+                TXN-TYPE-INVOICE)
+
+    (create-txn 7 1 YEAR "hybrid paycheck. earn $400+$20, less $110+$10"
+                (list (cons  310 bank)
+                      (cons -400 income)
+                      (cons  -20 reduced-gst-sales)
+                      (cons  100 expense)
+                      (cons   10 gst-purch)))
+
+    (create-txn 8 1 YEAR "pay bill from 6-january for $88 using creditcard"
+                (list (cons  88 payable)
+                      (cons -88 creditcard))
+                TXN-TYPE-PAYMENT)
+
+    (create-txn 2 2 YEAR "link"
+                (list (cons -77 income)
+                      (cons  77 income))
+                TXN-TYPE-LINK)
+
+    (create-txn 3 2 YEAR "payment"
+                (list (cons -22 income)
+                      (cons  22 income))
+                TXN-TYPE-PAYMENT)
+
+    (xaccTransSetIsClosingTxn
+     (create-txn 3 2 YEAR "closing"
+                 (list (cons -33 income)
+                       (cons  33 income)))
+     #t)
+
+    ;; Finally we can begin testing
+    (test-begin "display options")
+
+    (let ((options (default-testing-options)))
+      (set-option! options "Display" "Num" #f)
+      (set-option! options "Display" "Memo" #f)
+      (set-option! options "Display" "Account Name" #f)
+      (set-option! options "Sorting" "Primary Subtotal" 'date)
+      (set-option! options "Sorting" "Secondary Subtotal" 'account-name)
+      (let ((sxml (options->sxml options "initial setup")))
+        (test-equal "totals are as expected"
+          '("Grand Total" " " " " "$1,055.00" "$1,000.00" "$55.00" "$248.00" "$230.00" "$18.00")
+          (sxml->table-row-col sxml 1 -1 #f))
+
+        (test-equal "tax on sales as expected"
+          '(" " "\n" "$20.00" "$20.00" " " " " "\n" "$20.00" "$20.00" "\n" "$15.00" "$15.00" "$55.00")
+          (sxml->table-row-col sxml 1 #f 6))
+
+        (test-equal "tax on purchases as expected"
+          '(" " " " " " " " "\n" "$8.00" "\n" "$10.00" "$18.00" " " " " "$18.00")
+          (sxml->table-row-col sxml 1 #f 9)))
+
+      (set-option! options "Display" "Individual tax columns" #t)
+      (set-option! options "Display" "Individual expense columns" #t)
+      (set-option! options "Display" "Individual income columns" #t)
+      (set-option! options "Display" "Remittance amount" #t)
+      (set-option! options "Display" "Net Income" #t)
+      (set-option! options "Display" "Tax payable" #t)
+      (let ((sxml (options->sxml options "display options enabled")))
+        (test-equal "all display columns enabled"
+          '("Grand Total" " " " " "$1,055.00" "$1,000.00" "$20.00" "$35.00" "$248.00" "$230.00" "$18.00" "$807.00" "$770.00" "$37.00")
+          (sxml->table-row-col sxml 1 -1 #f))))
+
+    (test-end "display options")))

commit 66fcaa4f91566a5737cfeb3afa8dbb4b3ee5bf47
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed May 9 20:36:40 2018 +0800

    test-extras.scm: centralize (sxml->table-row-col)
    
    This is used in conjunction with (gnc:options->sxml) to extract
    html table cells.
    
    From SXML tree, retrieve, from a <table>, the th/tr/td cells as a list
    of string.

diff --git a/gnucash/report/report-system/test/test-extras.scm b/gnucash/report/report-system/test/test-extras.scm
index aef5a94..02bde41 100644
--- a/gnucash/report/report-system/test/test-extras.scm
+++ b/gnucash/report/report-system/test/test-extras.scm
@@ -23,6 +23,7 @@
 (use-modules (gnucash engine test test-extras))
 (use-modules (gnucash report report-system))
 (use-modules (sxml simple))
+(use-modules (sxml xpath))
 
 (export pattern-streamer)
 
@@ -120,3 +121,19 @@
           (format #t "*** XML error. see render output at ~a\n~a"
                   filename (gnc:html-render-options-changed options #t))
           (throw k args))))))
+
+(export sxml->table-row-col)
+(define (sxml->table-row-col sxml tbl row col)
+  ;; sxml - sxml input tree
+  ;; tbl - table number (e.g. 2 = second table in tree)
+  ;; row - row number (negative counts from bottom) or #f (all rows)
+  ;;       or zero (retrieves <th> headers)
+  ;; col - col number (negative counts from right) or all cols
+  ;;
+  ;; output: list-of-string
+  (let* ((tbl-path `(table ,tbl))
+         (row-path (if (and row (not (zero? row))) `(tr ,row) 'tr))
+         (col-tag  (if (and row (zero? row)) 'th 'td))
+         (col-path (if col `(,col-tag ,col) col-tag))
+         (xpath `(// ,tbl-path // ,row-path // ,col-path // *text*)))
+    ((sxpath xpath) sxml)))
diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index 7a88e59..df83c84 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -94,29 +94,7 @@
   (gnc:options->sxml trep-uuid options "test-trep" test-title))
 
 (define (get-row-col sxml row col)
-  ;; sxml, row & col (numbers or #f) -> list-of-string
-  ;;
-  ;; from an SXML table tree with tr/th/td elements, retrieve row/col
-  ;; if row  =  0 retrieve <tr><th> elements
-  ;; if row  = #f retrieve whole <td> col, excludes <th> cols
-  ;; if col  = #f retrieve whole <tr> row
-  ;; if both = #f retrieve all text elements
-  ;;
-  ;; NOTE: This will retrieve cells from the first table in the tree.
-  ;; If there are multiple tables, I recommend that the tree is first
-  ;; pruned to the desired table via e.g. '(// (table 2)) then sent as
-  ;; argument to this function.
-  (let ((xpath (cond
-                ((not (or row col))             '(// (table 1) // tr // *text*))
-                ((not row)                      `(// (table 1) // tr // (td ,col) // *text*))
-                ((and (equal? row 0) (not col)) '(// (table 1) // tr // th // *text*))
-                ((not col)                      `(// (table 1) // (tr ,row) // td // *text*))
-                ((equal? row 0)                 `(// (table 1) // tr // (th ,col) // *text*))
-                (else                           `(// (table 1) // (tr ,row) // (td ,col) // *text*)))))
-    ((sxpath xpath) sxml)))
-;;
-;; END CANDIDATES
-;;
+  (sxml->table-row-col sxml 1 row col))
 
 (define (set-option! options section name value)
   (let ((option (gnc:lookup-option options section name)))

commit bb551af9482b786088086ba2eabf1ada3cd778a7
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 8 23:52:24 2018 +0800

    collectors.scm: rewrite binary-search-lt to be clearer

diff --git a/gnucash/report/report-system/collectors.scm b/gnucash/report/report-system/collectors.scm
index 28b9ee7..5470d93 100644
--- a/gnucash/report/report-system/collectors.scm
+++ b/gnucash/report/report-system/collectors.scm
@@ -333,15 +333,15 @@
 ;; Binary search. Returns highest index with content less than or
 ;; equal to the supplied value.
 
-(define (binary-search-lt <= value vector)
-  (define (search low high)
-    (let* ((midpoint (+ low (ceiling (/ (- high low) 2))))
-	   (midvalue (vector-ref vector midpoint)))
-      (if (= low high)
-	  (if (<= midvalue value)
-	      low #f)
-	  (if (<= midvalue value)
-	      (search midpoint high)
-	      (search low (- midpoint 1))))))
-  (if (= 0 (vector-length vector)) #f
-      (search 0 (- (vector-length vector) 1))))
+(define (binary-search-lt <= val vec)
+  (and (not (zero? (vector-length vec)))
+       (let loop ((low 0)
+                  (high (1- (vector-length vec))))
+         (let* ((midpoint (ceiling (/ (+ low high) 2)))
+                (midvalue (vector-ref vec midpoint)))
+           (if (= low high)
+               (and (<= midvalue val)
+                    low)
+               (if (<= midvalue val)
+                   (loop midpoint high)
+                   (loop low (1- midpoint))))))))

commit 4e85102682909c68cbf8612aa0df0fd7d65c9603
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 8 23:47:46 2018 +0800

    report-system/cmakelists: fix scm_test_report_system_SOURCES
    
    These tests were disabled by mistake in cbd87647806ca3700d2ead8a6623b758a07ba2a7

diff --git a/gnucash/report/report-system/test/CMakeLists.txt b/gnucash/report/report-system/test/CMakeLists.txt
index efd6607..52ab315 100644
--- a/gnucash/report/report-system/test/CMakeLists.txt
+++ b/gnucash/report/report-system/test/CMakeLists.txt
@@ -13,7 +13,7 @@ set(scm_test_report_system_SOURCES
   test-load-report-system-module.scm
   test-collectors.scm
   test-report-utilities.scm
-# test-test-extras.scm ;;FIXME why is this not run
+  test-test-extras.scm
 )
 
 set (scm_test_report_system_with_srfi64_SOURCES
@@ -30,7 +30,7 @@ set(GUILE_DEPENDS
   scm-scm
   scm-report-system-3
   )
-gnc_add_scheme_tests(${scm_test_report_system_SOURCES})
+gnc_add_scheme_tests("${scm_test_report_system_SOURCES}")
 
 if (HAVE_SRFI64)
   gnc_add_scheme_tests ("${scm_test_report_system_with_srfi64_SOURCES}")

commit 4c55141d963452a2381a5bd5b3d4fe31bde2cd2c
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 8 23:05:59 2018 +0800

    html-utilities.scm: simplify

diff --git a/gnucash/report/report-system/html-utilities.scm b/gnucash/report/report-system/html-utilities.scm
index a701ff2..f67a9a5 100644
--- a/gnucash/report/report-system/html-utilities.scm
+++ b/gnucash/report/report-system/html-utilities.scm
@@ -27,9 +27,7 @@
 ;; returns a list with n #f (empty cell) values 
 (define (gnc:html-make-empty-cell) #f)
 (define (gnc:html-make-empty-cells n)
-  (if (> n 0)
-      (cons #f (gnc:html-make-empty-cells (- n 1)))
-      (list)))
+  (make-list n #f))
 
 (define (gnc:register-guid type guid)
   (gnc-build-url URL-TYPE-REGISTER (string-append type guid) ""))
@@ -816,8 +814,8 @@
     (gnc:html-markup-p
      (gnc:html-markup-anchor
       (gnc-build-url URL-TYPE-OPTIONS
-       (string-append "report-id=" (format #f "~a" report-id))
-       "")
+                     (format #f "report-id=~a" report-id)
+                     "")
       (_ "Edit report options")))))
 
 (define* (gnc:html-render-options-changed options #:optional plaintext?)

commit ded88b01dd4e9a80000eca2736a81e66567dc260
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 8 23:03:46 2018 +0800

    list-extras.scm: trim useless utility functions
    
    These functions are either better defined in R5RS (list-min-max),
    unused (function-compose), or being defined in the .scm using
    them (list-leaves).

diff --git a/gnucash/report/report-system/CMakeLists.txt b/gnucash/report/report-system/CMakeLists.txt
index a9116b3..d1887b4 100644
--- a/gnucash/report/report-system/CMakeLists.txt
+++ b/gnucash/report/report-system/CMakeLists.txt
@@ -52,7 +52,6 @@ set (report_system_SCHEME
 
 set (report_system_SCHEME_2a
     collectors.scm
-    list-extras.scm
 )
 
 set (report_system_SCHEME_2b
diff --git a/gnucash/report/report-system/list-extras.scm b/gnucash/report/report-system/list-extras.scm
deleted file mode 100644
index 3c35445..0000000
--- a/gnucash/report/report-system/list-extras.scm
+++ /dev/null
@@ -1,47 +0,0 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2 of
-;; the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, contact:
-;;
-;; Free Software Foundation           Voice:  +1-617-542-5942
-;; 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
-;; Boston, MA  02110-1301,  USA       gnu at gnu.org
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(define-module (gnucash report report-system list-extras))
-(use-modules (srfi srfi-1))
-
-(export list-min-max)
-(export list-leaves)
-(export function-compose)
-
-(define (list-min-max list ordered?)
-  (define (helper list min max)
-    (if (null? list) (cons min max)
-	(let ((elt (car list)))
-	  (helper (cdr list)
-		(if (ordered? elt min) elt min)
-		(if (ordered? elt max) max elt)))))
-  (helper (cdr list) (car list) (car list)))
-
-(define (list-leaves list)
-  (if (not (pair? list))
-      (cons list '())
-      (fold (lambda (next acc)
-	      (append (list-leaves next)
-		      acc))
-	    '()
-	    list)))
-
-(define (function-compose f1 f2)
-  (lambda a
-    (f1 (apply f2 a))))
diff --git a/gnucash/report/report-system/report-collectors.scm b/gnucash/report/report-system/report-collectors.scm
index 523c8a7..1e0b3a6 100644
--- a/gnucash/report/report-system/report-collectors.scm
+++ b/gnucash/report/report-system/report-collectors.scm
@@ -30,7 +30,6 @@
 (use-modules (gnucash app-utils))
 (use-modules (gnucash engine))
 (use-modules (gnucash report report-system collectors))
-(use-modules (gnucash report report-system list-extras))
 
 (export account-destination-alist)
 (export category-by-account-report)
@@ -150,13 +149,13 @@
     (splits-up-to (map car account-alist) min-date max-date)))
 
 (define (category-report-dates-intervals dates)
-  (let* ((min-date (car (list-min-max (map first dates) <)))
-         (max-date (cdr (list-min-max (map second dates) <))))
+  (let* ((min-date (apply min (map first dates)))
+         (max-date (apply max (map second dates))))
     (list min-date max-date dates)))
 
 (define (category-report-dates-accumulate dates)
   (let* ((min-date #f)
-         (max-date (cdr (list-min-max dates <)))
+         (max-date (apply max dates))
          (datepairs (reverse! (cdr (fold (lambda (next acc)
                                            (let ((prev (car acc))
                                                  (pairs-so-far (cdr acc)))
diff --git a/gnucash/report/report-system/test/CMakeLists.txt b/gnucash/report/report-system/test/CMakeLists.txt
index 67137bf..efd6607 100644
--- a/gnucash/report/report-system/test/CMakeLists.txt
+++ b/gnucash/report/report-system/test/CMakeLists.txt
@@ -12,7 +12,6 @@ gnc_add_test_with_guile(test-link-module-report-system test-link-module.c
 set(scm_test_report_system_SOURCES
   test-load-report-system-module.scm
   test-collectors.scm
-  test-list-extras.scm
   test-report-utilities.scm
 # test-test-extras.scm ;;FIXME why is this not run
 )
diff --git a/gnucash/report/report-system/test/test-list-extras.scm b/gnucash/report/report-system/test/test-list-extras.scm
deleted file mode 100644
index 46f04b5..0000000
--- a/gnucash/report/report-system/test/test-list-extras.scm
+++ /dev/null
@@ -1,42 +0,0 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2 of
-;; the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, contact:
-;;
-;; Free Software Foundation           Voice:  +1-617-542-5942
-;; 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
-;; Boston, MA  02110-1301,  USA       gnu at gnu.org
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(debug-set! stack 50000)
-(use-modules (gnucash gnc-module))
-(gnc:module-begin-syntax (gnc:module-load "gnucash/app-utils" 0))
-(use-modules (gnucash report report-system list-extras))
-(use-modules (gnucash engine test test-extras))
-
-(define (run-test)
-    (test test-list-min-max))
-
-(define (test-list-min-max)
-  (and (equal? (cons 1 1) (list-min-max (list 1) <))
-       (equal? (cons 1 2) (list-min-max (list 1 2) <))       
-       (equal? (cons 1 2) (list-min-max (list 2 1) <))       
-       (equal? (cons 1 2) (list-min-max (list 1 1 2) <))
-       (equal? (cons 1 2) (list-min-max (list 1 2 1) <))
-       (equal? (cons 1 2) (list-min-max (list 1 2 2) <))
-       (equal? (cons 1 2) (list-min-max (list 2 1 1) <))
-       (equal? (cons 1 2) (list-min-max (list 2 2 1) <))
-       (equal? (cons 1 3) (list-min-max (list 1 1 3) <))
-       (equal? (cons 1 3) (list-min-max (list 1 2 3) <))
-       (equal? (cons 1 3) (list-min-max (list 1 3 2) <))
-       (equal? (cons 1 3) (list-min-max (list 2 3 1) <))
-       (equal? (cons 1 3) (list-min-max (list 3 2 1) <))))

commit 1df7fb4048e8484fae4305d185e39a57305455ef
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 8 22:41:12 2018 +0800

    html-text.scm: schemify

diff --git a/gnucash/report/report-system/html-text.scm b/gnucash/report/report-system/html-text.scm
index ec903fa..b68ed2c 100644
--- a/gnucash/report/report-system/html-text.scm
+++ b/gnucash/report/report-system/html-text.scm
@@ -190,7 +190,7 @@
 (define (gnc:html-markup-anchor href . rest)
   (apply gnc:html-markup/attr 
          "a" 
-         (string-append "href=\"" href "\"")
+         (format #f "href=~s" href)
          rest))
 
 (define (gnc:html-markup-img src . rest)
@@ -198,15 +198,11 @@
    "img" 
    (with-output-to-string
      (lambda ()
-       (display "src=\"") (display src) (display"\"")
-       (display " ")
        (for-each 
         (lambda (kvp)
-          (display (car kvp))
-          (display "=\"")
-          (display (cadr kvp))
-          (display "\" "))
-        rest)))))
+          (format #f "~a=~s " (car kvp) (cadr kvp)))
+        (cons (list 'src src)
+              rest))))))
 
 (define (gnc:html-text-render p doc)
   (let* ((retval '())

commit d4cb87fe3d923cc6490168a27f91a24b65a02553
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun May 6 17:26:28 2018 +0800

    business-report/test: create test directory
    
    These tests will all be SRFI-64 based.

diff --git a/gnucash/report/business-reports/CMakeLists.txt b/gnucash/report/business-reports/CMakeLists.txt
index ee02ff4..9217934 100644
--- a/gnucash/report/business-reports/CMakeLists.txt
+++ b/gnucash/report/business-reports/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory (test)
 
 set (business_reports_SCHEME
   aging.scm
diff --git a/gnucash/report/business-reports/test/CMakeLists.txt b/gnucash/report/business-reports/test/CMakeLists.txt
new file mode 100644
index 0000000..9c62903
--- /dev/null
+++ b/gnucash/report/business-reports/test/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+set(scm_test_business_reports_with_srfi64_SOURCES
+)
+
+set(GUILE_DEPENDS
+  scm-gnc-module
+  scm-app-utils
+  scm-engine
+  scm-test-engine
+  scm-gettext
+  scm-scm
+  scm-test-report-system
+  scm-report-stylesheets
+  )
+
+if (HAVE_SRFI64)
+  gnc_add_scheme_tests("${scm_test_business_reports_with_srfi64_SOURCES}")
+endif (HAVE_SRFI64)
+
+gnc_add_scheme_targets(scm-test-business-reports
+  "${scm_test_business_reports_SOURCES}"
+  gnucash/report/business-reports/test
+  "scm-test-business-support"
+  FALSE
+)
+
+add_dependencies(check scm-test-business-reports)
+
+set_dist_list(test_business_reports_DIST CMakeLists.txt
+  ${scm_test_business_reports_with_srfi64_SOURCES}
+  )

commit 23410ca429aead77deeb271416bd461598f3bfdf
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun May 6 23:39:45 2018 +0800

    html-table.scm: centralize (gnc:html-table-set-last-row-style!)
    
    This html-table modifier seems common enough to centralize into
    html-table.scm.

diff --git a/gnucash/report/business-reports/customer-summary.scm b/gnucash/report/business-reports/customer-summary.scm
index 376bc0a..c8bc60b 100644
--- a/gnucash/report/business-reports/customer-summary.scm
+++ b/gnucash/report/business-reports/customer-summary.scm
@@ -97,13 +97,6 @@
 
 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define (set-last-row-style! table tag . rest)
-  (let ((arg-list 
-         (cons table 
-               (cons (- (gnc:html-table-num-rows table) 1)
-                     (cons tag rest)))))
-    (apply gnc:html-table-set-row-style! arg-list)))
-
 (define (date-col columns-used)
   (vector-ref columns-used 0))
 (define (num-col columns-used)
@@ -591,7 +584,7 @@
     (gnc:html-table-append-row!
      table
      (list "<br>"))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
@@ -609,7 +602,7 @@
      table "table"
      'attribute (list "border" 0)
      'attribute (list "cellpadding" 0))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
diff --git a/gnucash/report/business-reports/easy-invoice.scm b/gnucash/report/business-reports/easy-invoice.scm
index eb294b0..6a80711 100644
--- a/gnucash/report/business-reports/easy-invoice.scm
+++ b/gnucash/report/business-reports/easy-invoice.scm
@@ -39,13 +39,6 @@
 (use-modules (gnucash report standard-reports))
 (use-modules (gnucash report business-reports))
 
-(define (set-last-row-style! table tag . rest)
-  (let ((arg-list
-         (cons table
-               (cons (- (gnc:html-table-num-rows table) 1)
-                     (cons tag rest)))))
-    (apply gnc:html-table-set-row-style! arg-list)))
-
 (define (date-col columns-used)
   (vector-ref columns-used 0))
 (define (description-col columns-used)
@@ -585,7 +578,7 @@
 	       ;; This string is supposed to be an abbrev. for "Reference"?
 	       (string-append (_ "REF") ": " reference))))))
      orders)
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
@@ -605,7 +598,7 @@
      table "table"
      'attribute (list "border" 0)
      'attribute (list "cellpadding" 0))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
diff --git a/gnucash/report/business-reports/fancy-invoice.scm b/gnucash/report/business-reports/fancy-invoice.scm
index ddb2794..a7c7809 100644
--- a/gnucash/report/business-reports/fancy-invoice.scm
+++ b/gnucash/report/business-reports/fancy-invoice.scm
@@ -57,13 +57,6 @@
 (use-modules (gnucash report standard-reports))
 (use-modules (gnucash report business-reports))
 
-(define (set-last-row-style! table tag . rest)
-  (let ((arg-list
-         (cons table
-               (cons (- (gnc:html-table-num-rows table) 1)
-                     (cons tag rest)))))
-    (apply gnc:html-table-set-row-style! arg-list)))
-
 (define (date-col columns-used)
   (vector-ref columns-used 0))
 (define (description-col columns-used)
@@ -646,7 +639,7 @@
 	      (list
 	       (string-append (_ "REF") ": " reference))))))
      orders)
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
@@ -671,7 +664,7 @@
      table "table"
      'attribute (list "border" 0)
      'attribute (list "cellpadding" 0))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
diff --git a/gnucash/report/business-reports/invoice.scm b/gnucash/report/business-reports/invoice.scm
index 6b6b22c..447d9d1 100644
--- a/gnucash/report/business-reports/invoice.scm
+++ b/gnucash/report/business-reports/invoice.scm
@@ -33,13 +33,6 @@
 (use-modules (gnucash report standard-reports))
 (use-modules (gnucash report business-reports))
 
-(define (set-last-row-style! table tag . rest)
-  (let ((arg-list
-         (cons table
-               (cons (- (gnc:html-table-num-rows table) 1)
-                     (cons tag rest)))))
-    (apply gnc:html-table-set-row-style! arg-list)))
-
 (define (date-col columns-used)
   (vector-ref columns-used 0))
 (define (description-col columns-used)
@@ -561,7 +554,7 @@
 	      (list
 	       (string-append (_ "REF") ": " reference))))))
      orders)
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
@@ -582,7 +575,7 @@
      table "table"
      'attribute (list "border" 0)
      'attribute (list "cellpadding" 0))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
diff --git a/gnucash/report/business-reports/job-report.scm b/gnucash/report/business-reports/job-report.scm
index 8eb55ac..40b2bbf 100644
--- a/gnucash/report/business-reports/job-report.scm
+++ b/gnucash/report/business-reports/job-report.scm
@@ -46,13 +46,6 @@
 (define desc-header (N_ "Description"))
 (define amount-header (N_ "Amount"))
 
-(define (set-last-row-style! table tag . rest)
-  (let ((arg-list 
-         (cons table 
-               (cons (- (gnc:html-table-num-rows table) 1)
-                     (cons tag rest)))))
-    (apply gnc:html-table-set-row-style! arg-list)))
-
 (define (date-col columns-used)
   (vector-ref columns-used 0))
 (define (date-due-col columns-used)
@@ -479,7 +472,7 @@
     (gnc:html-table-append-row!
      table
      (list "<br/>"))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
@@ -497,7 +490,7 @@
      table "table"
      'attribute (list "border" 0)
      'attribute (list "cellpadding" 0))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
diff --git a/gnucash/report/business-reports/owner-report.scm b/gnucash/report/business-reports/owner-report.scm
index 89f48cd..20d8e28 100644
--- a/gnucash/report/business-reports/owner-report.scm
+++ b/gnucash/report/business-reports/owner-report.scm
@@ -117,13 +117,6 @@
         (else
           (_ "Vendor")))) 
 
-(define (set-last-row-style! table tag . rest)
-  (let ((arg-list 
-         (cons table 
-               (cons (- (gnc:html-table-num-rows table) 1)
-                     (cons tag rest)))))
-    (apply gnc:html-table-set-row-style! arg-list)))
-
 (define (date-col columns-used)
   (vector-ref columns-used 0))
 (define (date-due-col columns-used)
@@ -689,7 +682,7 @@
     (gnc:html-table-append-row!
      table
      (list "<br>"))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
@@ -707,7 +700,7 @@
      table "table"
      'attribute (list "border" 0)
      'attribute (list "cellpadding" 0))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
diff --git a/gnucash/report/report-system/html-table.scm b/gnucash/report/report-system/html-table.scm
index e33e6d6..405e4ad 100644
--- a/gnucash/report/report-system/html-table.scm
+++ b/gnucash/report/report-system/html-table.scm
@@ -756,3 +756,10 @@
     (push (gnc:html-document-markup-end doc "table"))
     (gnc:html-document-pop-style doc)
     retval))
+
+(define (gnc:html-table-set-last-row-style! table tag . rest)
+  (let ((arg-list
+         (cons table
+               (cons (1- (gnc:html-table-num-rows table))
+                     (cons tag rest)))))
+    (apply gnc:html-table-set-row-style! arg-list)))
diff --git a/gnucash/report/report-system/report-system.scm b/gnucash/report/report-system/report-system.scm
index 1ea0a3f..3ed2b71 100644
--- a/gnucash/report/report-system/report-system.scm
+++ b/gnucash/report/report-system/report-system.scm
@@ -601,6 +601,7 @@
 (export gnc:html-table-set-col-headers-style!)
 (export gnc:html-table-row-headers-style)
 (export gnc:html-table-set-row-headers-style!)
+(export gnc:html-table-set-last-row-style!)
 (export gnc:html-table-set-style!)
 (export gnc:html-table-set-col-style!)
 (export gnc:html-table-set-row-style!)
diff --git a/gnucash/report/standard-reports/register.scm b/gnucash/report/standard-reports/register.scm
index 063b408..08195b3 100644
--- a/gnucash/report/standard-reports/register.scm
+++ b/gnucash/report/standard-reports/register.scm
@@ -29,13 +29,6 @@
 
 (gnc:module-load "gnucash/report/report-system" 0)
 
-(define (set-last-row-style! table tag . rest)
-  (let ((arg-list 
-         (cons table 
-               (cons (- (gnc:html-table-num-rows table) 1)
-                     (cons tag rest)))))
-    (apply gnc:html-table-set-row-style! arg-list)))
-
 (define (date-col columns-used)
   (vector-ref columns-used 0))
 (define (num-col columns-used)
@@ -790,7 +783,7 @@
      (list
       (string-append (_ "Client") ": ")
       (string-expand address #\newline "<br>")))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))
@@ -810,7 +803,7 @@
        (string-expand (qof-print-date (current-time))
                       #\space " "))
       (make-client-table address)))
-    (set-last-row-style!
+    (gnc:html-table-set-last-row-style!
      table "td"
      'attribute (list "valign" "top"))
     table))

commit 97ab1b19fe081e06fe59d994294ae34e70291f75
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat May 5 23:07:52 2018 +0800

    test-date-utilities.scm: to SRFI64
    
    Clearer syntax helped find flawed test - while set-tm:mday directly
    accepts 1-31, set-tm:mon accepts 0-11 to represent 1-12, therefore
    must minus 1. set-tm:year accepts 92 to represent 1992, therefore must
    minus 1900.

diff --git a/libgnucash/app-utils/test/CMakeLists.txt b/libgnucash/app-utils/test/CMakeLists.txt
index 2fed2b9..8995b45 100644
--- a/libgnucash/app-utils/test/CMakeLists.txt
+++ b/libgnucash/app-utils/test/CMakeLists.txt
@@ -43,6 +43,9 @@ set(GUILE_DEPENDS
 set(test_app_utils_scheme_SOURCES
   test-c-interface.scm
   test-load-app-utils-module.scm
+)
+
+set (test_app_utils_scheme_SRFI64_SOURCES
   test-date-utilities.scm
 )
 
@@ -61,6 +64,11 @@ gnc_add_scheme_targets(scm-test-c-interface
 )
 
 gnc_add_scheme_tests("${test_app_utils_scheme_SOURCES}")
+
+if (HAVE_SRFI64)
+  gnc_add_scheme_tests("${test_app_utils_scheme_SRFI64_SOURCES}")
+endif ()
+
 # Doesn't work yet:
 gnc_add_test_with_guile(test-app-utils "${test_app_utils_SOURCES}" APP_UTILS_TEST_INCLUDE_DIRS APP_UTILS_TEST_LIBS)
 
diff --git a/libgnucash/app-utils/test/test-date-utilities.scm b/libgnucash/app-utils/test/test-date-utilities.scm
index 1dc30e1..51eb981 100644
--- a/libgnucash/app-utils/test/test-date-utilities.scm
+++ b/libgnucash/app-utils/test/test-date-utilities.scm
@@ -1,10 +1,15 @@
 (use-modules (gnucash gnc-module))
 (gnc:module-begin-syntax (gnc:module-load "gnucash/app-utils" 0))
 (use-modules (gnucash engine test test-extras))
+(use-modules (srfi srfi-64))
+(use-modules (gnucash engine test srfi64-extras))
 
 (define (run-test)
-  (and (test test-weeknum-calculator)
-       (test test-date-get-quarter-string)))
+  (test-runner-factory gnc:test-runner)
+  (test-begin "test-date-utilities.scm")
+  (test-weeknum-calculator)
+  (test-date-get-quarter-string)
+  (test-end "test-date-utilities.scm"))
 
 (define (create-datevec l)
   (let ((now (gnc-localtime (current-time))))
@@ -12,8 +17,8 @@
     (set-tm:min now (list-ref l 4))
     (set-tm:hour now (list-ref l 3))
     (set-tm:mday now (list-ref l 2))
-    (set-tm:mon now (list-ref l 1))
-    (set-tm:year now (list-ref l 0))
+    (set-tm:mon now (1- (list-ref l 1)))
+    (set-tm:year now (- (list-ref l 0) 1900))
     (set-tm:isdst now -1)
     now))
 
@@ -28,28 +33,39 @@
             (gnc:date-to-week (create-time64 d2)))))
 
 (define (test-weeknum-calculator)
-  (and (weeknums-equal? (cons '(1970 1 1 0 0 0)
-                              '(1970 1 1 23 59 59)))
-       (weeknums-equal? (cons '(1969 12 31 0 0 0)
-                              '(1969 12 31 23 59 59)))
-       (weeknums-equal? (cons '(1969 12 31 0 0 0)
-                              '(1970 1 1 0 0 1)))
-       (weeknums-equal? (cons '(2001 1 1 0 0 0)
-                              '(2001 1 1 23 59 59)))
-       (not (weeknums-equal? (cons '(1970 1 1 0 0 0)
-                                   '(1970 1 10 0 0 1))))
-       (not (weeknums-equal? (cons '(1969 12 28 0 0 1)
-                                   '(1970 1 5 0 0 1))))
-       ))
+  (test-assert "weeknums 1/1/70early = 1/1/70late"
+    (weeknums-equal? (cons '(1970 1 1 0 0 0)
+                           '(1970 1 1 23 59 59))))
+
+  (test-assert "weeknums 31/12/69early = 31/12/69late"
+    (weeknums-equal? (cons '(1969 12 31 0 0 0)
+                           '(1969 12 31 23 59 59))))
+
+  (test-assert "weeknums 31/12/69 = 1/1/70"
+    (weeknums-equal? (cons '(1969 12 31 0 0 0)
+                           '(1970 1 1 0 0 1))))
+
+  (test-assert "weeknums 1/1/01early = 01/01/01 late"
+    (weeknums-equal? (cons '(2001 1 1 0 0 0)
+                           '(2001 1 1 23 59 59))))
+
+  (test-assert "weeknums 1/1/70 != 10/1/70"
+    (not (weeknums-equal? (cons '(1970 1 1 0 0 0)
+                                '(1970 1 10 0 0 1)))))
+
+  (test-assert "weeknum 28/12/69 != 5/1/70"
+    (not (weeknums-equal? (cons '(1969 12 28 0 0 1)
+                                '(1970 1 5 0 0 1))))))
 
 (define (test-date-get-quarter-string)
-  (and (or (string=? "Q1" (gnc:date-get-quarter-string (create-datevec '(2001 2 14 11 42 23))))
-           (begin (format #t "Expected Q1, got ~a~%" (gnc:date-get-quarter-string (creaete-datevec '(2001 2 14 11 42 23))))
-                  #f))
-       (or (string=? "Q2" (gnc:date-get-quarter-string (create-datevec '(2013 4 23 18 11 49))))
-           (begin (format #t "Expected Q1, got ~a~%" (gnc:date-get-quarter-string (create-datevec '(2001 2 14 11 42 23))))
-                  #f))
-       (or (string=? "Q3" (gnc:date-get-quarter-string (create-datevec '(1997 9 11 08 14 21))))
-           (begin (format #t "Expected Q1, got ~a~%" (gnc:date-get-quarter-string (create-datevec '(2001 2 14 11 42 23)))))
-           #f)))
-       
+  (test-equal "14/02/2001 = Q1"
+    "Q1"
+    (gnc:date-get-quarter-string (create-datevec '(2001 2 14 11 42 23))))
+
+  (test-equal "23/04/2013 = Q2"
+    "Q2"
+    (gnc:date-get-quarter-string (create-datevec '(2013 4 23 18 11 49))))
+
+  (test-equal "11/09/1997 = Q3"
+    "Q3"
+    (gnc:date-get-quarter-string (create-datevec '(1997 9 11 08 14 21)))))

commit 13f31e0691a60af2c1b1e70152060bb76bec92b6
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon May 7 19:04:22 2018 +0800

    test-extras.scm: (logging-and) is obsolete
    
    Use the much nicer SRFI-64 forms instead.

diff --git a/gnucash/report/report-system/test/test-test-extras.scm b/gnucash/report/report-system/test/test-test-extras.scm
index f551748..676d130 100644
--- a/gnucash/report/report-system/test/test-test-extras.scm
+++ b/gnucash/report/report-system/test/test-test-extras.scm
@@ -24,10 +24,7 @@
 (use-modules (ice-9 streams))
 
 (define (run-test)
-  (and (logging-and #t)
-       (logging-and)
-       (not (logging-and #t #f))
-       (test-pattern-streamer)
+  (and (test-pattern-streamer)
        (test-create-account-structure)))
 
 (define (test-pattern-streamer)
diff --git a/gnucash/report/standard-reports/test/test-cashflow-barchart.scm b/gnucash/report/standard-reports/test/test-cashflow-barchart.scm
index 156f48f..248468a 100644
--- a/gnucash/report/standard-reports/test/test-cashflow-barchart.scm
+++ b/gnucash/report/standard-reports/test/test-cashflow-barchart.scm
@@ -39,9 +39,9 @@
 (setlocale LC_ALL "C")
 
 (define (run-test)
-  (logging-and (test-in-txn)
-               (test-out-txn)
-               (test-null-txn)))
+  (and (test-in-txn)
+       (test-out-txn)
+       (test-null-txn)))
 
 
 (define (set-option report page tag value)
diff --git a/gnucash/report/standard-reports/test/test-generic-net-barchart.scm b/gnucash/report/standard-reports/test/test-generic-net-barchart.scm
index c4a4bc2..d8585bb 100644
--- a/gnucash/report/standard-reports/test/test-generic-net-barchart.scm
+++ b/gnucash/report/standard-reports/test/test-generic-net-barchart.scm
@@ -40,15 +40,15 @@
 (define constructor (record-constructor <report>))
 
 (define (run-net-asset-income-test asset-report-uuid income-report-uuid)
-  (logging-and  (two-txn-test asset-report-uuid)
-		(two-txn-test-2 asset-report-uuid)
-		(two-txn-test-income income-report-uuid)
+  (and (two-txn-test asset-report-uuid)
+       (two-txn-test-2 asset-report-uuid)
+       (two-txn-test-income income-report-uuid)
 
-		(null-test asset-report-uuid)
-		(null-test income-report-uuid)
-		(single-txn-test asset-report-uuid)
-		(closing-test income-report-uuid)
-		#t))
+       (null-test asset-report-uuid)
+       (null-test income-report-uuid)
+       (single-txn-test asset-report-uuid)
+       (closing-test income-report-uuid)
+       #t))
 
 ;; Just prove that the report exists.
 (define (null-test uuid)
diff --git a/gnucash/report/standard-reports/test/test-generic-net-linechart.scm b/gnucash/report/standard-reports/test/test-generic-net-linechart.scm
index 4b12934..a59197a 100644
--- a/gnucash/report/standard-reports/test/test-generic-net-linechart.scm
+++ b/gnucash/report/standard-reports/test/test-generic-net-linechart.scm
@@ -40,13 +40,11 @@
 (define constructor (record-constructor <report>))
 
 (define (run-net-asset-test asset-report-uuid)
-  (logging-and  (two-txn-test asset-report-uuid)
-		(two-txn-test-2 asset-report-uuid)
+  (and (two-txn-test asset-report-uuid)
+       (two-txn-test-2 asset-report-uuid)
 
-		(null-test asset-report-uuid)
-		(single-txn-test asset-report-uuid)
-
-		#t))
+       (null-test asset-report-uuid)
+       (single-txn-test asset-report-uuid)))
 
 ;; Just prove that the report exists.
 (define (null-test uuid)
diff --git a/libgnucash/engine/test/test-extras.scm b/libgnucash/engine/test/test-extras.scm
index 9309e56..32712a6 100644
--- a/libgnucash/engine/test/test-extras.scm
+++ b/libgnucash/engine/test/test-extras.scm
@@ -27,7 +27,6 @@
 (use-modules (sw_app_utils))
 (use-modules (sw_engine))
 
-(export logging-and)
 (export test)
 
 (export with-account)
@@ -55,15 +54,6 @@
 ;; Random test related syntax and the like
 ;;
 
-;; logging-and is mostly for debugging tests
-(define-macro (logging-and . args)
-  (cons 'and (map (lambda (arg)
-		    (list 'begin
-			  (list 'format #t "Test: ~a\n" (list 'quote arg))
-			  arg))
-		  args)))
-
-;; ..and 'test' gives nicer output
 (define (test the-test)
   (format #t "(Running ~a " the-test)
   (let ((result (the-test)))
diff --git a/libgnucash/engine/test/test-test-extras.scm b/libgnucash/engine/test/test-test-extras.scm
index e735dae..cc70e6f 100644
--- a/libgnucash/engine/test/test-test-extras.scm
+++ b/libgnucash/engine/test/test-test-extras.scm
@@ -26,10 +26,7 @@
 (use-modules (sw_engine))
 
 (define (run-test)
-  (and (logging-and #t)
-       (logging-and)
-       (not (logging-and #t #f))
-       (test-create-account-structure)))
+ (test-create-account-structure))
 
 (define (test-create-account-structure)
   (let ((env (create-test-env)))

commit 5e0fc04f7ba8df4ed28823cc9248b5dae7c66f4c
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun May 6 22:58:38 2018 +0800

    test-extras.scm: remove dead code
    
    These functions are never used through code.

diff --git a/gnucash/report/report-system/test/test-extras.scm b/gnucash/report/report-system/test/test-extras.scm
index 7184d84..aef5a94 100644
--- a/gnucash/report/report-system/test/test-extras.scm
+++ b/gnucash/report/report-system/test/test-extras.scm
@@ -26,19 +26,12 @@
 
 (export pattern-streamer)
 
-(export create-option-set)
-(export option-set-setter)
-(export option-set-getter)
-
 (export tbl-column-count)
 (export tbl-row-count)
 (export tbl-ref)
 (export tbl-ref->number)
 
 (export gnc:options->sxml)
-;;
-;; Random report test related syntax and the like
-;;
 
 ;;
 ;; Table parsing
@@ -91,71 +84,6 @@
 (define (tbl-ref->number tbl row-index column-index)
   (string->number (car (tbl-ref tbl row-index column-index))))
 
-;;
-;; Test sinks
-;;
-
-(define (make-test-sink) (list 'sink 0 '()))
-
-(define (test-sink-count sink)
-  (second sink))
-
-(define (test-sink-count! sink value)
-  (set-car! (cdr sink) value))
-
-(define (test-sink-messages sink)
-  (third sink))
-
-(define (test-sink-messages! sink messages)
-  (set-car! (cdr (cdr sink)) messages))
-
-(define (test-sink-check sink message flag)
-  (test-sink-count! sink (+ (test-sink-count sink) 1))
-  (if flag #t
-      (test-sink-messages! sink (cons message (test-sink-messages sink)))))
-
-(define (test-sink-report sink)
-  (format #t "Completed ~a tests ~a\n"
-	  (test-sink-count sink)
-	  (if (null? (test-sink-messages sink)) "PASS" "FAIL"))
-  (if (null? (test-sink-messages sink)) #t
-      (begin (for-each (lambda (delayed-message)
-			 (delayed-format-render #t delayed-message))
-		       (test-sink-messages sink))
-	     #f)))
-
-(define (delayed-format . x) x)
-
-(define (delayed-format-render stream msg)
-  (apply format stream msg))
-
-;;
-;; options
-;;
-
-
-(define (create-option-set)
-  (make-hash-table) )
-
-(define (option-set-setter option-set)
-  (lambda (category name value)
-    (hash-set! option-set (list category name) value)))
-
-(define (option-set-getter option-set)
-  (lambda (category name)
-    (hash-ref option-set (list category name))))
-
-;;
-;;
-;;
-
-(define (report-show-options stream expense-options)
-  (gnc:options-for-each (lambda (option)
-			  (format stream "Option: ~a.~a Value ~a\n"
-				  (gnc:option-section option)
-				  (gnc:option-name option)
-				  (gnc:option-value option)))
-			expense-options))
 
 (define (gnc:options->sxml uuid options prefix test-title)
   ;; uuid - str to locate report uuid
diff --git a/libgnucash/engine/test/test-extras.scm b/libgnucash/engine/test/test-extras.scm
index 1d76b19..9309e56 100644
--- a/libgnucash/engine/test/test-extras.scm
+++ b/libgnucash/engine/test/test-extras.scm
@@ -29,13 +29,6 @@
 
 (export logging-and)
 (export test)
-(export make-test-sink)
-(export env-test-sink)
-(export test-sink-report)
-(export test-sink-check)
-
-(export delayed-format)
-(export delayed-format-render)
 
 (export with-account)
 (export with-transaction)
@@ -112,8 +105,7 @@
 
 (define (create-test-env)
   (list (cons 'random (seed->random-state (random 1000)))
-	(cons 'counter (make-counter))
-	(cons 'sink (make-test-sink))))
+	(cons 'counter (make-counter))))
 
 (define (env-random-amount env n)
   (/ (env-random env n) 1))
@@ -130,9 +122,6 @@
 (define (env-select-price-source env)
   'pricedb-nearest)
 
-(define (env-test-sink env)
-  (assoc-ref env 'sink))
-
 (define (env-any-date env) (gnc:get-today))
 
 (define (env-create-transaction env date credit debit aaa)
@@ -324,69 +313,5 @@
 					    (list "Other")
 					    (list "Expenses"
 						  (list (cons 'type ACCT-TYPE-EXPENSE))))))
-;;
-;; Test sinks
-;;
-
-(define (make-test-sink) (list 'sink 0 '()))
-
-(define (test-sink-count sink)
-  (second sink))
-
-(define (test-sink-count! sink value)
-  (set-car! (cdr sink) value))
-
-(define (test-sink-messages sink)
-  (third sink))
-
-(define (test-sink-messages! sink messages)
-  (set-car! (cdr (cdr sink)) messages))
-
-(define (test-sink-check sink message flag)
-  (test-sink-count! sink (+ (test-sink-count sink) 1))
-  (if flag #t
-      (test-sink-messages! sink (cons message (test-sink-messages sink)))))
-
-(define (test-sink-report sink)
-  (format #t "Completed ~a tests ~a\n"
-	  (test-sink-count sink)
-	  (if (null? (test-sink-messages sink)) "PASS" "FAIL"))
-  (if (null? (test-sink-messages sink)) #t
-      (begin (for-each (lambda (delayed-message)
-			 (delayed-format-render #t delayed-message))
-		       (test-sink-messages sink))
-	     #f)))
-
-(define (delayed-format . x) x)
-
-(define (delayed-format-render stream msg)
-  (apply format stream msg))
-
-;;
-;; options
-;;
-
-
-(define (create-option-set)
-  (make-hash-table) )
-
-(define (option-set-setter option-set)
-  (lambda (category name value)
-    (hash-set! option-set (list category name) value)))
-
-(define (option-set-getter option-set)
-  (lambda (category name)
-    (hash-ref option-set (list category name))))
-
-;;
-;;
-;;
 
-(define (report-show-options stream expense-options)
-  (gnc:options-for-each (lambda (option)
-			  (format stream "Option: ~a.~a Value ~a\n"
-				  (gnc:option-section option)
-				  (gnc:option-name option)
-				  (gnc:option-value option)))
-			expense-options))
 

commit 8ddee96463795fd89ad6ca8359c1a64911feb361
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun May 6 20:44:36 2018 +0800

    test-extras.scm: centralize (gnc:options->sxml)
    
    I think this is useful enough to be upgraded.

diff --git a/gnucash/report/report-system/test/test-extras.scm b/gnucash/report/report-system/test/test-extras.scm
index a150f38..7184d84 100644
--- a/gnucash/report/report-system/test/test-extras.scm
+++ b/gnucash/report/report-system/test/test-extras.scm
@@ -21,6 +21,8 @@
 
 (use-modules (gnucash gnc-module))
 (use-modules (gnucash engine test test-extras))
+(use-modules (gnucash report report-system))
+(use-modules (sxml simple))
 
 (export pattern-streamer)
 
@@ -33,6 +35,7 @@
 (export tbl-ref)
 (export tbl-ref->number)
 
+(export gnc:options->sxml)
 ;;
 ;; Random report test related syntax and the like
 ;;
@@ -154,3 +157,38 @@
 				  (gnc:option-value option)))
 			expense-options))
 
+(define (gnc:options->sxml uuid options prefix test-title)
+  ;; uuid - str to locate report uuid
+  ;; options object -> sxml tree
+  ;; prefix - str describing tests e.g. "test-trep"
+  ;; test-title: str describing each unit test e.g. "test disable filter"
+  ;;
+  ;; This function abstracts the report renderer. It also catches XML
+  ;; parsing errors, dumping the options changed.
+  ;;
+  ;; It also dumps the render into /tmp/XX-YY.html where XX is the
+  ;; test prefix and YY is the test title.
+
+  (let* ((template (gnc:find-report-template uuid))
+         (constructor (record-constructor <report>))
+         (report (constructor uuid "bar" options #t #t #f #f ""))
+         (renderer (gnc:report-template-renderer template))
+         (document (renderer report))
+         (sanitize-char (lambda (c)
+                          (if (char-alphabetic? c) c #\-)))
+         (fileprefix (string-map sanitize-char prefix))
+         (filename (string-map sanitize-char test-title)))
+    (gnc:html-document-set-style-sheet! document (gnc:report-stylesheet report))
+    (if test-title
+        (gnc:html-document-set-title! document test-title))
+    (let* ((filename (format #f "/tmp/~a-~a.html" fileprefix filename))
+           (render (gnc:html-document-render document)))
+      (with-output-to-file filename
+        (lambda ()
+          (display render)))
+      (catch 'parser-error
+        (lambda () (xml->sxml render))
+        (lambda (k . args)
+          (format #t "*** XML error. see render output at ~a\n~a"
+                  filename (gnc:html-render-options-changed options #t))
+          (throw k args))))))
diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index 1dfa2fd..7a88e59 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -91,24 +91,7 @@
   ;; It also catches XML parsing errors, dumping the options changed.
   ;;
   ;; It also dumps the render into /tmp/test-trep-XX.html where XX is the test title
-  (let* ((template (gnc:find-report-template trep-uuid))
-         (report (constructor trep-uuid "bar" options #t #t #f #f ""))
-         (renderer (gnc:report-template-renderer template))
-         (document (renderer report))
-         (filename (string-map (lambda (c) (if (char-alphabetic? c) c #\-)) test-title)))
-    (gnc:html-document-set-style-sheet! document (gnc:report-stylesheet report))
-    (if test-title
-        (gnc:html-document-set-title! document test-title))
-    (let* ((filename (format #f "/tmp/test-trep-~a.html" filename))
-           (render (gnc:html-document-render document))
-           (outfile (open-file filename "w")))
-      (display render outfile)
-      (close-output-port outfile)
-      (catch 'parser-error
-        (lambda () (xml->sxml render))
-        (lambda (k . args)
-          (test-assert k #f)            ; XML parse error doesn't cause a crash but logs as a failure
-          (format #t "see render output at ~a\n~a" filename (gnc:html-render-options-changed options #t)))))))
+  (gnc:options->sxml trep-uuid options "test-trep" test-title))
 
 (define (get-row-col sxml row col)
   ;; sxml, row & col (numbers or #f) -> list-of-string
@@ -135,8 +118,6 @@
 ;; END CANDIDATES
 ;;
 
-(define constructor (record-constructor <report>))
-
 (define (set-option! options section name value)
   (let ((option (gnc:lookup-option options section name)))
     (if option

commit c6032ac6ed52f44b112dee4c5cf0ed9d261a437e
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun May 6 20:43:32 2018 +0800

    srfi64-extras.scm: centralize (gnc:test-runner)
    
    This is good enough to be used widely.

diff --git a/gnucash/report/report-system/test/test-html-utilities-srfi64.scm b/gnucash/report/report-system/test/test-html-utilities-srfi64.scm
index 5c46793..ef712c7 100644
--- a/gnucash/report/report-system/test/test-html-utilities-srfi64.scm
+++ b/gnucash/report/report-system/test/test-html-utilities-srfi64.scm
@@ -6,37 +6,11 @@
 (use-modules (gnucash engine test test-extras))
 (use-modules (gnucash report report-system test test-extras))
 (use-modules (gnucash report report-system))
+(use-modules (gnucash engine test srfi64-extras))
 (use-modules (srfi srfi-64))
 
-(define (test-runner)
-  (let ((runner (test-runner-null))
-        (num-passed 0)
-        (num-failed 0))
-    (test-runner-on-test-end! runner
-      (lambda (runner)
-        (format #t "[~a] line:~a, test: ~a\n"
-                (test-result-ref runner 'result-kind)
-                (test-result-ref runner 'source-line)
-                (test-runner-test-name runner))
-        (case (test-result-kind runner)
-          ((pass xpass) (set! num-passed (1+ num-passed)))
-          ((fail xfail)
-           (if (test-result-ref runner 'expected-value)
-               (format #t "~a\n -> expected: ~s\n -> obtained: ~s\n"
-                       (string-join (test-runner-group-path runner) "/")
-                       (test-result-ref runner 'expected-value)
-                       (test-result-ref runner 'actual-value)))
-           (set! num-failed (1+ num-failed)))
-          (else #t))))
-    (test-runner-on-final! runner
-      (lambda (runner)
-        (format #t "Source:~a\npass = ~a, fail = ~a\n"
-                (test-result-ref runner 'source-file) num-passed num-failed)
-        (zero? num-failed)))
-    runner))
-
 (define (run-test)
-  (test-runner-factory test-runner)
+  (test-runner-factory gnc:test-runner)
   (test-begin "test-html-utilities-srfi64.scm")
   (test-gnc:html-string-sanitize)
   (test-end "test-html-utilities-srfi64.scm"))
diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index 29e8e48..1dfa2fd 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -6,6 +6,7 @@
 (use-modules (gnucash report report-system))
 (use-modules (gnucash report report-system test test-extras))
 (use-modules (srfi srfi-64))
+(use-modules (gnucash engine test srfi64-extras))
 (use-modules (sxml simple))
 (use-modules (sxml xpath))
 (use-modules (system vm coverage))
@@ -42,33 +43,6 @@
 ;; Explicitly set locale to make the report output predictable
 (setlocale LC_ALL "C")
 
-(define (test-runner)
-  (let ((runner (test-runner-null))
-        (num-passed 0)
-        (num-failed 0))
-    (test-runner-on-test-end! runner
-      (lambda (runner)
-        (format #t "[~a] line:~a, test: ~a\n"
-                (test-result-ref runner 'result-kind)
-                (test-result-ref runner 'source-line)
-                (test-runner-test-name runner))
-        (case (test-result-kind runner)
-          ((pass xpass) (set! num-passed (1+ num-passed)))
-          ((fail xfail)
-           (if (test-result-ref runner 'expected-value)
-               (format #t "~a\n -> expected: ~s\n -> obtained: ~s\n"
-                       (string-join (test-runner-group-path runner) "/")
-                       (test-result-ref runner 'expected-value)
-                       (test-result-ref runner 'actual-value)))
-           (set! num-failed (1+ num-failed)))
-          (else #t))))
-    (test-runner-on-final! runner
-      (lambda (runner)
-        (format #t "Source:~a\npass = ~a, fail = ~a\n"
-                (test-result-ref runner 'source-file) num-passed num-failed)
-        (zero? num-failed)))
-    runner))
-
 (define (run-test)
   (if #f
       (coverage-test)
@@ -86,7 +60,7 @@
         (close port)))))
 
 (define (run-test-proper)
-  (test-runner-factory test-runner)
+  (test-runner-factory gnc:test-runner)
   (test-begin "transaction.scm")
   (null-test)
   (trep-tests)
diff --git a/libgnucash/engine/test/CMakeLists.txt b/libgnucash/engine/test/CMakeLists.txt
index 587c0eb..7d698f5 100644
--- a/libgnucash/engine/test/CMakeLists.txt
+++ b/libgnucash/engine/test/CMakeLists.txt
@@ -233,6 +233,20 @@ gnc_add_scheme_targets(scm-test-engine-extras
   FALSE
   )
 
+if (HAVE_SRFI64)
+  gnc_add_scheme_targets (scm-srfi64-extras
+    "srfi64-extras.scm"
+    "gnucash/engine/test/"
+    "${GUILE_DEPENDS}"
+    FALSE
+    )
+
+  set(srfi64_extras_SCHEME_DIST
+    srfi64-extras.scm
+    )
+
+endif (HAVE_SRFI64)
+
 gnc_add_scheme_targets(scm-test-engine
   "${engine_test_SCHEME}"
   ""
@@ -311,4 +325,5 @@ set(test_engine_EXTRA_DIST
 )
 
 set_dist_list(test_engine_DIST CMakeLists.txt
+        ${srfi64_extras_SCHEME_DIST}
         ${test_engine_SOURCES_DIST} ${test_engine_SCHEME_DIST} ${test_engine_EXTRA_DIST})
diff --git a/libgnucash/engine/test/srfi64-extras.scm b/libgnucash/engine/test/srfi64-extras.scm
new file mode 100644
index 0000000..81329b2
--- /dev/null
+++ b/libgnucash/engine/test/srfi64-extras.scm
@@ -0,0 +1,49 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2 of
+;; the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, contact:
+;;
+;; Free Software Foundation           Voice:  +1-617-542-5942
+;; 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
+;; Boston, MA  02110-1301,  USA       gnu at gnu.org
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define-module (gnucash engine test srfi64-extras))
+(use-modules (srfi srfi-64))
+
+(export gnc:test-runner)
+(define (gnc:test-runner)
+  (let ((runner (test-runner-null))
+        (num-passed 0)
+        (num-failed 0))
+    (test-runner-on-test-end! runner
+      (lambda (runner)
+        (format #t "[~a] line:~a, test: ~a\n"
+                (test-result-ref runner 'result-kind)
+                (test-result-ref runner 'source-line)
+                (test-runner-test-name runner))
+        (case (test-result-kind runner)
+          ((pass xpass) (set! num-passed (1+ num-passed)))
+          ((fail xfail)
+           (if (test-result-ref runner 'expected-value)
+               (format #t "~a\n -> expected: ~s\n -> obtained: ~s\n"
+                       (string-join (test-runner-group-path runner) "/")
+                       (test-result-ref runner 'expected-value)
+                       (test-result-ref runner 'actual-value)))
+           (set! num-failed (1+ num-failed)))
+          (else #t))))
+    (test-runner-on-final! runner
+      (lambda (runner)
+        (format #t "Source:~a\npass = ~a, fail = ~a\n"
+                (test-result-ref runner 'source-file) num-passed num-failed)
+        (zero? num-failed)))
+    runner))

commit dda6730c44b82df6881baa083d78a87da4a916c6
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu May 3 08:52:59 2018 +0800

    utilities.scm: centralize and modernize addto!
    
    (define-macro) is discouraged in most scheme forms. Change
    to (define-syntax), and centralize common macro to utilities.scm

diff --git a/gnucash/report/business-reports/customer-summary.scm b/gnucash/report/business-reports/customer-summary.scm
index 34ca9d5..376bc0a 100644
--- a/gnucash/report/business-reports/customer-summary.scm
+++ b/gnucash/report/business-reports/customer-summary.scm
@@ -97,9 +97,6 @@
 
 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 (define (set-last-row-style! table tag . rest)
   (let ((arg-list 
          (cons table 
diff --git a/gnucash/report/business-reports/easy-invoice.scm b/gnucash/report/business-reports/easy-invoice.scm
index 439e592..eb294b0 100644
--- a/gnucash/report/business-reports/easy-invoice.scm
+++ b/gnucash/report/business-reports/easy-invoice.scm
@@ -33,14 +33,12 @@
 (use-modules (srfi srfi-1))
 (use-modules (gnucash gnc-module))
 (use-modules (gnucash gettext))
+(use-modules (gnucash utilities))
 
 (gnc:module-load "gnucash/report/report-system" 0)
 (use-modules (gnucash report standard-reports))
 (use-modules (gnucash report business-reports))
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 (define (set-last-row-style! table tag . rest)
   (let ((arg-list
          (cons table
diff --git a/gnucash/report/business-reports/fancy-invoice.scm b/gnucash/report/business-reports/fancy-invoice.scm
index 64c36c2..ddb2794 100644
--- a/gnucash/report/business-reports/fancy-invoice.scm
+++ b/gnucash/report/business-reports/fancy-invoice.scm
@@ -51,14 +51,12 @@
 (use-modules (srfi srfi-1))
 (use-modules (gnucash gnc-module))
 (use-modules (gnucash gettext))
+(use-modules (gnucash utilities))
 
 (gnc:module-load "gnucash/report/report-system" 0)
 (use-modules (gnucash report standard-reports))
 (use-modules (gnucash report business-reports))
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 (define (set-last-row-style! table tag . rest)
   (let ((arg-list
          (cons table
diff --git a/gnucash/report/business-reports/invoice.scm b/gnucash/report/business-reports/invoice.scm
index 7129849..6b6b22c 100644
--- a/gnucash/report/business-reports/invoice.scm
+++ b/gnucash/report/business-reports/invoice.scm
@@ -27,14 +27,12 @@
 (use-modules (srfi srfi-1))
 (use-modules (gnucash gnc-module))
 (use-modules (gnucash gettext))
+(use-modules (gnucash utilities))
 
 (gnc:module-load "gnucash/report/report-system" 0)
 (use-modules (gnucash report standard-reports))
 (use-modules (gnucash report business-reports))
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 (define (set-last-row-style! table tag . rest)
   (let ((arg-list
          (cons table
diff --git a/gnucash/report/business-reports/job-report.scm b/gnucash/report/business-reports/job-report.scm
index b377f94..8eb55ac 100644
--- a/gnucash/report/business-reports/job-report.scm
+++ b/gnucash/report/business-reports/job-report.scm
@@ -46,9 +46,6 @@
 (define desc-header (N_ "Description"))
 (define amount-header (N_ "Amount"))
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 (define (set-last-row-style! table tag . rest)
   (let ((arg-list 
          (cons table 
diff --git a/gnucash/report/business-reports/owner-report.scm b/gnucash/report/business-reports/owner-report.scm
index 39010d5..89f48cd 100644
--- a/gnucash/report/business-reports/owner-report.scm
+++ b/gnucash/report/business-reports/owner-report.scm
@@ -117,9 +117,6 @@
         (else
           (_ "Vendor")))) 
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 (define (set-last-row-style! table tag . rest)
   (let ((arg-list 
          (cons table 
diff --git a/gnucash/report/report-system/html-utilities.scm b/gnucash/report/report-system/html-utilities.scm
index 6fbe9ce..a701ff2 100644
--- a/gnucash/report/report-system/html-utilities.scm
+++ b/gnucash/report/report-system/html-utilities.scm
@@ -22,6 +22,8 @@
 ;; Boston, MA  02110-1301,  USA       gnu at gnu.org
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(use-modules (gnucash utilities))
+
 ;; returns a list with n #f (empty cell) values 
 (define (gnc:html-make-empty-cell) #f)
 (define (gnc:html-make-empty-cells n)
@@ -854,7 +856,7 @@
                            (disp value))))
         (if (not (or (equal? default-value value)
                      (char=? (string-ref section 0) #\_)))
-            (set! render-list (cons retval render-list)))))
+            (addto! render-list retval))))
     (gnc:options-for-each add-option-if-changed options)
     (if plaintext?
         (string-append
diff --git a/gnucash/report/standard-reports/register.scm b/gnucash/report/standard-reports/register.scm
index 029e9ac..063b408 100644
--- a/gnucash/report/standard-reports/register.scm
+++ b/gnucash/report/standard-reports/register.scm
@@ -29,9 +29,6 @@
 
 (gnc:module-load "gnucash/report/report-system" 0)
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 (define (set-last-row-style! table tag . rest)
   (let ((arg-list 
          (cons table 
diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 016b3e1..26c3529 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -40,7 +40,7 @@
 
 (define-module (gnucash report standard-reports transaction))
 
-(use-modules (gnucash utilities)) 
+(use-modules (gnucash utilities))
 (use-modules (srfi srfi-1))
 (use-modules (srfi srfi-11))
 (use-modules (srfi srfi-13))
@@ -50,9 +50,6 @@
 
 (gnc:module-load "gnucash/report/report-system" 0)
 
-(define-macro (addto! alist element)
-  `(set! ,alist (cons ,element ,alist)))
-
 ;; Define the strings here to avoid typos and make changes easier.
 (define reportname (N_ "Transaction Report"))
 
diff --git a/libgnucash/scm/utilities.scm b/libgnucash/scm/utilities.scm
index 4a75c02..f34fbd9 100644
--- a/libgnucash/scm/utilities.scm
+++ b/libgnucash/scm/utilities.scm
@@ -42,6 +42,7 @@
 (export gnc:error)
 (export gnc:msg)
 (export gnc:debug)
+(export addto!)
 
 ;; Do this stuff very early -- but other than that, don't add any
 ;; executable code until the end of the file if you can help it.
@@ -71,6 +72,10 @@
 (define (gnc:debug . items)
   (gnc-scm-log-debug (strify items)))
 
+(define-syntax addto!
+  (syntax-rules ()
+    ((addto! alist element)
+     (set! alist (cons element alist)))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;  gnc:substring-replace

commit 4a27285edd956b37f54eb2f9c94b144f5b48edb7
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Apr 29 07:32:20 2018 +0800

    html-utilities.scm: new home (gnc:html-render-options-changed)
    
    We want to sanitize render-options-changed, therefore it must return
    an html-object. Unfortunately this is not accessible to
    app-utils/options.scm. If we move this function to
    report-system/html-utilities.scm, it can access html-objects.
    
    Also rename it to gnc:html-render-options-changed

diff --git a/gnucash/report/report-system/html-utilities.scm b/gnucash/report/report-system/html-utilities.scm
index 637cfe0..6fbe9ce 100644
--- a/gnucash/report/report-system/html-utilities.scm
+++ b/gnucash/report/report-system/html-utilities.scm
@@ -818,6 +818,65 @@
        "")
       (_ "Edit report options")))))
 
+(define* (gnc:html-render-options-changed options #:optional plaintext?)
+  ;; options -> html-object or string, depending on plaintext?.  This
+  ;; summarises options that were changed by the user. Set plaintext?
+  ;; to #t for unit-tests only.
+  (define (disp d)
+    ;; option-value -> string.  The option is passed to various
+    ;; scm->string converters; ultimately a generic stringify
+    ;; function handles symbol/string/other types.
+    (define (try proc)
+      ;; Try proc with d as a parameter, catching 'wrong-type-arg
+      ;; exceptions to return #f to the or evaluator.
+      (catch 'wrong-type-arg
+        (lambda () (proc d))
+        (const #f)))
+    (or (and (boolean? d) (if d (_ "Enabled") (_ "Disabled")))
+        (and (null? d) "null")
+        (and (list? d) (string-join (map disp d) ", "))
+        (and (pair? d) (format #f "~a . ~a"
+                               (car d)
+                               (if (eq? (car d) 'absolute)
+                                   (qof-print-date (cdr d))
+                                   (disp (cdr d)))))
+        (try gnc-commodity-get-mnemonic)
+        (try xaccAccountGetName)
+        (try gnc-budget-get-name)
+        (format #f "~a" d)))
+  (let ((render-list '()))
+    (define (add-option-if-changed option)
+      (let* ((section (gnc:option-section option))
+             (name (gnc:option-name option))
+             (default-value (gnc:option-default-value option))
+             (value (gnc:option-value option))
+             (retval (cons (format #f "~a / ~a" section name)
+                           (disp value))))
+        (if (not (or (equal? default-value value)
+                     (char=? (string-ref section 0) #\_)))
+            (set! render-list (cons retval render-list)))))
+    (gnc:options-for-each add-option-if-changed options)
+    (if plaintext?
+        (string-append
+         (string-join
+          (map (lambda (item)
+                 (format #f "~a: ~a\n" (car item) (cdr item)))
+               render-list)
+          "")
+         "\n")
+        (apply
+         gnc:make-html-text
+         (apply
+          append
+          (map
+           (lambda (item)
+             (list
+              (gnc:html-markup-b (car item))
+              ": "
+              (cdr item)
+              (gnc:html-markup-br)))
+           render-list))))))
+
 (define (gnc:html-make-generic-warning
          report-title-string report-id
          warning-title-string warning-string)
@@ -877,3 +936,5 @@
             ((#\>) ">")
             (else c))))
        str))))
+
+
diff --git a/gnucash/report/report-system/report-system.scm b/gnucash/report/report-system/report-system.scm
index d305d54..1ea0a3f 100644
--- a/gnucash/report/report-system/report-system.scm
+++ b/gnucash/report/report-system/report-system.scm
@@ -112,6 +112,7 @@
 (export gnc:html-build-acct-table)
 (export gnc:first-html-build-acct-table)
 (export gnc:html-make-exchangerates)
+(export gnc:html-render-options-changed)
 (export gnc:html-make-generic-warning)
 (export gnc:html-make-no-account-warning)
 (export gnc:html-make-generic-budget-warning)
diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index 9ea0d5e..29e8e48 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -134,7 +134,7 @@
         (lambda () (xml->sxml render))
         (lambda (k . args)
           (test-assert k #f)            ; XML parse error doesn't cause a crash but logs as a failure
-          (format #t "see render output at ~a\n~a" filename (gnc:render-options-changed options #t)))))))
+          (format #t "see render output at ~a\n~a" filename (gnc:html-render-options-changed options #t)))))))
 
 (define (get-row-col sxml row col)
   ;; sxml, row & col (numbers or #f) -> list-of-string
diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index fc99b40..016b3e1 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -1880,7 +1880,7 @@ be excluded from periodic reporting.")
           (if (memq infobox-display '(always no-match))
               (gnc:html-document-add-object!
                document
-               (gnc:render-options-changed options))))
+               (gnc:html-render-options-changed options))))
 
         (begin
 
@@ -1956,7 +1956,7 @@ be excluded from periodic reporting.")
                 (if (memq infobox-display '(always no-match))
                     (gnc:html-document-add-object!
                      document
-                     (gnc:render-options-changed options))))
+                     (gnc:html-render-options-changed options))))
 
               (let-values (((table grid) (make-split-table splits options custom-calculated-cells)))
 
@@ -1985,7 +1985,7 @@ be excluded from periodic reporting.")
                 (if (eq? infobox-display 'always)
                     (gnc:html-document-add-object!
                      document
-                     (gnc:render-options-changed options)))
+                     (gnc:html-render-options-changed options)))
 
                 (gnc:html-document-add-object! document table)))))
 
diff --git a/libgnucash/app-utils/app-utils.scm b/libgnucash/app-utils/app-utils.scm
index a3d838a..e462d69 100644
--- a/libgnucash/app-utils/app-utils.scm
+++ b/libgnucash/app-utils/app-utils.scm
@@ -101,7 +101,6 @@
 (export gnc:make-radiobutton-option)
 (export gnc:make-radiobutton-callback-option)
 (export gnc:make-list-option)
-(export gnc:render-options-changed)
 (export gnc:options-make-end-date!)
 (export gnc:options-make-date-interval!)
 (export gnc:option-make-internal!)
diff --git a/libgnucash/app-utils/options.scm b/libgnucash/app-utils/options.scm
index fd82e21..f460f95 100644
--- a/libgnucash/app-utils/options.scm
+++ b/libgnucash/app-utils/options.scm
@@ -2001,64 +2001,6 @@
                                   (gnc:option-value src-option)))))
     src-options)))
 
-(define* (gnc:render-options-changed options #:optional plaintext?)
-  ;;
-  ;; options -> string
-  ;;
-  ;; this function will generate an string of options that were changed by the user.
-  ;; by default, it produces an html string.
-  ;; the optional plaintext? = #t will ensure the output is suitable for console output
-  ;; omitting all html elements, and is expected to be used for unit tests only.
-  ;;
-  (let ((row-contents '()))
-    (define (disp d)
-      ;; this function will intelligently display the option value. the option-value is subject to various tests
-      ;; the or clause below will test for boolean, null, list, and pairs. each will trigger a custom function
-      ;; returning a string. the pair option is handled differently because its car will define the data type
-      ;; for its cdr which is either a symbol, time64 number, percent or pixels. if the option does not satisfy
-      ;; any of the above, the function attempts to pass it as a parameter to gnc-commodity-get-mnemonic, or
-      ;; xaccAccountGetName, or gnc-budget-get-name; success leads to application of these functions, failure
-      ;; then leads to a generic stringify function which will handle symbol/string/other types.
-      (define (try thunk arg)
-        ;; this helper function will attempt to run thunk with arg as a parameter. we will catch any 
-        ;; 'wrong-type-arg exception, and return the #f value to the or evaluator below.
-        (catch 'wrong-type-arg
-          (lambda () (thunk arg))
-          (lambda (k . args) #f)))
-      (or (and (boolean? d) (if d (_ "Enabled") (_ "Disabled")))
-          (and (null? d) "null")
-          (and (list? d) (string-join (map disp d) ", "))
-          (and (pair? d) (string-append
-                          (disp (car d)) " . "
-                          (case (car d)
-                            ((relative) (symbol->string (cdr d)))
-                            ((absolute) (qof-print-date (cdr d)))
-                            ((pixels percent) (number->string (cdr d)))
-                            (else (format #f "unknown car of pair, cannot determine format for ~A" (cdr d))))))
-          (try gnc-commodity-get-mnemonic d)
-          (try xaccAccountGetName d)
-          (try gnc-budget-get-name d)
-          (format #f "~A" d)))
-    (define (disp-option-if-changed option)
-      ;; this function is called by gnc:options-for-each on each option, and will test whether default value
-      ;; has been changed and the option is not hidden, and display it using (disp val) as above.
-      (let* ((section (gnc:option-section option))
-             (name (gnc:option-name option))
-             (default-value (gnc:option-default-value option))
-             (value (gnc:option-value option))
-             (return-string (string-append (if plaintext? "" "<b>")
-                                           section " / " name
-                                           (if plaintext? "" "</b>")
-                                           ": "
-                                           (disp value))))
-        (if (not (or (equal? default-value value)
-                     (char=? (string-ref section 0) #\_)))
-            (set! row-contents (cons return-string row-contents)))))
-    (gnc:options-for-each disp-option-if-changed options)
-    (string-append (string-join (reverse row-contents)
-                                (if plaintext? "\n" "<br />\n"))
-                   (if plaintext? "\n\n" "<br />\n<br />\n"))))
-
 (define (gnc:send-options db_handle options)
   (gnc:options-for-each
    (lambda (option)

commit 44a568bc457022a4bea7c8b55d304e80a11aa6ba
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Apr 29 18:36:49 2018 +0800

    GSTR: sanitize string
    
    Instead of returning raw html string, return an html-object.

diff --git a/gnucash/report/standard-reports/income-gst-statement.scm b/gnucash/report/standard-reports/income-gst-statement.scm
index 82d6bb7..6aa289a 100644
--- a/gnucash/report/standard-reports/income-gst-statement.scm
+++ b/gnucash/report/standard-reports/income-gst-statement.scm
@@ -35,24 +35,27 @@
 (use-modules (gnucash report standard-reports transaction))
 
 ;; Define the strings here to avoid typos and make changes easier.
-(define reportname (N_ "Income & GST Statement"))
+(define reportname (N_ "Income and GST Statement"))
 (define pagename-sorting (N_ "Sorting"))
 (define pagename-filter (N_ "Filter"))
 (define TAX-SETUP-DESC
-  (string-append
+  (gnc:make-html-text
    (_ "This report is useful to calculate periodic business tax payable/receivable from
- authorities. From <i>Edit report options</i> above, choose your Business Income and Business Expense accounts.
+ authorities. From 'Edit report options' above, choose your Business Income and Business Expense accounts.
  Each transaction may contain, in addition to the accounts payable/receivable or bank accounts,
  a split to a tax account, e.g. Income:Sales -$1000, Liability:GST on Sales -$100, Asset:Bank $1100.")
-   "<br/><br/>"
+   (gnc:html-markup-br)
+   (gnc:html-markup-br)
    (_ "These tax accounts can either be populated using the standard register, or from Business Invoices and Bills
- which will require Business > Sales Tax Tables to be set up correctly. Please see the documentation.")
-   "<br/><br/>"
+ which will require Tax Tables to be set up correctly. Please see the documentation.")
+   (gnc:html-markup-br)
+   (gnc:html-markup-br)
    (_ "From the Report Options, you will need to select the accounts which will \
 hold the GST/VAT taxes collected or paid. These accounts must contain splits which document the \
 monies which are wholly sent or claimed from tax authorities during periodic GST/VAT returns. These \
 accounts must be of type ASSET for taxes paid on expenses, and type LIABILITY for taxes collected on sales.")
-   "<br/><br/>"))
+   (gnc:html-markup-br)
+   (gnc:html-markup-br)))
 
 (define (income-gst-statement-renderer rpt)
   (trep-renderer rpt

commit fd02871678a79653880e9a6dca7892edd0bf569a
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu May 3 17:19:36 2018 +0800

    TR: sanitize string
    
    This will change the HTML slightly, so, requires an update to the test
    suite.

diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index b359f2e..9ea0d5e 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -797,10 +797,10 @@
       (set-option! options "Sorting" "Show Account Description" #t)
       (let* ((sxml (options->sxml options "sorting=date")))
         (test-equal "expense acc friendly headers"
-          '("\n" "Expenses" "Expense" "Rebate")
+          '("\n" "Expenses" "\n" "Expense" "\n" "Rebate")
           (get-row-col sxml 47 #f))
         (test-equal "income acc friendly headers"
-          '("\n" "Income" "Charge" "Income")
+          '("\n" "Income" "\n" "Charge" "\n" "Income")
           (get-row-col sxml 69 #f)))
 
       (set-option! options "Accounts" "Accounts" (list bank))
diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 9a2e522..fc99b40 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -1300,11 +1300,10 @@ be excluded from periodic reporting.")
                                         1 (+ right-indent width-left-columns) data)))
               (for-each (lambda (cell)
                           (addto! row-contents
-                                  (gnc:make-html-table-cell
-                                   "<b>"
-                                   ((vector-ref cell 5)
-                                    ((keylist-get-info sortkey-list sortkey 'renderer-fn) split))
-                                   "</b>")))
+                                  (gnc:make-html-text
+                                   (gnc:html-markup-b
+                                    ((vector-ref cell 5)
+                                     ((keylist-get-info sortkey-list sortkey 'renderer-fn) split))))))
                         calculated-cells))
             (addto! row-contents (gnc:make-html-table-cell/size
                                   1 (+ right-indent width-left-columns width-right-columns) data)))

commit d68ccc330628d56178d2dd0d83bde8d084663ba6
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu May 3 21:59:22 2018 +0800

    TR: rename some variable names to be more descriptive
    
    The previous names were remnants of old transaction.scm and were not
    exactly consistent. Use more descriptive names.
    
    The only user-visible change is elimination of <br/> in the
    common-currency account header, because this will be sanitized.  The
    table col-headers cannot unfortunately accept a (gnc:make-html-text)
    object therefore we cannot add <br/> at all. I vote to display
    e.g. "Debit (USD)" instead.

diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index 6b27989..b359f2e 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -354,7 +354,7 @@
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'monthly)
       (let ((sxml (options->sxml options "test basic column headers, and original currency")))
         (test-equal "default headers, indented, includes common-currency"
-          '(" " " " "Date" "Num" "Description" "Memo/Notes" "Account" "Amount" "USD" "Amount")
+          '(" " " " "Date" "Num" "Description" "Memo/Notes" "Account" "Amount (USD)" "Amount")
           (get-row-col sxml 0 #f))
         (test-equal "grand total present, no blank cells, and is $2,280 in both common-currency and original-currency"
           '("Grand Total" "$2,280.00" "$2,280.00")
@@ -614,7 +614,7 @@
       (let* ((sxml (options->sxml options "single column, with original currency headers")))
         (test-equal "single amount column, with original currency headers"
           (list "Date" "Num" "Description" "Memo/Notes" "Account"
-                "Amount" "USD" "Amount")
+                "Amount (USD)" "Amount")
           (get-row-col sxml 0 #f)))
 
       (set-option! options "Display" "Amount" 'double)
@@ -631,7 +631,7 @@
         ;; output here too.
         (test-equal "dual amount headers"
           (list "Date" "Num" "Description" "Memo/Notes" "Account" "Transfer from/to"
-                "Debit" "USD" "Credit" "USD" "Debit" "Credit")
+                "Debit (USD)" "Credit (USD)" "Debit" "Credit")
           (get-row-col sxml 0 #f))
         (test-equal "Account Name and Code displayed"
           (list "01-GBP Root.Asset.GBP Bank")
@@ -693,7 +693,7 @@
       (let* ((sxml (options->sxml options "dual columns")))
         (test-equal "dual amount column, with original currency headers"
           (list "Date" "Num" "Description" "Memo/Notes" "Account"
-                "Debit" "USD" "Credit" "USD" "Debit" "Credit")
+                "Debit (USD)" "Credit (USD)" "Debit" "Credit")
           (get-row-col sxml 0 #f))
         (test-equal "dual amount column, grand totals available"
           (list "Grand Total" " " " " " " " " "$2,280.00" "$2,280.00")
diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 00bcf6d..9a2e522 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -1156,48 +1156,42 @@ be excluded from periodic reporting.")
 
     (define default-calculated-cells
       (letrec
-          ((damount (lambda (s) (if (gnc:split-voided? s)
-                                    (xaccSplitVoidFormerAmount s)
-                                    (xaccSplitGetAmount s))))
-           (trans-date (lambda (s) (xaccTransGetDate (xaccSplitGetParent s))))
-           (currency (lambda (s) (xaccAccountGetCommodity (xaccSplitGetAccount s))))
-           (report-currency (lambda (s) (if (column-uses? 'common-currency)
-                                            (opt-val gnc:pagename-general optname-currency)
-                                            (currency s))))
+          ((split-amount (lambda (s) (if (gnc:split-voided? s)
+                                         (xaccSplitVoidFormerAmount s)
+                                         (xaccSplitGetAmount s))))
+           (split-currency (lambda (s) (xaccAccountGetCommodity (xaccSplitGetAccount s))))
+           (row-currency (lambda (s) (if (column-uses? 'common-currency)
+                                         (opt-val gnc:pagename-general optname-currency)
+                                         (split-currency s))))
            (friendly-debit (lambda (a) (gnc:get-debit-string (xaccAccountGetType a))))
            (friendly-credit (lambda (a) (gnc:get-credit-string (xaccAccountGetType a))))
            (header-commodity (lambda (str)
                                (string-append
                                 str
                                 (if (column-uses? 'common-currency)
-                                    (string-append
-                                     "<br />"
-                                     (gnc-commodity-get-mnemonic
-                                      (opt-val gnc:pagename-general optname-currency)))
+                                    (format #f " (~a)"
+                                            (gnc-commodity-get-mnemonic
+                                             (opt-val gnc:pagename-general optname-currency)))
                                     ""))))
-           (convert (lambda (s num)
-                      (gnc:exchange-by-pricedb-nearest
-                       (gnc:make-gnc-monetary (currency s) num)
-                       (report-currency s)
-                       ;; Use midday as the transaction time so it matches a price
-                       ;; on the same day.  Otherwise it uses midnight which will
-                       ;; likely match a price on the previous day
-                       (time64CanonicalDayTime (trans-date s)))))
-           (split-value (lambda (s) (convert s (damount s)))) ; used for correct debit/credit
-           (amount (lambda (s) (split-value s)))
-           (debit-amount (lambda (s) (and (positive? (gnc:gnc-monetary-amount (split-value s)))
-                                          (split-value s))))
-           (credit-amount (lambda (s) (if (positive? (gnc:gnc-monetary-amount (split-value s)))
-                                          #f
-                                          (gnc:monetary-neg (split-value s)))))
-           (original-amount (lambda (s) (gnc:make-gnc-monetary (currency s) (damount s))))
-           (original-debit-amount (lambda (s) (if (positive? (damount s))
-                                                  (original-amount s)
-                                                  #f)))
-           (original-credit-amount (lambda (s) (if (positive? (damount s))
-                                                   #f
-                                                   (gnc:monetary-neg (original-amount s)))))
-           (running-balance (lambda (s) (gnc:make-gnc-monetary (currency s) (xaccSplitGetBalance s)))))
+           ;; For conversion to row-currency. Use midday as the
+           ;; transaction time so it matches a price on the same day.
+           ;; Otherwise it uses midnight which will likely match a
+           ;; price on the previous day
+           (converted-amount (lambda (s) (gnc:exchange-by-pricedb-nearest
+                                          (gnc:make-gnc-monetary (split-currency s) (split-amount s))
+                                          (row-currency s)
+                                          (time64CanonicalDayTime
+                                           (xaccTransGetDate (xaccSplitGetParent s))))))
+           (converted-debit-amount (lambda (s) (and (positive? (split-amount s))
+                                                    (converted-amount s))))
+           (converted-credit-amount (lambda (s) (and (not (positive? (split-amount s)))
+                                                     (gnc:monetary-neg (converted-amount s)))))
+           (original-amount (lambda (s) (gnc:make-gnc-monetary (split-currency s) (split-amount s))))
+           (original-debit-amount (lambda (s) (and (positive? (split-amount s))
+                                                   (original-amount s))))
+           (original-credit-amount (lambda (s) (and (not (positive? (split-amount s)))
+                                                    (gnc:monetary-neg (original-amount s)))))
+           (running-balance (lambda (s) (gnc:make-gnc-monetary (split-currency s) (xaccSplitGetBalance s)))))
         (append
          ;; each column will be a vector
          ;; (vector heading
@@ -1207,17 +1201,19 @@ be excluded from periodic reporting.")
          ;;         start-dual-column?                           ;; #t for the debit side of a dual column (i.e. debit/credit)
          ;;                                                      ;; which means the next column must be the credit side
          ;;         friendly-heading-fn                          ;; (friendly-heading-fn account) to retrieve friendly name for account debit/credit
+
          (if (column-uses? 'amount-single)
              (list (vector (header-commodity (_ "Amount"))
-                           amount #t #t #f
+                           converted-amount #t #t #f
                            (lambda (a) "")))
              '())
+
          (if (column-uses? 'amount-double)
              (list (vector (header-commodity (_ "Debit"))
-                           debit-amount #f #t #t
+                           converted-debit-amount #f #t #t
                            friendly-debit)
                    (vector (header-commodity (_ "Credit"))
-                           credit-amount #f #t #f
+                           converted-credit-amount #f #t #f
                            friendly-credit))
              '())
 

commit ac510d13be9e7522c5762378b79d3cf0422aeac1
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Fri Jan 19 15:22:48 2018 +0800

    TR: (ENH) add Closing-status filter, enable it by default
    
    This commit will add a filter to include/exclude closing
    transactions. In conventional reports, they are usually disruptive to
    the regular periodic reporting and the default ensures they are not
    included.
    
    This commit also changes income-gst-report.scm to use the closing
    filter just created, and disable its UI.

diff --git a/gnucash/report/standard-reports/income-gst-statement.scm b/gnucash/report/standard-reports/income-gst-statement.scm
index 2cd7b7e..82d6bb7 100644
--- a/gnucash/report/standard-reports/income-gst-statement.scm
+++ b/gnucash/report/standard-reports/income-gst-statement.scm
@@ -37,6 +37,7 @@
 ;; Define the strings here to avoid typos and make changes easier.
 (define reportname (N_ "Income & GST Statement"))
 (define pagename-sorting (N_ "Sorting"))
+(define pagename-filter (N_ "Filter"))
 (define TAX-SETUP-DESC
   (string-append
    (_ "This report is useful to calculate periodic business tax payable/receivable from
@@ -63,10 +64,9 @@ accounts must be of type ASSET for taxes paid on expenses, and type LIABILITY fo
   ;; split -> bool
   ;;
   ;; additional split filter - returns #t if split must be included
-  ;; we need to exclude Closing, Link and Payment transactions
-  (let ((trans (xaccSplitGetParent split)))
-    (and (member (xaccTransGetTxnType trans) (list TXN-TYPE-NONE TXN-TYPE-INVOICE))
-         (not (xaccTransGetIsClosingTxn trans)))))
+  ;; we need to exclude Link and Payment transactions
+  (memv (xaccTransGetTxnType (xaccSplitGetParent split))
+        (list TXN-TYPE-NONE TXN-TYPE-INVOICE)))
 
 (define (gst-statement-options-generator)
 
@@ -115,6 +115,9 @@ for taxes paid on expenses, and type LIABILITY for taxes collected on sales.")
   (gnc:option-make-internal! options gnc:pagename-accounts "Filter Type")
   (gnc:option-make-internal! options gnc:pagename-accounts "Filter By...")
   (gnc:option-make-internal! options gnc:pagename-general "Show original currency amount")
+  ;; Disallow closing transactions
+  (gnc:option-set-value (gnc:lookup-option options pagename-filter "Closing transactions") 'exclude-closing)
+  (gnc:option-make-internal! options pagename-filter "Closing transactions")
   ;; Disable display options not being used anymore
   (gnc:option-make-internal! options gnc:pagename-display "Shares")
   (gnc:option-make-internal! options gnc:pagename-display "Price")
diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index 35800f4..6b27989 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -184,6 +184,7 @@
         (list "Income" (list (cons 'type ACCT-TYPE-INCOME)))
         (list "Expenses" (list (cons 'type ACCT-TYPE-EXPENSE)))
         (list "Liabilities" (list (cons 'type ACCT-TYPE-LIABILITY)))
+        (list "Equity" (list (cons 'type ACCT-TYPE-EQUITY)))
         ))
 
 (define (null-test)
@@ -202,6 +203,7 @@
          (income (cdr (assoc "Income" account-alist)))
          (expense (cdr (assoc "Expenses" account-alist)))
          (liability (cdr (assoc "Liabilities" account-alist)))
+         (equity (cdr (assoc "Equity" account-alist)))
          (YEAR (gnc:time64-get-year (gnc:get-today)))
          (foreign1 (gnc-commodity-table-lookup
                     (gnc-commodity-table-get-table (gnc-account-get-book bank))
@@ -288,6 +290,10 @@
       (xaccTransSetNotes txn "multisplit")
       (xaccTransCommitEdit txn))
 
+    ;; A single closing transaction
+    (let ((closing-txn (env-transfer env 31 12 1999 expense equity 111 #:description "Closing")))
+      (xaccTransSetIsClosingTxn closing-txn #t))
+
     ;; A couple of transactions which involve foreign currency
     ;; conversions. We'll set the currencies to GBP and USD.
     (env-transfer-foreign env 15 01 2000 gbp-bank usd-bank 10 14 #:description "GBP 10 to USD 14")
@@ -464,7 +470,31 @@
       (let ((sxml (options->sxml options "both void and non-void")))
         (test-equal "filter void-transactions only, sum = $11.00"
           '("$11.00")
-          (get-row-col sxml -1 -1))))
+          (get-row-col sxml -1 -1)))
+
+      ;; Test Closing-Txn Filters
+      (set! options (default-testing-options))
+      (set-option! options "Accounts" "Accounts" (list expense))
+      (set-option! options "General" "Start Date" (cons 'absolute (gnc-dmy2time64 01 01 1911)))
+      (set-option! options "General" "End Date" (cons 'absolute (gnc-dmy2time64 31 12 2012)))      
+      (set-option! options "Filter" "Closing transactions" 'exclude-closing)
+      (let ((sxml (options->sxml options "filter closing - exclude closing txns ")))
+        (test-equal "filter exclude closing. bal = $111"
+          '("$111.00")
+          (get-row-col sxml -1 -1)))
+
+      (set-option! options "Filter" "Closing transactions" 'closing-only)
+      (let ((sxml (options->sxml options "filter closing - include closing only")))
+        (test-equal "filter closing only. bal = -$111"
+          '("-$111.00")
+          (get-row-col sxml -1 -1)))
+
+      (set-option! options "Filter" "Closing transactions" 'include-both)
+      (let ((sxml (options->sxml options "filter closing - include both")))
+        (test-equal "filter include both. bal = $0"
+          '("$0.00")
+          (get-row-col sxml -1 -1)))
+      )
 
     (test-end "accounts selectors and filtering")
 
diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 7178ddf..00bcf6d 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -17,6 +17,7 @@
 ;; - add support for indenting for better grouping
 ;; - add defaults suitable for a reconciliation report
 ;; - add subtotal summary grid
+;; - by default, exclude closing transactions from the report
 ;;
 ;; This program is free software; you can redistribute it and/or    
 ;; modify it under the terms of the GNU General Public License as   
@@ -98,6 +99,7 @@
 (define optname-transaction-matcher-regex (N_ "Use regular expressions for transaction filter"))
 (define optname-reconcile-status (N_ "Reconcile Status"))
 (define optname-void-transactions (N_ "Void Transactions"))
+(define optname-closing-transactions (N_ "Closing transactions"))
 
 ;;Styles
 (define def:grand-total-style "grand-total")
@@ -325,6 +327,23 @@ in the Options panel."))
                 (cons 'text (_ "Both"))
                 (cons 'tip (_ "Show both (and include void transactions in totals)."))))))
 
+(define show-closing-list
+  (list
+   (cons 'exclude-closing (list
+                           (cons 'text (_ "Exclude closing transactions"))
+                           (cons 'tip (_ "Exclude closing transactions from report."))
+                           (cons 'closing-match #f)))
+
+   (cons 'include-both (list
+                        (cons 'text (_ "Show both closing and regular transactions"))
+                        (cons 'tip (_ "Show both (and include closing transactions in totals)."))
+                        (cons 'closing-match 'both)))
+
+   (cons 'closing-only (list
+                        (cons 'text (_ "Show closing transactions only"))
+                        (cons 'tip (_ "Show only closing transactions."))
+                        (cons 'closing-match #t)))))
+
 (define reconcile-status-list
   ;; 'filter-types must be either #f (i.e. disable reconcile filter)
   ;; or a value defined as defined in Query.c
@@ -555,6 +574,16 @@ tags within description, notes or memo. ")
     'non-void-only
     (keylist->vectorlist show-void-list)))
 
+  (gnc:register-trep-option
+   (gnc:make-multichoice-option
+    pagename-filter optname-closing-transactions
+    "l" (_ "By default most users should not include closing \
+transactions in a transaction report. Closing transactions are \
+transfers from INCOME and EXPENSE accounts to equity, and must usually \
+be excluded from periodic reporting.")
+    'exclude-closing
+    (keylist->vectorlist show-closing-list)))
+
   ;; Accounts options
 
   ;; account to do report on
@@ -1787,6 +1816,9 @@ tags within description, notes or memo. ")
          (secondary-order (opt-val pagename-sorting optname-sec-sortorder))
          (secondary-date-subtotal (opt-val pagename-sorting optname-sec-date-subtotal))
          (void-status (opt-val pagename-filter optname-void-transactions))
+         (closing-match (keylist-get-info show-closing-list
+                                          (opt-val pagename-filter optname-closing-transactions)
+                                          'closing-match))
          (splits '())
          (custom-sort? (or (and (member primary-key DATE-SORTING-TYPES)   ; this will remain
                                 (not (eq? primary-date-subtotal 'none)))  ; until qof-query
@@ -1866,6 +1898,8 @@ tags within description, notes or memo. ")
             (else #f))
           (if reconcile-status-filter
               (xaccQueryAddClearedMatch query reconcile-status-filter QOF-QUERY-AND))
+          (if (boolean? closing-match)
+              (xaccQueryAddClosingTransMatch query closing-match QOF-QUERY-AND))
           (if (not custom-sort?)
               (begin
                 (qof-query-set-sort-order query

commit 4b9ec663f7a050a2cfea23729ab5fca6c20dcdcf
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu May 3 13:46:09 2018 +0800

    TR: (ENH) do not add headers if hiding transaction data

diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 1aeedf8..7178ddf 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -1111,10 +1111,11 @@ tags within description, notes or memo. ")
                                     "number-cell"
                                     (gnc:make-gnc-monetary currency price-decimal)))))))))
 
-        (if (and (null? left-cols-list)
-                 (or (opt-val gnc:pagename-display "Totals")
-                     (primary-get-info 'renderer-fn)
-                     (secondary-get-info 'renderer-fn)))
+        (if (or (column-uses? 'subtotals-only)
+                (and (null? left-cols-list)
+                     (or (opt-val gnc:pagename-display "Totals")
+                         (primary-get-info 'renderer-fn)
+                         (secondary-get-info 'renderer-fn))))
             (list (vector "" (lambda (s t) #f)))
             left-cols-list)))
 

commit f82e5a5b4b2d7f110af8041dad4a4af7ebbde368
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 1 21:07:07 2018 +0800

    TR: (ENH) enable subtotal/grouping for Split Memo

diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 638c592..1aeedf8 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -220,10 +220,10 @@ in the Options panel."))
                                    (cons 'renderer-fn #f)))
 
         (cons 'memo          (list (cons 'sortkey (list SPLIT-MEMO))
-                                   (cons 'split-sortvalue #f)
+                                   (cons 'split-sortvalue (lambda (s) (xaccSplitGetMemo s)))
                                    (cons 'text (_ "Memo"))
                                    (cons 'tip (_ "Sort by memo."))
-                                   (cons 'renderer-fn #f)))
+                                   (cons 'renderer-fn (lambda (s) (xaccSplitGetMemo s)))))
 
         (cons 'notes         (list (cons 'sortkey #f)
                                    (cons 'split-sortvalue (lambda (s) (xaccTransGetNotes (xaccSplitGetParent s))))

commit f89f00f59d375bd313426b45ec34cdd944b685a6
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 1 21:05:55 2018 +0800

    TR: (ENH) enable subtotal/grouping for Transaction Description

diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index c5b8867..638c592 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -194,10 +194,10 @@ in the Options panel."))
                                    (cons 'renderer-fn #f)))
 
         (cons 'description   (list (cons 'sortkey (list SPLIT-TRANS TRANS-DESCRIPTION))
-                                   (cons 'split-sortvalue #f)
+                                   (cons 'split-sortvalue (lambda (s) (xaccTransGetDescription (xaccSplitGetParent s))))
                                    (cons 'text (_ "Description"))
                                    (cons 'tip (_ "Sort by description."))
-                                   (cons 'renderer-fn #f)))
+                                   (cons 'renderer-fn (lambda (s) (xaccTransGetDescription (xaccSplitGetParent s))))))
 
         (if (and (gnc-current-session-exist)
                  (qof-book-use-split-action-for-num-field (gnc-get-current-book)))

commit 4a7bc0b53d434cd72f4ed58ae687a16f8bfc0046
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 1 21:06:54 2018 +0800

    TR: (ENH) enable subtotal/grouping for Transaction Notes

diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index c0b3518..35800f4 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -725,6 +725,12 @@
           '("Expenses" "Expenses" "Income" "Income" "Liabilities")
           (get-row-col sxml #f 6)))
 
+      (set-option! options "Sorting" "Primary Key" 'notes)
+      (let* ((sxml (options->sxml options "sorting=trans-notes")))
+        (test-equal "sort by transaction notes"
+          '("memo-3" "memo-2" "memo-1" "notes3")
+          (get-row-col sxml #f 4)))
+
       (set-option! options "Sorting" "Primary Key" 'amount)
       (let* ((sxml (options->sxml options "sorting=amount")))
         (test-equal "sort by amount"
diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index a1c01be..c5b8867 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -225,6 +225,12 @@ in the Options panel."))
                                    (cons 'tip (_ "Sort by memo."))
                                    (cons 'renderer-fn #f)))
 
+        (cons 'notes         (list (cons 'sortkey #f)
+                                   (cons 'split-sortvalue (lambda (s) (xaccTransGetNotes (xaccSplitGetParent s))))
+                                   (cons 'text (_ "Notes"))
+                                   (cons 'tip (_ "Sort by transaction notes."))
+                                   (cons 'renderer-fn (lambda (s) (xaccTransGetNotes (xaccSplitGetParent s))))))
+
         (cons 'none          (list (cons 'sortkey '())
                                    (cons 'split-sortvalue #f)
                                    (cons 'text (_ "None"))

commit 2102c55bb7ad5216537c553c0d6189033322a8e1
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 1 23:44:50 2018 +0800

    TR: (centralize) centralize custom-sorter split comparators
    
    This commit will modify the custom sorter to reuse 'split-sortvalue
    comparators. The original purpose of these functions was to *compare*
    splits *during* table generation to determine whether a subtotal group
    was changed. These functions can be easily reused by the custom sorter
    to *sort* splits *before* table generation.
    
    Also modify the sortkey renderer logic to catch all non-date,
    non-account sortkeys into the generic string renderer.

diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 8fd2c3d..a1c01be 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -145,13 +145,13 @@ in the Options panel."))
                                   (cons 'renderer-fn (lambda (a) (xaccSplitGetAccount a)))))
 
         (cons 'date         (list (cons 'sortkey (list SPLIT-TRANS TRANS-DATE-POSTED))
-                                  (cons 'split-sortvalue #f)
+                                  (cons 'split-sortvalue (lambda (s) (xaccTransGetDate (xaccSplitGetParent s))))
                                   (cons 'text (_ "Date"))
                                   (cons 'tip (_ "Sort by date."))
                                   (cons 'renderer-fn #f)))
 
         (cons 'reconciled-date (list (cons 'sortkey (list SPLIT-DATE-RECONCILED))
-                                     (cons 'split-sortvalue #f)
+                                     (cons 'split-sortvalue (lambda (s) (xaccSplitGetDateReconciled s)))
                                      (cons 'text (_ "Reconciled Date"))
                                      (cons 'tip (_ "Sort by the Reconciled Date."))
                                      (cons 'renderer-fn #f)))
@@ -188,7 +188,7 @@ in the Options panel."))
                                             (cons 'renderer-fn (lambda (a) (xaccSplitGetAccount (xaccSplitGetOtherSplit a))))))
 
         (cons 'amount        (list (cons 'sortkey (list SPLIT-VALUE))
-                                   (cons 'split-sortvalue #f)
+                                   (cons 'split-sortvalue (lambda (a) (gnc-numeric-to-scm (xaccSplitGetValue a))))
                                    (cons 'text (_ "Amount"))
                                    (cons 'tip (_ "Sort by amount."))
                                    (cons 'renderer-fn #f)))
@@ -202,19 +202,19 @@ in the Options panel."))
         (if (and (gnc-current-session-exist)
                  (qof-book-use-split-action-for-num-field (gnc-get-current-book)))
             (cons 'number    (list (cons 'sortkey (list SPLIT-ACTION))
-                                   (cons 'split-sortvalue #f)
+                                   (cons 'split-sortvalue (lambda (a) (xaccSplitGetAction a)))
                                    (cons 'text (_ "Number/Action"))
                                    (cons 'tip (_ "Sort by check number/action."))
                                    (cons 'renderer-fn #f)))
 
             (cons 'number    (list (cons 'sortkey (list SPLIT-TRANS TRANS-NUM))
-                                   (cons 'split-sortvalue #f)
+                                   (cons 'split-sortvalue (lambda (a) (xaccTransGetNum (xaccSplitGetParent a))))
                                    (cons 'text (_ "Number"))
                                    (cons 'tip (_ "Sort by check/transaction number."))
                                    (cons 'renderer-fn #f))))
 
         (cons 't-number      (list (cons 'sortkey (list SPLIT-TRANS TRANS-NUM))
-                                   (cons 'split-sortvalue #f)
+                                   (cons 'split-sortvalue (lambda (a) (xaccTransGetNum (xaccSplitGetParent a))))
                                    (cons 'text (_ "Transaction Number"))
                                    (cons 'tip (_ "Sort by transaction number."))
                                    (cons 'renderer-fn #f)))
@@ -251,36 +251,42 @@ in the Options panel."))
   (list
    (cons 'none (list
                 (cons 'split-sortvalue #f)
+                (cons 'date-sortvalue #f)
                 (cons 'text (_ "None"))
                 (cons 'tip (_ "None."))
                 (cons 'renderer-fn #f)))
 
    (cons 'daily (list
                   (cons 'split-sortvalue (lambda (s) (time64-day (split->time64 s))))
+                  (cons 'date-sortvalue time64-day)
                   (cons 'text (_ "Daily"))
                   (cons 'tip (_ "Daily."))
                   (cons 'renderer-fn (lambda (s) (time64->daily-string (split->time64 s))))))
 
    (cons 'weekly (list
                   (cons 'split-sortvalue (lambda (s) (time64-week (split->time64 s))))
+                  (cons 'date-sortvalue time64-week)
                   (cons 'text (_ "Weekly"))
                   (cons 'tip (_ "Weekly."))
                   (cons 'renderer-fn (lambda (s) (gnc:date-get-week-year-string (gnc-localtime (split->time64 s)))))))
 
    (cons 'monthly (list
                    (cons 'split-sortvalue (lambda (s) (time64-month (split->time64 s))))
+                   (cons 'date-sortvalue time64-month)
                    (cons 'text (_ "Monthly"))
                    (cons 'tip (_ "Monthly."))
                    (cons 'renderer-fn (lambda (s) (gnc:date-get-month-year-string (gnc-localtime (split->time64 s)))))))
 
    (cons 'quarterly (list
                      (cons 'split-sortvalue (lambda (s) (time64-quarter (split->time64 s))))
+                     (cons 'date-sortvalue time64-quarter)
                      (cons 'text (_ "Quarterly"))
                      (cons 'tip (_ "Quarterly."))
                      (cons 'renderer-fn (lambda (s) (gnc:date-get-quarter-year-string (gnc-localtime (split->time64 s)))))))
 
    (cons 'yearly (list
                   (cons 'split-sortvalue (lambda (s) (time64-year (split->time64 s))))
+                  (cons 'date-sortvalue time64-year)
                   (cons 'text (_ "Yearly"))
                   (cons 'tip (_ "Yearly."))
                   (cons 'renderer-fn (lambda (s) (gnc:date-get-year-string (gnc-localtime (split->time64 s)))))))))
@@ -1424,7 +1430,7 @@ tags within description, notes or memo. ")
           (render-date date-subtotal-key split))
          ((member sortkey ACCOUNT-SORTING-TYPES)
           (render-account sortkey split anchor?))
-         ((eq? sortkey 'reconciled-status)
+         (else
           (render-generic sortkey split)))))
 
     (define (render-grand-total)
@@ -1784,41 +1790,25 @@ tags within description, notes or memo. ")
          (infobox-display (opt-val gnc:pagename-general optname-infobox-display))
          (query (qof-query-create-for-splits)))
 
-    (define (generic-less? X Y key date-subtotal ascend?)
-      (define comparator-function
-        (if (member key DATE-SORTING-TYPES)
-            (let ((date (lambda (s)
-                          (case key
-                            ((date) (xaccTransGetDate (xaccSplitGetParent s)))
-                            ((reconciled-date) (xaccSplitGetDateReconciled s))))))
-              (case date-subtotal
-                ((yearly)    (lambda (s) (time64-year (date s))))
-                ((monthly)   (lambda (s) (time64-month (date s))))
-                ((quarterly) (lambda (s) (time64-quarter (date s))))
-                ((weekly)    (lambda (s) (time64-week (date s))))
-                ((daily)     (lambda (s) (time64-day (date s))))
-                ((none)      (lambda (s) (date s)))))
-            (case key
-              ((account-name) (lambda (s) (gnc-account-get-full-name (xaccSplitGetAccount s))))
-              ((account-code) (lambda (s) (xaccAccountGetCode (xaccSplitGetAccount s))))
-              ((corresponding-acc-name) (lambda (s) (xaccSplitGetCorrAccountFullName s)))
-              ((corresponding-acc-code) (lambda (s) (xaccSplitGetCorrAccountCode s)))
-              ((reconciled-status) (lambda (s) (length (memq (xaccSplitGetReconcile s)
-                                                             '(#\n #\c #\y #\f #\v)))))
-              ((amount) (lambda (s) (gnc-numeric-to-scm (xaccSplitGetValue s))))
-              ((description) (lambda (s) (xaccTransGetDescription (xaccSplitGetParent s))))
-              ((number) (lambda (s)
-                          (if BOOK-SPLIT-ACTION
-                              (xaccSplitGetAction s)
-                              (xaccTransGetNum (xaccSplitGetParent s)))))
-              ((t-number) (lambda (s) (xaccTransGetNum (xaccSplitGetParent s))))
-              ((register-order) (lambda (s) #f))
-              ((memo) (lambda (s) (xaccSplitGetMemo s)))
-              ((none) (lambda (s) #f)))))
-      (cond
-       ((string? (comparator-function X)) ((if ascend? string<? string>?) (comparator-function X) (comparator-function Y)))
-       ((comparator-function X)           ((if ascend? < >)               (comparator-function X) (comparator-function Y)))
-       (else                              #f)))
+    (define (generic-less? split-X split-Y sortkey date-subtotal-key ascend?)
+      ;; compare splits X and Y, whereby
+      ;; sortkey and date-subtotal-key specify the options used
+      ;; ascend? specifies whether ascending or descending
+      (let* ((comparator-function
+              (if (memq sortkey DATE-SORTING-TYPES)
+                  (let ((date (keylist-get-info sortkey-list sortkey 'split-sortvalue))
+                        (date-comparator (keylist-get-info date-subtotal-list date-subtotal-key 'date-sortvalue)))
+                    (lambda (s)
+                      (and date-comparator
+                           (date-comparator (date s)))))
+                  (or (keylist-get-info sortkey-list sortkey 'split-sortvalue)
+                      (lambda (s) #f))))
+             (value-of-X (comparator-function split-X))
+             (value-of-Y (comparator-function split-Y))
+             (op (if (string? value-of-X)
+                     (if ascend? string<? string>?)
+                     (if ascend? < >))))
+        (and value-of-X (op value-of-X value-of-Y))))
 
     (define (primary-comparator? X Y)
       (generic-less? X Y primary-key
@@ -1834,7 +1824,6 @@ tags within description, notes or memo. ")
     (define (date-comparator? X Y)
       (generic-less? X Y 'date 'none #t))
 
-
     (if (or (or (null? c_account_1) (and-map not c_account_1))
             (eq? account-matcher-regexp 'invalid-regex)
             (eq? transaction-matcher-regexp 'invalid-regex))

commit b95fa5ba8cd6a8cdd4416504f52a36529fa4ce05
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 1 20:41:38 2018 +0800

    TR: (simplify) dynamically check CUSTOM-SORTING?
    
    Instead of a list needing manual adjustments, this function will check
    if sortkey requires custom sorter, depending on sortkey capabilities.

diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 9420dc2..8fd2c3d 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -116,8 +116,6 @@ in the Options panel."))
 (define ACCOUNT-SORTING-TYPES (list 'account-name 'corresponding-acc-name
                                     'account-code 'corresponding-acc-code))
 
-(define CUSTOM-SORTING (list 'reconciled-status))
-
 (define SORTKEY-INFORMAL-HEADERS (list 'account-name 'account-code))
 
 (define sortkey-list
@@ -398,6 +396,16 @@ Credit Card, and Income accounts."))
   ;; it checks whether a renderer-fn is defined.
   (keylist-get-info sortkey-list sortkey 'renderer-fn))
 
+(define (CUSTOM-SORTING? sortkey)
+  ;; sortkey -> bool
+  ;;
+  ;; this returns which sortkeys which *must* use the custom sorter.
+  ;; it filters whereby a split-sortvalue is defined (i.e. the splits
+  ;; can be compared according to their 'sortvalue) but the QofQuery
+  ;; sortkey is not defined (i.e. their 'sortkey is #f).
+  (and (keylist-get-info sortkey-list sortkey 'split-sortvalue)
+       (not (keylist-get-info sortkey-list sortkey 'sortkey))))
+
 ;;
 ;; Set defaults for reconcilation report
 ;;
@@ -1771,8 +1779,8 @@ tags within description, notes or memo. ")
                                 (not (eq? primary-date-subtotal 'none)))  ; until qof-query
                            (and (member secondary-key DATE-SORTING-TYPES) ; is upgraded
                                 (not (eq? secondary-date-subtotal 'none)))
-                           (or (member primary-key CUSTOM-SORTING)
-                               (member secondary-key CUSTOM-SORTING))))
+                           (or (CUSTOM-SORTING? primary-key)
+                               (CUSTOM-SORTING? secondary-key))))
          (infobox-display (opt-val gnc:pagename-general optname-infobox-display))
          (query (qof-query-create-for-splits)))
 

commit 6210b80fd0b94d9504cef688a3769d638539393d
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue May 1 19:08:56 2018 +0800

    TR: (simplify) dynamically check SUBTOTAL-ENABLED?
    
    This function checks whether the sortkey can be grouped. Instead of
    manually creating list, test it dynamically.
    
    Sortkeys whose 'renderer-fn is defined can be grouped.

diff --git a/gnucash/report/standard-reports/transaction.scm b/gnucash/report/standard-reports/transaction.scm
index 6dbb894..9420dc2 100644
--- a/gnucash/report/standard-reports/transaction.scm
+++ b/gnucash/report/standard-reports/transaction.scm
@@ -113,14 +113,9 @@ in the Options panel."))
 
 (define DATE-SORTING-TYPES (list 'date 'reconciled-date))
 
-;; The option-values of the sorting key multichoice option, for
-;; which a subtotal should be enabled.
-(define SUBTOTAL-ENABLED (list 'account-name 'corresponding-acc-name
-                               'account-code 'corresponding-acc-code
-                               'reconciled-status))
-
 (define ACCOUNT-SORTING-TYPES (list 'account-name 'corresponding-acc-name
                                     'account-code 'corresponding-acc-code))
+
 (define CUSTOM-SORTING (list 'reconciled-status))
 
 (define SORTKEY-INFORMAL-HEADERS (list 'account-name 'account-code))
@@ -386,7 +381,6 @@ Credit Card, and Income accounts."))
                                   ACCT-TYPE-EQUITY ACCT-TYPE-CREDIT
                                   ACCT-TYPE-INCOME))))))
 
-
 (define (keylist-get-info keylist key info)
   (cdr (assq info (cdr (assq key keylist)))))
 
@@ -399,6 +393,10 @@ Credit Card, and Income accounts."))
       (keylist-get-info keylist (car item) 'tip)))
    keylist))
 
+(define (SUBTOTAL-ENABLED? sortkey)
+  ;; this returns whether sortkey *can* be subtotalled/grouped.
+  ;; it checks whether a renderer-fn is defined.
+  (keylist-get-info sortkey-list sortkey 'renderer-fn))
 
 ;;
 ;; Set defaults for reconcilation report
@@ -585,10 +583,10 @@ tags within description, notes or memo. ")
 
     (define (apply-selectable-by-name-sorting-options)
       (let* ((prime-sortkey-enabled (not (eq? prime-sortkey 'none)))
-             (prime-sortkey-subtotal-enabled (member prime-sortkey SUBTOTAL-ENABLED))
+             (prime-sortkey-subtotal-enabled (SUBTOTAL-ENABLED? prime-sortkey))
              (prime-date-sortingtype-enabled (member prime-sortkey DATE-SORTING-TYPES))
              (sec-sortkey-enabled (not (eq? sec-sortkey 'none)))
-             (sec-sortkey-subtotal-enabled (member sec-sortkey SUBTOTAL-ENABLED))
+             (sec-sortkey-subtotal-enabled (SUBTOTAL-ENABLED? sec-sortkey))
              (sec-date-sortingtype-enabled (member sec-sortkey DATE-SORTING-TYPES)))
 
         (gnc-option-db-set-option-selectable-by-name
@@ -962,17 +960,17 @@ tags within description, notes or memo. ")
     (let ((sortkey (opt-val pagename-sorting optname-prime-sortkey)))
       (if (member sortkey DATE-SORTING-TYPES)
           (keylist-get-info date-subtotal-list (opt-val pagename-sorting optname-prime-date-subtotal) info)
-          (and (member sortkey SUBTOTAL-ENABLED)
-               (and (opt-val pagename-sorting optname-prime-subtotal)
-                    (keylist-get-info sortkey-list sortkey info))))))
+          (and (SUBTOTAL-ENABLED? sortkey)
+               (opt-val pagename-sorting optname-prime-subtotal)
+               (keylist-get-info sortkey-list sortkey info)))))
 
   (define (secondary-get-info info)
     (let ((sortkey (opt-val pagename-sorting optname-sec-sortkey)))
       (if (member sortkey DATE-SORTING-TYPES)
           (keylist-get-info date-subtotal-list (opt-val pagename-sorting optname-sec-date-subtotal) info)
-          (and (member sortkey SUBTOTAL-ENABLED)
-               (and (opt-val pagename-sorting optname-sec-subtotal)
-                    (keylist-get-info sortkey-list sortkey info))))))
+          (and (SUBTOTAL-ENABLED? sortkey)
+               (opt-val pagename-sorting optname-sec-subtotal)
+               (keylist-get-info sortkey-list sortkey info)))))
 
   (let* ((work-to-do (length splits))
          (work-done 0)

commit 6e78fa1d99936244fd74772fc3a329fd8120168c
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed May 2 22:54:31 2018 +0800

    test-TR: change report out filenames
    
    This will allow easier addition of tests.
    
    Also fix (use-modules) usage. VM is only needed for coverage reporting.

diff --git a/gnucash/report/standard-reports/test/test-transaction.scm b/gnucash/report/standard-reports/test/test-transaction.scm
index 7297851..c0b3518 100644
--- a/gnucash/report/standard-reports/test/test-transaction.scm
+++ b/gnucash/report/standard-reports/test/test-transaction.scm
@@ -8,8 +8,8 @@
 (use-modules (srfi srfi-64))
 (use-modules (sxml simple))
 (use-modules (sxml xpath))
-(use-modules (system vm coverage)
-             (system vm vm))
+(use-modules (system vm coverage))
+(use-modules (system vm vm))
 
 ;; Guide to the test-transaction.scm
 
@@ -24,7 +24,7 @@
 ;; which sets the SRFI-64 test runner, and initiates the proper test suite
 ;; in (null-test) and (trep-tests). Please note the tests will all call
 ;; (options->sxml) which in turn generates the transaction report, and
-;; dumps the output at /tmp/out-XX.html for review.
+;; dumps the output at /tmp/test-trep-*.html for review.
 
 ;; For coverage analysis, please amend (run-test) (if #f ...) to (if
 ;; #t ...)  and this will run (coverage-test) instead, which will
@@ -110,27 +110,22 @@
                     (memv c '(#\- #\.))))
     str)))
 
-(define counter
-  (let ((count 0))
-    (lambda ()
-      (set! count (1+ count))
-      count)))
-
 (define (options->sxml options test-title)
   ;; options object -> sxml tree
   ;;
   ;; This function abstracts the whole transaction report renderer.
   ;; It also catches XML parsing errors, dumping the options changed.
   ;;
-  ;; It also dumps the render into /tmp/out-N.html where N is a counter
+  ;; It also dumps the render into /tmp/test-trep-XX.html where XX is the test title
   (let* ((template (gnc:find-report-template trep-uuid))
          (report (constructor trep-uuid "bar" options #t #t #f #f ""))
          (renderer (gnc:report-template-renderer template))
-         (document (renderer report)))
+         (document (renderer report))
+         (filename (string-map (lambda (c) (if (char-alphabetic? c) c #\-)) test-title)))
     (gnc:html-document-set-style-sheet! document (gnc:report-stylesheet report))
     (if test-title
         (gnc:html-document-set-title! document test-title))
-    (let* ((filename (format #f "/tmp/out-~a.html" (counter)))
+    (let* ((filename (format #f "/tmp/test-trep-~a.html" filename))
            (render (gnc:html-document-render document))
            (outfile (open-file filename "w")))
       (display render outfile)
@@ -194,7 +189,7 @@
 (define (null-test)
   ;; This null-test tests for the presence of report.
   (let ((options (gnc:make-report-options trep-uuid)))
-    (test-assert "null-test" (options->sxml options "null-test")))) ;out-1.html
+    (test-assert "null-test" (options->sxml options "null-test"))))
 
 (define (trep-tests)
   ;; This function will perform implementation testing on the transaction report.
@@ -325,7 +320,7 @@
     (test-begin "general options")
 
     (let* ((options (default-testing-options))
-           (sxml (options->sxml options "general options")) ;out-2.html
+           (sxml (options->sxml options "general options"))
            (default-headers '("Date" "Num" "Description" "Memo/Notes" "Account" "Amount")))
       (test-equal "default headers"
         default-headers
@@ -351,7 +346,7 @@
       (set-option! options "Sorting" "Primary Subtotal" #t)
       (set-option! options "Sorting" "Secondary Key" 'date)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'monthly)
-      (let ((sxml (options->sxml options "test basic column headers, and original currency"))) ;out-3.html
+      (let ((sxml (options->sxml options "test basic column headers, and original currency")))
         (test-equal "default headers, indented, includes common-currency"
           '(" " " " "Date" "Num" "Description" "Memo/Notes" "Account" "Amount" "USD" "Amount")
           (get-row-col sxml 0 #f))
@@ -377,19 +372,19 @@
 
       ;; Filter Account Name Filters
       (set-option! options "Filter" "Account Name Filter" "Expenses")
-      (let ((sxml (options->sxml options "accounts filter expenses"))) ;out-4.html
+      (let ((sxml (options->sxml options "accounts filter expenses")))
         (test-equal "account name filter to 'expenses', sum = $31.00"
           '("$31.00")
           (get-row-col sxml -1 -1)))
 
       (set-option! options "Filter" "Account Name Filter" "Expen.es")
-      (let ((sxml (options->sxml options "accounts filter expen.es"))) ;out-5.html
+      (let ((sxml (options->sxml options "accounts filter expen.es")))
         (test-equal "account name filter to 'expen.es', blank report"
           '()
           (get-row-col sxml #f #f)))
 
       (set-option! options "Filter" "Use regular expressions for account name filter" #t)
-      (let ((sxml (options->sxml options "accounts filter expen.es regex"))) ;out-6.html
+      (let ((sxml (options->sxml options "accounts filter expen.es regex")))
         (test-equal "account name filter to 'expen.es' and switch on regex filter, sum = $31.00"
           '("$31.00")
           (get-row-col sxml -1 -1)))
@@ -399,19 +394,19 @@
       (set-option! options "General" "Start Date" (cons 'absolute (gnc-dmy2time64 01 01 1969)))
       (set-option! options "General" "End Date" (cons 'absolute (gnc-dmy2time64 31 12 1970)))
       (set-option! options "Filter" "Transaction Filter" "desc-3")
-      (let ((sxml (options->sxml options "transaction filter to ponies"))) ;out-7.html
+      (let ((sxml (options->sxml options "transaction filter to ponies")))
         (test-equal "transaction filter in bank to 'desc-3', sum = $29.00"
           '("$29.00")
           (get-row-col sxml -1 -1)))
 
       (set-option! options "Filter" "Transaction Filter" "not.s?")
-      (let ((sxml (options->sxml options "transaction filter not.s?"))) ;out-8.html
+      (let ((sxml (options->sxml options "transaction filter not.s?")))
         (test-equal "transaction filter in bank to 'not.s?', blank report"
           '()
           (get-row-col sxml #f #f)))
 
       (set-option! options "Filter" "Use regular expressions for transaction filter" #t)
-      (let ((sxml (options->sxml options "transaction filter not.s? regex"))) ;out-9.html
+      (let ((sxml (options->sxml options "transaction filter not.s? regex")))
         (test-equal "transaction filter in bank to 'not.s?' and switch regex, sum = -$23.00"
           '("-$23.00")
           (get-row-col sxml -1 -1)))
@@ -421,19 +416,19 @@
       (set-option! options "General" "Start Date" (cons 'absolute (gnc-dmy2time64 01 01 1969)))
       (set-option! options "General" "End Date" (cons 'absolute (gnc-dmy2time64 31 12 1970)))      
       (set-option! options "Filter" "Reconcile Status" 'unreconciled)
-      (let ((sxml (options->sxml options "unreconciled"))) ;out-10.html
+      (let ((sxml (options->sxml options "unreconciled")))
         (test-equal "filter unreconciled only, sum = -$20.00"
           '("-$20.00")
           (get-row-col sxml -1 -1)))
 
       (set-option! options "Filter" "Reconcile Status" 'cleared)
-      (let ((sxml (options->sxml options "cleared"))) ;out-11.html
+      (let ((sxml (options->sxml options "cleared")))
         (test-equal "filter cleared only, sum = $29.00"
           '("$29.00")
           (get-row-col sxml -1 -1)))
 
       (set-option! options "Filter" "Reconcile Status" 'reconciled)
-      (let ((sxml (options->sxml options "reconciled"))) ;out-12.html
+      (let ((sxml (options->sxml options "reconciled")))
         (test-equal "filter reconciled only, sum = -$8.00"
           '("-$8.00")
           (get-row-col sxml -1 -1)))
@@ -444,13 +439,13 @@
       (set-option! options "General" "End Date" (cons 'absolute (gnc-dmy2time64 31 12 1970)))      
       (set-option! options "Accounts" "Filter By..." (list income))
       (set-option! options "Accounts" "Filter Type" 'include)
-      (let ((sxml (options->sxml options "including bank-income accts only"))) ;out-13.html
+      (let ((sxml (options->sxml options "including bank-income accts only")))
         (test-equal "filter includes bank-income, sum = -$29.00"
           '("$29.00")
           (get-row-col sxml -1 -1)))
 
       (set-option! options "Accounts" "Filter Type" 'exclude)
-      (let ((sxml (options->sxml options "bank exclude bank-income accts"))) ;out-14.html
+      (let ((sxml (options->sxml options "bank exclude bank-income accts")))
         (test-equal "filter excludes bank-income, sum = -$28.00"
           '("-$28.00")
           (get-row-col sxml -1 -1)))
@@ -460,13 +455,13 @@
       (set-option! options "General" "Start Date" (cons 'absolute (gnc-dmy2time64 01 01 1969)))
       (set-option! options "General" "End Date" (cons 'absolute (gnc-dmy2time64 31 12 1970)))      
       (set-option! options "Filter" "Void Transactions" 'void-only)
-      (let ((sxml (options->sxml options "void only"))) ;out-15.html
+      (let ((sxml (options->sxml options "void only")))
         (test-equal "filter void-transactions only, sum = -$10.00"
           '("$10.00")
           (get-row-col sxml -1 -1)))
 
       (set-option! options "Filter" "Void Transactions" 'both)
-      (let ((sxml (options->sxml options "both void and non-void"))) ;out-16.html
+      (let ((sxml (options->sxml options "both void and non-void")))
         (test-equal "filter void-transactions only, sum = $11.00"
           '("$11.00")
           (get-row-col sxml -1 -1))))
@@ -483,7 +478,7 @@
        (list "Date" "Reconciled Date" "Num" "Description" "Memo" "Notes"
              "Account Name" "Other Account Name" "Shares" "Price" "Running Balance"
              "Totals"))
-      (let ((sxml (options->sxml options "all columns off"))) ;out-17.html
+      (let ((sxml (options->sxml options "all columns off")))
         (test-assert "all display columns off, except amount and subtotals are enabled, there should be 2 columns"
           (= (length ((sxpath '(// (table 1) // (tr 1) // th)) sxml))
              (length ((sxpath '(// (table 1) // (tr 4) // td)) sxml))
@@ -494,7 +489,7 @@
       (set-option! options "Sorting" "Primary Subtotal for Date Key" 'none)
       (set-option! options "Sorting" "Secondary Subtotal" #f)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'none)
-      (let ((sxml (options->sxml options "only amounts"))) ;out-18.html
+      (let ((sxml (options->sxml options "only amounts")))
         (test-assert "all display columns off, and no subtotals, but amount enabled, there should be 1 column"
           (= (length ((sxpath '(// (table 1) // (tr 1) // th)) sxml))
              (length ((sxpath '(// (table 1) // (tr 4) // td)) sxml))
@@ -502,7 +497,7 @@
              1)))
 
       (set-option! options "Display" "Amount" 'none)
-      (let ((sxml (options->sxml options "no columns"))) ;out-19.html
+      (let ((sxml (options->sxml options "no columns")))
         (test-assert "all display columns off, without amount nor subtotals, there should be 0 column"
           (= (length ((sxpath '(// (table 1) // (tr 1) // th)) sxml))
              (length ((sxpath '(// (table 1) // (tr 4) // td)) sxml))
@@ -513,7 +508,7 @@
       (set-option! options "Sorting" "Primary Subtotal for Date Key" 'weekly)
       (set-option! options "Sorting" "Secondary Subtotal" #t)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'weekly)
-      (let ((sxml (options->sxml options "subtotals only"))) ;out-20.html
+      (let ((sxml (options->sxml options "subtotals only")))
         (test-assert "all display columns including amount are disabled, but subtotals are enabled, there should be 1 column"
           (= (length ((sxpath '(// (table 1) // (tr 1) // th)) sxml))
              (length ((sxpath '(// (table 1) // (tr -1) // td)) sxml))
@@ -531,7 +526,7 @@
        (list "Date" "Reconciled Date" "Num" "Description" "Memo" "Notes"
              "Account Name" "Other Account Name" "Shares" "Price" "Running Balance"
              "Totals" "Use Full Other Account Name" "Use Full Account Name"))
-      (let* ((sxml (options->sxml options "all columns on"))) ;out-21.html
+      (let* ((sxml (options->sxml options "all columns on")))
         (test-equal "all display columns on, displays correct columns"
           (list "Date" "Reconciled Date" "Num" "Description" "Memo/Notes" "Account"
                 "Transfer from/to" "Shares" "Price" "Amount" "Running Balance")
@@ -560,7 +555,7 @@
       (set-option! options "Sorting" "Primary Subtotal for Date Key" 'none)
       (set-option! options "Sorting" "Secondary Subtotal" #f)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'none)
-      (let* ((sxml (options->sxml options "multiline"))) ;out-22.html
+      (let* ((sxml (options->sxml options "multiline")))
         (test-assert "multi line transaction with 1st split have same memo"
           (apply string=? (get-row-col sxml #f 4)))
 
@@ -573,7 +568,7 @@
       ;; Remove expense multisplit, transaction is not shown
       (set-option! options "Accounts" "Filter By..." (list expense))
       (set-option! options "Accounts" "Filter Type" 'exclude)
-      (let* ((sxml (options->sxml options "multiline, filtered out"))) ;out-23.html
+      (let* ((sxml (options->sxml options "multiline, filtered out")))
         (test-equal "multi-line has been excluded"
           '()
           (get-row-col sxml #f #f)))
@@ -586,7 +581,7 @@
       (set-option! options "General" "End Date" (cons 'absolute (gnc-dmy2time64 31 12 2000)))
       (set-option! options "General" "Common Currency" #t)
       (set-option! options "General" "Show original currency amount" #t)
-      (let* ((sxml (options->sxml options "single column, with original currency headers"))) ;out-24.html
+      (let* ((sxml (options->sxml options "single column, with original currency headers")))
         (test-equal "single amount column, with original currency headers"
           (list "Date" "Num" "Description" "Memo/Notes" "Account"
                 "Amount" "USD" "Amount")
@@ -597,7 +592,7 @@
       (set-option! options "Display" "Account Code" #t)
       (set-option! options "Display" "Other Account Name" #t)
       (set-option! options "Display" "Other Account Code" #t)
-      (let* ((sxml (options->sxml options "dual column"))) ;out-25.html
+      (let* ((sxml (options->sxml options "dual column")))
         ;; Note. It's difficult to test converted monetary
         ;; amounts. Although I've set transfers from USD/GBP, the
         ;; transfers do not update the pricedb automatically,
@@ -638,21 +633,21 @@
       (set-option! options "Sorting" "Primary Subtotal" #f)
       (set-option! options "Sorting" "Secondary Key" 'description)
       (set-option! options "Sorting" "Secondary Subtotal" #f)
-      (let* ((sxml (options->sxml options "sign-reversal is none, correct signs of amounts?"))) ;out-26.html
+      (let* ((sxml (options->sxml options "sign-reversal is none, correct signs of amounts?")))
         (test-equal "sign-reversal is none, correct signs of amounts"
           '(#f #t #t #f #f #t #t #t #t #f #f #f #f #t)
           (map (lambda (s) (not (string-contains s "-")))
                ((sxpath '(// (table 1) // tr // (td -1) // a // *text*)) sxml))))
 
       (set-option! options "Display" "Sign Reverses" 'income-expense)
-      (let* ((sxml (options->sxml options "sign-reversal is income-expense, correct signs of amounts?"))) ;out-27.html
+      (let* ((sxml (options->sxml options "sign-reversal is income-expense, correct signs of amounts?")))
         (test-equal "sign-reversal is income-expense, correct signs of amounts"
           '(#f #t #t #f #f #f #f #f #f #t #t #f #f #t)
           (map (lambda (s) (not (string-contains s "-")))
                ((sxpath '(// (table 1) // tr // (td -1) // a // *text*)) sxml))))
 
       (set-option! options "Display" "Sign Reverses" 'credit-accounts)
-      (let* ((sxml (options->sxml options "sign-reversal is credit-accounts, correct signs of amounts?"))) ;out-28.html
+      (let* ((sxml (options->sxml options "sign-reversal is credit-accounts, correct signs of amounts?")))
         (test-equal "sign-reversal is credit-accounts, correct signs of amounts"
           '(#f #t #t #f #f #t #t #t #t #t #t #t #t #f)
           (map (lambda (s) (not (string-contains s "-")))
@@ -665,7 +660,7 @@
       (set-option! options "General" "Show original currency amount" #t)
       (set-option! options "Sorting" "Primary Key" 'date)
       (set-option! options "Sorting" "Primary Subtotal for Date Key" 'none)
-      (let* ((sxml (options->sxml options "dual columns"))) ;out-29.html
+      (let* ((sxml (options->sxml options "dual columns")))
         (test-equal "dual amount column, with original currency headers"
           (list "Date" "Num" "Description" "Memo/Notes" "Account"
                 "Debit" "USD" "Credit" "USD" "Debit" "Credit")
@@ -696,42 +691,42 @@
       (set-option! options "Sorting" "Secondary Subtotal" #f)
 
       (set-option! options "Sorting" "Primary Key" 'date)
-      (let* ((sxml (options->sxml options "sorting=date"))) ;out-30.html
+      (let* ((sxml (options->sxml options "sorting=date")))
         (test-equal "dates are sorted"
           '("12/31/69" "12/31/69" "01/01/70" "02/01/70" "02/10/70")
           (get-row-col sxml #f 1)))
 
       (set-option! options "Sorting" "Primary Key" 'number)
-      (let* ((sxml (options->sxml options "sorting=number"))) ;out-31.html
+      (let* ((sxml (options->sxml options "sorting=number")))
         (test-equal "sort by number"
           '("trn1" "trn2" "trn3" "trn4" "trn7")
           (get-row-col sxml #f 2)))
 
       (set-option! options "Sorting" "Primary Key" 'reconciled-status)
-      (let* ((sxml (options->sxml options "sorting=reconciled-status"))) ;out-32.html
+      (let* ((sxml (options->sxml options "sorting=reconciled-status")))
         (test-equal "sort by reconciled status"
           '("desc-2" "desc-7" "desc-3" "desc-1" "desc-4")
           (get-row-col sxml #f 3)))
 
       (set-option! options "Sorting" "Primary Key" 'memo)
-      (let* ((sxml (options->sxml options "sorting=memo"))) ;out-33.html
+      (let* ((sxml (options->sxml options "sorting=memo")))
         (test-equal "sort by memo"
           '("notes3" "memo-1" "memo-2" "memo-3")
           (get-row-col sxml #f 4)))
 
       (set-option! options "Sorting" "Primary Key" 'account-name)
-      (let* ((sxml (options->sxml options "sorting=account-name"))) ;out-34.html
+      (let* ((sxml (options->sxml options "sorting=account-name")))
         (test-assert "account names are sorted"
           (sorted? (get-row-col sxml #f 5) string<?)))
 
       (set-option! options "Sorting" "Primary Key" 'corresponding-acc-name)
-      (let* ((sxml (options->sxml options "sorting=corresponding-acc-name"))) ;out-35.html
+      (let* ((sxml (options->sxml options "sorting=corresponding-acc-name")))
         (test-equal "sort by corresponding-acc-name"
           '("Expenses" "Expenses" "Income" "Income" "Liabilities")
           (get-row-col sxml #f 6)))
 
       (set-option! options "Sorting" "Primary Key" 'amount)
-      (let* ((sxml (options->sxml options "sorting=amount"))) ;out-36.html
+      (let* ((sxml (options->sxml options "sorting=amount")))
         (test-equal "sort by amount"
           '("-$15.00" "-$8.00" "-$5.00" "$10.00" "$29.00")
           ((sxpath '(// (table 1) // tr // (td -1) // a // *text*)) sxml)))
@@ -746,7 +741,7 @@
       (set-option! options "Display" "Totals" #t)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'quarterly)
       (set-option! options "Sorting" "Show subtotals only (hide transactional data)" #t)
-      (let* ((sxml (options->sxml options "sorting=account-name, date-quarterly, subtotals only"))) ;out-37.html
+      (let* ((sxml (options->sxml options "sorting=account-name, date-quarterly, subtotals only")))
         (test-equal "sorting=account-name, date-quarterly, subtotals only"
           '("$570.00" "$570.00" "$570.00" "$570.00" "$2,280.00" "$2,280.00")
           (get-row-col sxml #f -1)))
@@ -764,7 +759,7 @@
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'quarterly)
       (set-option! options "Sorting" "Show Informal Debit/Credit Headers" #t)
       (set-option! options "Sorting" "Show Account Description" #t)
-      (let* ((sxml (options->sxml options "sorting=date"))) ;out-38.html
+      (let* ((sxml (options->sxml options "sorting=date")))
         (test-equal "expense acc friendly headers"
           '("\n" "Expenses" "Expense" "Rebate")
           (get-row-col sxml 47 #f))
@@ -775,19 +770,19 @@
       (set-option! options "Accounts" "Accounts" (list bank))
       (set-option! options "Display" "Totals" #f)
       (set-option! options "Sorting" "Show subtotals only (hide transactional data)" #t)
-      (let* ((sxml (options->sxml options "sorting=date quarterly"))) ;out-39.html
+      (let* ((sxml (options->sxml options "sorting=date quarterly")))
         (test-equal "quarterly subtotals are correct"
           '("$570.00" "$570.00" "$570.00" "$570.00")
           (get-row-col sxml #f 4)))
 
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'monthly)
-      (let* ((sxml (options->sxml options "sorting=date monthly"))) ;out-40.html
+      (let* ((sxml (options->sxml options "sorting=date monthly")))
         (test-equal "monthly subtotals are correct"
           '("$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00")
           (get-row-col sxml #f 4)))
 
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'yearly)
-      (let* ((sxml (options->sxml options "sorting=date yearly"))) ;out-41.html
+      (let* ((sxml (options->sxml options "sorting=date yearly")))
         (test-equal "yearly subtotals are correct"
           '("$2,280.00")
           (get-row-col sxml #f 4)))
@@ -797,14 +792,14 @@
       (set-option! options "Sorting" "Show subtotals only (hide transactional data)" #f)
       (set-option! options "Filter" "Void Transactions" 'both)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'daily)
-      (let* ((sxml (options->sxml options "sorting=date"))) ;out-42.html
+      (let* ((sxml (options->sxml options "sorting=date")))
         (test-equal "daily subtotals are correct"
           '("$39.00")
           (get-row-col sxml 5 4)))
 
       (set-option! options "Sorting" "Show subtotals only (hide transactional data)" #t)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'weekly)
-      (let* ((sxml (options->sxml options "sorting=date weekly"))) ;out-43.html
+      (let* ((sxml (options->sxml options "sorting=date weekly")))
         (test-equal "weekly subtotals are correct (1)"
           '("$34.00" "$89.00")
           (get-row-col sxml #f 4))
@@ -825,7 +820,7 @@
       (set-option! options "Sorting" "Primary Subtotal" #t)
       (set-option! options "Sorting" "Secondary Key" 'date)
       (set-option! options "Sorting" "Secondary Subtotal for Date Key" 'monthly)
-      (let ((sxml (options->sxml options "subtotal table"))) ;out-44.html
+      (let ((sxml (options->sxml options "subtotal table")))
         (test-equal "summary bank-row is correct"
           (list "Bank" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00"
                 "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$190.00" "$2,280.00")
@@ -845,7 +840,7 @@
 
       (set-option! options "General" "Start Date" (cons 'absolute (gnc-dmy2time64 01 01 1969)))
       (set-option! options "General" "End Date" (cons 'absolute (gnc-dmy2time64 31 12 1970)))
-      (let ((sxml (options->sxml options "sparse subtotal table"))) ;out-45.html
+      (let ((sxml (options->sxml options "sparse subtotal table")))
         (test-equal "sparse summary-table - row 1"
           (list "Bank" "$29.00" "-$5.00" "-$23.00" "$1.00")
           (get-row-col sxml 1 #f))

commit 2e53d647263c20a9e1a9a7fd6893ec7ef186280f
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Wed May 9 17:39:29 2018 +0200

    Work around gtk warnings with gcc 8.0

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce4b99a..5310ad1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -556,8 +556,8 @@ set(CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}")  # FIXME: should be -std=
 
 if (UNIX)
   set( CMAKE_C_FLAGS "-Werror -Wdeclaration-after-statement -Wno-pointer-sign -Wall -Wmissing-prototypes -Wmissing-declarations -Wno-unused ${CMAKE_C_FLAGS}")
-  set( CMAKE_CXX_FLAGS "-Werror -Wall -Wmissing-declarations -Wno-unused ${CMAKE_CXX_FLAGS}")
-  set( CMAKE_C_FLAGS "-Wno-deprecated-declarations -std=gnu11 ${CMAKE_C_FLAGS}")
+  set( CMAKE_CXX_FLAGS "-Werror -Wall -Wmissing-declarations -Wno-unused -Wno-error=parentheses ${CMAKE_CXX_FLAGS}")
+  set( CMAKE_C_FLAGS "-Wno-deprecated-declarations -std=gnu11 -Wno-error=parentheses ${CMAKE_C_FLAGS}")
   set( CMAKE_C_FLAGS_RELEASE "-O3 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 ${CMAKE_C_FLAGS}")
 endif (UNIX)
 if (MINGW)

commit 1f3cf845c4588e787f9b26ad06b05d7cd73326b7
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Wed May 9 17:20:13 2018 +0200

    Work around a conflict between gcc 8.0 and swig 3.0
    
    The swig 3.0 generated python wrappers trigger a warning converted into an error issued
    by gcc 8.0 for using strncpy as follows:
    strncpy(buff, "swig_ptr: ", 10);
    The reason is this call will truncate the trailing null byte from the string.
    This appears to have been fixed in swig master already but that's not released yet
    so let disable the warning when compiling the swig wrappers until it is.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e58f9f1..ce4b99a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -524,8 +524,13 @@ endif (Boost_FOUND)
 
 # Compiler flags
 
+include (CheckCCompilerFlag)
+check_c_compiler_flag(-Wstringop-truncation have_stringop_truncation)
+if (have_stringop_truncation)
+    set(HAVE_STRINGOP_TRUNCATION TRUE)
+endif()
+
 if (APPLE)
-  include (CheckCCompilerFlag)
   include (CheckCxxCompilerFlag)
   check_cxx_compiler_flag(-Wno-unused-local-typedef, have_wno_ult)
   if (have_wno_ult)
diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt
index df90698..8350920 100644
--- a/bindings/python/CMakeLists.txt
+++ b/bindings/python/CMakeLists.txt
@@ -66,11 +66,17 @@ if(WITH_PYTHON)
   target_link_libraries(gnucash_core_c gncmod-app-utils gncmod-engine gnc-module ${GLIB_LIBS} ${PYTHON_LIBRARIES})
   set_target_properties(gnucash_core_c PROPERTIES PREFIX "_")
   target_compile_options(gnucash_core_c PRIVATE -Wno-implicit -Wno-missing-prototypes -Wno-declaration-after-statement -Wno-missing-declarations)
+  if (HAVE_STRINGOP_TRUNCATION)
+    target_compile_options(gnucash_core_c PRIVATE -Wno-error=stringop-truncation)
+  endif()
 
   add_executable(sqlite3test EXCLUDE_FROM_ALL sqlite3test.c ${SWIG_GNUCASH_CORE_C})
   target_link_libraries(sqlite3test gncmod-app-utils gncmod-engine gnc-module ${GLIB_LIBS} ${PYTHON_LIBRARIES})
   target_include_directories(sqlite3test PRIVATE ${gnucash_core_c_INCLUDE_DIRS})
   target_compile_options(sqlite3test PRIVATE -Wno-implicit -Wno-missing-prototypes -Wno-declaration-after-statement -Wno-missing-declarations)
+  if (HAVE_STRINGOP_TRUNCATION)
+    target_compile_options(sqlite3test PRIVATE -Wno-error=stringop-truncation)
+  endif()
 
   add_test(NAME sqlite3test COMMAND sqlite3test)
   add_dependencies(check sqlite3test)
diff --git a/common/test-core/CMakeLists.txt b/common/test-core/CMakeLists.txt
index 229cb39..b57ab5c 100644
--- a/common/test-core/CMakeLists.txt
+++ b/common/test-core/CMakeLists.txt
@@ -48,6 +48,9 @@ if (WITH_PYTHON)
   target_link_libraries(unittest_support test-core ${PYTHON_LIBRARIES})
   target_include_directories(unittest_support PRIVATE ${PYTHON_INCLUDE_DIRS})
   set_target_properties(unittest_support PROPERTIES PREFIX "_")
+  if (HAVE_STRINGOP_TRUNCATION)
+    target_compile_options(unittest_support PRIVATE -Wno-error=stringop-truncation)
+  endif()
 endif()
 
 set(test_core_SCHEME unittest-support.scm)
diff --git a/libgnucash/app-utils/CMakeLists.txt b/libgnucash/app-utils/CMakeLists.txt
index d44dbe2..eb6fd3d 100644
--- a/libgnucash/app-utils/CMakeLists.txt
+++ b/libgnucash/app-utils/CMakeLists.txt
@@ -116,6 +116,9 @@ if (WITH_PYTHON)
 
   target_link_libraries(sw_app_utils gncmod-app-utils ${app_utils_ALL_LIBRARIES} ${PYTHON_LIBRARIES})
   set_target_properties(sw_app_utils PROPERTIES PREFIX "_")
+  if (HAVE_STRINGOP_TRUNCATION)
+    target_compile_options(sw_app_utils PRIVATE -Wno-error=stringop-truncation)
+  endif()
 
   target_include_directories (sw_app_utils
     PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/libgnucash/core-utils/CMakeLists.txt b/libgnucash/core-utils/CMakeLists.txt
index fa3972c..0093de0 100644
--- a/libgnucash/core-utils/CMakeLists.txt
+++ b/libgnucash/core-utils/CMakeLists.txt
@@ -171,6 +171,10 @@ if (WITH_PYTHON)
   target_link_libraries(sw_core_utils gnc-core-utils ${core_utils_ALL_LIBRARIES} ${PYTHON_LIBRARIES})
   set_target_properties(sw_core_utils PROPERTIES PREFIX "_")
 
+  if (HAVE_STRINGOP_TRUNCATION)
+    target_compile_options(sw_core_utils PRIVATE -Wno-error=stringop-truncation)
+  endif()
+
   target_include_directories (sw_core_utils
     PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
     PRIVATE ${core_utils_ALL_INCLUDES} ${PYTHON_INCLUDE_DIRS}

commit 27c1df30afda7998c8f1dccd3253fb53a95fbe8e
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat May 5 13:42:13 2018 +0200

    Handle the common csv double quote escape variation (repeating the double quote)

diff --git a/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp b/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp
index b5ad206..bb4f8c8 100644
--- a/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp
+++ b/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp
@@ -76,6 +76,16 @@ int GncCsvTokenizer::tokenize()
                 bs_pos = line.find ('\\', bs_pos);
             }
 
+            // Deal with repeated " ("") in strings.
+            // This is commonly used as escape mechanism for double quotes in csv files.
+            // However boost just eats them.
+            bs_pos = line.find ("\"\"");
+            while (bs_pos != std::string::npos)
+            {
+                line.replace (bs_pos, 2, "\\\"");
+                bs_pos = line.find ("\"\"");
+            }
+
             Tokenizer tok(line, sep);
             vec.assign(tok.begin(),tok.end());
             m_tokenized_contents.push_back(vec);
diff --git a/gnucash/import-export/csv-imp/test/test-tokenizer.cpp b/gnucash/import-export/csv-imp/test/test-tokenizer.cpp
index fdbd1e1..961ac65 100644
--- a/gnucash/import-export/csv-imp/test/test-tokenizer.cpp
+++ b/gnucash/import-export/csv-imp/test/test-tokenizer.cpp
@@ -176,6 +176,7 @@ static tokenize_csv_test_data comma_separated [] = {
         { "05/01/15,45,Acme Inc.,,Miscellaneous,", 6, { "05/01/15","45","Acme Inc.","","Miscellaneous","",NULL,NULL } },
         { "Test\\ with backslash,nextfield", 2, { "Test\\ with backslash","nextfield",NULL,NULL,NULL,NULL,NULL,NULL } },
         { "Test with \\\" escaped quote,nextfield", 2, { "Test with \" escaped quote","nextfield",NULL,NULL,NULL,NULL,NULL,NULL } },
+        { "Test with \"\" escaped quote,nextfield", 2, { "Test with \" escaped quote","nextfield",NULL,NULL,NULL,NULL,NULL,NULL } },
         { NULL, 0, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
 };
 

commit 682b5cf581895a5da3296cfbfc24acc9ece0185e
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat May 5 12:42:17 2018 +0200

    Bug 795666 - Backslash "\" in Description field spoils CSV Import without helpful error message
    
    We've configure boost::tokenizer to take the backslash as the escape character
    However boost::tokenizer will throw if it encounters a sole backslash that's
    not an escape (it would expect two if a pure backslash is to be inserted).
    Avoid this by replacing lone backslashes (not part of escapes) with double
    backslashes before passing control to the tokenizer.

diff --git a/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp b/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp
index 402900a..b5ad206 100644
--- a/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp
+++ b/gnucash/import-export/csv-imp/gnc-tokenizer-csv.cpp
@@ -63,6 +63,19 @@ int GncCsvTokenizer::tokenize()
             }
             // ---
 
+            // Deal with backslashes that are not meant to be escapes
+            // The boost::tokenizer with escaped_list_separator as we use
+            // it would choke on this.
+            auto bs_pos = line.find ('\\');
+            while (bs_pos != std::string::npos)
+            {
+                if ((bs_pos == line.size()) ||                                 // got trailing single backslash
+                    (line.find_first_of ("\"\\n", bs_pos + 1) != bs_pos + 1))  // backslash is not part of known escapes \\, \" or \n
+                    line = line.substr(0, bs_pos) + "\\\\" + line.substr(bs_pos + 1);
+                bs_pos += 2;
+                bs_pos = line.find ('\\', bs_pos);
+            }
+
             Tokenizer tok(line, sep);
             vec.assign(tok.begin(),tok.end());
             m_tokenized_contents.push_back(vec);
diff --git a/gnucash/import-export/csv-imp/test/test-tokenizer.cpp b/gnucash/import-export/csv-imp/test/test-tokenizer.cpp
index c97902a..fdbd1e1 100644
--- a/gnucash/import-export/csv-imp/test/test-tokenizer.cpp
+++ b/gnucash/import-export/csv-imp/test/test-tokenizer.cpp
@@ -138,17 +138,6 @@ TEST_F (GncTokenizerTest, tokenize_from_csv_file)
  * independently.
  */
 
-/* First test whether we're properly catching boost::tokenizer throws
- * This happens when the input data has invalid escape sequences */
-TEST_F (GncTokenizerTest, tokenize_binary_data)
-{
-    GncCsvTokenizer *csvtok = dynamic_cast<GncCsvTokenizer*>(csv_tok.get());
-    csvtok->set_separators (",");
-
-    set_utf8_contents (csv_tok, R"(\764Test,Something)");
-    EXPECT_THROW (csv_tok->tokenize(), std::range_error);
-}
-
 /* This helper function will run the parse step on the given data
  * with the parser as configured by the calling test function.
  * This allows the same code to be used with different csv test strings
@@ -185,6 +174,8 @@ static tokenize_csv_test_data comma_separated [] = {
         { "Date,Num,Description,Notes,Account,Deposit,Withdrawal,Balance", 8, { "Date","Num","Description","Notes","Account","Deposit","Withdrawal","Balance" } },
         { "05/01/15,45,Acme Inc.,,Miscellaneous,,\"1,100.00\",", 8, { "05/01/15","45","Acme Inc.","","Miscellaneous","","1,100.00","" } },
         { "05/01/15,45,Acme Inc.,,Miscellaneous,", 6, { "05/01/15","45","Acme Inc.","","Miscellaneous","",NULL,NULL } },
+        { "Test\\ with backslash,nextfield", 2, { "Test\\ with backslash","nextfield",NULL,NULL,NULL,NULL,NULL,NULL } },
+        { "Test with \\\" escaped quote,nextfield", 2, { "Test with \" escaped quote","nextfield",NULL,NULL,NULL,NULL,NULL,NULL } },
         { NULL, 0, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
 };
 



Summary of changes:
 CMakeLists.txt                                     |  11 +-
 bindings/python/CMakeLists.txt                     |   6 +
 common/test-core/CMakeLists.txt                    |   3 +
 gnucash/gnome/reconcile-view.c                     |  29 +--
 gnucash/gnome/reconcile-view.h                     |  10 +
 gnucash/gnome/window-reconcile.c                   |  16 +-
 gnucash/gnome/window-reconcile2.c                  |  10 +-
 .../import-export/csv-imp/gnc-tokenizer-csv.cpp    |  23 ++
 .../import-export/csv-imp/test/test-tokenizer.cpp  |  14 +-
 gnucash/report/business-reports/CMakeLists.txt     |   1 +
 .../report/business-reports/customer-summary.scm   |  20 +-
 gnucash/report/business-reports/easy-invoice.scm   |  27 +--
 gnucash/report/business-reports/fancy-invoice.scm  |  19 +-
 gnucash/report/business-reports/invoice.scm        |  33 +--
 gnucash/report/business-reports/job-report.scm     |  14 +-
 gnucash/report/business-reports/owner-report.scm   |  20 +-
 gnucash/report/business-reports/receipt.scm        |   2 +-
 gnucash/report/business-reports/taxinvoice.scm     |   2 +-
 .../report/business-reports/test/CMakeLists.txt    |  31 +++
 gnucash/report/report-system/CMakeLists.txt        |   1 -
 gnucash/report/report-system/collectors.scm        |  24 +-
 gnucash/report/report-system/html-table.scm        |   7 +
 gnucash/report/report-system/html-text.scm         |  12 +-
 gnucash/report/report-system/html-utilities.scm    |  71 +++++-
 gnucash/report/report-system/list-extras.scm       |  47 ----
 gnucash/report/report-system/report-collectors.scm |   7 +-
 gnucash/report/report-system/report-system.scm     |   2 +
 gnucash/report/report-system/test/CMakeLists.txt   |   5 +-
 gnucash/report/report-system/test/test-extras.scm  | 128 +++++-----
 .../test/test-html-utilities-srfi64.scm            |  30 +--
 .../report/report-system/test/test-list-extras.scm |  42 ----
 .../report/report-system/test/test-test-extras.scm |   5 +-
 .../standard-reports/income-gst-statement.scm      |  28 ++-
 gnucash/report/standard-reports/register.scm       |  14 +-
 .../report/standard-reports/test/CMakeLists.txt    |   1 +
 .../test/test-cashflow-barchart.scm                |   6 +-
 .../test/test-generic-net-barchart.scm             |  16 +-
 .../test/test-generic-net-linechart.scm            |  10 +-
 .../standard-reports/test/test-income-gst.scm      | 213 +++++++++++++++++
 .../standard-reports/test/test-transaction.scm     | 228 ++++++++----------
 gnucash/report/standard-reports/transaction.scm    | 266 ++++++++++++---------
 libgnucash/app-utils/CMakeLists.txt                |   3 +
 libgnucash/app-utils/app-utils.scm                 |   1 -
 libgnucash/app-utils/options.scm                   |  58 -----
 libgnucash/app-utils/test/CMakeLists.txt           |   8 +
 libgnucash/app-utils/test/test-date-utilities.scm  |  70 +++---
 libgnucash/core-utils/CMakeLists.txt               |   4 +
 libgnucash/engine/test/CMakeLists.txt              |  15 ++
 libgnucash/engine/test/srfi64-extras.scm           |  49 ++++
 libgnucash/engine/test/test-extras.scm             |  87 +------
 libgnucash/engine/test/test-test-extras.scm        |   5 +-
 libgnucash/scm/utilities.scm                       |   5 +
 po/POTFILES.in                                     |   1 -
 53 files changed, 931 insertions(+), 829 deletions(-)
 create mode 100644 gnucash/report/business-reports/test/CMakeLists.txt
 delete mode 100644 gnucash/report/report-system/list-extras.scm
 delete mode 100644 gnucash/report/report-system/test/test-list-extras.scm
 create mode 100644 gnucash/report/standard-reports/test/test-income-gst.scm
 create mode 100644 libgnucash/engine/test/srfi64-extras.scm



More information about the gnucash-changes mailing list