slack_messaging/blocks/elements/
image.rs1use crate::composition_objects::SlackFile;
2use crate::errors::ValidationErrorKind;
3use crate::validators::*;
4
5use serde::Serialize;
6use slack_messaging_derive::Builder;
7
8#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
61#[serde(tag = "type", rename = "image")]
62#[builder(validate = "validate")]
63pub struct Image {
64 #[builder(validate("required"))]
65 pub(crate) alt_text: Option<String>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
68 #[builder(validate("text::max_3000"))]
69 pub(crate) image_url: Option<String>,
70
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub(crate) slack_file: Option<SlackFile>,
73}
74
75fn validate(val: &Image) -> Vec<ValidationErrorKind> {
76 match (val.image_url.as_ref(), val.slack_file.as_ref()) {
77 (Some(_), Some(_)) => {
78 vec![ValidationErrorKind::ExclusiveField(
79 "image_url",
80 "slack_file",
81 )]
82 }
83 (None, None) => {
84 vec![ValidationErrorKind::EitherRequired(
85 "image_url",
86 "slack_file",
87 )]
88 }
89 _ => vec![],
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::composition_objects::test_helpers::*;
97
98 #[test]
99 fn it_implements_builder() {
100 let expected = Image {
102 alt_text: Some("Cute kitten".into()),
103 image_url: Some("http://placekitten.com/700/500".into()),
104 slack_file: None,
105 };
106
107 let val = Image::builder()
108 .set_alt_text(Some("Cute kitten"))
109 .set_image_url(Some("http://placekitten.com/700/500"))
110 .build()
111 .unwrap();
112
113 assert_eq!(val, expected);
114
115 let val = Image::builder()
116 .alt_text("Cute kitten")
117 .image_url("http://placekitten.com/700/500")
118 .build()
119 .unwrap();
120
121 assert_eq!(val, expected);
122
123 let expected = Image {
125 alt_text: Some("Cute kitten".into()),
126 image_url: None,
127 slack_file: Some(slack_file()),
128 };
129
130 let val = Image::builder()
131 .set_alt_text(Some("Cute kitten"))
132 .set_slack_file(Some(slack_file()))
133 .build()
134 .unwrap();
135
136 assert_eq!(val, expected);
137
138 let val = Image::builder()
139 .alt_text("Cute kitten")
140 .slack_file(slack_file())
141 .build()
142 .unwrap();
143
144 assert_eq!(val, expected);
145 }
146
147 #[test]
148 fn it_requires_alt_text_field() {
149 let err = Image::builder()
150 .slack_file(slack_file())
151 .build()
152 .unwrap_err();
153 assert_eq!(err.object(), "Image");
154
155 let errors = err.field("alt_text");
156 assert!(errors.includes(ValidationErrorKind::Required));
157 }
158
159 #[test]
160 fn it_requires_image_url_less_than_3000_characters_long() {
161 let err = Image::builder()
162 .alt_text("Cute kitten")
163 .image_url("a".repeat(3001))
164 .build()
165 .unwrap_err();
166 assert_eq!(err.object(), "Image");
167
168 let errors = err.field("image_url");
169 assert!(errors.includes(ValidationErrorKind::MaxTextLength(3000)));
170 }
171
172 #[test]
173 fn it_prevents_from_setting_both_image_url_and_slack_file() {
174 let err = Image::builder()
175 .alt_text("Cute kitten")
176 .image_url("http://placekitten.com/700/500")
177 .slack_file(slack_file())
178 .build()
179 .unwrap_err();
180 assert_eq!(err.object(), "Image");
181
182 let errors = err.across_fields();
183 assert!(errors.includes(ValidationErrorKind::ExclusiveField(
184 "image_url",
185 "slack_file"
186 )));
187 }
188
189 #[test]
190 fn it_requires_either_image_url_or_slack_file_is_set() {
191 let err = Image::builder()
192 .alt_text("Cute kitten")
193 .build()
194 .unwrap_err();
195 assert_eq!(err.object(), "Image");
196
197 let errors = err.across_fields();
198 assert!(errors.includes(ValidationErrorKind::EitherRequired(
199 "image_url",
200 "slack_file"
201 )));
202 }
203}