Skip to content

Commit

Permalink
internal: parse cost date with chumsky
Browse files Browse the repository at this point in the history
  • Loading branch information
jcornaz committed Mar 3, 2024
1 parent 472475d commit cbc49f2
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added

* implement `FromStr` for `Account` and `Date`
* implement `Default` for `Cost<D>`
* `Date::new(year: u16, month: u8, day: u8) -> Self`


Expand Down
55 changes: 45 additions & 10 deletions src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub struct Posting<D> {
/// Cost of a posting
///
/// It is the amount within `{` and `}`.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq)]
#[non_exhaustive]
pub struct Cost<D> {
/// Cost basis of the posting
Expand Down Expand Up @@ -397,12 +397,35 @@ mod chumsky {
use super::Cost;

fn cost<D: Decimal + 'static>() -> impl ChumskyParser<Cost<D>> {
crate::amount::chumsky::amount()
.or_not()
.padded()
.delimited_by(just('{'), just('}'))
.map(|amount| Cost { amount, date: None })
.labelled("cost")
choice((
crate::amount::chumsky::amount()
.then(
just(',')
.padded()
.ignore_then(crate::date::chumsky::date())
.or_not(),
)
.map(|(amount, date)| Cost {
amount: Some(amount),
date,
}),
crate::date::chumsky::date()
.then(
just(',')
.padded()
.ignore_then(crate::amount::chumsky::amount())
.or_not(),
)
.map(|(date, amount)| Cost {
amount,
date: Some(date),
}),
))
.or_not()
.padded()
.delimited_by(just('{'), just('}'))
.map(Option::unwrap_or_default)
.labelled("cost")
}

#[cfg(test)]
Expand All @@ -420,16 +443,20 @@ mod chumsky {
}

#[rstest]
fn should_parse_cost_amount(#[values("{1 EUR}", "{ 1 EUR }")] input: &str) {
fn should_parse_cost_amount(
#[values("{1 EUR}", "{ 1 EUR }, {2024-03-03, 1 EUR}")] input: &str,
) {
let cost: Cost<i32> = cost().parse(input).unwrap();
let amount = cost.amount.unwrap();
assert_eq!(amount.value, 1);
assert_eq!(amount.currency.as_str(), "EUR");
}

#[rstest]
#[ignore = "not implemented"]
fn should_parse_cost_date(#[values("{2024-03-02}", "{ 1 EUR , 2024-03-02 }")] input: &str) {
fn should_parse_cost_date(
#[values("{2024-03-02}", "{ 1 EUR , 2024-03-02 }", "{ 2024-03-02, 2 EUR }")]
input: &str,
) {
let cost: Cost<i32> = cost().parse(input).unwrap();
assert_eq!(
cost.date,
Expand All @@ -440,5 +467,13 @@ mod chumsky {
})
);
}

#[rstest]
#[case::duplicated_date("{2023-03-03, 2023-03-04}")]
#[case::duplicated_amount("{1 EUR, 2 CHF}")]
fn should_not_parse_invalid_cost(#[case] input: &str) {
let result: Result<Cost<i32>, _> = cost().parse(input);
assert!(result.is_err(), "{result:?}");
}
}
}

0 comments on commit cbc49f2

Please sign in to comment.