• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lennart-k / ical-rs / #68

12 Jan 2026 10:17AM UTC coverage: 80.485% (+2.7%) from 77.802%
#68

Pull #2

lennart-k
fixes
Pull Request #2: Major overhaul

935 of 1181 new or added lines in 30 files covered. (79.17%)

21 existing lines in 9 files now uncovered.

1262 of 1568 relevant lines covered (80.48%)

2.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/src/parser/ical/component/journal.rs
1
use crate::{
2
    PropertyParser,
3
    parser::{
4
        Component, ComponentMut, GetProperty, IcalDTSTAMPProperty, IcalDTSTARTProperty,
5
        IcalEXDATEProperty, IcalEXRULEProperty, IcalRDATEProperty, IcalRECURIDProperty,
6
        IcalRRULEProperty, IcalUIDProperty, ParserError,
7
    },
8
    property::ContentLine,
9
};
10
use rrule::RRule;
11
use std::{
12
    collections::{HashMap, HashSet},
13
    io::BufRead,
14
};
15

16
#[derive(Debug, Clone, Default)]
17
pub struct IcalJournalBuilder {
18
    pub properties: Vec<ContentLine>,
19
}
20

21
#[derive(Debug, Clone)]
22
pub struct IcalJournal {
23
    uid: String,
24
    pub dtstamp: IcalDTSTAMPProperty,
25
    pub dtstart: Option<IcalDTSTARTProperty>,
26
    pub properties: Vec<ContentLine>,
27
    rdates: Vec<IcalRDATEProperty>,
28
    rrules: Vec<RRule>,
29
    exdates: Vec<IcalEXDATEProperty>,
30
    exrules: Vec<RRule>,
31
    pub(crate) recurid: Option<IcalRECURIDProperty>,
32
}
33

34
impl IcalJournalBuilder {
35
    pub fn new() -> Self {
1✔
36
        Self {
37
            properties: Vec::new(),
1✔
38
        }
39
    }
40
}
41

42
impl IcalJournal {
UNCOV
43
    pub fn get_uid(&self) -> &str {
×
NEW
44
        &self.uid
×
45
    }
46

47
    pub fn has_rruleset(&self) -> bool {
1✔
48
        !self.rrules.is_empty()
1✔
49
            || !self.rdates.is_empty()
1✔
50
            || !self.exrules.is_empty()
1✔
51
            || !self.exdates.is_empty()
1✔
52
    }
53
}
54

55
impl Component for IcalJournalBuilder {
56
    const NAMES: &[&str] = &["VJOURNAL"];
57
    type Unverified = IcalJournalBuilder;
58

59
    fn get_properties(&self) -> &Vec<ContentLine> {
1✔
60
        &self.properties
61
    }
62

NEW
63
    fn mutable(self) -> Self::Unverified {
×
NEW
64
        self
×
65
    }
66
}
67

68
impl Component for IcalJournal {
69
    const NAMES: &[&str] = &["VJOURNAL"];
70
    type Unverified = IcalJournalBuilder;
71

72
    fn get_properties(&self) -> &Vec<ContentLine> {
1✔
73
        &self.properties
1✔
74
    }
75

76
    fn mutable(self) -> Self::Unverified {
1✔
77
        IcalJournalBuilder {
78
            properties: self.properties,
1✔
79
        }
80
    }
81
}
82

83
impl ComponentMut for IcalJournalBuilder {
84
    type Verified = IcalJournal;
85

86
    fn get_properties_mut(&mut self) -> &mut Vec<ContentLine> {
1✔
87
        &mut self.properties
88
    }
89

90
    fn add_sub_component<B: BufRead>(
×
91
        &mut self,
92
        value: &str,
93
        _: &mut PropertyParser<B>,
94
    ) -> Result<(), ParserError> {
NEW
95
        Err(ParserError::InvalidComponent(value.to_owned()))
×
96
    }
97

98
    fn build(
1✔
99
        self,
100
        timezones: Option<&HashMap<String, Option<chrono_tz::Tz>>>,
101
    ) -> Result<IcalJournal, ParserError> {
102
        // REQUIRED, ONLY ONCE
103
        let IcalUIDProperty(uid, _) = self.safe_get_required(timezones)?;
2✔
104
        let dtstamp = self.safe_get_required(timezones)?;
1✔
105

106
        // OPTIONAL, ONLY ONCE: class / created / dtstart / last-mod / organizer / recurid / seq / status / summary / url / rrule
107
        let dtstart = self.safe_get_optional::<IcalDTSTARTProperty>(timezones)?;
2✔
108
        let recurid = self.safe_get_optional::<IcalRECURIDProperty>(timezones)?;
2✔
109
        if let Some(IcalDTSTARTProperty(dtstart, _)) = &dtstart
1✔
110
            && let Some(recurid) = &recurid
1✔
111
        {
NEW
112
            recurid.validate_dtstart(dtstart)?;
×
113
        }
114

115
        // OPTIONAL, MULTIPLE ALLOWED: attach / attendee / categories / comment / contact / description / exdate / related / rdate / rstatus / x-prop / iana-prop
116
        let rdates = self.safe_get_all::<IcalRDATEProperty>(timezones)?;
2✔
117
        let exdates = self.safe_get_all::<IcalEXDATEProperty>(timezones)?;
2✔
118
        let (rrules, exrules) = if let Some(dtstart) = dtstart.as_ref() {
3✔
119
            let rrule_dtstart = dtstart.0.utc().with_timezone(&rrule::Tz::UTC);
2✔
120
            let rrules = self
2✔
121
                .safe_get_all::<IcalRRULEProperty>(timezones)?
1✔
122
                .into_iter()
123
                .map(|rrule| rrule.0.validate(rrule_dtstart))
1✔
124
                .collect::<Result<Vec<_>, _>>()?;
125
            let exrules = self
2✔
126
                .safe_get_all::<IcalEXRULEProperty>(timezones)?
1✔
127
                .into_iter()
128
                .map(|rrule| rrule.0.validate(rrule_dtstart))
1✔
129
                .collect::<Result<Vec<_>, _>>()?;
130
            (rrules, exrules)
1✔
131
        } else {
NEW
132
            (vec![], vec![])
×
133
        };
134

135
        let verified = IcalJournal {
136
            uid,
137
            dtstamp,
138
            dtstart,
139
            rdates,
140
            rrules,
141
            exdates,
142
            exrules,
143
            recurid,
144
            properties: self.properties,
1✔
145
        };
146
        Ok(verified)
1✔
147
    }
148
}
149

150
impl IcalJournal {
151
    pub fn get_tzids(&self) -> HashSet<&str> {
1✔
152
        self.properties
1✔
153
            .iter()
154
            .filter_map(|prop| prop.params.get_tzid())
3✔
155
            .collect()
156
    }
157
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc