opsview/config/timeperiod.rs
1use super::{HostRef, ServiceCheckRef, TimeZone};
2use crate::{prelude::*, util::*};
3use serde::{Deserialize, Serialize};
4use std::sync::Arc;
5
6/// Represents a [Time Period](https://docs.itrsgroup.com/docs/opsview/current/configuration/time-periods/time-periods/index.html) in Opsview.
7///
8/// Time periods are used within Opsview Monitor for one of two purposes; determining when a
9/// [`super::Host`] or [`super::ServiceCheck`] is being actively monitored, and determining when
10/// notifications should be sent.
11///
12/// For example, if a Host only needs to be monitored during office hours, then an administrator can
13/// create a Time Period called ‘Working Hours’ that is 9am-5pm, Monday to Friday, and then ‘apply’
14/// this `TimePeriod` to the Host via a field called the ‘Check Period’, i.e. ‘What *period *of time
15/// should I actively *check *this Host’. Service Checks can be configured to have a fixed Time
16/// Period or to inherit the check period from the Host. This will apply to all Service Checks
17/// whether the Service Checks are applied individually via the ‘Service Checks’ tab or in bulk via
18/// the addition of a Host template.
19///
20/// There are seven days within the `TimePeriod`, Sunday through to Saturday. In each day, the hours
21/// can be defined in an ‘HH:MM’ format, and comma-separated for multiple ranges. For example,
22/// ‘00:00-24:00’ means ‘all day’, ‘09:00-17:00’ means ‘9am to 5pm’, ‘00:00-09:00,17:00-23:59’ means
23/// ’not 9-5pm’, and so forth.
24///
25/// An important point to note is the hours defined do not go over the midnight boundary, for
26/// example “22:00-02:00” is not valid - instead use ‘22:00-23:59’ on the first day, and
27/// ‘00:00-02:00’ on the following day.
28///
29/// This struct represents the structure of a time period entity as used in the [Opsview
30/// API](https://docs.itrsgroup.com/docs/opsview/current/rest-api/config/api-config-time-period/index.html).
31///
32/// # Example
33/// ```rust
34/// use opsview::config::TimePeriod;
35/// use opsview::prelude::*;
36///
37/// let time_period = TimePeriod::builder()
38/// .name("MyTimePeriod")
39/// .alias("My Time Period Alias")
40/// .monday("00:00-09:00,17:00-24:00")
41/// .tuesday("00:00-09:00,17:00-24:00")
42/// .wednesday("00:00-09:00,17:00-24:00")
43/// .thursday("00:00-09:00,17:00-24:00")
44/// .friday("00:00-09:00,17:00-24:00")
45/// .saturday("00:00-09:00,17:00-24:00")
46/// .sunday("00:00-09:00,17:00-24:00")
47/// .build()
48/// .unwrap();
49///
50/// assert_eq!(time_period.name, "MyTimePeriod".to_string());
51/// assert_eq!(time_period.alias, Some("My Time Period Alias".to_string()));
52/// assert_eq!(time_period.monday, Some("00:00-09:00,17:00-24:00".to_string()));
53/// ```
54#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
55pub struct TimePeriod {
56 // Required fields ---------------------------------------------------------------------------//
57 /// The name of the `TimePeriod`.
58 pub name: String,
59
60 // Optional fields ---------------------------------------------------------------------------//
61 /// Optional alias for the `TimePeriod`.
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub alias: Option<String>,
64
65 /// Optional string representing the `TimePeriod` for Friday.
66 ///
67 /// Example: `"00:00-09:00,17:00-24:00"`
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub friday: Option<String>,
70
71 /// Optional string representing the `TimePeriod` for Monday.
72 ///
73 /// Example: `"00:00-09:00,17:00-24:00"`
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub monday: Option<String>,
76
77 /// Optional string representing the `TimePeriod` for Saturday.
78 ///
79 /// Example: `"00:00-09:00,17:00-24:00"`
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub saturday: Option<String>,
82
83 /// Optional string representing the `TimePeriod` for Sunday.
84 ///
85 /// Example: `"00:00-09:00,17:00-24:00"`
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub sunday: Option<String>,
88
89 /// Optional string representing the `TimePeriod` for Thursday.
90 ///
91 /// Example: `"00:00-09:00,17:00-24:00"`
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub thursday: Option<String>,
94
95 /// Optional string representing the `TimePeriod` for Tuesday.
96 ///
97 /// Example: `"00:00-09:00,17:00-24:00"`
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub tuesday: Option<String>,
100
101 /// Optional string representing the `TimePeriod` for Wednesday.
102 ///
103 /// Example: `"00:00-09:00,17:00-24:00"`
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub wednesday: Option<String>,
106
107 /// Optional [`TimeZone`] in which the `TimePeriod` is defined.
108 ///
109 /// Default: `Some(TimeZone{ name: "SYSTEM".to_string(), ref_: "/rest/config/timezone/1".to_string() })`.
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub zone: Option<TimeZone>,
112
113 // Read-only fields --------------------------------------------------------------------------//
114 /// [`ConfigRefMap`] of [`HostRef`] objects associated with this `TimePeriod` for their checks.
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub host_check_periods: Option<ConfigRefMap<HostRef>>,
117
118 /// [`ConfigRefMap`] of [`HostRef`] objects associated with this `TimePeriod` for their notifications.
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub host_notification_periods: Option<ConfigRefMap<HostRef>>,
121
122 /// The unique identifier of the `TimePeriod`.
123 #[serde(
124 skip_serializing_if = "Option::is_none",
125 deserialize_with = "deserialize_string_or_number_to_u64",
126 default
127 )]
128 pub id: Option<u64>,
129
130 // TODO: This is not in the API documentation, but is returned in the JSON response.
131 // It is not clear what this field is used for.
132 /// Optional boolean indicating whether the `TimePeriod` is locked.
133 #[serde(
134 skip_serializing_if = "Option::is_none",
135 deserialize_with = "deserialize_string_or_number_to_option_bool",
136 serialize_with = "serialize_option_bool_as_string",
137 default
138 )]
139 pub object_locked: Option<bool>,
140
141 /// A reference string unique to this `TimePeriod`.
142 #[serde(
143 rename = "ref",
144 skip_serializing_if = "Option::is_none",
145 deserialize_with = "deserialize_readonly",
146 default
147 )]
148 pub ref_: Option<String>,
149
150 /// [`ConfigRefMap`] of [`ServiceCheckRef`] objects associated with this `TimePeriod` for their checks.
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub servicecheck_check_periods: Option<ConfigRefMap<ServiceCheckRef>>,
153
154 /// [`ConfigRefMap`] of [`ServiceCheckRef`] objects associated with this `TimePeriod` for their notifications.
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub servicecheck_notification_periods: Option<ConfigRefMap<ServiceCheckRef>>,
157
158 /// A boolean indicating whether the `TimePeriod` is uncommitted.
159 #[serde(
160 skip_serializing_if = "Option::is_none",
161 deserialize_with = "deserialize_string_or_number_to_option_bool",
162 serialize_with = "serialize_option_bool_as_string",
163 default
164 )]
165 pub uncommitted: Option<bool>,
166}
167
168impl Default for TimePeriod {
169 fn default() -> Self {
170 let tz = TimeZone::builder()
171 .name("SYSTEM")
172 .ref_("/rest/config/timezone/1")
173 .build()
174 .unwrap();
175
176 TimePeriod {
177 name: String::new(),
178 alias: None,
179 friday: None,
180 host_check_periods: None,
181 host_notification_periods: None,
182 id: None,
183 monday: None,
184 object_locked: None,
185 ref_: None,
186 saturday: None,
187 servicecheck_check_periods: None,
188 servicecheck_notification_periods: None,
189 sunday: None,
190 thursday: None,
191 tuesday: None,
192 uncommitted: None,
193 wednesday: None,
194 zone: Some(tz),
195 }
196 }
197}
198
199/// Enables the creation of a [`TimePeriod`] instance from a JSON representation.
200/// Typically used when parsing JSON data from the Opsview API.
201impl CreateFromJson for TimePeriod {}
202
203impl ConfigObject for TimePeriod {
204 type Builder = TimePeriodBuilder;
205
206 /// Returns a builder for constructing a [`TimePeriod`] object.
207 ///
208 /// # Returns
209 /// A [`TimePeriodBuilder`] object.
210 fn builder() -> Self::Builder {
211 TimePeriodBuilder::new()
212 }
213
214 /// Provides the configuration path for a [`TimePeriod`] object within the Opsview system.
215 ///
216 /// # Returns
217 /// A string representing the API path where time periods are configured.
218 fn config_path() -> Option<String> {
219 Some("/config/timeperiod".to_string())
220 }
221
222 /// Returns the unique name of the [`TimePeriod`] object.
223 ///
224 /// This name is used to identify the `TimePeriod` when building the `HashMap` for an
225 /// `ConfigObjectMap`.
226 ///
227 /// # Returns
228 /// A string representing the unique name of the `TimePeriod`.
229 fn unique_name(&self) -> String {
230 self.name.clone()
231 }
232
233 fn minimal(name: &str) -> Result<Self, OpsviewConfigError> {
234 Ok(Self {
235 name: validate_and_trim_timeperiod_name(name)?,
236 ..Default::default()
237 })
238 }
239}
240
241impl Persistent for TimePeriod {
242 /// Returns the unique identifier.
243 fn id(&self) -> Option<u64> {
244 self.id
245 }
246
247 /// Returns the reference string if it's not empty.
248 fn ref_(&self) -> Option<String> {
249 if self.ref_.as_ref().is_some_and(|x| !x.is_empty()) {
250 self.ref_.clone()
251 } else {
252 None
253 }
254 }
255 /// Returns the name if it's not empty.
256 fn name(&self) -> Option<String> {
257 if self.name.is_empty() {
258 None
259 } else {
260 Some(self.name.clone())
261 }
262 }
263
264 fn name_regex(&self) -> Option<String> {
265 Some(TIMEPERIOD_NAME_REGEX_STR.to_string())
266 }
267
268 fn validated_name(&self, name: &str) -> Result<String, OpsviewConfigError> {
269 validate_and_trim_timeperiod_name(name)
270 }
271
272 fn set_name(&mut self, new_name: &str) -> Result<String, OpsviewConfigError> {
273 self.name = self.validated_name(new_name)?;
274 Ok(self.name.clone())
275 }
276
277 fn clear_readonly(&mut self) {
278 self.host_check_periods = None;
279 self.host_notification_periods = None;
280 self.id = None;
281 self.object_locked = None;
282 self.ref_ = None;
283 self.servicecheck_check_periods = None;
284 self.servicecheck_notification_periods = None;
285 self.uncommitted = None;
286 }
287}
288
289impl PersistentMap for ConfigObjectMap<TimePeriod> {
290 fn config_path() -> Option<String> {
291 Some("/config/timeperiod".to_string())
292 }
293}
294
295/// Builder for [`TimePeriod`] objects.
296///
297/// Provides a fluent interface for constructing a `TimePeriod` object with optional fields.
298#[derive(Clone, Debug, Default)]
299pub struct TimePeriodBuilder {
300 alias: Option<String>,
301 friday: Option<String>,
302 monday: Option<String>,
303 name: Option<String>,
304 saturday: Option<String>,
305 sunday: Option<String>,
306 thursday: Option<String>,
307 tuesday: Option<String>,
308 wednesday: Option<String>,
309 zone: Option<TimeZone>,
310}
311
312impl Builder for TimePeriodBuilder {
313 type ConfigObject = TimePeriod;
314
315 /// Creates a new [`TimePeriodBuilder`] instance used to construct a [`TimePeriod`] object.
316 ///
317 /// # Returns
318 /// A `TimePeriodBuilder` instance.
319 fn new() -> Self {
320 Self::default()
321 }
322
323 /// Sets the name field for the `TimePeriod`.
324 ///
325 /// # Arguments
326 /// * `name` - The name for the `TimePeriod`.
327 fn name(mut self, name: &str) -> Self {
328 self.name = Some(name.to_string());
329 self
330 }
331
332 /// Consumes the builder and returns a [`TimePeriod`] object.
333 ///
334 /// # Returns
335 /// A `TimePeriod` object with the configured settings.
336 ///
337 /// # Errors
338 /// Returns a `OpsviewConfigError` if the name field is not set.
339 fn build(self) -> Result<Self::ConfigObject, OpsviewConfigError> {
340 let name = require_field(&self.name, "name")?;
341 let validated_alias = validate_opt_string(self.alias, validate_and_trim_timeperiod_alias)?;
342 let validated_monday =
343 validate_opt_string(self.monday, validate_and_trim_timeperiod_weekday)?;
344 let validated_tuesday =
345 validate_opt_string(self.tuesday, validate_and_trim_timeperiod_weekday)?;
346 let validated_wednesday =
347 validate_opt_string(self.wednesday, validate_and_trim_timeperiod_weekday)?;
348 let validated_thursday =
349 validate_opt_string(self.thursday, validate_and_trim_timeperiod_weekday)?;
350 let validated_friday =
351 validate_opt_string(self.friday, validate_and_trim_timeperiod_weekday)?;
352 let validated_saturday =
353 validate_opt_string(self.saturday, validate_and_trim_timeperiod_weekday)?;
354 let validated_sunday =
355 validate_opt_string(self.sunday, validate_and_trim_timeperiod_weekday)?;
356
357 Ok(TimePeriod {
358 name: validate_and_trim_timeperiod_name(&name)?,
359 alias: validated_alias,
360 friday: validated_friday,
361 monday: validated_monday,
362 saturday: validated_saturday,
363 sunday: validated_sunday,
364 thursday: validated_thursday,
365 tuesday: validated_tuesday,
366 wednesday: validated_wednesday,
367 zone: self.zone,
368 host_check_periods: None,
369 host_notification_periods: None,
370 id: None,
371 object_locked: None,
372 ref_: None,
373 servicecheck_check_periods: None,
374 servicecheck_notification_periods: None,
375 uncommitted: None,
376 })
377 }
378}
379
380impl TimePeriodBuilder {
381 /// Sets the alias field for the `TimePeriod`.
382 ///
383 /// # Arguments
384 /// * `alias` - The alias for the `TimePeriod`.
385 pub fn alias(mut self, alias: &str) -> Self {
386 self.alias = Some(alias.to_string());
387 self
388 }
389
390 /// Clears the alias field for the `TimePeriod`.
391 pub fn clear_alias(mut self) -> Self {
392 self.alias = None;
393 self
394 }
395
396 /// Clears the friday field for the `TimePeriod`.
397 pub fn clear_friday(mut self) -> Self {
398 self.friday = None;
399 self
400 }
401
402 /// Clears the monday field for the `TimePeriod`.
403 pub fn clear_monday(mut self) -> Self {
404 self.monday = None;
405 self
406 }
407
408 /// Clears the name field for the `TimePeriod`.
409 pub fn clear_name(mut self) -> Self {
410 self.name = None;
411 self
412 }
413
414 /// Clears the saturday field for the `TimePeriod`.
415 pub fn clear_saturday(mut self) -> Self {
416 self.saturday = None;
417 self
418 }
419
420 /// Clears the sunday field for the `TimePeriod`.
421 pub fn clear_sunday(mut self) -> Self {
422 self.sunday = None;
423 self
424 }
425
426 /// Clears the thursday field for the `TimePeriod`.
427 pub fn clear_thursday(mut self) -> Self {
428 self.thursday = None;
429 self
430 }
431
432 /// Clears the tuesday field for the `TimePeriod`.
433 pub fn clear_tuesday(mut self) -> Self {
434 self.tuesday = None;
435 self
436 }
437
438 /// Clears the wednesday field for the `TimePeriod`.
439 pub fn clear_wednesday(mut self) -> Self {
440 self.wednesday = None;
441 self
442 }
443
444 /// Clears the zone field for the `TimePeriod`.
445 pub fn clear_zone(mut self) -> Self {
446 self.zone = None;
447 self
448 }
449
450 /// Sets the friday field for the `TimePeriod`.
451 ///
452 /// # Arguments
453 /// * `friday` - The friday field for the `TimePeriod`.
454 ///
455 /// Example: `"00:00-09:00,17:00-24:00"`
456 pub fn friday(mut self, friday: &str) -> Self {
457 self.friday = Some(friday.to_string());
458 self
459 }
460
461 /// Sets the monday field for the `TimePeriod`.
462 ///
463 /// # Arguments
464 /// * `monday` - The monday field for the `TimePeriod`.
465 ///
466 /// Example: `"00:00-09:00,17:00-24:00"`
467 pub fn monday(mut self, monday: &str) -> Self {
468 self.monday = Some(monday.to_string());
469 self
470 }
471
472 /// Sets the saturday field for the `TimePeriod`.
473 ///
474 /// # Arguments
475 /// * `saturday` - The saturday field for the `TimePeriod`.
476 ///
477 /// Example: `"00:00-09:00,17:00-24:00"`
478 pub fn saturday(mut self, saturday: &str) -> Self {
479 self.saturday = Some(saturday.to_string());
480 self
481 }
482
483 /// Sets the sunday field for the `TimePeriod`.
484 ///
485 /// # Arguments
486 /// * `sunday` - The sunday field for the `TimePeriod`.
487 ///
488 /// Example: `"00:00-09:00,17:00-24:00"`
489 pub fn sunday(mut self, sunday: &str) -> Self {
490 self.sunday = Some(sunday.to_string());
491 self
492 }
493
494 /// Sets the thursday field for the `TimePeriod`.
495 ///
496 /// # Arguments
497 /// * `thursday` - The thursday field for the `TimePeriod`.
498 ///
499 /// Example: `"00:00-09:00,17:00-24:00"`
500 pub fn thursday(mut self, thursday: &str) -> Self {
501 self.thursday = Some(thursday.to_string());
502 self
503 }
504
505 /// Sets the tuesday field for the `TimePeriod`.
506 ///
507 /// # Arguments
508 /// * `tuesday` - The tuesday field for the `TimePeriod`.
509 ///
510 /// Example: `"00:00-09:00,17:00-24:00"`
511 pub fn tuesday(mut self, tuesday: &str) -> Self {
512 self.tuesday = Some(tuesday.to_string());
513 self
514 }
515
516 /// Sets the wednesday field for the `TimePeriod`.
517 ///
518 /// # Arguments
519 /// * `wednesday` - The wednesday field for the `TimePeriod`.
520 ///
521 /// Example: `"00:00-09:00,17:00-24:00"`
522 pub fn wednesday(mut self, wednesday: &str) -> Self {
523 self.wednesday = Some(wednesday.to_string());
524 self
525 }
526
527 /// Sets the zone field for the `TimePeriod`.
528 ///
529 /// # Arguments
530 /// * `zone` - The [`TimeZone`] in which the `TimePeriod` is defined.
531 pub fn zone(mut self, zone: TimeZone) -> Self {
532 self.zone = Some(zone);
533 self
534 }
535}
536
537/// A reference version of [`TimePeriod`] that is used when passing or retrieving a
538/// [`TimePeriod`] object as part of another object.
539#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq)]
540pub struct TimePeriodRef {
541 name: String,
542 #[serde(
543 rename = "ref",
544 skip_serializing_if = "Option::is_none",
545 deserialize_with = "deserialize_readonly",
546 default
547 )]
548 ref_: Option<String>,
549}
550
551/// Enables the creation of a [`TimePeriodRef`] instance from a JSON representation.
552/// Typically used when parsing JSON data from the Opsview API.
553impl CreateFromJson for TimePeriodRef {}
554
555impl ConfigRef for TimePeriodRef {
556 type FullObject = TimePeriod;
557
558 /// Returns the reference string of the [`TimePeriodRef`] object.
559 fn ref_(&self) -> Option<String> {
560 self.ref_.clone()
561 }
562
563 /// Returns the name of the [`TimePeriodRef`] object.
564 fn name(&self) -> String {
565 self.name.clone()
566 }
567
568 /// Returns the unique name of the [`TimePeriodRef`] object.
569 ///
570 /// This name is used to identify the `TimePeriodRef` when building the `HashMap` for a
571 /// [`ConfigRefMap`].
572 fn unique_name(&self) -> String {
573 self.name.clone()
574 }
575}
576
577impl From<TimePeriod> for TimePeriodRef {
578 /// Creates a [`TimePeriodRef`] object from a [`TimePeriod`] object.
579 ///
580 /// # Arguments
581 /// * `timeperiod` - The [`TimePeriod`] object from which to create the [`TimePeriodRef`] object.
582 ///
583 /// # Returns
584 /// A [`TimePeriodRef`] object.
585 fn from(timeperiod: TimePeriod) -> Self {
586 TimePeriodRef {
587 name: timeperiod.name.clone(),
588 ref_: timeperiod.ref_.clone(),
589 }
590 }
591}
592
593impl From<Arc<TimePeriod>> for TimePeriodRef {
594 /// Creates a [`TimePeriodRef`] object from an [`Arc`] wrapped [`TimePeriod`] object.
595 ///
596 /// # Arguments
597 /// * `timeperiod` - The [`Arc`] wrapped [`TimePeriod`] object from which to create the [`TimePeriodRef`] object.
598 ///
599 /// # Returns
600 /// A [`TimePeriodRef`] object.
601 fn from(timeperiod: Arc<TimePeriod>) -> Self {
602 TimePeriodRef {
603 name: timeperiod.name.clone(),
604 ref_: timeperiod.ref_.clone(),
605 }
606 }
607}
608
609impl From<&ConfigObjectMap<TimePeriod>> for ConfigRefMap<TimePeriodRef> {
610 fn from(timeperiods: &ConfigObjectMap<TimePeriod>) -> Self {
611 ref_map_from(timeperiods)
612 }
613}
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618
619 #[test]
620 fn test_timeperiod_default() {
621 let tz = TimeZone::builder()
622 .name("SYSTEM")
623 .ref_("/rest/config/timezone/1")
624 .build()
625 .unwrap();
626
627 let timeperiod = TimePeriod::default();
628
629 assert_eq!(timeperiod.name, String::new());
630 assert_eq!(timeperiod.alias, None);
631 assert_eq!(timeperiod.friday, None);
632 assert_eq!(timeperiod.host_check_periods, None);
633 assert_eq!(timeperiod.host_notification_periods, None);
634 assert_eq!(timeperiod.id, None);
635 assert_eq!(timeperiod.monday, None);
636 assert_eq!(timeperiod.object_locked, None);
637 assert_eq!(timeperiod.ref_, None);
638 assert_eq!(timeperiod.saturday, None);
639 assert_eq!(timeperiod.servicecheck_check_periods, None);
640 assert_eq!(timeperiod.servicecheck_notification_periods, None);
641 assert_eq!(timeperiod.sunday, None);
642 assert_eq!(timeperiod.thursday, None);
643 assert_eq!(timeperiod.tuesday, None);
644 assert_eq!(timeperiod.uncommitted, None);
645 assert_eq!(timeperiod.wednesday, None);
646 assert_eq!(timeperiod.zone, Some(tz));
647 }
648
649 #[test]
650 fn test_timeperiod_minimal() {
651 let timeperiod = TimePeriod::minimal("MyTimePeriod");
652
653 assert_eq!(timeperiod.unwrap().name, "MyTimePeriod".to_string());
654 }
655
656 #[test]
657 fn test_is_valid_timeperiod_name() {
658 // Valid names
659 assert!(validate_and_trim_timeperiod_name("24x7").is_ok());
660
661 // Invalid names
662 assert!(validate_and_trim_timeperiod_name("My Time Period").is_err());
663 }
664
665 #[test]
666 fn test_valid_timeperiods() {
667 let valid_strings = [
668 "00:00-09:00,17:00-24:00",
669 "00:00-24:00",
670 "00:00-09:00,10:00-11:00,12:00-24:00",
671 ];
672
673 for s in valid_strings {
674 println!("Testing timeperiod string '{}'", s);
675 let tp = TimePeriod::builder()
676 .name("foo")
677 .monday(s)
678 .tuesday(s)
679 .wednesday(s)
680 .thursday(s)
681 .friday(s)
682 .saturday(s)
683 .sunday(s)
684 .build();
685
686 assert!(tp.is_ok());
687 }
688 }
689
690 #[test]
691 fn test_invalid_timeperiods() {
692 let invalid_strings = ["foo", "00:00-22:00 23:00-24:00", "10:00-11:00Z", ""];
693
694 for s in invalid_strings {
695 println!("Testing timeperiod string '{}'", s);
696 let tp = TimePeriod::builder()
697 .name("foo")
698 .monday(s)
699 .tuesday(s)
700 .wednesday(s)
701 .thursday(s)
702 .friday(s)
703 .saturday(s)
704 .sunday(s)
705 .build();
706
707 assert!(tp.is_err());
708 }
709 }
710}