mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Test for overflow limits in gnc_numeric_add.
For analysis of Bug 665707. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@23494 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
de3a6e3df2
commit
e4fc44dd1c
@ -546,8 +546,113 @@ check_add_subtract (void)
|
||||
}
|
||||
}
|
||||
|
||||
extern gint64 pwr64 (gint64 op, int exp);
|
||||
|
||||
static void
|
||||
check_add_subtract_overflow (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NREPS; i++)
|
||||
{
|
||||
/* Div to avoid addition overflows; we're looking for lcd conversion overflows here. */
|
||||
|
||||
int exp_a = rand () % 1000;
|
||||
int exp_b = rand () % 1000;
|
||||
gint64 bin_deno_a = (exp_a == 0 ? 1 : exp_a);
|
||||
gint64 bin_deno_b = (exp_b == 0 ? 1 : exp_b);
|
||||
/*
|
||||
int exp_a = rand () % 11;
|
||||
int exp_b = rand () % 11;
|
||||
gint64 bin_deno_a = (1 << exp_a);
|
||||
gint64 bin_deno_b = (1 << exp_a);
|
||||
*/
|
||||
gint64 dec_deno_a = pwr64 (10, exp_a % 7);
|
||||
gint64 dec_deno_b = pwr64 (10, exp_b % 7);
|
||||
gint64 na = get_random_gint64 () % (1000000 * dec_deno_a);
|
||||
gint64 nb = get_random_gint64 () % (1000000 * dec_deno_b);
|
||||
gnc_numeric result;
|
||||
GNCNumericErrorCode err;
|
||||
gchar *errmsg;
|
||||
|
||||
gnc_numeric ba = gnc_numeric_create(na, bin_deno_a);
|
||||
gnc_numeric bb = gnc_numeric_create(nb, bin_deno_b);
|
||||
gnc_numeric da = gnc_numeric_create(na, dec_deno_a);
|
||||
gnc_numeric db = gnc_numeric_create(nb, dec_deno_b);
|
||||
gchar *ba_str = gnc_numeric_to_string (ba);
|
||||
gchar *bb_str = gnc_numeric_to_string (bb);
|
||||
gchar *da_str = gnc_numeric_to_string (da);
|
||||
gchar *db_str = gnc_numeric_to_string (db);
|
||||
|
||||
|
||||
/* Add */
|
||||
|
||||
result = gnc_numeric_add(ba, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, bb_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
|
||||
result = gnc_numeric_add(da, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", da_str, bb_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
result = gnc_numeric_add(ba, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, db_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
|
||||
result = gnc_numeric_add(da, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", da_str, db_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
/* Subtract */
|
||||
|
||||
result = gnc_numeric_sub(ba, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, bb_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
|
||||
result = gnc_numeric_sub(da, bb, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", da_str, bb_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
result = gnc_numeric_sub(ba, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, db_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
|
||||
result = gnc_numeric_sub(da, db, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
|
||||
err = gnc_numeric_check (result);
|
||||
errmsg = g_strdup_printf ("%s + %s raised %s", da_str, db_str,
|
||||
gnc_numeric_errorCode_to_string (err));
|
||||
do_test (err == 0, errmsg);
|
||||
g_free (errmsg);
|
||||
|
||||
g_free (ba_str);
|
||||
g_free (bb_str);
|
||||
g_free (da_str);
|
||||
g_free (db_str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ======================================================= */
|
||||
|
||||
|
||||
static void
|
||||
check_mult_div (void)
|
||||
{
|
||||
@ -871,6 +976,7 @@ run_test (void)
|
||||
check_double();
|
||||
check_neg();
|
||||
check_add_subtract();
|
||||
check_add_subtract_overflow ();
|
||||
check_mult_div ();
|
||||
check_reciprocal();
|
||||
}
|
||||
|
@ -45,6 +45,23 @@
|
||||
|
||||
/* static short module = MOD_ENGINE; */
|
||||
|
||||
gint64
|
||||
pwr64 (gint64 op, int exp)
|
||||
{
|
||||
qofint128 tmp;
|
||||
if (exp == 0) return 1;
|
||||
if (exp % 2)
|
||||
{
|
||||
tmp = mult128 (op, pwr64 (op, exp - 1));
|
||||
if (tmp.isbig) return 0;
|
||||
return tmp.lo;
|
||||
}
|
||||
tmp.lo = pwr64 (op, exp / 2);
|
||||
tmp = mult128 (tmp.lo, tmp.lo);
|
||||
if (tmp.isbig) return 0;
|
||||
return tmp.lo;
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
/* This function is small, simple, and used everywhere below,
|
||||
* lets try to inline it.
|
||||
|
47
src/libqof/qof/test/test-gnc-numeric.c
Normal file
47
src/libqof/qof/test/test-gnc-numeric.c
Normal file
@ -0,0 +1,47 @@
|
||||
/********************************************************************
|
||||
* test_qofbackend.c: GLib g_test test suite for qofbackend. *
|
||||
* 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 <qof.h>
|
||||
#include <unittest-support.h>
|
||||
|
||||
static const gchar *suitename = "/qof/gnc_numeric";
|
||||
|
||||
static void
|
||||
test_gnc_numeric_add (void)
|
||||
{
|
||||
gnc_numeric a = { 123456789987654321, 1000000000 };
|
||||
gnc_numeric b = { 65432198765432198, 100000000 };
|
||||
gnc_numeric goal_ab = { 777778777641976301, 1000000000 };
|
||||
gnc_numeric result;
|
||||
|
||||
result = gnc_numeric_add (a, b, GNC_DENOM_AUTO,
|
||||
GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER);
|
||||
g_assert (gnc_numeric_equal (result, goal_ab));
|
||||
}
|
||||
|
||||
void
|
||||
test_suite_gnc_numeric ( void )
|
||||
{
|
||||
GNC_TEST_ADD_FUNC( suitename, "gnc-numeric add", test_gnc_numeric_add );
|
||||
}
|
Loading…
Reference in New Issue
Block a user