It is now an error to use an uninitialized amount for any operation

other than is_null and parse.
This commit is contained in:
John Wiegley 2007-05-08 10:33:13 +00:00
parent 0477dd119a
commit 4e9056b6ce
4 changed files with 152 additions and 176 deletions

View file

@ -133,6 +133,8 @@ void amount_t::shutdown()
void amount_t::_init() void amount_t::_init()
{ {
// This is only called on an initialized amount by amount_t::parse.
if (! quantity) { if (! quantity) {
quantity = new bigint_t; quantity = new bigint_t;
} }
@ -140,6 +142,7 @@ void amount_t::_init()
_release(); _release();
quantity = new bigint_t; quantity = new bigint_t;
} }
commodity_ = NULL;
} }
void amount_t::_copy(const amount_t& amt) void amount_t::_copy(const amount_t& amt)
@ -301,28 +304,25 @@ namespace {
} }
} }
amount_t::amount_t(const double val) amount_t::amount_t(const double val) : commodity_(NULL)
{ {
TRACE_CTOR(amount_t, "const double"); TRACE_CTOR(amount_t, "const double");
quantity = new bigint_t; quantity = new bigint_t;
quantity->prec = convert_double(MPZ(quantity), val); quantity->prec = convert_double(MPZ(quantity), val);
commodity_ = NULL;
} }
amount_t::amount_t(const unsigned long val) amount_t::amount_t(const unsigned long val) : commodity_(NULL)
{ {
TRACE_CTOR(amount_t, "const unsigned long"); TRACE_CTOR(amount_t, "const unsigned long");
quantity = new bigint_t; quantity = new bigint_t;
mpz_set_ui(MPZ(quantity), val); mpz_set_ui(MPZ(quantity), val);
commodity_ = NULL;
} }
amount_t::amount_t(const long val) amount_t::amount_t(const long val) : commodity_(NULL)
{ {
TRACE_CTOR(amount_t, "const long"); TRACE_CTOR(amount_t, "const long");
quantity = new bigint_t; quantity = new bigint_t;
mpz_set_si(MPZ(quantity), val); mpz_set_si(MPZ(quantity), val);
commodity_ = NULL;
} }
@ -340,15 +340,17 @@ amount_t& amount_t::operator=(const amount_t& amt)
int amount_t::compare(const amount_t& amt) const int amount_t::compare(const amount_t& amt) const
{ {
if (! quantity) { if (! quantity || ! amt.quantity) {
if (! amt.quantity) if (quantity)
return 0; throw_(amount_error, "Cannot compare an amount to an uninitialized amount");
return - amt.sign(); else if (amt.quantity)
throw_(amount_error, "Cannot compare an uninitialized amount to an amount");
else
throw_(amount_error, "Cannot compare two uninitialized amounts");
} }
if (! amt.quantity)
return sign();
if (has_commodity() && amt.commodity() && commodity() != amt.commodity()) if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity())
throw_(amount_error, throw_(amount_error,
"Cannot compare amounts with different commodities: " << "Cannot compare amounts with different commodities: " <<
commodity().symbol() << " and " << amt.commodity().symbol()); commodity().symbol() << " and " << amt.commodity().symbol());
@ -371,6 +373,15 @@ int amount_t::compare(const amount_t& amt) const
amount_t& amount_t::operator+=(const amount_t& amt) amount_t& amount_t::operator+=(const amount_t& amt)
{ {
if (! quantity || ! amt.quantity) {
if (quantity)
throw_(amount_error, "Cannot add an amount to an uninitialized amount");
else if (amt.quantity)
throw_(amount_error, "Cannot add an uninitialized amount to an amount");
else
throw_(amount_error, "Cannot add two uninitialized amounts");
}
if (commodity() != amt.commodity()) if (commodity() != amt.commodity())
throw_(amount_error, throw_(amount_error,
"Adding amounts with different commodities: " << "Adding amounts with different commodities: " <<
@ -378,14 +389,6 @@ amount_t& amount_t::operator+=(const amount_t& amt)
" != " << " != " <<
(amt.has_commodity() ? amt.commodity().symbol() : "NONE")); (amt.has_commodity() ? amt.commodity().symbol() : "NONE"));
if (! amt.quantity)
return *this;
if (! quantity) {
_copy(amt);
return *this;
}
_dup(); _dup();
if (quantity->prec == amt.quantity->prec) { if (quantity->prec == amt.quantity->prec) {
@ -406,6 +409,15 @@ amount_t& amount_t::operator+=(const amount_t& amt)
amount_t& amount_t::operator-=(const amount_t& amt) amount_t& amount_t::operator-=(const amount_t& amt)
{ {
if (! quantity || ! amt.quantity) {
if (quantity)
throw_(amount_error, "Cannot subtract an amount from an uninitialized amount");
else if (amt.quantity)
throw_(amount_error, "Cannot subtract an uninitialized amount from an amount");
else
throw_(amount_error, "Cannot subtract two uninitialized amounts");
}
if (commodity() != amt.commodity()) if (commodity() != amt.commodity())
throw_(amount_error, throw_(amount_error,
"Subtracting amounts with different commodities: " << "Subtracting amounts with different commodities: " <<
@ -413,16 +425,6 @@ amount_t& amount_t::operator-=(const amount_t& amt)
" != " << " != " <<
(amt.has_commodity() ? amt.commodity().symbol() : "NONE")); (amt.has_commodity() ? amt.commodity().symbol() : "NONE"));
if (! amt.quantity)
return *this;
if (! quantity) {
quantity = new bigint_t(*amt.quantity);
commodity_ = amt.commodity_;
mpz_neg(MPZ(quantity), MPZ(quantity));
return *this;
}
_dup(); _dup();
if (quantity->prec == amt.quantity->prec) { if (quantity->prec == amt.quantity->prec) {
@ -491,6 +493,15 @@ namespace {
amount_t& amount_t::operator*=(const amount_t& amt) amount_t& amount_t::operator*=(const amount_t& amt)
{ {
if (! quantity || ! amt.quantity) {
if (quantity)
throw_(amount_error, "Cannot multiply an amount by an uninitialized amount");
else if (amt.quantity)
throw_(amount_error, "Cannot multiply an uninitialized amount by an amount");
else
throw_(amount_error, "Cannot multiply two uninitialized amounts");
}
if (has_commodity() && amt.has_commodity() && if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity()) commodity() != amt.commodity())
throw_(amount_error, throw_(amount_error,
@ -499,16 +510,6 @@ amount_t& amount_t::operator*=(const amount_t& amt)
" != " << " != " <<
(amt.has_commodity() ? amt.commodity().symbol() : "NONE")); (amt.has_commodity() ? amt.commodity().symbol() : "NONE"));
if (! amt.quantity) {
*this = *this - *this; // preserve our commodity
goto finish;
}
else if (! quantity) {
*this = amt;
*this = *this - *this; // preserve the foreign commodity
goto finish;
}
_dup(); _dup();
mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity)); mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
@ -531,6 +532,15 @@ amount_t& amount_t::operator*=(const amount_t& amt)
amount_t& amount_t::operator/=(const amount_t& amt) amount_t& amount_t::operator/=(const amount_t& amt)
{ {
if (! quantity || ! amt.quantity) {
if (quantity)
throw_(amount_error, "Cannot divide an amount by an uninitialized amount");
else if (amt.quantity)
throw_(amount_error, "Cannot divide an uninitialized amount by an amount");
else
throw_(amount_error, "Cannot divide two uninitialized amounts");
}
if (has_commodity() && amt.has_commodity() && if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity()) commodity() != amt.commodity())
throw_(amount_error, throw_(amount_error,
@ -539,14 +549,8 @@ amount_t& amount_t::operator/=(const amount_t& amt)
" != " << " != " <<
(amt.has_commodity() ? amt.commodity().symbol() : "NONE")); (amt.has_commodity() ? amt.commodity().symbol() : "NONE"));
if (! amt.quantity || ! amt) { if (! amt)
throw_(amount_error, "Divide by zero"); throw_(amount_error, "Divide by zero");
}
else if (! quantity) {
*this = amt;
*this = *this - *this; // preserve the foreign commodity
goto finish;
}
_dup(); _dup();
@ -584,6 +588,9 @@ amount_t& amount_t::operator/=(const amount_t& amt)
amount_t::precision_t amount_t::precision() const amount_t::precision_t amount_t::precision() const
{ {
if (! quantity)
throw_(amount_error, "Cannot determine precision of an uninitialized amount");
return quantity->prec; return quantity->prec;
} }
@ -592,6 +599,8 @@ amount_t& amount_t::in_place_negate()
if (quantity) { if (quantity) {
_dup(); _dup();
mpz_neg(MPZ(quantity), MPZ(quantity)); mpz_neg(MPZ(quantity), MPZ(quantity));
} else {
throw_(amount_error, "Cannot negate an uninitialized amount");
} }
return *this; return *this;
} }
@ -600,7 +609,10 @@ amount_t amount_t::round(precision_t prec) const
{ {
amount_t t = *this; amount_t t = *this;
if (! quantity || quantity->prec <= prec) { if (! quantity)
throw_(amount_error, "Cannot round an uninitialized amount");
if (quantity->prec <= prec) {
if (quantity && quantity->has_flags(BIGINT_KEEP_PREC)) { if (quantity && quantity->has_flags(BIGINT_KEEP_PREC)) {
t._dup(); t._dup();
t.quantity->drop_flags(BIGINT_KEEP_PREC); t.quantity->drop_flags(BIGINT_KEEP_PREC);
@ -620,15 +632,10 @@ amount_t amount_t::round(precision_t prec) const
amount_t amount_t::unround() const amount_t amount_t::unround() const
{ {
if (! quantity) { if (! quantity)
amount_t t(0L); throw_(amount_error, "Cannot unround an uninitialized amount");
assert(t.quantity); else if (quantity->has_flags(BIGINT_KEEP_PREC))
t.quantity->add_flags(BIGINT_KEEP_PREC);
return t;
}
else if (quantity->has_flags(BIGINT_KEEP_PREC)) {
return *this; return *this;
}
amount_t t = *this; amount_t t = *this;
t._dup(); t._dup();
@ -639,6 +646,9 @@ amount_t amount_t::unround() const
amount_t& amount_t::in_place_reduce() amount_t& amount_t::in_place_reduce()
{ {
if (! quantity)
throw_(amount_error, "Cannot reduce an uninitialized amount");
while (commodity_ && commodity().smaller()) { while (commodity_ && commodity().smaller()) {
*this *= commodity().smaller()->number(); *this *= commodity().smaller()->number();
commodity_ = commodity().smaller()->commodity_; commodity_ = commodity().smaller()->commodity_;
@ -648,6 +658,9 @@ amount_t& amount_t::in_place_reduce()
amount_t& amount_t::in_place_unreduce() amount_t& amount_t::in_place_unreduce()
{ {
if (! quantity)
throw_(amount_error, "Cannot unreduce an uninitialized amount");
while (commodity_ && commodity().larger()) { while (commodity_ && commodity().larger()) {
*this /= commodity().larger()->number(); *this /= commodity().larger()->number();
commodity_ = commodity().larger()->commodity_; commodity_ = commodity().larger()->commodity_;
@ -663,6 +676,8 @@ optional<amount_t> amount_t::value(const optional<moment_t>& moment) const
optional<amount_t> amt(commodity().value(moment)); optional<amount_t> amt(commodity().value(moment));
if (amt) if (amt)
return (*amt * number()).round(); return (*amt * number()).round();
} else {
throw_(amount_error, "Cannot determine value of an uninitialized amount");
} }
return optional<amount_t>(); return optional<amount_t>();
} }
@ -670,13 +685,16 @@ optional<amount_t> amount_t::value(const optional<moment_t>& moment) const
int amount_t::sign() const int amount_t::sign() const
{ {
return quantity ? mpz_sgn(MPZ(quantity)) : 0; if (! quantity)
throw_(amount_error, "Cannot determine sign of an uninitialized amount");
return mpz_sgn(MPZ(quantity));
} }
bool amount_t::is_zero() const bool amount_t::is_zero() const
{ {
if (! quantity) if (! quantity)
return true; throw_(amount_error, "Cannot determine sign if an uninitialized amount is zero");
if (has_commodity()) { if (has_commodity()) {
if (quantity->prec <= commodity().precision()) if (quantity->prec <= commodity().precision())
@ -691,7 +709,7 @@ bool amount_t::is_zero() const
double amount_t::to_double(bool no_check) const double amount_t::to_double(bool no_check) const
{ {
if (! quantity) if (! quantity)
return 0.0; throw_(amount_error, "Cannot convert an uninitialized amount to a double");
mpz_t remainder; mpz_t remainder;
mpz_init(remainder); mpz_init(remainder);
@ -722,7 +740,7 @@ double amount_t::to_double(bool no_check) const
long amount_t::to_long(bool no_check) const long amount_t::to_long(bool no_check) const
{ {
if (! quantity) if (! quantity)
return 0; throw_(amount_error, "Cannot convert an uninitialized amount to a long");
mpz_set(temp, MPZ(quantity)); mpz_set(temp, MPZ(quantity));
mpz_ui_pow_ui(divisor, 10, quantity->prec); mpz_ui_pow_ui(divisor, 10, quantity->prec);
@ -754,6 +772,11 @@ void amount_t::annotate_commodity(const annotation_t& details)
commodity_t * this_base; commodity_t * this_base;
annotated_commodity_t * this_ann = NULL; annotated_commodity_t * this_ann = NULL;
if (! quantity)
throw_(amount_error, "Cannot annotate the commodity of an uninitialized amount");
else if (! has_commodity())
throw_(amount_error, "Cannot annotate an amount with no commodity");
if (commodity().annotated) { if (commodity().annotated) {
this_ann = &commodity().as_annotated(); this_ann = &commodity().as_annotated();
this_base = &this_ann->referent(); this_base = &this_ann->referent();
@ -780,6 +803,10 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
const bool _keep_date, const bool _keep_date,
const bool _keep_tag) const const bool _keep_tag) const
{ {
if (! quantity)
throw_(amount_error,
"Cannot strip commodity annotations from an uninitialized amount");
if (! commodity().annotated || if (! commodity().annotated ||
(_keep_price && _keep_date && _keep_tag)) (_keep_price && _keep_date && _keep_tag))
return *this; return *this;
@ -817,12 +844,20 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
bool amount_t::commodity_annotated() const bool amount_t::commodity_annotated() const
{ {
if (! quantity)
throw_(amount_error,
"Cannot determine if an uninitialized amount's commodity is annotated");
assert(! commodity().annotated || commodity().as_annotated().details); assert(! commodity().annotated || commodity().as_annotated().details);
return commodity().annotated; return commodity().annotated;
} }
annotation_t amount_t::annotation_details() const annotation_t amount_t::annotation_details() const
{ {
if (! quantity)
throw_(amount_error,
"Cannot return commodity annotation details of an uninitialized amount");
assert(! commodity().annotated || commodity().as_annotated().details); assert(! commodity().annotated || commodity().as_annotated().details);
if (commodity().annotated) { if (commodity().annotated) {
@ -1019,7 +1054,7 @@ void amount_t::parse(std::istream& in, flags_t flags)
if (quant.empty()) if (quant.empty())
throw_(amount_error, "No quantity specified for amount"); throw_(amount_error, "No quantity specified for amount");
_init(); _init(); // this will reuse a current value
// Create the commodity if has not already been seen, and update the // Create the commodity if has not already been seen, and update the
// precision if something greater was used for the quantity. // precision if something greater was used for the quantity.
@ -1133,6 +1168,9 @@ void amount_t::parse_conversion(const string& larger_str,
void amount_t::print(std::ostream& _out, bool omit_commodity, void amount_t::print(std::ostream& _out, bool omit_commodity,
bool full_precision) const bool full_precision) const
{ {
if (! quantity)
throw_(amount_error, "Cannot write out an uninitialized amount");
amount_t base(*this); amount_t base(*this);
if (! amount_t::keep_base) if (! amount_t::keep_base)
base.in_place_unreduce(); base.in_place_unreduce();
@ -1341,6 +1379,9 @@ void amount_t::read(char *& data)
void amount_t::write(std::ostream& out) const void amount_t::write(std::ostream& out) const
{ {
if (! quantity)
throw_(amount_error, "Cannot serialize an uninitialized amount");
if (commodity_) if (commodity_)
write_binary_long(out, commodity_->ident); write_binary_long(out, commodity_->ident);
else else
@ -1435,11 +1476,7 @@ void amount_t::write_quantity(std::ostream& out) const
{ {
char byte; char byte;
if (! quantity) { assert(quantity);
byte = 0;
out.write(&byte, sizeof(byte));
return;
}
if (quantity->index == 0) { if (quantity->index == 0) {
quantity->index = ++bigints_index; quantity->index = ++bigints_index;

View file

@ -403,7 +403,7 @@ public:
bool is_null() const { bool is_null() const {
if (! quantity) { if (! quantity) {
assert(! has_commodity()); assert(! commodity_);
return true; return true;
} }
return false; return false;
@ -477,6 +477,8 @@ public:
bool has_commodity() const; bool has_commodity() const;
void set_commodity(commodity_t& comm) { void set_commodity(commodity_t& comm) {
if (! quantity)
*this = 0L;
commodity_ = &comm; commodity_ = &comm;
} }
void clear_commodity() { void clear_commodity() {
@ -486,6 +488,7 @@ public:
amount_t number() const { amount_t number() const {
if (! has_commodity()) if (! has_commodity())
return *this; return *this;
amount_t temp(*this); amount_t temp(*this);
temp.clear_commodity(); temp.clear_commodity();
return temp; return temp;

View file

@ -34,10 +34,10 @@ void AmountTestCase::testConstructors()
amount_t x10(x6); amount_t x10(x6);
amount_t x11(x8); amount_t x11(x8);
assertEqual(amount_t(0L), x0); assertThrow(amount_t(0L) == x0, amount_error);
assertEqual(amount_t(), x0); assertThrow(amount_t() == x0, amount_error);
assertEqual(amount_t("0"), x0); assertThrow(amount_t("0") == x0, amount_error);
assertEqual(amount_t("0.0"), x0); assertThrow(amount_t("0.0") == x0, amount_error);
assertEqual(x2, x1); assertEqual(x2, x1);
assertEqual(x5, x1); assertEqual(x5, x1);
assertEqual(x7, x1); assertEqual(x7, x1);
@ -108,7 +108,6 @@ void AmountTestCase::testCommodityConstructors()
void AmountTestCase::testAssignment() void AmountTestCase::testAssignment()
{ {
amount_t x0;
amount_t x1 = 123456L; amount_t x1 = 123456L;
amount_t x2 = 123456UL; amount_t x2 = 123456UL;
amount_t x3 = 123.456; amount_t x3 = 123.456;
@ -119,7 +118,6 @@ void AmountTestCase::testAssignment()
amount_t x9 = x3; amount_t x9 = x3;
amount_t x10 = amount_t(x6); amount_t x10 = amount_t(x6);
assertEqual(amount_t(0L), x0);
assertEqual(x2, x1); assertEqual(x2, x1);
assertEqual(x5, x1); assertEqual(x5, x1);
assertEqual(x7, x1); assertEqual(x7, x1);
@ -128,7 +126,6 @@ void AmountTestCase::testAssignment()
assertEqual(x10, x3); assertEqual(x10, x3);
assertEqual(x10, x9); assertEqual(x10, x9);
x0 = amount_t();
x1 = 123456L; x1 = 123456L;
x2 = 123456UL; x2 = 123456UL;
x3 = 123.456; x3 = 123.456;
@ -139,7 +136,6 @@ void AmountTestCase::testAssignment()
x9 = x3; x9 = x3;
x10 = amount_t(x6); x10 = amount_t(x6);
assertEqual(amount_t(0L), x0);
assertEqual(x2, x1); assertEqual(x2, x1);
assertEqual(x5, x1); assertEqual(x5, x1);
assertEqual(x7, x1); assertEqual(x7, x1);
@ -148,7 +144,6 @@ void AmountTestCase::testAssignment()
assertEqual(x10, x3); assertEqual(x10, x3);
assertEqual(x10, x9); assertEqual(x10, x9);
assertTrue(x0.valid());
assertTrue(x1.valid()); assertTrue(x1.valid());
assertTrue(x2.valid()); assertTrue(x2.valid());
assertTrue(x3.valid()); assertTrue(x3.valid());
@ -246,12 +241,12 @@ void AmountTestCase::testCommodityEquality()
amount_t x10 = "-123.45€"; amount_t x10 = "-123.45€";
assertTrue(x0.is_null()); assertTrue(x0.is_null());
assertTrue(x0.is_zero()); assertThrow(x0.is_zero(), amount_error);
assertTrue(x0.is_realzero()); assertThrow(x0.is_realzero(), amount_error);
assertTrue(x0.sign() == 0); assertThrow(x0.sign() == 0, amount_error);
assertTrue(x0.compare(x1) < 0); assertThrow(x0.compare(x1) < 0, amount_error);
assertTrue(x0.compare(x2) > 0); assertThrow(x0.compare(x2) > 0, amount_error);
assertTrue(x0.compare(x0) == 0); assertThrow(x0.compare(x0) == 0, amount_error);
assertTrue(x1 != x2); assertTrue(x1 != x2);
assertTrue(x1 != x4); assertTrue(x1 != x4);
@ -286,12 +281,12 @@ void AmountTestCase::testComparisons()
amount_t x5("-123.45"); amount_t x5("-123.45");
amount_t x6("123.45"); amount_t x6("123.45");
assertTrue(x0 > x1); assertThrow(x0 > x1, amount_error);
assertTrue(x0 < x2); assertThrow(x0 < x2, amount_error);
assertTrue(x0 > x3); assertThrow(x0 > x3, amount_error);
assertTrue(x0 < x4); assertThrow(x0 < x4, amount_error);
assertTrue(x0 > x5); assertThrow(x0 > x5, amount_error);
assertTrue(x0 < x6); assertThrow(x0 < x6, amount_error);
assertTrue(x1 > x3); assertTrue(x1 > x3);
assertTrue(x3 <= x5); assertTrue(x3 <= x5);
@ -317,7 +312,6 @@ void AmountTestCase::testComparisons()
void AmountTestCase::testCommodityComparisons() void AmountTestCase::testCommodityComparisons()
{ {
amount_t x0;
amount_t x1("$-123"); amount_t x1("$-123");
amount_t x2("$123.00"); amount_t x2("$123.00");
amount_t x3(internalAmount("$-123.4544")); amount_t x3(internalAmount("$-123.4544"));
@ -325,13 +319,6 @@ void AmountTestCase::testCommodityComparisons()
amount_t x5("$-123.45"); amount_t x5("$-123.45");
amount_t x6("$123.45"); amount_t x6("$123.45");
assertTrue(x0 > x1);
assertTrue(x0 < x2);
assertTrue(x0 > x3);
assertTrue(x0 < x4);
assertTrue(x0 > x5);
assertTrue(x0 < x6);
assertTrue(x1 > x3); assertTrue(x1 > x3);
assertTrue(x3 <= x5); assertTrue(x3 <= x5);
assertTrue(x3 < x5); assertTrue(x3 < x5);
@ -340,7 +327,6 @@ void AmountTestCase::testCommodityComparisons()
assertTrue(x3 < x1); assertTrue(x3 < x1);
assertTrue(x3 < x4); assertTrue(x3 < x4);
assertValid(x0);
assertValid(x1); assertValid(x1);
assertValid(x2); assertValid(x2);
assertValid(x3); assertValid(x3);
@ -847,7 +833,6 @@ void AmountTestCase::testCommodityDivision()
void AmountTestCase::testNegation() void AmountTestCase::testNegation()
{ {
amount_t x0;
amount_t x1(-123456L); amount_t x1(-123456L);
amount_t x3(-123.456); amount_t x3(-123.456);
amount_t x5("-123456"); amount_t x5("-123456");
@ -856,7 +841,6 @@ void AmountTestCase::testNegation()
amount_t x8(string("-123.456")); amount_t x8(string("-123.456"));
amount_t x9(- x3); amount_t x9(- x3);
assertEqual(amount_t(0L), x0);
assertEqual(x5, x1); assertEqual(x5, x1);
assertEqual(x7, x1); assertEqual(x7, x1);
assertEqual(x6, x3); assertEqual(x6, x3);
@ -868,7 +852,6 @@ void AmountTestCase::testNegation()
assertEqual(x3, x10); assertEqual(x3, x10);
assertTrue(x0.valid());
assertTrue(x1.valid()); assertTrue(x1.valid());
assertTrue(x3.valid()); assertTrue(x3.valid());
assertTrue(x5.valid()); assertTrue(x5.valid());
@ -940,7 +923,7 @@ void AmountTestCase::testAbs()
amount_t x1(-1234L); amount_t x1(-1234L);
amount_t x2(1234L); amount_t x2(1234L);
assertEqual(amount_t(), x0.abs()); assertThrow(x0.abs(), amount_error);
assertEqual(amount_t(1234L), x1.abs()); assertEqual(amount_t(1234L), x1.abs());
assertEqual(amount_t(1234L), x2.abs()); assertEqual(amount_t(1234L), x2.abs());
@ -951,15 +934,12 @@ void AmountTestCase::testAbs()
void AmountTestCase::testCommodityAbs() void AmountTestCase::testCommodityAbs()
{ {
amount_t x0;
amount_t x1("$-1234.56"); amount_t x1("$-1234.56");
amount_t x2("$1234.56"); amount_t x2("$1234.56");
assertEqual(amount_t(), x0.abs());
assertEqual(amount_t("$1234.56"), x1.abs()); assertEqual(amount_t("$1234.56"), x1.abs());
assertEqual(amount_t("$1234.56"), x2.abs()); assertEqual(amount_t("$1234.56"), x2.abs());
assertValid(x0);
assertValid(x1); assertValid(x1);
assertValid(x2); assertValid(x2);
} }
@ -1010,7 +990,7 @@ void AmountTestCase::testFractionalRound()
assertEqual(amount_t("0.0000000000000000000000000000000000001"), assertEqual(amount_t("0.0000000000000000000000000000000000001"),
x5.round(37)); x5.round(37));
assertEqual(amount_t(), x5.round(36)); assertEqual(amount_t(0L), x5.round(36));
assertTrue(x1.valid()); assertTrue(x1.valid());
assertTrue(x2.valid()); assertTrue(x2.valid());
@ -1127,7 +1107,7 @@ void AmountTestCase::testSign()
amount_t x3("1"); amount_t x3("1");
amount_t x4("-1"); amount_t x4("-1");
assertEqual(x0.sign(), 0); assertThrow(x0.sign(), amount_error);
assertTrue(x1.sign() > 0); assertTrue(x1.sign() > 0);
assertTrue(x2.sign() < 0); assertTrue(x2.sign() < 0);
assertTrue(x3.sign() > 0); assertTrue(x3.sign() > 0);
@ -1142,19 +1122,16 @@ void AmountTestCase::testSign()
void AmountTestCase::testCommoditySign() void AmountTestCase::testCommoditySign()
{ {
amount_t x0;
amount_t x1(internalAmount("$0.0000000000000000000000000000000000001")); amount_t x1(internalAmount("$0.0000000000000000000000000000000000001"));
amount_t x2(internalAmount("$-0.0000000000000000000000000000000000001")); amount_t x2(internalAmount("$-0.0000000000000000000000000000000000001"));
amount_t x3("$1"); amount_t x3("$1");
amount_t x4("$-1"); amount_t x4("$-1");
assertFalse(x0.sign());
assertTrue(x1.sign() != 0); assertTrue(x1.sign() != 0);
assertTrue(x2.sign() != 0); assertTrue(x2.sign() != 0);
assertTrue(x3.sign() > 0); assertTrue(x3.sign() > 0);
assertTrue(x4.sign() < 0); assertTrue(x4.sign() < 0);
assertValid(x0);
assertValid(x1); assertValid(x1);
assertValid(x2); assertValid(x2);
assertValid(x3); assertValid(x3);
@ -1167,10 +1144,7 @@ void AmountTestCase::testTruth()
amount_t x1("1234"); amount_t x1("1234");
amount_t x2("1234.56"); amount_t x2("1234.56");
if (x0) assertThrow(x0 ? 1 : 0, amount_error);
assertTrue(false);
else
assertTrue(true);
assertTrue(x1); assertTrue(x1);
assertTrue(x2); assertTrue(x2);
@ -1204,10 +1178,9 @@ void AmountTestCase::testForZero()
amount_t x0; amount_t x0;
amount_t x1("0.000000000000000000001"); amount_t x1("0.000000000000000000001");
assertFalse(x0);
assertTrue(x1); assertTrue(x1);
assertTrue(x0.is_zero()); assertThrow(x0.is_zero(), amount_error);
assertTrue(x0.is_realzero()); assertThrow(x0.is_realzero(), amount_error);
assertFalse(x1.is_zero()); assertFalse(x1.is_zero());
assertFalse(x1.is_realzero()); assertFalse(x1.is_realzero());
@ -1271,9 +1244,7 @@ void AmountTestCase::testPrinting()
{ {
std::ostringstream bufstr; std::ostringstream bufstr;
bufstr << x0; assertThrow(bufstr << x0, amount_error);
assertEqual(std::string("0"), bufstr.str());
} }
{ {
@ -1290,17 +1261,9 @@ void AmountTestCase::testPrinting()
void AmountTestCase::testCommodityPrinting() void AmountTestCase::testCommodityPrinting()
{ {
amount_t x0;
amount_t x1(internalAmount("$982340823.386238098235098235098235098")); amount_t x1(internalAmount("$982340823.386238098235098235098235098"));
amount_t x2("$982340823.38"); amount_t x2("$982340823.38");
{
std::ostringstream bufstr;
bufstr << x0;
assertEqual(std::string("0"), bufstr.str());
}
{ {
std::ostringstream bufstr; std::ostringstream bufstr;
bufstr << x1; bufstr << x1;
@ -1324,7 +1287,6 @@ void AmountTestCase::testCommodityPrinting()
assertEqual(std::string("$964993493285024293.18"), bufstr.str()); assertEqual(std::string("$964993493285024293.18"), bufstr.str());
} }
assertValid(x0);
assertValid(x1); assertValid(x1);
assertValid(x2); assertValid(x2);
} }

View file

@ -33,10 +33,10 @@ class AmountTestCase(unittest.TestCase):
x9 = amount(x3) x9 = amount(x3)
x10 = amount(x6) x10 = amount(x6)
self.assertEqual(amount(0), x0) self.assertRaises(exceptions.ArithmeticError, operator.eq, amount(0), x0)
self.assertEqual(amount(), x0) self.assertRaises(exceptions.ArithmeticError, operator.eq, amount(), x0)
self.assertEqual(amount("0"), x0) self.assertRaises(exceptions.ArithmeticError, operator.eq, amount("0"), x0)
self.assertEqual(amount("0.0"), x0) self.assertRaises(exceptions.ArithmeticError, operator.eq, amount("0.0"), x0)
self.assertEqual(x2, x1) self.assertEqual(x2, x1)
self.assertEqual(x5, x1) self.assertEqual(x5, x1)
self.assertEqual(x6, x3) self.assertEqual(x6, x3)
@ -98,7 +98,6 @@ class AmountTestCase(unittest.TestCase):
self.assertValid(x10) self.assertValid(x10)
def testAssignment(self): def testAssignment(self):
x0 = amount()
x1 = amount(123456) x1 = amount(123456)
x2 = amount(123456L) x2 = amount(123456L)
x3 = amount(123.456) x3 = amount(123.456)
@ -107,14 +106,12 @@ class AmountTestCase(unittest.TestCase):
x9 = x3 x9 = x3
x10 = amount(x6) x10 = amount(x6)
self.assertEqual(amount(0), x0)
self.assertEqual(x2, x1) self.assertEqual(x2, x1)
self.assertEqual(x5, x1) self.assertEqual(x5, x1)
self.assertEqual(x6, x3) self.assertEqual(x6, x3)
self.assertEqual(x10, x3) self.assertEqual(x10, x3)
self.assertEqual(x10, x9) self.assertEqual(x10, x9)
x0 = amount()
x1 = amount(123456) x1 = amount(123456)
x2 = amount(123456L) x2 = amount(123456L)
x3 = amount(123.456) x3 = amount(123.456)
@ -123,14 +120,12 @@ class AmountTestCase(unittest.TestCase):
x9 = x3 x9 = x3
x10 = amount(x6) x10 = amount(x6)
self.assertEqual(amount(0), x0)
self.assertEqual(x2, x1) self.assertEqual(x2, x1)
self.assertEqual(x5, x1) self.assertEqual(x5, x1)
self.assertEqual(x6, x3) self.assertEqual(x6, x3)
self.assertEqual(x10, x3) self.assertEqual(x10, x3)
self.assertEqual(x10, x9) self.assertEqual(x10, x9)
self.assertValid(x0)
self.assertValid(x1) self.assertValid(x1)
self.assertValid(x2) self.assertValid(x2)
self.assertValid(x3) self.assertValid(x3)
@ -217,12 +212,10 @@ class AmountTestCase(unittest.TestCase):
x10 = amount("-123.45€") x10 = amount("-123.45€")
self.assertTrue(x0.is_null()) self.assertTrue(x0.is_null())
self.assertTrue(x0.is_zero()) self.assertRaises(exceptions.ArithmeticError, amount.is_zero, x0)
self.assertTrue(x0.is_realzero()) self.assertRaises(exceptions.ArithmeticError, amount.is_realzero, x0)
self.assertTrue(x0.sign() == 0) self.assertRaises(exceptions.ArithmeticError, amount.sign, x0)
self.assertTrue(x0.compare(x1) < 0) self.assertRaises(exceptions.ArithmeticError, amount.compare, x0, 0)
self.assertTrue(x0.compare(x2) > 0)
self.assertTrue(x0.compare(x0) == 0)
self.assertTrue(x1 != x2) self.assertTrue(x1 != x2)
self.assertTrue(x1 != x4) self.assertTrue(x1 != x4)
@ -255,12 +248,12 @@ class AmountTestCase(unittest.TestCase):
x5 = amount("-123.45") x5 = amount("-123.45")
x6 = amount("123.45") x6 = amount("123.45")
self.assertTrue(x0 > x1) self.assertRaises(exceptions.ArithmeticError, operator.gt, x0, x1)
self.assertTrue(x0 < x2) self.assertRaises(exceptions.ArithmeticError, operator.lt, x0, x2)
self.assertTrue(x0 > x3) self.assertRaises(exceptions.ArithmeticError, operator.gt, x0, x3)
self.assertTrue(x0 < x4) self.assertRaises(exceptions.ArithmeticError, operator.lt, x0, x4)
self.assertTrue(x0 > x5) self.assertRaises(exceptions.ArithmeticError, operator.gt, x0, x5)
self.assertTrue(x0 < x6) self.assertRaises(exceptions.ArithmeticError, operator.lt, x0, x6)
self.assertTrue(x1 > x3) self.assertTrue(x1 > x3)
self.assertTrue(x3 <= x5) self.assertTrue(x3 <= x5)
@ -284,7 +277,6 @@ class AmountTestCase(unittest.TestCase):
self.assertValid(x6) self.assertValid(x6)
def testCommodityComparisons(self): def testCommodityComparisons(self):
x0 = amount()
x1 = amount("$-123") x1 = amount("$-123")
x2 = amount("$123.00") x2 = amount("$123.00")
x3 = amount(internalAmount("$-123.4544")) x3 = amount(internalAmount("$-123.4544"))
@ -292,13 +284,6 @@ class AmountTestCase(unittest.TestCase):
x5 = amount("$-123.45") x5 = amount("$-123.45")
x6 = amount("$123.45") x6 = amount("$123.45")
self.assertTrue(x0 > x1)
self.assertTrue(x0 < x2)
self.assertTrue(x0 > x3)
self.assertTrue(x0 < x4)
self.assertTrue(x0 > x5)
self.assertTrue(x0 < x6)
self.assertTrue(x1 > x3) self.assertTrue(x1 > x3)
self.assertTrue(x3 <= x5) self.assertTrue(x3 <= x5)
self.assertTrue(x3 < x5) self.assertTrue(x3 < x5)
@ -307,7 +292,6 @@ class AmountTestCase(unittest.TestCase):
self.assertTrue(x3 < x1) self.assertTrue(x3 < x1)
self.assertTrue(x3 < x4) self.assertTrue(x3 < x4)
self.assertValid(x0)
self.assertValid(x1) self.assertValid(x1)
self.assertValid(x2) self.assertValid(x2)
self.assertValid(x3) self.assertValid(x3)
@ -792,14 +776,12 @@ class AmountTestCase(unittest.TestCase):
self.assertValid(x7) self.assertValid(x7)
def testNegation(self): def testNegation(self):
x0 = amount()
x1 = amount(-123456) x1 = amount(-123456)
x3 = amount(-123.456) x3 = amount(-123.456)
x5 = amount("-123456") x5 = amount("-123456")
x6 = amount("-123.456") x6 = amount("-123.456")
x9 = amount(- x3) x9 = amount(- x3)
self.assertEqual(amount(0), x0)
self.assertEqual(x5, x1) self.assertEqual(x5, x1)
self.assertEqual(x6, x3) self.assertEqual(x6, x3)
self.assertEqual(- x6, x9) self.assertEqual(- x6, x9)
@ -809,7 +791,6 @@ class AmountTestCase(unittest.TestCase):
self.assertEqual(x3, x10) self.assertEqual(x3, x10)
self.assertValid(x0)
self.assertValid(x1) self.assertValid(x1)
self.assertValid(x3) self.assertValid(x3)
self.assertValid(x5) self.assertValid(x5)
@ -875,7 +856,7 @@ class AmountTestCase(unittest.TestCase):
x1 = amount(-1234) x1 = amount(-1234)
x2 = amount(1234) x2 = amount(1234)
self.assertEqual(amount(), abs(x0)) self.assertRaises(exceptions.ArithmeticError, amount.abs, x0)
self.assertEqual(amount(1234), abs(x1)) self.assertEqual(amount(1234), abs(x1))
self.assertEqual(amount(1234), abs(x2)) self.assertEqual(amount(1234), abs(x2))
@ -884,15 +865,12 @@ class AmountTestCase(unittest.TestCase):
self.assertValid(x2) self.assertValid(x2)
def testCommodityAbs(self): def testCommodityAbs(self):
x0 = amount()
x1 = amount("$-1234.56") x1 = amount("$-1234.56")
x2 = amount("$1234.56") x2 = amount("$1234.56")
self.assertEqual(amount(), abs(x0))
self.assertEqual(amount("$1234.56"), abs(x1)) self.assertEqual(amount("$1234.56"), abs(x1))
self.assertEqual(amount("$1234.56"), abs(x2)) self.assertEqual(amount("$1234.56"), abs(x2))
self.assertValid(x0)
self.assertValid(x1) self.assertValid(x1)
self.assertValid(x2) self.assertValid(x2)
@ -941,7 +919,7 @@ class AmountTestCase(unittest.TestCase):
self.assertEqual(amount("0.0000000000000000000000000000000000001"), self.assertEqual(amount("0.0000000000000000000000000000000000001"),
x5.round(37)) x5.round(37))
self.assertEqual(amount(), x5.round(36)) self.assertEqual(amount(0), x5.round(36))
self.assertValid(x1) self.assertValid(x1)
self.assertValid(x2) self.assertValid(x2)
@ -1050,7 +1028,7 @@ class AmountTestCase(unittest.TestCase):
x3 = amount("1") x3 = amount("1")
x4 = amount("-1") x4 = amount("-1")
self.assertEqual(x0.sign(), 0) self.assertRaises(exceptions.ArithmeticError, amount.sign, x0)
self.assertTrue(x1.sign() > 0) self.assertTrue(x1.sign() > 0)
self.assertTrue(x2.sign() < 0) self.assertTrue(x2.sign() < 0)
self.assertTrue(x3.sign() > 0) self.assertTrue(x3.sign() > 0)
@ -1063,19 +1041,16 @@ class AmountTestCase(unittest.TestCase):
self.assertValid(x4) self.assertValid(x4)
def testCommoditySign(self): def testCommoditySign(self):
x0 = amount()
x1 = amount(internalAmount("$0.0000000000000000000000000000000000001")) x1 = amount(internalAmount("$0.0000000000000000000000000000000000001"))
x2 = amount(internalAmount("$-0.0000000000000000000000000000000000001")) x2 = amount(internalAmount("$-0.0000000000000000000000000000000000001"))
x3 = amount("$1") x3 = amount("$1")
x4 = amount("$-1") x4 = amount("$-1")
self.assertFalse(x0.sign())
self.assertTrue(x1.sign() != 0) self.assertTrue(x1.sign() != 0)
self.assertTrue(x2.sign() != 0) self.assertTrue(x2.sign() != 0)
self.assertTrue(x3.sign() > 0) self.assertTrue(x3.sign() > 0)
self.assertTrue(x4.sign() < 0) self.assertTrue(x4.sign() < 0)
self.assertValid(x0)
self.assertValid(x1) self.assertValid(x1)
self.assertValid(x2) self.assertValid(x2)
self.assertValid(x3) self.assertValid(x3)
@ -1086,7 +1061,7 @@ class AmountTestCase(unittest.TestCase):
x1 = amount("1234") x1 = amount("1234")
x2 = amount("1234.56") x2 = amount("1234.56")
self.assertFalse(x0) self.assertRaises(exceptions.ArithmeticError, operator.truth, x0)
self.assertTrue(x1) self.assertTrue(x1)
self.assertTrue(x2) self.assertTrue(x2)
@ -1115,10 +1090,9 @@ class AmountTestCase(unittest.TestCase):
x0 = amount() x0 = amount()
x1 = amount("0.000000000000000000001") x1 = amount("0.000000000000000000001")
self.assertFalse(x0)
self.assertTrue(x1) self.assertTrue(x1)
self.assertTrue(x0.is_zero()) self.assertRaises(exceptions.ArithmeticError, amount.is_zero, x0)
self.assertTrue(x0.is_realzero()) self.assertRaises(exceptions.ArithmeticError, amount.is_realzero, x0)
self.assertFalse(x1.is_zero()) self.assertFalse(x1.is_zero())
self.assertFalse(x1.is_realzero()) self.assertFalse(x1.is_realzero())