From 4e3b1b41d2eac928de03fcecd42ee8b88456a5a3 Mon Sep 17 00:00:00 2001 From: rhigman <73792779+rhigman@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:56:24 +0000 Subject: [PATCH] Correct and extend test_onix3_thoth_works to cover most cases --- thoth-export-server/src/xml/onix3_thoth.rs | 1441 ++++++++++++++++---- 1 file changed, 1144 insertions(+), 297 deletions(-) diff --git a/thoth-export-server/src/xml/onix3_thoth.rs b/thoth-export-server/src/xml/onix3_thoth.rs index 13ad464e..1fec848f 100644 --- a/thoth-export-server/src/xml/onix3_thoth.rs +++ b/thoth-export-server/src/xml/onix3_thoth.rs @@ -700,19 +700,26 @@ impl XmlElementBlock for Work { })?; } XmlElement::::xml_element(&self.work_status, w)?; - write_element_block("PublishingDate", w, |w| { - write_element_block("PublishingDateRole", w, |w| { - // 01 Publication date - w.write(XmlEvent::Characters("01")).map_err(|e| e.into()) + if let Some(date) = &self.publication_date { + write_element_block("PublishingDate", w, |w| { + write_element_block("PublishingDateRole", w, |w| { + // 01 Publication date + w.write(XmlEvent::Characters("01")).map_err(|e| e.into()) + })?; + // dateformat="00" YYYYMMDD + write_full_element_block( + "Date", + Some(vec![("dateformat", "00")]), + w, + |w| { + w.write(XmlEvent::Characters( + &date.format("%Y%m%d").to_string(), + )) + .map_err(|e| e.into()) + }, + ) })?; - // dateformat="00" YYYYMMDD - write_full_element_block("Date", Some(vec![("dateformat", "00")]), w, |w| { - w.write(XmlEvent::Characters( - &self.publication_date.unwrap().format("%Y%m%d").to_string(), - )) - .map_err(|e| e.into()) - }) - })?; + } if let Some(copyright_holder) = &self.copyright_holder { write_element_block("CopyrightStatement", w, |w| { write_element_block("CopyrightOwner", w, |w| { @@ -746,8 +753,11 @@ impl XmlElementBlock for Work { && r.related_work.doi.is_some() }) .collect(); - // If only one ISBN is present, it'll be for the current product, not a related product - if isbns.len() > 1 || !non_child_relations.is_empty() || !self.references.is_empty() + // Only output ISBNs in RelatedMaterial if at least one is present which + // doesn't relate to the current publication + if (!isbns.is_empty() && !isbns.eq(&vec![current_isbn.clone().unwrap_or_default()])) + || !non_child_relations.is_empty() + || !self.references.is_empty() { write_element_block("RelatedMaterial", w, |w| { // RelatedWorks should be listed before RelatedProducts @@ -886,28 +896,26 @@ impl XmlElementBlock for Work { write_element_block("ProductAvailability", w, |w| { w.write(XmlEvent::Characters("99")).map_err(|e| e.into()) })?; - write_element_block("SupplyDate", w, |w| { - write_element_block("SupplyDateRole", w, |w| { - // 02 Expected availability date - w.write(XmlEvent::Characters("08")).map_err(|e| e.into()) + if let Some(date) = &self.publication_date { + write_element_block("SupplyDate", w, |w| { + write_element_block("SupplyDateRole", w, |w| { + // 02 Expected availability date + w.write(XmlEvent::Characters("08")).map_err(|e| e.into()) + })?; + // dateformat="00" YYYYMMDD + write_full_element_block( + "Date", + Some(vec![("dateformat", "00")]), + w, + |w| { + w.write(XmlEvent::Characters( + &date.format("%Y%m%d").to_string(), + )) + .map_err(|e| e.into()) + }, + ) })?; - // dateformat="00" YYYYMMDD - write_full_element_block( - "Date", - Some(vec![("dateformat", "00")]), - w, - |w| { - w.write(XmlEvent::Characters( - &self - .publication_date - .unwrap() - .format("%Y%m%d") - .to_string(), - )) - .map_err(|e| e.into()) - }, - ) - })?; + } if publication.prices.is_empty() { // 04 Contact supplier write_element_block("UnpricedItemType", w, |w| { @@ -2070,63 +2078,61 @@ mod tests { title: "Book Title".to_string(), subtitle: Some("Book Subtitle".to_string()), work_type: WorkType::MONOGRAPH, - reference: None, - edition: Some(1), + reference: Some("IntRef1".to_string()), + edition: Some(2), doi: Some(Doi::from_str("https://doi.org/10.00001/BOOK.0001").unwrap()), publication_date: chrono::NaiveDate::from_ymd_opt(1999, 12, 31), license: Some("https://creativecommons.org/licenses/by/4.0/".to_string()), copyright_holder: Some("Author 1; Author 2".to_string()), - short_abstract: None, - long_abstract: Some("Lorem ipsum dolor sit amet".to_string()), - general_note: None, - bibliography_note: None, + short_abstract: Some("Lorem ipsum dolor sit amet.".to_string()), + long_abstract: Some( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.".to_string(), + ), + general_note: Some("This is a general note".to_string()), + bibliography_note: Some("This is a bibliography note".to_string()), place: Some("León, Spain".to_string()), page_count: Some(334), page_breakdown: None, first_page: None, last_page: None, page_interval: None, - image_count: None, - table_count: None, - audio_count: None, - video_count: None, + image_count: Some(15), + table_count: Some(20), + audio_count: Some(25), + video_count: Some(30), landing_page: Some("https://www.book.com".to_string()), toc: Some("1. Chapter 1".to_string()), - lccn: None, - oclc: None, + lccn: Some("123456789".to_string()), + oclc: Some("987654321".to_string()), cover_url: Some("https://www.book.com/cover".to_string()), - cover_caption: None, + cover_caption: Some("This is a cover caption".to_string()), imprint: WorkImprint { imprint_name: "OA Editions Imprint".to_string(), - imprint_url: None, + imprint_url: Some("https://imprint.oa".to_string()), publisher: WorkImprintPublisher { publisher_name: "OA Editions".to_string(), - publisher_shortname: Some("OAE".to_string()), - publisher_url: None, + publisher_shortname: None, + publisher_url: Some("https://publisher.oa".to_string()), }, }, issues: vec![], contributions: vec![], - languages: vec![WorkLanguages { - language_code: LanguageCode::SPA, - language_relation: LanguageRelation::TRANSLATED_FROM, - main_language: true, - }], + languages: vec![], publications: vec![WorkPublications { - publication_id: Uuid::from_str("00000000-0000-0000-DDDD-000000000004").unwrap(), - publication_type: PublicationType::PDF, + publication_id: Uuid::from_str("00000000-0000-0000-BBBB-000000000001").unwrap(), + publication_type: PublicationType::PAPERBACK, isbn: Some(Isbn::from_str("978-3-16-148410-0").unwrap()), - width_mm: None, - width_cm: None, - width_in: None, - height_mm: None, - height_cm: None, - height_in: None, - depth_mm: None, - depth_cm: None, - depth_in: None, - weight_g: None, - weight_oz: None, + width_mm: Some(156.0), + width_cm: Some(15.6), + width_in: Some(6.14), + height_mm: Some(234.0), + height_cm: Some(23.4), + height_in: Some(9.21), + depth_mm: Some(25.0), + depth_cm: Some(2.5), + depth_in: Some(1.0), + weight_g: Some(152.0), + weight_oz: Some(5.3616), prices: vec![ WorkPublicationsPrices { currency_code: CurrencyCode::EUR, @@ -2142,9 +2148,9 @@ mod tests { }, ], locations: vec![WorkPublicationsLocations { - landing_page: Some("https://www.book.com/ebook_landing".to_string()), - full_text_url: Some("https://www.book.com/ebook_fulltext".to_string()), - location_platform: LocationPlatform::OTHER, + landing_page: Some("https://www.book.com/pb_landing".to_string()), + full_text_url: None, + location_platform: LocationPlatform::PUBLISHER_WEBSITE, canonical: true, }], }], @@ -2177,256 +2183,1097 @@ mod tests { WorkSubjects { subject_code: "custom1".to_string(), subject_type: SubjectType::CUSTOM, - subject_ordinal: 6, + subject_ordinal: 1, + }, + WorkSubjects { + subject_code: "custom2".to_string(), + subject_type: SubjectType::CUSTOM, + subject_ordinal: 1, }, ], fundings: vec![], - relations: vec![], - references: vec![], + relations: vec![ + WorkRelations { + relation_type: RelationType::HAS_CHILD, + relation_ordinal: 1, + related_work: WorkRelationsRelatedWork { + full_title: "Related work title".to_string(), + title: "N/A".to_string(), + subtitle: None, + edition: None, + doi: Some(Doi::from_str("https://doi.org/10.00001/RELATION.0001").unwrap()), + publication_date: None, + license: None, + short_abstract: None, + long_abstract: None, + place: None, + first_page: Some("10".to_string()), + last_page: Some("20".to_string()), + page_count: Some(11), + page_interval: None, + landing_page: None, + imprint: WorkRelationsRelatedWorkImprint { + publisher: WorkRelationsRelatedWorkImprintPublisher { + publisher_name: "N/A".to_string(), + }, + }, + contributions: vec![], + publications: vec![], + references: vec![], + fundings: vec![], + }, + }, + WorkRelations { + relation_type: RelationType::HAS_PART, + relation_ordinal: 2, + related_work: WorkRelationsRelatedWork { + full_title: "N/A".to_string(), + title: "N/A".to_string(), + subtitle: None, + edition: None, + doi: Some(Doi::from_str("https://doi.org/10.00001/RELATION.0002").unwrap()), + publication_date: None, + license: None, + short_abstract: None, + long_abstract: None, + place: None, + first_page: None, + last_page: None, + page_count: None, + page_interval: None, + landing_page: None, + imprint: WorkRelationsRelatedWorkImprint { + publisher: WorkRelationsRelatedWorkImprintPublisher { + publisher_name: "N/A".to_string(), + }, + }, + contributions: vec![], + publications: vec![], + references: vec![], + fundings: vec![], + }, + }, + WorkRelations { + relation_type: RelationType::HAS_TRANSLATION, + relation_ordinal: 3, + related_work: WorkRelationsRelatedWork { + full_title: "N/A".to_string(), + title: "N/A".to_string(), + subtitle: None, + edition: None, + doi: Some(Doi::from_str("https://doi.org/10.00001/RELATION.0003").unwrap()), + publication_date: None, + license: None, + short_abstract: None, + long_abstract: None, + place: None, + first_page: None, + last_page: None, + page_count: None, + page_interval: None, + landing_page: None, + imprint: WorkRelationsRelatedWorkImprint { + publisher: WorkRelationsRelatedWorkImprintPublisher { + publisher_name: "N/A".to_string(), + }, + }, + contributions: vec![], + publications: vec![], + references: vec![], + fundings: vec![], + }, + }, + ], + references: vec![WorkReferences { + reference_ordinal: 1, + doi: Some(Doi::from_str("https://doi.org/10.00001/reference").unwrap()), + unstructured_citation: None, + issn: None, + isbn: None, + journal_title: None, + article_title: None, + series_title: None, + volume_title: None, + edition: None, + author: None, + volume: None, + issue: None, + first_page: None, + component_number: None, + standard_designator: None, + standards_body_name: None, + standards_body_acronym: None, + publication_date: None, + retrieval_date: None, + }], }; // Test standard output let output = generate_test_output(true, &test_work); - assert!(output.contains(r#""#)); - assert!(output.contains( - r#" urn:uuid:00000000-0000-0000-aaaa-000000000001"# - )); - assert!(output.contains(r#" 03"#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output - .contains(r#" urn:uuid:00000000-0000-0000-aaaa-000000000001"#)); - assert!(output.contains(r#" 15"#)); - assert!(output.contains(r#" 9783161484100"#)); - assert!(output.contains(r#" 06"#)); - assert!(output.contains(r#" 10.00001/BOOK.0001"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 00"#)); - assert!(output.contains(r#" EB"#)); - assert!(output.contains(r#" E107"#)); - assert!(output.contains(r#" 10"#)); - assert!(output.contains(r#" "#)); - assert!( - output.contains(r#" Creative Commons License"#) - ); - assert!(output.contains(r#" "#)); - assert!( - output.contains(r#" 02"#) - ); - assert!(output.contains(r#" https://creativecommons.org/licenses/by/4.0/"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains(r#" Book Title"#)); - assert!(output.contains(r#" Book Subtitle"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 02"#)); - assert!(output.contains(r#" spa"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 00"#)); - assert!(output.contains(r#" 334"#)); - assert!(output.contains(r#" 03"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 12"#)); - assert!(output.contains(r#" AAB"#)); - assert!(output.contains(r#" 10"#)); - assert!(output.contains(r#" AAA000000"#)); - assert!(output.contains(r#" 04"#)); - assert!(output.contains(r#" JA85"#)); - assert!(output.contains(r#" 93"#)); - assert!(output.contains(r#" JWA"#)); - assert!(output.contains(r#" 20"#)); - assert!(output.contains(r#" keyword1"#)); - assert!(output.contains(r#" B2"#)); - assert!(output.contains(r#" custom1"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains(r#" 06"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 03"#)); - assert!(output.contains(r#" 00"#)); - assert!(output.contains(r#" Lorem ipsum dolor sit amet"#)); - assert!(output.contains(r#" 04"#)); - assert!(output.contains(r#" 1. Chapter 1"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains(r#" 03"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 02"#)); - assert!( - output.contains(r#" https://www.book.com/cover"#) - ); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" OA Editions Imprint"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains(r#" OA Editions"#)); - assert!(output.contains(r#" León, Spain"#)); - assert!(output.contains(r#" 04"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains(r#" 19991231"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 02"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" WORLD"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 06"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 15"#)); - assert!(output.contains(r#" 9783161484100"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" WORLD"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 09"#)); - assert!(output.contains(r#" OA Editions"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 01"#)); - assert!(output.contains( - r#" Publisher's website: web shop"# - )); - assert!(output.contains(r#" https://www.book.com"#)); - assert!(output.contains(r#" 20"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 02"#)); - assert!(output.contains(r#" 19991231"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 02"#)); - assert!(output.contains(r#" 8.00"#)); - assert!(output.contains(r#" USD"#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" WORLD"#)); - assert!(output.contains(r#" 29"#)); - assert!(output.contains(r#" Publisher's website: download the title"#)); - assert!(output.contains( - r#" https://www.book.com/ebook_fulltext"# + println!("{output}"); + // Non-repeatable blocks should appear in a guaranteed order + assert!(output.contains( + r#" + + urn:uuid:00000000-0000-0000-bbbb-000000000001 + 03 + 01"# + )); + assert!(output.contains( + r#" + + 01 + thoth-work-id + urn:uuid:00000000-0000-0000-aaaa-000000000001 + "# + )); + assert!(output.contains( + r#" + + 01 + thoth-publication-id + urn:uuid:00000000-0000-0000-bbbb-000000000001 + "# + )); + assert!(output.contains( + r#" + + 15 + 9783161484100 + "# + )); + assert!(output.contains( + r#" + + 06 + 10.00001/BOOK.0001 + "# + )); + assert!(output.contains( + r#" + + 13 + 123456789 + "# + )); + assert!(output.contains( + r#" + + 23 + 987654321 + "# + )); + assert!(output.contains( + r#" + + 01 + internal-reference + IntRef1 + "# + )); + assert!(output.contains( + r#" + + 00 + BC + 10"# + )); + assert!(output.contains( + r#" + + 01 + 234 + mm + "# + )); + assert!(output.contains( + r#" + + 01 + 23.4 + cm + "# + )); + assert!(output.contains( + r#" + + 01 + 9.21 + in + "# + )); + assert!(output.contains( + r#" + + 02 + 156 + mm + "# + )); + assert!(output.contains( + r#" + + 02 + 15.6 + cm + "# + )); + assert!(output.contains( + r#" + + 02 + 6.14 + in + "# + )); + assert!(output.contains( + r#" + + 03 + 25 + mm + "# + )); + assert!(output.contains( + r#" + + 03 + 2.5 + cm + "# + )); + assert!(output.contains( + r#" + + 03 + 1 + in + "# + )); + assert!(output.contains( + r#" + + 08 + 152 + gr + "# + )); + assert!(output.contains( + r#" + + 08 + 5.3616 + oz + "# + )); + assert!(output.contains( + r#" + + Creative Commons Attribution 4.0 International license (CC BY 4.0). + + 02 + https://creativecommons.org/licenses/by/4.0/ + + + + 01 + + 01 + Book Title + Book Subtitle + + + + 2 + + + 00 + 334 + 03 + + This is a bibliography note"#)); + assert!(output.contains( + r#" + + 09 + 15 + "# + )); + assert!(output.contains( + r#" + + 11 + 20 + "# + )); + assert!(output.contains( + r#" + + 19 + 25 + "# + )); + assert!(output.contains( + r#" + + 00 + Videos + 30 + "# + )); + assert!(output.contains( + r#" + + + 12 + AAB + "# + )); + assert!(output.contains( + r#" + + 10 + AAA000000 + "# + )); + assert!(output.contains( + r#" + + 04 + JA85 + "# + )); + assert!(output.contains( + r#" + + 93 + JWA + "# + )); + assert!(output.contains( + r#" + + 20 + keyword1 + "# + )); + assert!(output.contains( + r#" + + + B2 + custom1 + "# + )); + assert!(output.contains( + r#" + + B2 + custom2 + "# + )); + assert!(output.contains( + r#" + + 01 + 06 + + + "# + )); + assert!(output.contains( + r#" + + 02 + 00 + Lorem ipsum dolor sit amet. + "# + )); + assert!(output.contains( + r#" + + 03 + 00 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + "# + )); + assert!(output.contains( + r#" + + 30 + 00 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + "# + )); + assert!(output.contains( + r#" + + 04 + 00 + 1. Chapter 1 + "# + )); + assert!(output.contains( + r#" + + 20 + 00 + Open Access + "# + )); + assert!(output.contains( + r#" + + 13 + 00 + This is a general note + "# + )); + assert!(output.contains( + r#" + + 01 + 00 + 03 + + 02 + This is a cover caption + + + 02 + https://www.book.com/cover + + + + + + 1 + + + 03 + + 06 + 10.00001/RELATION.0001 + + + + 10 + 20 + + 11 + + + + OA Editions Imprint + + 01 + URL + https://imprint.oa + + + + 01 + OA Editions"# + )); + assert!(output.contains( + r#" + + 01 + Publisher's website: home page + https://publisher.oa + "# + )); + assert!(output.contains( + r#" + + 02 + Publisher's website: webpage for this title + https://www.book.com + "# + )); + assert!(output.contains( + r#" + + León, Spain + 04 + + 01 + 19991231 + + + + Author 1; Author 2 + + + + 02 + + WORLD + + + + + + 49 + + 06 + 10.00001/RELATION.0003 + + "# + )); + assert!(output.contains( + r#" + + 01 + + 06 + 10.00001/RELATION.0002 + + "# + )); + assert!(output.contains( + r#" + + 34 + + 06 + 10.00001/reference + + "# + )); + assert!(output.contains( + r#" + + + + + WORLD + + + + + 09 + OA Editions + + 02 + Publisher's website: webpage for this product + https://www.book.com/pb_landing + + + 99 + + 08 + 19991231 + "# + )); + assert!(output.contains( + r#" + + 02 + 5.95 + EUR + + WORLD + + "# + )); + assert!(output.contains( + r#" + + 02 + 4.95 + GBP + + WORLD + + "# + )); + assert!(output.contains( + r#" + + 02 + 8.00 + USD + + WORLD + + "# )); + // Test ProductForm[Detail] with different publication types + test_work.publications[0].publication_type = PublicationType::HARDBACK; + let output = generate_test_output(true, &test_work); + assert!(!output.contains(r#" BC"#)); + assert!(output.contains(r#" BB"#)); + assert!(!output.contains(r#" "#)); + test_work.publications[0].publication_type = PublicationType::PDF; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E107"# + )); + test_work.publications[0].publication_type = PublicationType::HTML; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E105"# + )); + test_work.publications[0].publication_type = PublicationType::XML; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E113"# + )); + test_work.publications[0].publication_type = PublicationType::EPUB; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E101"# + )); + test_work.publications[0].publication_type = PublicationType::MOBI; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E127"# + )); + test_work.publications[0].publication_type = PublicationType::AZW3; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E116"# + )); + test_work.publications[0].publication_type = PublicationType::DOCX; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E104"# + )); + test_work.publications[0].publication_type = PublicationType::FICTION_BOOK; + let output = generate_test_output(true, &test_work); + assert!(output.contains( + r#" + EB + E100"# + )); + test_work.publications[0].publication_type = PublicationType::PAPERBACK; + // Remove/change some values to test (non-)output of optional blocks test_work.doi = None; + test_work.lccn = None; + test_work.oclc = None; + test_work.reference = None; test_work.license = None; test_work.subtitle = None; + test_work.edition = Some(1); test_work.page_count = None; + test_work.bibliography_note = None; + test_work.image_count = None; + test_work.short_abstract = None; + test_work.long_abstract = None; test_work.toc = None; - test_work.cover_url = None; - test_work.place = None; + test_work.general_note = None; + test_work.cover_caption = None; test_work.landing_page = None; - test_work.publications[0].publication_type = PublicationType::EPUB; - test_work.subjects.clear(); + test_work.place = None; + test_work.publication_date = None; + test_work.copyright_holder = None; + test_work.publications[0].isbn = None; + test_work.publications[0].height_mm = None; + test_work.publications[0].locations.clear(); + test_work.publications[0].prices.pop(); + test_work.relations[0].related_work.last_page = None; + test_work.relations[0].related_work.page_count = None; + test_work.references.clear(); + test_work.imprint.imprint_url = None; + test_work.imprint.publisher.publisher_url = None; + test_work.subjects.pop(); let output = generate_test_output(true, &test_work); - // Ebook type changed - assert!(!output.contains(r#" E107"#)); - assert!(output.contains(r#" E101"#)); - // No DOI supplied - assert!(!output.contains(r#" 06"#)); - assert!(!output.contains(r#" 10.00001/BOOK.0001"#)); - // No licence supplied - assert!(!output.contains(r#" "#)); - assert!(!output - .contains(r#" Creative Commons License"#)); - assert!(!output.contains(r#" "#)); - assert!(!output - .contains(r#" 02"#)); - assert!(!output.contains(r#" https://creativecommons.org/licenses/by/4.0/"#)); - // No subtitle supplied (within Thoth UI this would automatically update full_title) + println!("{output}"); + assert!(!output.contains( + r#" + + 15 + 9783161484100 + "# + )); + assert!(!output.contains( + r#" + + 06 + 10.00001/BOOK.0001 + "# + )); + assert!(!output.contains( + r#" + + 13 + 123456789 + "# + )); + assert!(!output.contains( + r#" + + 23 + 987654321 + "# + )); + assert!(!output.contains( + r#" + + 01 + internal-reference + IntRef1 + "# + )); + assert!(!output.contains( + r#" + + 01 + 234 + mm + "# + )); + assert!(!output.contains( + r#" + + Creative Commons Attribution 4.0 International license (CC BY 4.0). + + 02 + https://creativecommons.org/licenses/by/4.0/ + + "# + )); + // Title block still present but Subtitle absent + assert!(output.contains( + r#" + + 01 + + 01 + Book Title + + "# + )); assert!(!output.contains(r#" Book Subtitle"#)); - // No page count supplied + assert!(!output.contains(r#" "#)); assert!(!output.contains(r#" "#)); - assert!(!output.contains(r#" 00"#)); - assert!(!output.contains(r#" 334"#)); - assert!(!output.contains(r#" 03"#)); - // No table of contents or cover URL supplied: CollateralDetail block only contains long abstract - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" "#)); - assert!(output.contains(r#" 03"#)); - assert!(output.contains(r#" 00"#)); - assert!(output.contains(r#" Lorem ipsum dolor sit amet"#)); - assert!(!output.contains(r#" 04"#)); - assert!(!output.contains(r#" 1. Chapter 1"#)); - assert!(!output.contains(r#" "#)); - assert!(!output.contains(r#" 01"#)); - assert!(!output.contains(r#" 03"#)); - assert!(!output.contains(r#" "#)); - assert!(!output.contains(r#" 02"#)); assert!(!output - .contains(r#" "https://www.book.com/cover""#)); - // No place supplied + .contains(r#" This is a bibliography note"#)); + assert!(!output.contains( + r#" + + 09 + 15 + "# + )); + assert!(!output.contains( + r#" + + B2 + custom2 + "# + )); + assert!(!output.contains( + r#" + + 02 + 00 + Lorem ipsum dolor sit amet. + "# + )); + assert!(!output.contains( + r#" + + 03 + 00 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + "# + )); + assert!(!output.contains( + r#" + + 30 + 00 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + "# + )); + assert!(!output.contains( + r#" + + 04 + 00 + 1. Chapter 1 + "# + )); + assert!(!output.contains( + r#" + + 13 + 00 + This is a general note + "# + )); + // SupportingResource block still present but ResourceFeature absent + assert!(output.contains( + r#" + + 01 + 00 + 03 + + 02 + https://www.book.com/cover + + "# + )); + assert!(!output.contains( + r#" + + 02 + This is a cover caption + "# + )); + // PageRun block still present but LastPageNumber absent + assert!(output.contains( + r#" + + 10 + "# + )); + assert!(!output.contains(r#" 20"#)); + assert!(!output.contains(r#" 11"#)); + // Imprint block still present but ImprintIdentifier absent + assert!(output.contains( + r#" + + OA Editions Imprint + "# + )); + assert!(!output.contains( + r#" + + 01 + URL + https://imprint.oa + "# + )); + assert!(!output.contains( + r#" + + 01 + Publisher's website: home page + https://publisher.oa + "# + )); + assert!(!output.contains( + r#" + + 02 + Publisher's website: webpage for this title + https://www.book.com + "# + )); assert!(!output.contains(r#" León, Spain"#)); - // No landing page supplied: only one SupplyDetail block, linking to ebook download - assert!(!output.contains(r#" 01"#)); assert!(!output.contains( - r#" Publisher's website: web shop"# + r#" + + 01 + 19991231 + "# + )); + assert!(!output.contains( + r#" + + + Author 1; Author 2 + + "# + )); + assert!(!output.contains( + r#" + + 34 + + 06 + 10.00001/reference + + "# + )); + // Supplier block still present but Website absent + assert!(output.contains( + r#" + + 09 + OA Editions + "# + )); + assert!(!output.contains( + r#" + + 02 + Publisher's website: webpage for this product + https://www.book.com/pb_landing + "# + )); + assert!(!output.contains( + r#" + + 02 + 8.00 + USD + + WORLD + + "# )); - assert!(!output.contains(r#" https://www.book.com"#)); - // No subjects supplied - assert!(!output.contains(r#" "#)); - assert!(!output.contains(r#" 12"#)); - assert!(!output.contains(r#" AAB"#)); - assert!(!output.contains(r#" 10"#)); - assert!(!output.contains(r#" AAA000000"#)); - assert!(!output.contains(r#" 04"#)); - assert!(!output.contains(r#" JA85"#)); - assert!(!output.contains(r#" 93"#)); - assert!(!output.contains(r#" JWA"#)); - assert!(!output.contains(r#" 20"#)); - assert!(!output.contains(r#" keyword1"#)); - assert!(!output.contains(r#" B2"#)); - assert!(!output.contains(r#" custom1"#)); - - // Remove the only language: result is error - test_work.languages.clear(); - let output = generate_test_output(false, &test_work); - assert_eq!( - output, - "Could not generate onix_3.0::thoth: Missing Language Code(s)".to_string() - ); - - // Replace language but remove long abstract: result is error - test_work.languages = vec![WorkLanguages { - language_code: LanguageCode::SPA, - language_relation: LanguageRelation::TRANSLATED_FROM, - main_language: true, - }]; - test_work.long_abstract = None; - let output = generate_test_output(false, &test_work); - assert_eq!( - output, - "Could not generate onix_3.0::thoth: Missing Long Abstract".to_string() - ); - // Replace long abstract but remove publication date: result is error - test_work.long_abstract = Some("Lorem ipsum dolor sit amet".to_string()); - test_work.publication_date = None; - let output = generate_test_output(false, &test_work); - assert_eq!( - output, - "Could not generate onix_3.0::thoth: Missing Publication Date".to_string() - ); + // Remove even more values + test_work.edition = None; + test_work.table_count = None; + test_work.audio_count = None; + test_work.video_count = None; + test_work.cover_url = None; + test_work.relations[0].related_work.first_page = None; + // If first page is missing, last page isn't included even if present + test_work.relations[0].related_work.last_page = Some("20".to_string()); + test_work.relations.pop(); + test_work.subjects.clear(); + test_work.publications[0].height_cm = None; + test_work.publications[0].height_in = None; + test_work.publications[0].width_mm = None; + test_work.publications[0].width_cm = None; + test_work.publications[0].width_in = None; + test_work.publications[0].depth_mm = None; + test_work.publications[0].depth_cm = None; + test_work.publications[0].depth_in = None; + test_work.publications[0].weight_g = None; + test_work.publications[0].weight_oz = None; + test_work.publications[0].prices.clear(); + let output = generate_test_output(true, &test_work); + println!("{output}"); + // Still no Edition, same as when value was 1 + assert!(!output.contains(r#" "#)); + // No AncillaryContent or Subject blocks at all - skip from TitleDetail straight to Audience + assert!(output.contains( + r#" + + "# + )); + assert!(!output.contains(r#" "#)); + assert!(!output.contains(r#" "#)); + // No cover URL means no SupportingResource block - CollateralDetail only contains OA statement + assert!(output.contains( + r#" + + + 20 + 00 + Open Access + + "# + )); + assert!(!output.contains(r#" "#)); + assert!(!output.contains(r#" "#)); + assert!(!output.contains(r#" 10"#)); + assert!(!output.contains(r#" 20"#)); + // Only one item left in RelatedMaterial + assert!(output.contains( + r#" + + + 01 + + 06 + 10.00001/RELATION.0002 + + + "# + )); + assert!(!output.contains(r#" "#)); + // UnpricedItemType block instead of any Prices + assert!(output.contains(r#" 04"#)); + assert!(!output.contains(r#" "#)); - // Replace publication date but remove USD price: result is error - test_work.publication_date = chrono::NaiveDate::from_ymd_opt(1999, 12, 31); - test_work.publications[0].prices.pop(); - let output = generate_test_output(false, &test_work); - assert_eq!( - output, - "Could not generate onix_3.0::thoth: No USD price found".to_string() - ); + // Remove chapter DOI: can't output ContentDetail block + test_work.relations[0].related_work.doi = None; + // Remove remaining related work DOI: can't output RelatedMaterial block + test_work.relations[1].related_work.doi = None; + // Test truncation of short abstract + test_work.short_abstract = Some("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vel libero eleifend, ultrices purus vitae, suscipit ligula. Aliquam ornare quam et nulla vestibulum, id euismod tellus malesuada. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam ornare bibendum ex nec dapibus. Proin porta risus elementum odio feugiat tempus. Etiam eu felis ac metus viverra ornare. In consectetur neque sed feugiat ornare. Mauris at purus fringilla orci tincidunt pulvinar sed a massa. Nullam vestibulum posuere augue, sit amet tincidunt nisl pulvinar ac.".to_string()); + let output = generate_test_output(true, &test_work); + println!("{output}"); + assert!(!output.contains(r#" "#)); + assert!(!output.contains(r#" "#)); + assert!(!output.contains(r#" "#)); + assert!(output.contains( + r#" + + 02 + 00 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vel libero eleifend, ultrices purus vitae, suscipit ligula. Aliquam ornare quam et nulla vestibulum, id euismod tellus malesuada. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam ornare bibendum ex nec dapibus. Proin porta risus elementu + "# + )); + test_work.short_abstract = None; - // Replace USD price but remove the only (PDF) publication's only location - // Result: error (can't generate OverDrive ONIX without EPUB or PDF URL) - test_work.publications[0].prices[0].currency_code = CurrencyCode::USD; - test_work.publications[0].locations.clear(); - let output = generate_test_output(false, &test_work); - assert_eq!( - output, - "Could not generate onix_3.0::thoth: No priced EPUB or PDF URL".to_string() - ); + // Add second publication, and test that two records are produced + test_work.publications.push(WorkPublications { + publication_id: Uuid::from_str("00000000-0000-0000-CCCC-000000000001").unwrap(), + publication_type: PublicationType::HARDBACK, + isbn: Some(Isbn::from_str("978-1-4028-9462-6").unwrap()), + width_mm: None, + width_cm: None, + width_in: None, + height_mm: None, + height_cm: None, + height_in: None, + depth_mm: None, + depth_cm: None, + depth_in: None, + weight_g: None, + weight_oz: None, + prices: vec![], + locations: vec![], + }); + let output = generate_test_output(true, &test_work); + println!("{output}"); + assert!(output.contains( + r#" + + urn:uuid:00000000-0000-0000-bbbb-000000000001"# + )); + assert!(output.contains( + r#" + + urn:uuid:00000000-0000-0000-cccc-000000000001"# + )); + // First record will now have a RelatedMaterial block (again) representing second record + assert!(output.contains( + r#" + + + + 06 + + 15 + 9781402894626 + + + + "# + )); + // No RelatedMaterial block in second record, as no ISBN in first + // Skip straight from PublishingDetail to ProductSupply + assert!(output.contains( + r#" + + "# + )); } }