Fix bug where .total used in value exprs breaks totals

* Re-initialize (to VOID) totals for the account and its ancestors on adding
  postings.  Otherwise the cache intended for use by recursive calls of C++
  function total() in computing family (i.e. account hierarchy) totals is
  incorrectly retained from one top-level call to the next, causing
  inconsistent and broken behaviour.

* Re-initialize (to false) calculated and gathered.  Otherwise we won't
  e.g. recalculate stale totals for ancestor accounts (e.g. won't recalculate
  Assets:Savings total if Assets:Savings changes via a posting).

Although the value expression total function is used by ledger itself in
computing totals, this bug would only appear on use of .total in user-supplied
value expressions computed *during parsing* of ledger files, rather than after
parsing (I believe ledger only ever calls it for internal purposes after
parsing is complete).

It is possible this bug also affected other functions than total (perhaps even
in circumstances other than analagous to that described in the preceding
paragraph).  I have not checked that.
This commit is contained in:
John Lee 2017-10-25 22:17:47 +01:00
parent b41454477a
commit de1b48a013
3 changed files with 71 additions and 0 deletions

View file

@ -136,6 +136,19 @@ void account_t::add_post(post_t * post)
xdata_->self_details.calculated = false;
xdata_->family_details.gathered = false;
xdata_->family_details.calculated = false;
if (! xdata_->family_details.total.is_null()) {
xdata_->family_details.total = ledger::value_t();
}
account_t *ancestor = this;
while (ancestor->parent) {
ancestor = ancestor->parent;
if (ancestor->has_xdata()) {
xdata_t &xdata = ancestor->xdata();
xdata.family_details.gathered = false;
xdata.family_details.calculated = false;
xdata.family_details.total = ledger::value_t();
}
}
}
}

28
test/regress/total-1.test Normal file
View file

@ -0,0 +1,28 @@
; Test that calling total does not affect future calls to that function via a
; stale cache entry for the totalled account, because of a change to that same
; account
2017-10-01 * Opening Balance
Assets:Current Account $1000.00
Equity:Opening Balances
2017-10-02 * Savings
Assets:Savings $100.00
Assets:Current Account
assert account("Assets:Current Account").total == $900.00
2017-10-03 * Savings
Assets:Savings $100.00
Assets:Current Account
assert account("Assets:Current Account").total == $800.00
test bal
$1000.00 Assets
$800.00 Current Account
$200.00 Savings
$-1000.00 Equity:Opening Balances
--------------------
0
end test

30
test/regress/total-2.test Normal file
View file

@ -0,0 +1,30 @@
; Test that calling total does not affect future calls to that function via a
; stale cache entry for the totalled account, because of a change to an
; descendant (Assets:Current:Unallocated) of that account (Assets:Current)
2017-10-01 * Opening entry
Assets:Current:Unallocated $2000.00
Equity:Opening Balances
2017-10-02 * Initial savings
Assets:Current:Savings $1000.00
Assets:Current:Unallocated
assert account("Assets:Current").total == $2000.00
2017-10-03 * Balance
Assets:Current:Unallocated $1.00
Equity:Adjustments
assert account("Assets:Current").total == $2001.00
test bal
$2001.00 Assets:Current
$1000.00 Savings
$1001.00 Unallocated
$-2001.00 Equity
$-1.00 Adjustments
$-2000.00 Opening Balances
--------------------
0
end test