Skip to main content

crossref_xml/journal/
mod.rs

1use crate::journal::{article::JournalArticle, issue::JournalIssue, metadata::JournalMetadata};
2use serde::Serialize;
3use validator::Validate;
4
5pub mod article;
6pub mod issue;
7pub mod metadata;
8
9#[derive(Debug, Clone, Default, Serialize, Validate)]
10#[serde(rename = "journal")]
11pub struct Journal {
12    #[validate(nested)]
13    pub journal_metadata: JournalMetadata,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    #[validate(nested)]
16    pub journal_issue: Option<JournalIssue>,
17    #[serde(default, skip_serializing_if = "Vec::is_empty")]
18    #[validate(nested)]
19    pub journal_article: Vec<JournalArticle>,
20}
21
22#[cfg(test)]
23mod unit {
24    use super::*;
25    use crate::enums::{ContentVersion, Iso639_1, MediaType, MediaTypeDate, PublicationType};
26    use crate::journal::article::JournalArticle;
27    use crate::journal::issue::{JournalIssue, PublicationDate, Titles};
28    use crate::journal::metadata::{ArchiveLocations, DoiData, Issn, JournalMetadata, Resource};
29
30    fn valid_journal() -> Journal {
31        Journal {
32            journal_metadata: JournalMetadata {
33                lang: Iso639_1::En,
34                full_title: "Example Journal".to_string(),
35                abbrev_title: Some("Ex. J.".to_string()),
36                issn: Some(Issn {
37                    media_type: MediaType::Electronic,
38                    value: "1234-5678".to_string(),
39                }),
40                coden: None,
41                archive_locations: ArchiveLocations::default(),
42                doi_data: DoiData {
43                    doi: "10.1234/journal".to_string(),
44                    timestamp: (),
45                    resource: Resource {
46                        value: "https://example.com/journal".to_string(),
47                        mime_type: None,
48                        content_version: ContentVersion::Vor,
49                    },
50                },
51            },
52            journal_issue: None,
53            journal_article: vec![],
54        }
55    }
56
57    #[test]
58    fn valid_journal_passes() {
59        let journal = valid_journal();
60        assert!(journal.validate().is_ok());
61    }
62
63    #[test]
64    fn journal_with_issue_passes() {
65        let mut journal = valid_journal();
66        journal.journal_issue = Some(JournalIssue {
67            contributors: vec![],
68            titles: Some(Titles {
69                title: "Issue 1".to_string(),
70                subtitle: None,
71                original_language_title: None,
72                orginal_language_subtitle: None,
73            }),
74            publication_date: PublicationDate {
75                media_type: MediaTypeDate::Online,
76                month: Some(6),
77                day: Some(15),
78                year: 2024,
79            },
80            issue: Some("1".to_string()),
81            special_numbering: None,
82            archive_locations: ArchiveLocations::default(),
83            doi_data: DoiData {
84                doi: "10.1234/issue.001".to_string(),
85                timestamp: (),
86                resource: Resource {
87                    value: "https://example.com/issue/1".to_string(),
88                    mime_type: None,
89                    content_version: ContentVersion::Vor,
90                },
91            },
92        });
93        assert!(journal.validate().is_ok());
94    }
95
96    #[test]
97    fn journal_with_articles_passes() {
98        let mut journal = valid_journal();
99        journal.journal_article = vec![JournalArticle {
100            publication_type: PublicationType::FullText,
101            language: Iso639_1::En,
102            titles: Titles {
103                title: "Example Article".to_string(),
104                subtitle: None,
105                original_language_title: None,
106                orginal_language_subtitle: None,
107            },
108            contributors: vec![],
109            jats_abstract: None,
110            publication_date: PublicationDate {
111                media_type: MediaTypeDate::Online,
112                month: Some(6),
113                day: Some(15),
114                year: 2024,
115            },
116            acceptance_date: None,
117            pages: None,
118            publisher_item: None,
119            crossmark: None,
120            archive_locations: ArchiveLocations::default(),
121            doi_data: DoiData {
122                doi: "10.1234/article.001".to_string(),
123                timestamp: (),
124                resource: Resource {
125                    value: "https://example.com/article".to_string(),
126                    mime_type: None,
127                    content_version: ContentVersion::Vor,
128                },
129            },
130            citation_list: Default::default(),
131            component_list: Default::default(),
132        }];
133        assert!(journal.validate().is_ok());
134    }
135
136    #[test]
137    fn journal_with_invalid_metadata_fails() {
138        let mut journal = valid_journal();
139        journal.journal_metadata.full_title = "".to_string(); // Too short
140        assert!(journal.validate().is_err());
141    }
142
143    #[test]
144    fn journal_with_invalid_issue_fails() {
145        let mut journal = valid_journal();
146        journal.journal_issue = Some(JournalIssue {
147            contributors: vec![],
148            titles: None,
149            publication_date: PublicationDate {
150                media_type: MediaTypeDate::Online,
151                month: None,
152                day: None,
153                year: 1000, // Invalid year
154            },
155            issue: None,
156            special_numbering: None,
157            archive_locations: ArchiveLocations::default(),
158            doi_data: DoiData {
159                doi: "10.1234/issue.001".to_string(),
160                timestamp: (),
161                resource: Resource {
162                    value: "https://example.com/issue/1".to_string(),
163                    mime_type: None,
164                    content_version: ContentVersion::Vor,
165                },
166            },
167        });
168        assert!(journal.validate().is_err());
169    }
170
171    #[test]
172    fn journal_with_invalid_article_fails() {
173        let mut journal = valid_journal();
174        journal.journal_article = vec![JournalArticle {
175            publication_type: PublicationType::FullText,
176            language: Iso639_1::En,
177            titles: Titles {
178                title: "Example Article".to_string(),
179                subtitle: None,
180                original_language_title: None,
181                orginal_language_subtitle: None,
182            },
183            contributors: vec![],
184            jats_abstract: None,
185            publication_date: PublicationDate {
186                media_type: MediaTypeDate::Online,
187                month: None,
188                day: None,
189                year: 1000, // Invalid year
190            },
191            acceptance_date: None,
192            pages: None,
193            publisher_item: None,
194            crossmark: None,
195            archive_locations: ArchiveLocations::default(),
196            doi_data: DoiData {
197                doi: "10.1234/article.001".to_string(),
198                timestamp: (),
199                resource: Resource {
200                    value: "https://example.com/article".to_string(),
201                    mime_type: None,
202                    content_version: ContentVersion::Vor,
203                },
204            },
205            citation_list: Default::default(),
206            component_list: Default::default(),
207        }];
208        assert!(journal.validate().is_err());
209    }
210
211    #[test]
212    fn minimal_journal_passes() {
213        let journal = Journal {
214            journal_metadata: JournalMetadata {
215                lang: Iso639_1::En,
216                full_title: "J".to_string(),
217                abbrev_title: None,
218                issn: None,
219                coden: None,
220                archive_locations: ArchiveLocations::default(),
221                doi_data: DoiData {
222                    doi: "10.1234/j".to_string(),
223                    timestamp: (),
224                    resource: Resource {
225                        value: "https://example.com".to_string(),
226                        mime_type: None,
227                        content_version: ContentVersion::Vor,
228                    },
229                },
230            },
231            journal_issue: None,
232            journal_article: vec![],
233        };
234        assert!(journal.validate().is_ok());
235    }
236}