1use serde::Serialize;
2use validator::{Validate, ValidationError};
3
4use crate::journal::Journal;
5
6#[derive(Debug, Clone, Default, Serialize, Validate)]
7#[serde(rename = "body")]
8pub struct Body {
9 #[serde(default, skip_serializing_if = "Vec::is_empty")]
11 #[validate(nested)]
12 pub journal: Vec<Journal>,
13 }
34
35impl Body {
36 pub fn is_empty(&self) -> bool {
37 self.journal.is_empty()
38 }
49}
50
51#[allow(dead_code)]
52fn validate_body_has_exactly_one(body: &Body) -> Result<(), ValidationError> {
53 let count = [
54 !body.journal.is_empty(),
55 ]
66 .iter()
67 .filter(|&&x| x)
68 .count();
69
70 match count {
71 0 => Err(ValidationError::new("body_empty")
72 .with_message("Body must contain exactly one content type".into())),
73 1 => Ok(()),
74 _ => Err(ValidationError::new("body_multiple")
75 .with_message("Body must contain only one content type, found multiple".into())),
76 }
77}
78
79#[cfg(test)]
80mod unit {
81 use super::*;
82 use crate::enums::{ContentVersion, Iso639_1, MediaType};
83 use crate::journal::Journal;
84 use crate::journal::metadata::{ArchiveLocations, DoiData, Issn, JournalMetadata, Resource};
85
86 fn valid_journal() -> Journal {
87 Journal {
88 journal_metadata: JournalMetadata {
89 lang: Iso639_1::En,
90 full_title: "Example Journal".to_string(),
91 abbrev_title: Some("Ex. J.".to_string()),
92 issn: Some(Issn {
93 media_type: MediaType::Electronic,
94 value: "1234-5678".to_string(),
95 }),
96 coden: None,
97 archive_locations: ArchiveLocations::default(),
98 doi_data: DoiData {
99 doi: "10.1234/journal".to_string(),
100 timestamp: (),
101 resource: Resource {
102 value: "https://example.com/journal".to_string(),
103 mime_type: None,
104 content_version: ContentVersion::Vor,
105 },
106 },
107 },
108 journal_issue: None,
109 journal_article: vec![],
110 }
111 }
112
113 #[test]
114 fn empty_body_passes() {
115 let body = Body::default();
116 assert!(body.validate().is_ok());
117 assert!(body.is_empty());
118 }
119
120 #[test]
121 fn body_with_journal_passes() {
122 let body = Body {
123 journal: vec![valid_journal()],
124 };
125 assert!(body.validate().is_ok());
126 assert!(!body.is_empty());
127 }
128
129 #[test]
130 fn body_with_multiple_journals_passes() {
131 let body = Body {
132 journal: vec![valid_journal(), valid_journal()],
133 };
134 assert!(body.validate().is_ok());
135 }
136
137 #[test]
138 fn body_with_invalid_journal_fails() {
139 let mut journal = valid_journal();
140 journal.journal_metadata.full_title = "".to_string(); let body = Body {
142 journal: vec![journal],
143 };
144 assert!(body.validate().is_err());
145 }
146
147 mod validate_body_has_exactly_one_tests {
148 use super::*;
149
150 #[test]
151 fn empty_body_fails() {
152 let body = Body::default();
153 assert!(validate_body_has_exactly_one(&body).is_err());
154 }
155
156 #[test]
157 fn body_with_one_content_type_passes() {
158 let body = Body {
159 journal: vec![valid_journal()],
160 };
161 assert!(validate_body_has_exactly_one(&body).is_ok());
162 }
163
164 #[test]
165 fn body_with_multiple_content_types_fails() {
166 }
168 }
169}