Merge branch 'maint'

Resolved conflicts:
	src/import-export/csv-imp/gnc-csv-model.h
	src/libqof/qof/gnc-date.h
	src/optional/gtkmm/test/Makefile.am
This commit is contained in:
Geert Janssens 2016-01-22 11:43:23 +01:00
commit ce748cceb8
26 changed files with 8659 additions and 41362 deletions

View File

@ -15,6 +15,7 @@ dist_doc_DATA = \
AUTHORS \
COPYING \
ChangeLog \
ChangeLog.2015 \
ChangeLog.2014 \
ChangeLog.2013 \
ChangeLog.2012 \

View File

@ -93,11 +93,11 @@ AC_DEFINE_UNQUOTED(GNUCASH_LATEST_STABLE_SERIES, "$GNUCASH_LATEST_STABLE_SERIES"
[Most recent stable GnuCash series])
dnl Set of available languages.
TP_LINGUAS="az ca cs da eu fa ja nl pt rw sk sr sv tr uk zh_CN"
TP_LINGUAS="az ca cs da eu fa ja nl rw sk sr sv tr uk zh_CN"
dnl already marked as external at TP:
GC_LINGUAS="ar bg de el en_GB es fi fr gu he hi hu it kn ko lt lv mr nb ne pl pt_BR ro ru ta te ur vi zh_TW "
GC_LINGUAS="ar bg de el en_GB es fi fr gu he hi hu it kn ko lt lv mr nb ne pl pt pt_BR ro ru ta te ur vi zh_TW "
dnl not marked or no TP team:
NEW_LINGUAS="as brx doi es_NI kok kok@latin ks mai mni mni@bengali pt_PT"
NEW_LINGUAS="as brx doi es_NI kok kok@latin ks mai mni mni@bengali"
ALL_LINGUAS="$TP_LINGUAS $GC_LINGUAS $NEW_LINGUAS"
@ -568,7 +568,7 @@ AC_SUBST(GUILE, [`pwd`/gnc-guile])
AC_CHECK_HEADERS(ltdl.h,
[],
[AC_MSG_ERROR([ltdl.h not found. Perhaps you need to install
the intltool-ltdl development packages ?])])
the libtool(-ltdl) development package?])])
### --------------------------------------------------------------------------
### SWIG version checks (only when building from SCM)
@ -1743,6 +1743,7 @@ AC_CONFIG_FILES(
src/import-export/ofx/test/Makefile
src/import-export/csv-imp/Makefile
src/import-export/csv-imp/gschemas/Makefile
src/import-export/csv-imp/test/Makefile
src/import-export/csv-exp/Makefile
src/import-export/csv-exp/gschemas/Makefile
src/import-export/log-replay/Makefile
@ -1876,6 +1877,8 @@ AC_CONFIG_FILES([src/tax/us/test/test-load-module],
# A few files need extra actions at creation time
AC_CONFIG_FILES([src/bin/overrides/gnucash-make-guids], [chmod u+x src/bin/overrides/gnucash-make-guids])
#Link (copy on Windows) test data files:
AC_CONFIG_LINKS([src/import-export/csv-imp/test/sample1.csv:src/import-export/csv-imp/test/sample1.csv])
LDFLAGS="${LDFLAGS} ${NOUNDEF}"
AC_OUTPUT

23336
po/pt.po

File diff suppressed because it is too large Load Diff

25695
po/pt_PT.po

File diff suppressed because it is too large Load Diff

View File

@ -603,6 +603,8 @@ gnc_plugin_page_owner_tree_create_widget (GncPluginPage *plugin_page)
{
case GNC_OWNER_NONE :
case GNC_OWNER_UNDEFINED :
PWARN("missing owner_type");
label = _("Unknown");
break;
case GNC_OWNER_CUSTOMER :
label = _("Customers");

View File

@ -208,6 +208,21 @@ gnc_utf8_strip_invalid_strdup(const gchar* str)
return result;
}
void
gnc_utf8_strip_invalid_and_controls (gchar *str)
{
gchar *c = NULL;
const gchar *controls = "\b\f\n\r\t\v";
g_return_if_fail (str != NULL && strlen (str) > 0);
gnc_utf8_strip_invalid (str); /* First fix the UTF-8 */
for(c = str + strlen (str) - 1; c != str; --c)
{
gboolean line_control = ((unsigned char)(*c) < 0x20);
if (line_control || strchr(controls, *c) != NULL)
*c = ' '; /*replace controls with a single space. */
}
}
gchar *
gnc_locale_from_utf8(const gchar* str)
{

View File

@ -108,6 +108,14 @@ void gnc_utf8_strip_invalid (gchar *str);
* caller. */
gchar *gnc_utf8_strip_invalid_strdup (const gchar* str);
/** Strip any non-utf8 characters and any control characters (everything < 0x20,
* \b, \f, \n, \r, \t, and \v) from a string. Rewrites the string in-place.
*
* @param str Pointer to the string to clean up.
*/
void gnc_utf8_strip_invalid_and_controls (gchar* str);
/**
* @brief Converts a string from UTF-8 to the encoding used for
* strings in the current locale.

View File

@ -1,3 +1,5 @@
include $(top_srcdir)/test-templates/Makefile.decl
MODULEPATH = src/core-utils
AM_CPPFLAGS = \
-I${top_srcdir} \
@ -17,9 +19,11 @@ LDADD = \
# these tests are ordered kind more or less in the order
# that they should be executed, with more basic tests coming first.
#
TESTS = \
test-gnc-uri-utils \
test-resolve-file-path
test-resolve-file-path \
test-gnc-glib-utils
GNC_TEST_DEPS = \
--library-dir ${top_builddir}/src/libqof/qof \
@ -29,10 +33,21 @@ TESTS_ENVIRONMENT = \
SRCDIR=${srcdir} \
$(shell ${abs_top_srcdir}/src/gnc-test-env.pl --noexports ${GNC_TEST_DEPS})
check_PROGRAMS = \
test-gnc-uri-utils \
test-resolve-file-path
check_PROGRAMS = ${TESTS}
test_gnc_glib_utils_SOURCES = \
$(top_srcdir)/$(MODULEPATH)/gnc-glib-utils.c \
test-gnc-glib-utils.c
test_gnc_glib_utils_LDADD = \
${top_builddir}/src/libqof/qof/libgnc-qof.la \
${top_builddir}/src/test-core/libtest-core.la \
$(GLIB_LIBS)
test_gnc_glib_utils_CFLAGS = \
${DEFAULT_INCLUDES} \
-I${top_srcdir}/${MODULEPATH} \
${GLIB_CFLAGS}
EXTRA_DIST =

View File

@ -0,0 +1,67 @@
/********************************************************************
* testmain.c: GLib g_test test execution file. *
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
* *
* 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@gnu.org *
\********************************************************************/
#include <config.h>
#include <string.h>
#include <glib.h>
#include <gnc-glib-utils.h>
#include <unittest-support.h>
static void
test_gnc_utf8_strip_invalid_and_controls (gconstpointer data)
{
gchar *str = g_strdup (data);
const gchar *controls = "\b\f\n\r\t\v\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\xa\xb\xc\xd\xe\xf\x10\x11\x12\x13\x14\x15\x16"
"\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
char *msg1 = g_strdup_printf ("Invalid utf8 string: %s",
(const gchar*)data);
const GLogLevelFlags level = G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL;
TestErrorStruct check = {level, NULL, msg1, 0};
guint handler = g_log_set_handler (NULL, level,
(GLogFunc)test_null_handler, &check);
g_test_log_set_fatal_handler((GTestLogFatalFunc)test_checked_handler,
&check);
gnc_utf8_strip_invalid_and_controls (str);
g_assert (g_utf8_validate(str, -1, NULL) == TRUE);
g_assert (strpbrk(str, controls) == NULL);
g_assert (g_utf8_strlen(str, -1) > 0);
g_log_remove_handler (NULL, handler);
g_free (str);
g_free (msg1);
}
int
main (int argc, char *argv[])
{
const gchar *invalid_utf8 = "Η γρήγορη καφέ αλεπού πήδηξε πάνω από την \xb2\xf3ργή σκύλο.";
const gchar *controls = "Η γρήγορη καφέ αλεπού\bπήδηξε\nπάνω από\tτην αργή σκύλο.";
g_test_init (&argc, &argv, NULL); // initialize test program
g_test_add_data_func ("/core-utils/gnc_utf8_strip_invalid_and_controls invalid utf8", (gconstpointer)invalid_utf8, test_gnc_utf8_strip_invalid_and_controls);
g_test_add_data_func ("/core-utils/gnc_utf8_strip_invalid_and_controls control chars", (gconstpointer)controls, test_gnc_utf8_strip_invalid_and_controls);
return g_test_run();
}

View File

@ -565,6 +565,19 @@
smallest-fraction="100"
local-symbol="Br"
/>
<!-- "BYN" - "Belarussian Ruble"
-->
<currency
isocode="BYN"
fullname="Belarussian Ruble"
unitname="ruble"
partname="kapeyka"
namespace="ISO4217"
exchange-code="933"
parts-per-unit="100"
smallest-fraction="1"
local-symbol="Br"
/>
<!-- "BZD" - "Belize Dollar"
-->
<currency

View File

@ -837,7 +837,7 @@ xaccAccountCommitEdit checks the flag and finding it true:
Again checking that the book isn't shutting down:
run destroy_pending_splits_for_account
destroy all of the lots in the lots list (again, destroy, not unref or even dispose)
free the lot list (regardless of whether the book is shuttin down) and NULL the pointer
free the lot list (regardless of whether the book is shutting down) and NULL the pointer
set the instance dirty
unconditionally calls qof_commit_edit_part2 with acc_free
qof_commit_edit_part2:

View File

@ -73,6 +73,7 @@ gnc_show_splash_screen (void)
gtk_window_set_title (GTK_WINDOW (splash), "GnuCash");
gtk_window_set_position (GTK_WINDOW (splash), GTK_WIN_POS_CENTER);
gtk_window_set_type_hint (GTK_WINDOW (splash), GDK_WINDOW_TYPE_HINT_DIALOG);
pixmap = gnc_gnome_get_pixmap ("gnucash_splash.png");

View File

@ -363,9 +363,36 @@ gnc_tree_view_owner_new (GncOwnerType owner_type)
GncTreeView *view;
GtkTreeModel *model, *f_model, *s_model;
const gchar *sample_type, *sample_currency;
const gchar *owner_name = NULL, * owner_id = NULL;
GncTreeViewOwnerPrivate *priv;
ENTER(" ");
switch (owner_type)
{
case GNC_OWNER_NONE :
case GNC_OWNER_UNDEFINED :
PWARN("missing owner_type");
owner_name = _("Name");
owner_id = _("ID #");
break;
case GNC_OWNER_CUSTOMER :
owner_name = _("Company Name");
owner_id = _("Customer Number");
break;
case GNC_OWNER_JOB :
owner_name = _("Job Name");
owner_id = _("Job Number");
break;
case GNC_OWNER_VENDOR :
owner_name = _("Company Name");
owner_id = _("Vendor Number");
break;
case GNC_OWNER_EMPLOYEE :
owner_name = _("Employee Name");
owner_id = _("Employee Number");
break;
}
/* Create our view */
view = g_object_new (GNC_TYPE_TREE_VIEW_OWNER,
"name", "owner_tree", NULL);
@ -394,7 +421,7 @@ gnc_tree_view_owner_new (GncOwnerType owner_type)
sample_currency = gnc_commodity_get_fullname(gnc_default_currency());
priv->name_column
= gnc_tree_view_add_text_column(view, _("Owner Name"), GNC_OWNER_TREE_NAME_COL,
= gnc_tree_view_add_text_column(view, owner_name, GNC_OWNER_TREE_NAME_COL,
NULL, "GnuCash Inc.",
GNC_TREE_MODEL_OWNER_COL_NAME,
GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
@ -405,7 +432,7 @@ gnc_tree_view_owner_new (GncOwnerType owner_type)
GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
sort_by_string);
priv->id_column
= gnc_tree_view_add_text_column(view, _("Owner ID"), GNC_OWNER_TREE_ID_COL,
= gnc_tree_view_add_text_column(view, owner_id, GNC_OWNER_TREE_ID_COL,
NULL, "1-123-1234",
GNC_TREE_MODEL_OWNER_COL_ID,
GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,

View File

@ -1,4 +1,4 @@
SUBDIRS = . gschemas
SUBDIRS = . gschemas test
pkglib_LTLIBRARIES=libgncmod-csv-import.la

View File

@ -717,7 +717,7 @@ csv_import_trans_file_chooser_confirm_cb (GtkWidget *button, CsvImportTrans *inf
{
/* If we couldn't load the file ... */
gnc_error_dialog (NULL, "%s", error->message);
if (error->code == GNC_CSV_FILE_OPEN_ERR)
if (error->code == GNC_CSV_IMP_ERROR_OPEN)
{
g_free (file_name);
gnc_csv_parse_data_free (parse_data);

View File

@ -50,6 +50,12 @@
#include <stdlib.h>
#include <math.h>
GQuark
gnc_csv_imp_error_quark (void)
{
return g_quark_from_static_string ("g-csv-imp-error-quark");
}
G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_IMPORT;
const int num_date_formats = 5;
@ -158,10 +164,14 @@ static time64 parse_date_with_year (const char* date_str, int format)
}
}
/* Put some sane values in retvalue by using the current time for
/* Put some sane values in retvalue by using a fixed time for
* the non-year-month-day parts of the date. */
gnc_time (&rawtime);
gnc_localtime_r (&rawtime, &retvalue);
retvalue.tm_hour = 11;
retvalue.tm_min = 0;
retvalue.tm_sec = 0;
retvalue.tm_isdst = -1;
/* j traverses pmatch (index 0 contains the entire string, so we
* start at index 1 for the first meaningful match). */
@ -181,7 +191,7 @@ static time64 parse_date_with_year (const char* date_str, int format)
date_segment[mem_length] = '\0';
/* Set the appropriate member of retvalue. Save the original
* values so that we can check if the change when we use gnc_mktime
* values so that we can check if they change when we use gnc_mktime
* below. */
switch (segment_type)
{
@ -268,10 +278,14 @@ static time64 parse_date_without_year (const char* date_str, int format)
if (pmatch[0].rm_eo == 0)
return -1;
/* Put some sane values in retvalue by using the current time for
/* Put some sane values in retvalue by using a fixed time for
* the non-year-month-day parts of the date. */
gnc_time (&rawtime);
gnc_localtime_r (&rawtime, &retvalue);
retvalue.tm_hour = 11;
retvalue.tm_min = 0;
retvalue.tm_sec = 0;
retvalue.tm_isdst = -1;
orig_year = retvalue.tm_year;
/* j traverses pmatch (index 0 contains the entire string, so we
@ -293,7 +307,7 @@ static time64 parse_date_without_year (const char* date_str, int format)
date_segment[mem_length] = '\0';
/* Set the appropriate member of retvalue. Save the original
* values so that we can check if the change when we use gnc_mktime
* values so that we can check if they change when we use gnc_mktime
* below. */
switch (segment_type)
{
@ -357,6 +371,7 @@ GncCsvParseData* gnc_csv_new_parse_data (void)
/* All of the data pointers are initially NULL. This is so that, if
* gnc_csv_parse_data_free is called before all of the data is
* initialized, only the data that needs to be freed is freed. */
parse_data->raw_mapping = NULL;
parse_data->raw_str.begin = parse_data->raw_str.end
= parse_data->file_str.begin = parse_data->file_str.end = NULL;
parse_data->orig_lines = NULL;
@ -417,7 +432,7 @@ void gnc_csv_parse_data_free (GncCsvParseData* parse_data)
g_list_free (parse_data->transactions);
}
g_free (parse_data->chunk);
g_string_chunk_free (parse_data->chunk);
g_free (parse_data);
}
@ -475,14 +490,13 @@ int gnc_csv_load_file (GncCsvParseData* parse_data, const char* filename,
const char* guess_enc = NULL;
/* Get the raw data first and handle an error if one occurs. */
parse_data->raw_mapping = g_mapped_file_new (filename, FALSE, error);
parse_data->raw_mapping = g_mapped_file_new (filename, FALSE, NULL);
if (parse_data->raw_mapping == NULL)
{
/* TODO Handle file opening errors more specifically,
* e.g. inexistent file versus no read permission. */
parse_data->raw_str.begin = NULL;
g_clear_error (error);
g_set_error (error, 0, GNC_CSV_FILE_OPEN_ERR, "%s", _("File opening failed."));
g_set_error (error, GNC_CSV_IMP_ERROR, GNC_CSV_IMP_ERROR_OPEN, "%s", _("File opening failed."));
return 1;
}
@ -497,7 +511,7 @@ int gnc_csv_load_file (GncCsvParseData* parse_data, const char* filename,
"UTF-8", NULL);
if (guess_enc == NULL)
{
g_set_error (error, 0, GNC_CSV_ENCODING_ERR, "%s", _("Unknown encoding."));
g_set_error (error, GNC_CSV_IMP_ERROR, GNC_CSV_IMP_ERROR_ENCODING, "%s", _("Unknown encoding."));
return 1;
}
/* Convert using the guessed encoding into parse_data->file_str and
@ -505,7 +519,7 @@ int gnc_csv_load_file (GncCsvParseData* parse_data, const char* filename,
gnc_csv_convert_encoding (parse_data, guess_enc, error);
if (parse_data->file_str.begin == NULL)
{
g_set_error (error, 0, GNC_CSV_ENCODING_ERR, "%s", _("Unknown encoding."));
g_set_error (error, GNC_CSV_IMP_ERROR, GNC_CSV_IMP_ERROR_ENCODING, "%s", _("Unknown encoding."));
return 1;
}
else
@ -568,7 +582,7 @@ int gnc_csv_parse (GncCsvParseData* parse_data, gboolean guessColTypes, GError**
/* If it failed, generate an error. */
if (parse_data->orig_lines == NULL)
{
g_set_error (error, 0, 0, "Parsing failed.");
g_set_error (error, GNC_CSV_IMP_ERROR, GNC_CSV_IMP_ERROR_PARSE, "Parsing failed.");
return 1;
}

View File

@ -38,27 +38,34 @@
* columns that can exist in a CSV/Fixed-Width file. There should be
* no two columns with the same type except for the GNC_CSV_NONE
* type. */
enum GncCsvColumnType {GNC_CSV_NONE,
GNC_CSV_DATE,
GNC_CSV_NUM,
GNC_CSV_DESCRIPTION,
GNC_CSV_NOTES,
GNC_CSV_ACCOUNT,
GNC_CSV_DEPOSIT,
GNC_CSV_WITHDRAWAL,
GNC_CSV_BALANCE,
GNC_CSV_MEMO,
GNC_CSV_OACCOUNT,
GNC_CSV_OMEMO,
GNC_CSV_NUM_COL_TYPES
};
enum GncCsvColumnType {
GNC_CSV_NONE,
GNC_CSV_DATE,
GNC_CSV_NUM,
GNC_CSV_DESCRIPTION,
GNC_CSV_NOTES,
GNC_CSV_ACCOUNT,
GNC_CSV_DEPOSIT,
GNC_CSV_WITHDRAWAL,
GNC_CSV_BALANCE,
GNC_CSV_MEMO,
GNC_CSV_OACCOUNT,
GNC_CSV_OMEMO,
GNC_CSV_NUM_COL_TYPES
};
/** Error domain for the csv importer. */
#define GNC_CSV_IMP_ERROR gnc_csv_imp_error_quark ()
GQuark gnc_csv_imp_error_quark (void);
/** Enumeration for error types. These are the different types of
* errors that various functions used for the CSV/Fixed-Width importer
* can have. */
enum GncCsvErrorType {GNC_CSV_FILE_OPEN_ERR,
GNC_CSV_ENCODING_ERR
};
enum GncCsvErrorType {
GNC_CSV_IMP_ERROR_OPEN,
GNC_CSV_IMP_ERROR_ENCODING,
GNC_CSV_IMP_ERROR_PARSE
};
/** Struct for containing a string. This struct simply contains
* pointers to the beginning and end of a string. We need this because

View File

@ -0,0 +1,98 @@
# A template Makefile.am for GLib g_test-based test directories.
# Copyright 2011 John Ralls <jralls@ceridwen.us>
include $(top_srcdir)/test-templates/Makefile.decl
#You will only need one of these: It points to the module directory
#after $(top_srcdir) or ${top_builddir}:
MODULEPATH = src/import-export/csv-imp
#The test program. You'll need to add to this if you have more than one module above.
check_PROGRAMS = test-csv-imp
TESTS = ${check_PROGRAMS}
test_csv_impdir = ${top_srcdir}/${MODULEPATH}/test
#Program files for tests go here. It's probably best to have one for
#each file in the parent directory. Include
#test_foo_support.c if you have one and aren't building the
#support library.
test_csv_imp_SOURCES = \
test-csv-imp.c \
utest-gnc-csv-model.c
test_csv_imp_HEADERS =
#The tests might require more libraries, but try to keep them
#as independent as possible.
test_csv_imp_LDADD = \
${top_builddir}/${MODULEPATH}/libgncmod-csv-import.la \
${top_builddir}/src/import-export/libgncmod-generic-import.la \
${top_builddir}/src/gnome/libgnc-gnome.la \
${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \
${top_builddir}/src/register/ledger-core/libgncmod-ledger-core.la \
${top_builddir}/src/report/report-gnome/libgncmod-report-gnome.la \
${top_builddir}/src/app-utils/libgncmod-app-utils.la \
${top_builddir}/src/backend/xml/libgnc-backend-xml-utils.la \
${top_builddir}/src/engine/libgncmod-engine.la \
${top_builddir}/src/core-utils/libgnc-core-utils.la \
${top_builddir}/src/gnc-module/libgnc-module.la \
${top_builddir}/src/libqof/qof/libgnc-qof.la \
${top_builddir}/lib/stf/libgnc-stf.la \
${GLIB_LIBS}
test_csv_imp_CFLAGS = \
-DTESTPROG=test_csv-imp \
${DEFAULT_INCLUDES} \
-I$(top_srcdir)/${MODULEPATH}/ \
-I${top_srcdir}/src/test-core \
-I${top_srcdir}/src \
-I${top_srcdir}/src/import-export \
-I${top_srcdir}/src/gnome \
-I${top_srcdir}/src/register/ledger-core \
-I${top_srcdir}/src/register/register-gnome \
-I${top_srcdir}/src/register/register-core \
-I${top_srcdir}/src/gnome-utils \
-I${top_srcdir}/src/app-utils \
-I${top_srcdir}/src/engine \
-I${top_srcdir}/src/core-utils \
-I${top_srcdir}/src/gnc-module \
-I${top_srcdir}/src/libqof/qof \
-I${top_srcdir}/lib/libc \
-I${top_srcdir}/lib \
${GTK_CFLAGS} \
${GLIB_CFLAGS}
GNC_TEST_DEPS = \
--library-dir ${top_builddir}/${MODULEPATH} \
--library-dir ${top_builddir}/src/import-export \
--library-dir ${top_builddir}/src/gnome \
--library-dir ${top_builddir}/src/gnome-utils \
--library-dir ${top_builddir}/src/gnome-search \
--library-dir ${top_builddir}/src/register/ledger-core \
--library-dir ${top_builddir}/src/register/register-core \
--library-dir ${top_builddir}/src/register/register-gnome \
--library-dir ${top_builddir}/src/report/report-system \
--library-dir ${top_builddir}/src/report/report-gnome \
--library-dir ${top_builddir}/src/html \
--library-dir ${top_builddir}/src/app-utils \
--library-dir ${top_builddir}/src/backend/xml \
--library-dir ${top_builddir}/src/engine \
--library-dir ${top_builddir}/src/core-utils \
--library-dir ${top_builddir}/src/gnc-module \
--library-dir ${top_builddir}/src/libqof/qof \
--library-dir ${top_builddir}/lib/stf
TESTS_ENVIRONMENT = \
SRCDIR=${srcdir} \
G_DEBUG= \
$(shell ${abs_top_srcdir}/src/gnc-test-env.pl --noexports ${GNC_TEST_DEPS})
EXTRA_DIST= \
sample1.csv
AM_CPPFLAGS = -DG_LOG_DOMAIN=\"gnc.import.csv\"

View File

@ -0,0 +1,2 @@
Date,Num,Description,Notes,Account,Deposit,Withdrawal,Balance
05/01/15,45,Acme Inc.,,Miscellaneous,,"1,100.00",
1 Date Num Description Notes Account Deposit Withdrawal Balance
2 05/01/15 45 Acme Inc. Miscellaneous 1,100.00

View File

@ -0,0 +1,60 @@
/********************************************************************
* testmain.c: GLib g_test test execution file. *
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
* *
* 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@gnu.org *
\********************************************************************/
#include <glib.h>
#include "config.h"
#include <qof.h>
#include "backend/xml/gnc-backend-xml.h"
#include "gnc-module/gnc-module.h"
#include "engine/gnc-engine.h"
#include <engine/TransLog.h>
/* Declare the test suite assembly functions (see test-suite.c) for
* each sub-suite; avoids having header files. */
extern GTestSuite *test_suite_gnc_csv_model();
int
main (int argc,
char *argv[])
{
qof_init(); /* Initialize the GObject system */
qof_log_init_filename_special("stderr"); /* Init the log system */
g_test_init ( &argc, &argv, NULL ); /* initialize test program */
qof_log_set_level("gnc", (QofLogLevel)G_LOG_LEVEL_DEBUG);
g_test_bug_base("https://bugzilla.gnome.org/show_bug.cgi?id="); /* init the bugzilla URL */
/* Disable the transaction log */
xaccLogDisable();
gnc_module_system_init();
gnc_engine_init_static(argc, argv);
qof_load_backend_library ("../../../backend/xml/.libs/",
"gncmod-backend-xml");
/* Add test functions and suites. See
* http://library.gnome.org/devel/glib/stable/glib-Testing.html for
* details. Unfortunately, GLib-Testing doesn't provide the automatic
* registration features of more sophisticated frameworks. */
test_suite_gnc_csv_model();
return g_test_run();
}

View File

@ -0,0 +1,462 @@
/********************************************************************
* utest-gnc-csv-model.c: GLib g_test test suite for gnc-csv-model.c. *
* Copyright 2015 Geert Janssens <geert.gnucash@kobaltwit.be> *
* *
* 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, you can retrieve it from *
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html *
* or 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@gnu.org *
********************************************************************/
#include <config.h>
#include <string.h>
#include <glib.h>
#include <unittest-support.h>
/* Add specific headers for this class */
#include "import-export/csv-imp/gnc-csv-model.h"
typedef struct
{
GncCsvParseData* parse_data;
} Fixture;
typedef struct
{
int date_fmt;
const gchar *date_str;
int exp_year;
int exp_month;
int exp_day;
} parse_date_data;
typedef struct
{
const gchar *csv_line;
int num_fields;
const gchar *fields [8];
} parse_test_data;
static const gchar* samplefile1 = "sample1.csv";
static parse_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,", 4, { "05/01/15","45","Acme Inc.","",NULL,NULL,NULL,NULL } },
{ NULL, 0, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
};
static parse_test_data semicolon_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;", 4, { "05/01/15","45","Acme Inc.","",NULL,NULL,NULL,NULL } },
{ NULL, 0, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } },
};
static char* get_filepath(const char* filename, gboolean test_existence)
{
char *result;
const char *srcdir = g_getenv("SRCDIR");
if (!srcdir)
{
g_test_message("No env variable SRCDIR exists, assuming \".\"\n");
srcdir = ".";
}
result = g_strdup_printf("%s/%s", srcdir, filename);
g_test_message("Using file path %s\n", result);
// Test whether the file really exists
if (test_existence)
g_assert(g_file_test(result, G_FILE_TEST_EXISTS));
return result;
}
static void
setup( Fixture *fixture, gconstpointer pData )
{
fixture->parse_data = gnc_csv_new_parse_data ();
}
static void
setup_one_file( Fixture *fixture, gconstpointer pData )
{
const gchar *filename = (const gchar*) pData;
char *filepath = get_filepath (filename, TRUE);
GError *the_error = NULL;
int resultcode = 0;
fixture->parse_data = gnc_csv_new_parse_data ();
resultcode = gnc_csv_load_file (fixture->parse_data, filepath,
&the_error);
g_assert (resultcode == 0);
g_free(filepath);
}
static void
teardown( Fixture *fixture, gconstpointer pData )
{
gnc_csv_parse_data_free (fixture->parse_data);
}
static const gchar *suitename = "/import-export/csv-imp/gnc-csv-model";
void test_suite_gnc_csv_model ( void );
/* parse_date_with_year
time64 parse_date_with_year (const char* date_str, int format)// Local: 1:0:0
*/
// Internal helper only - no tests.
/* parse_date_without_year
static time64 parse_date_without_year (const char* date_str, int format)// Local: 1:0:0
*/
// Internal helper only - no tests.
/* parse_date
time64 parse_date (const char* date_str, int format)// C: 14 in 7 SCM: 9 in 2 Local: 1:0:0
*/
static void
test_parse_date (void)
{
time64 rawtime = gnc_time_utc (NULL);
struct tm *tm = gnc_gmtime (&rawtime);
int curr_year = tm->tm_year;
/* Note: tm_year = year - 1900 and tm_mon = 0-11
* I'm writing the expected values as subtractions for easier
* comparison with the date string under test
*/
parse_date_data test_dates[] =
{
// supported combinations -/.'
{ 0, "2013-08-01", 2013 - 1900, 8 - 1, 1},
{ 0, "2013-8-01", 2013 - 1900, 8 - 1, 1},
{ 0, "2013-08-1", 2013 - 1900, 8 - 1, 1},
{ 0, "2013-8-1", 2013 - 1900, 8 - 1, 1},
{ 0, "13-08-01", 2013 - 1900, 8 - 1, 1},
{ 0, "13-8-01", 2013 - 1900, 8 - 1, 1},
{ 0, "13-08-1", 2013 - 1900, 8 - 1, 1},
{ 0, "13-8-1", 2013 - 1900, 8 - 1, 1},
{ 0, "2009/11/04", 2009 - 1900, 11 - 1, 4},
{ 0, "1985.3.12", 1985 - 1900, 3 - 1, 12},
{ 0, "3'6'8", 2003 - 1900, 6 - 1, 8},
{ 0, "20130801", 2013 - 1900, 8 - 1, 1},
{ 1, "01-08-2013", 2013 - 1900, 8 - 1, 1},
{ 1, "01-8-2013", 2013 - 1900, 8 - 1, 1},
{ 1, "1-08-2013", 2013 - 1900, 8 - 1, 1},
{ 1, "1-8-2013", 2013 - 1900, 8 - 1, 1},
{ 1, "01-08-13", 2013 - 1900, 8 - 1, 1},
{ 1, "01-8-13", 2013 - 1900, 8 - 1, 1},
{ 1, "1-08-13", 2013 - 1900, 8 - 1, 1},
{ 1, "1-8-13", 2013 - 1900, 8 - 1, 1},
{ 1, "04/11/2009", 2009 - 1900, 11 - 1, 4},
{ 1, "12.3.1985", 1985 - 1900, 3 - 1, 12},
{ 1, "8'6'3", 2003 - 1900, 6 - 1, 8},
{ 1, "01082013", 2013 - 1900, 8 - 1, 1},
{ 2, "08-01-2013", 2013 - 1900, 8 - 1, 1},
{ 2, "8-01-2013", 2013 - 1900, 8 - 1, 1},
{ 2, "08-1-2013", 2013 - 1900, 8 - 1, 1},
{ 2, "8-1-2013", 2013 - 1900, 8 - 1, 1},
{ 2, "08-01-13", 2013 - 1900, 8 - 1, 1},
{ 2, "8-01-13", 2013 - 1900, 8 - 1, 1},
{ 2, "08-1-13", 2013 - 1900, 8 - 1, 1},
{ 2, "8-1-13", 2013 - 1900, 8 - 1, 1},
{ 2, "11/04/2009", 2009 - 1900, 11 - 1, 4},
{ 2, "3.12.1985", 1985 - 1900, 3 - 1, 12},
{ 2, "6'8'3", 2003 - 1900, 6 - 1, 8},
{ 2, "08012013", 2013 - 1900, 8 - 1, 1},
{ 3, "01-08", curr_year, 8 - 1, 1},
{ 3, "01-8", curr_year, 8 - 1, 1},
{ 3, "1-08", curr_year, 8 - 1, 1},
{ 3, "1-8", curr_year, 8 - 1, 1},
{ 3, "04/11", curr_year, 11 - 1, 4},
{ 3, "12.3", curr_year, 3 - 1, 12},
{ 3, "8'6", curr_year, 6 - 1, 8},
{ 4, "08-01", curr_year, 8 - 1, 1},
{ 4, "8-01", curr_year, 8 - 1, 1},
{ 4, "08-1", curr_year, 8 - 1, 1},
{ 4, "8-1", curr_year, 8 - 1, 1},
{ 4, "11/04", curr_year, 11 - 1, 4},
{ 4, "3.12", curr_year, 3 - 1, 12},
{ 4, "6'8", curr_year, 6 - 1, 8},
// ambiguous date formats
// current parser doesn't know how to disambiguate
// and hence refuses to parse
// can possibly improved with a smarter parser
{ 0, "130801", -1, -1, -1},
{ 1, "010813", -1, -1, -1},
{ 2, "080113", -1, -1, -1},
{ 3, "0108", -1, -1, -1},
{ 4, "0801", -1, -1, -1},
// Combinations that don't make sense
// but can still be entered by a user
// Should ideally all result in refusal to parse...
{ 0, "08-01", -1, -1, -1},
{ 0, "0801", -1, -1, -1},
{ 1, "01-08", -1, -1, -1},
{ 1, "0108", -1, -1, -1},
{ 2, "08-01", -1, -1, -1},
{ 2, "0801", -1, -1, -1},
{ 3, "01-08-2013", curr_year, 8 - 1, 1}, // BAD behavior !
{ 3, "01-08-13", curr_year, 8 - 1, 1}, // BAD behavior !
{ 3, "08-08-08", curr_year, 8 - 1, 8}, // BAD behavior !
{ 3, "01082013", -1, -1, -1},
{ 3, "010813", -1, -1, -1},
{ 3, "20130108", -1, -1, -1},
{ 4, "08-01-2013", curr_year, 8 - 1, 1}, // BAD behavior !
{ 4, "08-01-13", curr_year, 8 - 1, 1}, // BAD behavior !
{ 4, "2013-08-01", -1, -1, -1},
{ 4, "09-08-01", curr_year, 9 - 1, 8}, // BAD behavior !
{ 4, "08012013", -1, -1, -1},
{ 4, "080113", -1, -1, -1},
{ 4, "20130801", -1, -1, -1},
// Sentinel to mark the end of available tests
{ 0, NULL, 0, 0, 0},
};
int i = 0;
gnc_tm_free(tm);
while (test_dates[i].date_str)
{
gboolean success = TRUE;
int got_year = 0, got_month = 0, got_day = 0;
rawtime = parse_date (test_dates[i].date_str, test_dates[i].date_fmt);
if (rawtime == -1)
got_year = got_month = got_day = -1;
else
{
tm = gnc_gmtime (&rawtime);
got_year = tm->tm_year;
got_month = tm->tm_mon;
got_day = tm->tm_mday;
gnc_tm_free(tm);
}
if ((got_year != test_dates[i].exp_year) ||
(got_month != test_dates[i].exp_month) ||
(got_day != test_dates[i].exp_day))
{
g_error ("Parse_date failed for date '%s' and format '%d'.\n"
"Expected result: year %d, month %d, day %d\n"
"Obtained result: year %d, month %d, day %d",
test_dates[i].date_str,
test_dates[i].date_fmt,
test_dates[i].exp_year,
test_dates[i].exp_month,
test_dates[i].exp_day,
got_year, got_month, got_day);
}
i++;
}
}
/* gnc_csv_new_parse_data
GncCsvParseData* gnc_csv_new_parse_data (void)// C: 1 in 1 Local: 0:0:0
*/
static void
test_gnc_csv_new_parse_data (void)
{
GncCsvParseData* parse_data = gnc_csv_new_parse_data ();
g_assert (parse_data != NULL);
g_assert (parse_data->chunk != NULL);
gnc_csv_parse_data_free (parse_data);
}
/* gnc_csv_parse_data_free
void gnc_csv_parse_data_free (GncCsvParseData* parse_data)// C: 3 in 1 Local: 0:0:0
*/
// Basic freeing of memory - no test
/* gnc_csv_convert_encoding
int gnc_csv_convert_encoding (GncCsvParseData* parse_data, const char* encoding,// C: 1 Local: 1:0:0
*/
/* static void
test_gnc_csv_convert_encoding (Fixture *fixture, gconstpointer pData)
{
}*/
/* gnc_csv_load_file
int gnc_csv_load_file (GncCsvParseData* parse_data, const char* filename,// C: 1 Local: 0:0:0
*/
static void
test_gnc_csv_load_file (Fixture *fixture, gconstpointer pData)
{
char *file1 = get_filepath ("notexist.csv", FALSE);
char *file2 = get_filepath ("sample1.csv", TRUE);
GError *the_error = NULL;
int resultcode = 0;
/* Test loading of a non-existing file */
resultcode = gnc_csv_load_file (fixture->parse_data, file1,
&the_error);
g_assert ((the_error->domain == GNC_CSV_IMP_ERROR) &&
(the_error->code == GNC_CSV_IMP_ERROR_OPEN));
/* Test loading of a valid csv file */
resultcode = gnc_csv_load_file (fixture->parse_data, file2,
&the_error);
g_assert (resultcode == 0);
}
/* gnc_csv_parse
int gnc_csv_parse (GncCsvParseData* parse_data, gboolean guessColTypes, GError** error)// C: 13 in 1 Local: 0:0:0
*/
static void
test_gnc_csv_parse_from_file (Fixture *fixture, gconstpointer pData)
{
GError *the_error = NULL;
int resultcode = 0;
/* Test basic parsing of the loaded file
* A few fields are sampled in the parsed data. */
resultcode = gnc_csv_parse (fixture->parse_data, TRUE, &the_error);
g_assert (g_strcmp0 ((char*)((GPtrArray*)(fixture->parse_data->orig_lines->pdata[0]))->pdata[0],
"Date") == 0);
g_assert (g_strcmp0 ((char*)((GPtrArray*)(fixture->parse_data->orig_lines->pdata[1]))->pdata[6],
"1,100.00") == 0);
}
/* Test parsing for several different prepared strings
* These tests bypass file loading, rather taking a
* prepared set of strings as input. This makes it
* easier to add test cases without having to create new test files
* each time to load from.
* Note this bypasses encoding configuration, which should be tested
* independently.
*/
/* 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
* and parser option combinations.
*/
static void
test_gnc_csv_parse_helper (GncCsvParseData *parse_data, gconstpointer pData)
{
parse_test_data *test_data = (parse_test_data *) pData;
GError *the_error = NULL;
int resultcode = 0;
int i = 0;
while (test_data[i].csv_line)
{
int j;
parse_test_data cur_line = test_data[i];
g_test_message("Using string %s\n", cur_line.csv_line);
g_free (parse_data->file_str.begin);
parse_data->file_str.begin = g_strdup (cur_line.csv_line);
parse_data->file_str.end = parse_data->file_str.begin + strlen (parse_data->file_str.begin);
resultcode = gnc_csv_parse (parse_data, TRUE, &the_error);
g_assert (resultcode == 0);
for (j=0; j < cur_line.num_fields; j++)
{
g_assert (g_strcmp0 ((char*)((GPtrArray*)(parse_data->orig_lines->pdata[0]))->pdata[j],
(cur_line.fields[j])) == 0);
}
i++;
}
}
static void
test_gnc_csv_parse_comma_sep (Fixture *fixture, gconstpointer pData)
{
GSList* sep_list = NULL;
sep_list = g_slist_append (sep_list, ",");
stf_parse_options_csv_set_separators (fixture->parse_data->options, NULL, sep_list);
g_slist_free (sep_list);
test_gnc_csv_parse_helper (fixture->parse_data, pData);
}
static void
test_gnc_csv_parse_semicolon_sep (Fixture *fixture, gconstpointer pData)
{
GSList* sep_list = NULL;
sep_list = g_slist_append (sep_list, ";");
stf_parse_options_csv_set_separators (fixture->parse_data->options, NULL, sep_list);
g_slist_free (sep_list);
test_gnc_csv_parse_helper (fixture->parse_data, pData);
}
/* trans_property_free
static void trans_property_free (TransProperty* prop)// Local: 2:0:0
*/
// Internal helper function - no test
/* trans_property_set
static gboolean trans_property_set (TransProperty* prop, char* str)// Local: 1:0:0
*/
// Internal helper function - no test
/* trans_property_list_free
static void trans_property_list_free (TransPropertyList* list)// Local: 1:0:0
*/
// Internal helper function - no test
/* trans_property_list_add
static void trans_property_list_add (TransProperty* property)// Local: 1:0:0
*/
// Internal helper function - no test
/* trans_add_split
static void trans_add_split (Transaction* trans, Account* account, QofBook* book,// Local: 2:0:0
*/
// Internal helper function - no test
/* trans_property_list_verify_essentials
static gboolean trans_property_list_verify_essentials (TransPropertyList* list, gchar** error)// Local: 1:0:0
*/
// Internal helper function - no test
/* gnc_csv_parse_to_trans
int gnc_csv_parse_to_trans (GncCsvParseData* parse_data, Account* account,// C: 2 in 1 Local: 0:0:0
*/
/* static void
test_gnc_csv_parse_to_trans (Fixture *fixture, gconstpointer pData)
{
}*/
void
test_suite_gnc_csv_model (void)
{
// GNC_TEST_ADD (suitename, "parse date with year", Fixture, NULL, setup, test_parse_date_with_year, teardown);
// GNC_TEST_ADD (suitename, "parse date without year", Fixture, NULL, setup, test_parse_date_without_year, teardown);
GNC_TEST_ADD_FUNC (suitename, "parse date", test_parse_date);
GNC_TEST_ADD_FUNC (suitename, "gnc csv new parse data", test_gnc_csv_new_parse_data);
// GNC_TEST_ADD (suitename, "gnc csv parse data free", Fixture, NULL, setup, test_gnc_csv_parse_data_free, teardown);
// GNC_TEST_ADD (suitename, "gnc csv convert encoding", Fixture, NULL, setup, test_gnc_csv_convert_encoding, teardown);
GNC_TEST_ADD (suitename, "gnc csv load file", Fixture, NULL, setup, test_gnc_csv_load_file, teardown);
GNC_TEST_ADD (suitename, "gnc csv parse from file", Fixture, samplefile1, setup_one_file, test_gnc_csv_parse_from_file, teardown);
GNC_TEST_ADD (suitename, "parse comma", Fixture, comma_separated, setup, test_gnc_csv_parse_comma_sep, teardown);
GNC_TEST_ADD (suitename, "parse semicolon", Fixture, semicolon_separated, setup, test_gnc_csv_parse_semicolon_sep, teardown);
// GNC_TEST_ADD (suitename, "trans property free", Fixture, NULL, setup, test_trans_property_free, teardown);
// GNC_TEST_ADD (suitename, "trans property set", Fixture, NULL, setup, test_trans_property_set, teardown);
// GNC_TEST_ADD (suitename, "trans property list free", Fixture, NULL, setup, test_trans_property_list_free, teardown);
// GNC_TEST_ADD (suitename, "trans property list add", Fixture, NULL, setup, test_trans_property_list_add, teardown);
// GNC_TEST_ADD (suitename, "trans add split", Fixture, NULL, setup, test_trans_add_split, teardown);
// GNC_TEST_ADD (suitename, "trans property list verify essentials", Fixture, NULL, setup, test_trans_property_list_verify_essentials, teardown);
// GNC_TEST_ADD (suitename, "gnc csv parse to trans", Fixture, NULL, setup, test_gnc_csv_parse_to_trans, teardown);
}

View File

@ -38,7 +38,7 @@
stores and use UNIVERSAL TIME internally. Universal time is the
'one true time' that is independent of one's location on planet
Earth. It is measured in seconds from midnight January 1, 1970
in localtime-Grenwich (GMT). If one wants to display the local
in localtime-Greenwich (GMT). If one wants to display the local
time, then the display-print routine should make all final
tweaks to print the local time. The local time *must not* be
kept as a numeric value anywhere in the program. If one wants
@ -108,10 +108,10 @@ extern const char *gnc_default_strftime_date_format;
/** Constants *******************************************************/
/** \brief UTC date format string.
Timezone independent, date and time inclusive, as used in the QSF backend.
Time zone independent, date and time inclusive, as used in the QSF backend.
The T and Z characters are from xsd:dateTime format in coordinated universal time, UTC.
You can reproduce the string from the GNU/Linux command line using the date utility:
date -u +%Y-%m-%dT%H:M:SZ = 2004-12-12T23:39:11Z The datestring must be timezone independent
date -u +%Y-%m-%dT%H:M:SZ = 2004-12-12T23:39:11Z The datestring must be time zone independent
and include all specified fields. Remember to use gmtime() NOT localtime()!
*/
@ -305,12 +305,12 @@ gboolean timespec_equal(const Timespec *ta, const Timespec *tb);
/** comparison: if (ta < tb) -1; else if (ta > tb) 1; else 0; */
gint timespec_cmp(const Timespec *ta, const Timespec *tb);
/** difference between ta and tb, results are normalised
/** difference between ta and tb, results are normalized
* ie tv_sec and tv_nsec of the result have the same size
* abs(result.tv_nsec) <= 1000000000 */
Timespec timespec_diff(const Timespec *ta, const Timespec *tb);
/** absolute value, also normalised */
/** absolute value, also normalized */
Timespec timespec_abs(const Timespec *t);
/** convert a timepair on a certain day (localtime) to
@ -344,15 +344,15 @@ Timespec gnc_dmy2timespec_end (gint day, gint month, gint year);
/** The gnc_iso8601_to_timespec_gmt() routine converts an ISO-8601 style
* date/time string to Timespec. Please note that ISO-8601 strings
* are a representation of Universal Time (UTC), and as such, they
* 'store' UTC. To make them human readable, they show timezone
* 'store' UTC. To make them human readable, they show time zone
* information along with a local-time string. But fundamentally,
* they *are* UTC. Thus, thir routine takes a UTC input, and
* they *are* UTC. Thus, this routine takes a UTC input, and
* returns a UTC output.
*
* For example: 1998-07-17 11:00:00.68-0500
* is 680 milliseconds after 11 o'clock, central daylight time
* It is also 680 millisecs after 16:00:00 hours UTC.
* \return The universl time.
* It is also 680 milliseconds after 16:00:00 hours UTC.
* \return The universal time.
*
* XXX Caution: this routine does not handle strings that specify
* times before January 1 1970.
@ -368,12 +368,12 @@ Timespec gnc_iso8601_to_timespec_gmt(const gchar *);
*
* Please note that ISO-8601 strings are a representation of
* Universal Time (UTC), and as such, they 'store' UTC. To make them
* human readable, they show timezone information along with a
* human readable, they show time zone information along with a
* local-time string. But fundamentally, they *are* UTC. Thus,
* this routine takes a UTC input, and returns a UTC output.
*
* The string generated by this routine uses the local timezone
* on the machine on which it is executing to create the timestring.
* The string generated by this routine uses the local time zone
* on the machine on which it is executing to create the time string.
*/
gchar * gnc_timespec_to_iso8601_buff (Timespec ts, gchar * buff);
@ -391,7 +391,7 @@ void gnc_timespec2dmy (Timespec ts, gint *day, gint *month, gint *year);
/** \name QofDateFormat functions */
// @{
/** The qof_date_format_get routine returns the date format that
* the date printing will use when printing a date, and the scaning
* the date printing will use when printing a date, and the scanning
* routines will assume when parsing a date.
* @returns: the one of the enumerated date formats.
*/

View File

@ -8,17 +8,25 @@ include $(top_srcdir)/test-templates/Makefile.decl
#after $(top_srcdir) or $(top_builddir):
MODULEPATH = src/optional/gtkmm
test_gtkmm_SOURCES = \
test-gtkmm.cpp \
test-book.cpp
test_gtkmm_HEADERSS = \
$(top_srcdir)/${MODULEPATH}/gncmm/Book.hpp
#The test program. You'll need to add to this if you have more than one module above.
check_PROGRAMS = test-gtkmm
TESTS = ${check_PROGRAMS}
test_gtkmmdir = ${top_srcdir}/${MODULEPATH}/test
#Program files for tests go here. It's probably best to have one for
#each file in the parent directory. Include
#test_foo_support.c if you have one and aren't building the
#support library.
test_gtkmm_SOURCES = \
test-gtkmm.cpp \
test-book.cpp
test_gtkmm_HEADERS = \
$(top_srcdir)/${MODULEPATH}/gncmm/Book.hpp
#The tests might require more libraries, but try to keep them
#as independent as possible.
test_gtkmm_LDADD = ${top_builddir}/${MODULEPATH}/libgncmod-gtkmm.la \

View File

@ -46,6 +46,7 @@
#include <sys/stat.h>
#include <errno.h>
#include <gnc-glib-utils.h>
#include "gfec.h"
#include "dialog-custom-report.h"
#include "gnc-component-manager.h"
@ -604,11 +605,11 @@ gnc_plugin_page_report_option_change_cb(gpointer data)
"Report name", NULL);
if (strcmp(old_name, new_name) != 0)
{
/* Bug 727130 - escape the non-printable characters from the name */
new_name_escaped = g_strescape(new_name,NULL);
ENTER("Escaped new report name: %s", new_name_escaped);
main_window_update_page_name(GNC_PLUGIN_PAGE(report), new_name_escaped);
g_free(new_name_escaped);
/* Bug 727130, 760711 - remove only the non-printable
* characters from the new name */
gnc_utf8_strip_invalid_and_controls(new_name);
ENTER("Cleaned-up new report name: %s", new_name);
main_window_update_page_name(GNC_PLUGIN_PAGE(report), new_name);
}
g_free(new_name);

View File

@ -278,7 +278,7 @@ make_testfile "Author Name <author@email.addr>" path/to/input [path/to/output]
Creates template unit test files from C source files. The default
output file is utest-filename in a subdirectory named "test". For
example, if the input file is src/engine/Account.c, the default output
file will be src/engine/test/test-Account.c.
file will be src/engine/test/utest-Account.c.
The program scans the input file to find function signatures. Each
function signature will generate a comment with the function's

54
util/check-po.pl Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/perl -w
use strict;
my $filename = $ARGV[0];
my ($last_merge, $last_rev, $msgtot, $msgtrans, $msgfuzz);
my $date_re = '(\d{4}-\d{2}-\d{2})';
my $merge_re = qr/^"POT-Creation-Date: $date_re/;
my $rev_re = qr/^"PO-Revision-Date: $date_re/;
my $msgid_re = qr(^msgid ".+");
my $str_re = qr/^msgstr ".+"/;
while (<>) {
$last_merge = $1 if ($_ =~ $merge_re);
$last_rev = $1 if ($_ =~ $rev_re);
}
my ($strings, $fuzzy, $missing);
open STATS, "msgfmt --stat $filename 2>&1 |" or die;
while (<STATS>) {
#print;
$_ =~ /^(\d+) translated messages(?:, (\d+) fuzzy translations)?(?:, (\d+) untranslated messages)?./;
$strings = $1 || 0;
$fuzzy = $2 || 0;
$missing = $3 ||0;
}
close STATS;
my $total = ($strings + $fuzzy + $missing) || 1;
my $percent = $strings/$total * 100.0;
my $fuzpct = ($strings + $fuzzy) / $total * 100.0;
printf "%14s: %s %s\t%4d\t%4d\t%4d\t%3.2f%%\t %3.2f%%\n", $filename, $last_rev,
$last_merge, $strings, $fuzzy, $total, $percent, $fuzpct;
=head1 NAME
check-po.pl
=head1 SYNOPSIS
check-po.pl po-filename
=head1 SUMMARY
Prints the filename, last revision date, date of the potfile with which it was
last merged, the number of translated strings not marked fuzzy, the number of
translated strings marked fuzzy, the total number of translatable strings, the
percentage of strings with not-fuzzy translations and the percentage of strings
with both fuzzy and non-fuzzy translations.
Most effectively used in a shell for loop, e.g.:
C<for i in *.po; do check-po.pl $i; done>
The results of which can be piped to sort(1) for simple analysis.
=cut