slack_messaging/composition_objects/
slack_file.rs

1use crate::errors::ValidationErrorKind;
2
3use serde::Serialize;
4use slack_messaging_derive::Builder;
5
6/// [Slack file object](https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object)
7/// representation.
8///
9/// # Fields and Validations
10///
11/// For more details, see the [official
12/// documentation](https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object).
13///
14/// | Field | Type | Required | Validation |
15/// |-------|------|----------|------------|
16/// | id | String | Conditionally | N/A |
17/// | url | String | Conditionally | N/A |
18///
19/// # Validation Across Fields
20///
21/// * Exactly one of the fields `id` or `url` must be provided.
22///
23/// # Example
24///
25/// ```
26/// use slack_messaging::composition_objects::SlackFile;
27/// # use std::error::Error;
28///
29/// # fn try_main() -> Result<(), Box<dyn Error>> {
30/// let file = SlackFile::builder()
31///     .id("F0123456")
32///     .build()?;
33///
34/// let expected = serde_json::json!({
35///     "id": "F0123456"
36/// });
37///
38/// let json = serde_json::to_value(file).unwrap();
39///
40/// assert_eq!(json, expected);
41///
42/// // If your object has any validation errors, the build method returns Result::Err
43/// let file = SlackFile::builder().build();
44/// assert!(file.is_err());
45/// #     Ok(())
46/// # }
47/// # fn main() {
48/// #     try_main().unwrap()
49/// # }
50/// ```
51#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
52#[builder(validate = "validate")]
53pub struct SlackFile {
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub(crate) id: Option<String>,
56
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub(crate) url: Option<String>,
59}
60
61fn validate(val: &SlackFile) -> Vec<ValidationErrorKind> {
62    match (val.id.as_ref(), val.url.as_ref()) {
63        (Some(_), Some(_)) => vec![ValidationErrorKind::ExclusiveField("id", "url")],
64        (None, None) => vec![ValidationErrorKind::EitherRequired("id", "url")],
65        _ => vec![],
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use crate::errors::*;
73
74    #[test]
75    fn it_implements_builder() {
76        let expected = SlackFile {
77            id: Some("F0123456".into()),
78            url: None,
79        };
80
81        let val = SlackFile::builder()
82            .set_id(Some("F0123456"))
83            .build()
84            .unwrap();
85
86        assert_eq!(val, expected);
87
88        let val = SlackFile::builder().id("F0123456").build().unwrap();
89
90        assert_eq!(val, expected);
91
92        let expected = SlackFile {
93            id: None,
94            url: Some("https://files.slack.com/files-pri/T0123456-F0123456/xyz.png".into()),
95        };
96
97        let val = SlackFile::builder()
98            .set_url(Some(
99                "https://files.slack.com/files-pri/T0123456-F0123456/xyz.png",
100            ))
101            .build()
102            .unwrap();
103
104        assert_eq!(val, expected);
105
106        let val = SlackFile::builder()
107            .url("https://files.slack.com/files-pri/T0123456-F0123456/xyz.png")
108            .build()
109            .unwrap();
110
111        assert_eq!(val, expected);
112    }
113
114    #[test]
115    fn it_requires_either_id_or_url_field() {
116        let err = SlackFile::builder()
117            .id("F0123456")
118            .url("https://files.slack.com/files-pri/T0123456-F0123456/xyz.png")
119            .build()
120            .unwrap_err();
121        assert_eq!(err.object(), "SlackFile");
122
123        let errors = err.across_fields();
124        assert!(errors.includes(ValidationErrorKind::ExclusiveField("id", "url")));
125
126        let err = SlackFile::builder().build().unwrap_err();
127        assert_eq!(err.object(), "SlackFile");
128
129        let errors = err.across_fields();
130        assert!(errors.includes(ValidationErrorKind::EitherRequired("id", "url")));
131    }
132}