Skip to content

Commit

Permalink
support balance assertion tolerance
Browse files Browse the repository at this point in the history
resolve #70
  • Loading branch information
jcornaz committed Jan 29, 2024
1 parent 45e02bb commit 652ad86
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 8 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]


### Added

* `Balance::tolerance` field

### Fixed

* Accept tolerance syntax


## [2.0.4] - 2024-01-19

### Fixed
Expand Down
25 changes: 23 additions & 2 deletions src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ pub struct Balance<D> {
pub account: Account,
/// Amount the amount should have on the date
pub amount: Amount<D>,
/// Explicit precision tolerance
///
/// See: <https://beancount.github.io/docs/precision_tolerances.html#explicit-tolerances-on-balance-assertions>
pub tolerance: Option<D>,
}

/// Pad directive
Expand Down Expand Up @@ -222,8 +226,25 @@ pub(super) fn close(input: Span<'_>) -> IResult<'_, Close> {
pub(super) fn balance<D: Decimal>(input: Span<'_>) -> IResult<'_, Balance<D>> {
let (input, account) = parse(input)?;
let (input, _) = space1(input)?;
let (input, amount) = amount::parse(input)?;
Ok((input, Balance { account, amount }))
let (input, value) = amount::expression(input)?;
let (input, tolerance) = opt(preceded(space0, tolerance))(input)?;
let (input, _) = space1(input)?;
let (input, currency) = amount::currency(input)?;
Ok((
input,
Balance {
account,
amount: Amount { value, currency },
tolerance,
},
))
}

fn tolerance<D: Decimal>(input: Span<'_>) -> IResult<'_, D> {
let (input, _) = char('~')(input)?;
let (input, _) = space0(input)?;
let (input, tolerance) = amount::expression(input)?;
Ok((input, tolerance))
}

pub(super) fn pad(input: Span<'_>) -> IResult<'_, Pad> {
Expand Down
2 changes: 1 addition & 1 deletion src/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub(crate) fn parse<D: Decimal>(input: Span<'_>) -> IResult<'_, Amount<D>> {
Ok((input, Amount { value, currency }))
}

pub(super) fn expression<D: Decimal>(input: Span<'_>) -> IResult<'_, D> {
pub(crate) fn expression<D: Decimal>(input: Span<'_>) -> IResult<'_, D> {
alt((negation, sum))(input)
}

Expand Down
25 changes: 20 additions & 5 deletions tests/parser_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,35 @@ fn should_parse_pad_source_account(#[case] input: &str, #[case] expected: &str)

#[rstest]
#[case(
"2020-04-10 balance Assets:US:BofA:Checking 2473 USD",
2473,
"USD"
"2013-09-10 balance Assets:US:Vanguard 305.205 RGAGX",
305.205,
None,
"RGAGX"
)]
#[case(
"2013-09-10 balance Assets:US:Vanguard 305.205 ~ 0.002 RGAGX",
305.205,
Some(0.002),
"RGAGX"
)]
#[case(
"2013-09-10 balance Assets:US:Vanguard 305.205~0.002 RGAGX",
305.205,
Some(0.002),
"RGAGX"
)]
fn should_parse_balance_assertion_amount(
#[case] input: &str,
#[case] expected_value: impl Into<f64>,
#[case] expected_value: f64,
#[case] expected_tolerance: Option<f64>,
#[case] expected_currency: &str,
) {
let DirectiveContent::Balance(assertion) = parse_single_directive(input).content else {
panic!("was not an open directive");
};
assert_eq!(assertion.amount.value, expected_value.into());
assert_eq!(assertion.amount.value, expected_value);
assert_eq!(assertion.amount.currency.as_str(), expected_currency);
assert_eq!(assertion.tolerance, expected_tolerance);
}

#[rstest]
Expand Down

0 comments on commit 652ad86

Please sign in to comment.