diff --git a/ChangeLog b/ChangeLog index e5d780dee2..e986ad1bc9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2001-10-11 Dave Peticolas + + * src/test-core/test-stuff.c: allow option of including funky + characters in random strings + + * src/engine/Transaction.c (xaccTransEqual): add warning strings + + * src/backend/postgres/test/.cvsignore: ignore test-escape + + * src/backend/postgres/test/test-escape: test string escaping + + * src/backend/postgres/test/Makefile.am: add test-escape + + * src/backend/postgres/builder.c (sqlBuild_Where_Str): don't + escape string twice + + * src/backend/postgres/escape.c (sqlEscapeString): check for + already-escaped string + + * src/backend/postgres/kvp-sql.c: escape path strings + + * src/backend/file/test/test-xml-transaction.c (test_add_transaction): + test in reverse order, first orig, then new. + 2001-10-10 Rob Browning * src/test-core/Makefile.am diff --git a/src/backend/file/test/test-xml-transaction.c b/src/backend/file/test/test-xml-transaction.c index 7d776b4205..f031b9e962 100644 --- a/src/backend/file/test/test-xml-transaction.c +++ b/src/backend/file/test/test-xml-transaction.c @@ -296,7 +296,7 @@ test_add_transaction(const char *tag, gpointer globaldata, gpointer data) xaccTransSetCurrency (trans, gdata->com); xaccTransCommitEdit (trans); - do_test_args(xaccTransEqual(trans, gdata->trn, TRUE, TRUE), + do_test_args(xaccTransEqual(gdata->trn, trans, TRUE, TRUE), "gnc_transaction_sixtp_parser_create", __FILE__, __LINE__, "%d", gdata->value); diff --git a/src/backend/postgres/builder.c b/src/backend/postgres/builder.c index 2f609f3fc5..6810d53263 100644 --- a/src/backend/postgres/builder.c +++ b/src/backend/postgres/builder.c @@ -317,7 +317,6 @@ sqlBuild_Where_Str (sqlBuilder *b, const char *tag, const char *val) { if (!b || !tag || !val) return; - val = sqlEscapeString (b->escape, val); switch (b->qtype) { case SQL_INSERT: @@ -328,6 +327,8 @@ sqlBuild_Where_Str (sqlBuilder *b, const char *tag, const char *val) case SQL_UPDATE: case SQL_SELECT: case SQL_DELETE: + val = sqlEscapeString (b->escape, val); + if (b->where_need_and) b->pval = stpcpy(b->pval, " AND "); b->where_need_and = 1; @@ -338,11 +339,9 @@ sqlBuild_Where_Str (sqlBuilder *b, const char *tag, const char *val) break; - default: PERR ("mustn't happen"); }; - } /* ================================================ */ diff --git a/src/backend/postgres/escape.c b/src/backend/postgres/escape.c index 66267992be..8a4b7ed782 100644 --- a/src/backend/postgres/escape.c +++ b/src/backend/postgres/escape.c @@ -53,7 +53,13 @@ sqlEscapeString (sqlEscape *b, const char *str) const char *p, *src_head; char *dst_tail; size_t len, slen; - + + if (!b || !str) return NULL; + + /* if a string is escaped twice, just return the first */ + if (b->escape == str) + return str; + /* if nothing to escape, just return */ len = strlen (str); slen = strcspn (str, "\\\'"); diff --git a/src/backend/postgres/kvp-sql.c b/src/backend/postgres/kvp-sql.c index 0286db116d..ce02701cd9 100644 --- a/src/backend/postgres/kvp-sql.c +++ b/src/backend/postgres/kvp-sql.c @@ -37,6 +37,7 @@ #include #include +#include "escape.h" #include "gnc-engine-util.h" #include "kvp-sql.h" #include "PostgresBackend.h" @@ -180,6 +181,7 @@ pgendGetPathCache (PGBackend *be, const char *path_str) typedef struct store_data_s { PGBackend *be; + sqlEscape *escape; int iguid; int ipath; char *path; @@ -192,7 +194,6 @@ typedef struct store_data_s { const GUID *guid; GList *list; } u; - } store_data_t; #include "kvp-autogen.c" @@ -208,7 +209,8 @@ store_cb (const char *key, kvp_value *val, gpointer p) path_save = cb_data->path; cb_data->path = g_strjoin ("/", path_save, key, 0); - ipath = pgendGetPathCache (be, cb_data->path); + ipath = pgendGetPathCache (be, sqlEscapeString (cb_data->escape, + cb_data->path)); cb_data->ipath = ipath; if (ipath) @@ -321,10 +323,14 @@ pgendKVPStore (PGBackend *be, guint32 iguid, kvp_frame *kf) ENTER (" "); cb_data.be = be; + cb_data.escape = sqlEscape_new (); cb_data.iguid = iguid; cb_data.path = ""; kvp_frame_for_each_slot (kf, store_cb, &cb_data); + + sqlEscape_destroy (cb_data.escape); + LEAVE (" "); } diff --git a/src/backend/postgres/test/.cvsignore b/src/backend/postgres/test/.cvsignore index 57ef1fd386..9f697a9c10 100644 --- a/src/backend/postgres/test/.cvsignore +++ b/src/backend/postgres/test/.cvsignore @@ -3,3 +3,4 @@ Makefile Makefile.in gnc_test test-db +test-escape diff --git a/src/backend/postgres/test/Makefile.am b/src/backend/postgres/test/Makefile.am index a01f50c623..7564078bb2 100644 --- a/src/backend/postgres/test/Makefile.am +++ b/src/backend/postgres/test/Makefile.am @@ -1,5 +1,6 @@ TESTS = \ test-load-module \ + test-escape \ run-tests.sh TESTS_ENVIRONMENT=\ @@ -9,7 +10,8 @@ TESTS_ENVIRONMENT=\ LD_LIBRARY_PATH=${top_srcdir}/src/gnc-module:${top_srcdir}/src/gnc-module/.libs:${top_srcdir}/src/engine:${top_srcdir}/src/engine/.libs noinst_PROGRAMS = \ - test-db + test-db \ + test-escape LDADD = -L${top_srcdir}/src/gnc-module -L${top_srcdir}/src/gnc-module/.libs \ -L${top_srcdir}/src/engine -L${top_srcdir}/src/engine/.libs \ diff --git a/src/backend/postgres/test/test-db.c b/src/backend/postgres/test/test-db.c index 2c81cad390..bbc88cf54d 100644 --- a/src/backend/postgres/test/test-db.c +++ b/src/backend/postgres/test/test-db.c @@ -87,6 +87,8 @@ guile_main (int argc, char **argv) set_max_group_depth (3); set_max_group_accounts (5); + random_character_include_funky_chars (FALSE); + xaccLogDisable (); run_test (); diff --git a/src/backend/postgres/test/test-escape.c b/src/backend/postgres/test/test-escape.c new file mode 100644 index 0000000000..7541454d86 --- /dev/null +++ b/src/backend/postgres/test/test-escape.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "escape.h" +#include "test-stuff.h" + +static sqlEscape *escape = NULL; + +static void +test_escape (const char *s, const char *expected) +{ + const char *escaped; + gboolean success; + + escaped = sqlEscapeString (escape, s); + + if (escaped == expected) + success = TRUE; + else + success = (strcmp (escaped, expected) == 0); + + do_test_args (success, "escape test", __FILE__, __LINE__, + "bad escaping: expected %s -> %s, got %s", + s, expected, escaped); +} + +int +main (int argc, char *argv[]) +{ + int i; + + random_character_include_funky_chars (TRUE); + + escape = sqlEscape_new (); + + test_escape (NULL, NULL); + test_escape ("", ""); + test_escape ("'", "\\'"); + test_escape ("\\", "\\\\"); + + for (i = 0; i < 200; i++) + { + char *s; + const char *ss; + + s = get_random_string (); + + ss = sqlEscapeString (escape, s); + sqlEscapeString (escape, ss); + + g_free (s); + } + + success ("crash test"); + + sqlEscape_destroy (escape); + + print_test_results (); + exit (get_rv ()); +} diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index 8f0294e254..ce64210959 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -226,29 +226,78 @@ xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_txn_splits) { if(!sa && !sb) return TRUE; - if(!sa) return FALSE; - if(!sb) return FALSE; + + if (!sa || !sb) + { + PWARN ("one is NULL"); + return FALSE; + } if(check_guids) { - if(!guid_equal(&(sa->guid), &(sb->guid))) return FALSE; + if(!guid_equal(&(sa->guid), &(sb->guid))) + { + PWARN ("GUIDs differ"); + return FALSE; + } } /* Since these strings are cached we can just use pointer equality */ - if(sa->memo != sb->memo) return FALSE; - if(sa->action != sb->action) return FALSE; + if (sa->memo != sb->memo) + { + PWARN ("memos differ: %s vs %s", sa->memo, sb->memo); + return FALSE; + } - if(kvp_frame_compare(sa->kvp_data, sb->kvp_data) != 0) return FALSE; + if (sa->action != sb->action) + { + PWARN ("actions differ: %s vs %s", sa->action, sb->action); + return FALSE; + } - if(sa->reconciled != sb->reconciled) return FALSE; - if(timespec_cmp(&(sa->date_reconciled), - &(sb->date_reconciled))) return FALSE; + if (kvp_frame_compare(sa->kvp_data, sb->kvp_data) != 0) + { + char *frame_a; + char *frame_b; - if(!gnc_numeric_eq(sa->amount, sb->amount)) return FALSE; - if(!gnc_numeric_eq(sa->value, sb->value)) return FALSE; + frame_a = kvp_frame_to_string (sa->kvp_data); + frame_b = kvp_frame_to_string (sb->kvp_data); - if(!xaccTransEqual(sa->parent, sb->parent, - check_guids, - check_txn_splits)) { + PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b); + + g_free (frame_a); + g_free (frame_b); + + return FALSE; + } + + if (sa->reconciled != sb->reconciled) + { + PWARN ("reconcile flags differ: %c vs %c", sa->reconciled, sb->reconciled); + return FALSE; + } + + if (timespec_cmp(&(sa->date_reconciled), + &(sb->date_reconciled))) + { + PWARN ("reconciled date differs"); + return FALSE; + } + + if (!gnc_numeric_eq(sa->amount, sb->amount)) + { + PWARN ("amount differs"); + return FALSE; + } + + if (!gnc_numeric_eq(sa->value, sb->value)) + { + PWARN ("value differs"); + return FALSE; + } + + if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits)) + { + PWARN ("transactions differ"); return FALSE; } @@ -800,43 +849,103 @@ xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_splits) { if(!ta && !tb) return TRUE; - if(!ta) return FALSE; - if(!tb) return FALSE; + + if(!ta || !tb) + { + PWARN ("one is NULL"); + return FALSE; + } if(check_guids) { - if(!guid_equal(&(ta->guid), &(tb->guid))) return FALSE; + if(!guid_equal(&(ta->guid), &(tb->guid))) + { + PWARN ("GUIDs differ"); + return FALSE; + } } if(!gnc_commodity_equiv(ta->common_currency, tb->common_currency)) + { + PWARN ("commodities differ %s vs %s", + gnc_commodity_get_unique_name (ta->common_currency), + gnc_commodity_get_unique_name (tb->common_currency)); return FALSE; + } + + if(timespec_cmp(&(ta->date_entered), &(tb->date_entered))) + { + PWARN ("date entered differs"); + return FALSE; + } + + if(timespec_cmp(&(ta->date_posted), &(tb->date_posted))) + { + PWARN ("date posted differs"); + return FALSE; + } - if(timespec_cmp(&(ta->date_entered), &(tb->date_entered))) return FALSE; - if(timespec_cmp(&(ta->date_posted), &(tb->date_posted))) return FALSE; /* Since we use cached strings, we can just compare pointer * equality for num and description */ - if(ta->num != tb->num) return FALSE; - if(ta->description != tb->description) return FALSE; + if(ta->num != tb->num) + { + PWARN ("num differs: %s vs %s", ta->num, tb->num); + return FALSE; + } - if(kvp_frame_compare(ta->kvp_data, tb->kvp_data) != 0) return FALSE; + if(ta->description != tb->description) + { + PWARN ("descriptions differ: %s vs %s", ta->description, tb->description); + return FALSE; + } - if(check_splits) { + if(kvp_frame_compare(ta->kvp_data, tb->kvp_data) != 0) + { + char *frame_a; + char *frame_b; + + frame_a = kvp_frame_to_string (ta->kvp_data); + frame_b = kvp_frame_to_string (tb->kvp_data); + + PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b); + + g_free (frame_a); + g_free (frame_b); + + return FALSE; + } + + if (check_splits) + { GList *sa = ta->splits; GList *sb = tb->splits; - if(!sa && sb) return FALSE; - if(!sb && sa) return FALSE; + if ((!sa && sb) || (!sb && sa)) + { + PWARN ("only one has splits"); + return FALSE; + } - if(sa && sb) { + if (sa && sb) + { /* presume that the splits are in the same order */ - while(sa && sb) { - if(!xaccSplitEqual(sa->data, sb->data, check_guids, FALSE)) + while (sa && sb) + { + if (!xaccSplitEqual(sa->data, sb->data, check_guids, FALSE)) + { + PWARN ("splits differ"); return(FALSE); + } + sa = sa->next; sb = sb->next; } - if(sa != NULL) return(FALSE); - if(sb != NULL) return(FALSE); + + if ((sa != NULL) || (sb != NULL)) + { + PWARN ("different number of splits"); + return(FALSE); + } } } diff --git a/src/test-core/test-stuff.c b/src/test-core/test-stuff.c index 5fc53b2223..00fddf75e6 100644 --- a/src/test-core/test-stuff.c +++ b/src/test-core/test-stuff.c @@ -202,27 +202,40 @@ get_random_int_in_range(int start, int end) return start + (int)((double)end * rand() / (RAND_MAX + 1.0)); } -static char random_chars[] = +static char *random_chars = NULL; + +static char plain_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "1234567890" -" " -#if 0 +" "; + +static char funky_chars[] = ",.'\"`~!@#$%^*(){}[]/=?+-_\\|" "<>&" -"\n\t" -#endif -""; +"\n\t"; + +static int rcend = 0; + +void +random_character_include_funky_chars (gboolean use_funky_chars) +{ + g_free (random_chars); + + if (use_funky_chars) + random_chars = g_strconcat (plain_chars, funky_chars, NULL); + else + random_chars = g_strdup (plain_chars); + + rcend = strlen (random_chars) - 1; +} gchar get_random_character(void) { - static int rcend = 0; - if(!rcend) - { - rcend = strlen(random_chars) - 1; - } - + if (!rcend) + random_character_include_funky_chars (FALSE); + return random_chars[get_random_int_in_range(0, rcend)]; } @@ -255,7 +268,8 @@ get_random_string(void) { ret[i] = get_random_character(); } - return ret; + + return g_strstrip (ret); } gint64 diff --git a/src/test-core/test-stuff.h b/src/test-core/test-stuff.h index 4b3d39937d..c0d05aa159 100644 --- a/src/test-core/test-stuff.h +++ b/src/test-core/test-stuff.h @@ -120,6 +120,7 @@ void failure_args( gboolean get_random_boolean(void); gint get_random_int_in_range(int start, int end); +void random_character_include_funky_chars (gboolean use_funky_chars); gchar get_random_character(void); gchar* get_random_string(void); gint64 get_random_gint64(void);