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

lennart-k / ical-rs / #73

12 Jan 2026 01:50PM UTC coverage: 77.771% (-0.03%) from 77.802%
#73

Pull #2

lennart-k
IcalCalendarObjectBuilder: Make attributes public
Pull Request #2: Major overhaul

908 of 1184 new or added lines in 30 files covered. (76.69%)

32 existing lines in 10 files now uncovered.

1221 of 1570 relevant lines covered (77.77%)

2.77 hits per line

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

77.27
/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 {
×
77
        IcalJournalBuilder {
78
            properties: self.properties,
×
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
    #[inline]
UNCOV
91
    fn add_sub_component<B: BufRead>(
×
92
        &mut self,
93
        value: &str,
94
        _: &mut PropertyParser<B>,
95
    ) -> Result<(), ParserError> {
NEW
96
        Err(ParserError::InvalidComponent(value.to_owned()))
×
97
    }
98

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

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

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

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

151
impl IcalJournal {
152
    pub fn get_tzids(&self) -> HashSet<&str> {
1✔
153
        self.properties
1✔
154
            .iter()
155
            .filter_map(|prop| prop.params.get_tzid())
3✔
156
            .collect()
157
    }
158
}
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