From ed24fd13db7ff6bf5022114aa71762ddd06b2714 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Sat, 16 Apr 2022 19:19:44 +0200 Subject: [PATCH] Expand roundtrip apkg test --- rslib/src/import_export/package/apkg/tests.rs | 175 ++++++++++++++---- rslib/src/lib.rs | 1 + 2 files changed, 137 insertions(+), 39 deletions(-) diff --git a/rslib/src/import_export/package/apkg/tests.rs b/rslib/src/import_export/package/apkg/tests.rs index 0f6d5dac4..557245898 100644 --- a/rslib/src/import_export/package/apkg/tests.rs +++ b/rslib/src/import_export/package/apkg/tests.rs @@ -3,50 +3,147 @@ #![cfg(test)] -use std::path::Path; +use std::{collections::HashSet, fs::File, io::Write}; -use tempfile::tempdir; +use crate::{ + media::files::sha1_of_data, prelude::*, search::SearchNode, tests::open_fs_test_collection, +}; -use crate::{collection::CollectionBuilder, media::MediaManager, prelude::*, search::SearchNode}; - -fn collection_with_media(dir: &Path, name: &str) -> Result { - let name = format!("{name}_src"); - let media_folder = dir.join(format!("{name}.media")); - std::fs::create_dir(&media_folder)?; - // add collection with sentinel note - let mut col = CollectionBuilder::new(dir.join(format!("{name}.anki2"))) - .set_media_paths(media_folder, dir.join(format!("{name}.mdb"))) - .build()?; - let nt = col.get_notetype_by_name("Basic")?.unwrap(); - let mut note = nt.new_note(); - col.add_note(&mut note, DeckId(1))?; - // add sample media - let mgr = MediaManager::new(&col.media_folder, &col.media_db)?; - let mut ctx = mgr.dbctx(); - mgr.add_file(&mut ctx, "1", b"1")?; - mgr.add_file(&mut ctx, "2", b"2")?; - mgr.add_file(&mut ctx, "3", b"3")?; - Ok(col) -} +const SAMPLE_JPG: &str = "sample.jpg"; +const SAMPLE_MP3: &str = "sample.mp3"; +const SAMPLE_JS: &str = "_sample.js"; +const JPG_DATA: &[u8] = b"1"; +const MP3_DATA: &[u8] = b"2"; +const JS_DATA: &[u8] = b"3"; +const OTHER_MP3_DATA: &[u8] = b"4"; #[test] -fn roundtrip() -> Result<()> { - let _dir = tempdir()?; - let dir = _dir.path(); - const NAME: &str = "mycol"; +fn roundtrip() { + let (mut src_col, src_tempdir) = open_fs_test_collection("src"); + let (mut target_col, _target_tempdir) = open_fs_test_collection("target"); + let apkg_path = src_tempdir.path().join("test.apkg"); - let mut col = collection_with_media(dir, NAME)?; - let apkg_path = dir.join(format!("{NAME}.apkg")); + let (main_deck, sibling_deck) = src_col.add_sample_decks(); + let notetype = src_col.add_sample_notetype(); + let note = src_col.add_sample_note(&main_deck, &sibling_deck, ¬etype); + src_col.add_sample_media(); + target_col.add_conflicting_media(); - col.export_apkg( - &apkg_path, - SearchNode::WholeCollection, - true, - true, - None, - |_| (), - )?; - col.import_apkg(&apkg_path)?; + src_col + .export_apkg( + &apkg_path, + SearchNode::from_deck_name("parent::sample"), + true, + true, + None, + |_| (), + ) + .unwrap(); + target_col.import_apkg(&apkg_path, |_| Ok(())).unwrap(); - Ok(()) + target_col.assert_decks(); + target_col.assert_notetype(¬etype); + target_col.assert_note_and_media(¬e); + + target_col.undo().unwrap(); + target_col.assert_empty(); +} + +impl Collection { + fn add_sample_decks(&mut self) -> (Deck, Deck) { + let sample = self.add_named_deck("parent\x1fsample"); + self.add_named_deck("parent\x1fsample\x1fchild"); + let siblings = self.add_named_deck("siblings"); + + (sample, siblings) + } + + fn add_named_deck(&mut self, name: &str) -> Deck { + let mut deck = Deck::new_normal(); + deck.name = NativeDeckName::from_native_str(name); + self.add_deck(&mut deck).unwrap(); + deck + } + + fn add_sample_notetype(&mut self) -> Notetype { + let mut nt = Notetype { + name: "sample".into(), + ..Default::default() + }; + nt.add_field("sample"); + nt.add_template("sample1", "{{sample}}", ""); + nt.add_template("sample2", "{{sample}}2", ""); + self.add_notetype(&mut nt, true).unwrap(); + nt + } + + fn add_sample_note( + &mut self, + main_deck: &Deck, + sibling_decks: &Deck, + notetype: &Notetype, + ) -> Note { + let mut sample = notetype.new_note(); + sample.fields_mut()[0] = format!(" [sound:{SAMPLE_MP3}]"); + sample.tags = vec!["sample".into()]; + self.add_note(&mut sample, main_deck.id).unwrap(); + + let card = self + .storage + .get_card_by_ordinal(sample.id, 1) + .unwrap() + .unwrap(); + self.set_deck(&[card.id], sibling_decks.id).unwrap(); + + sample + } + + fn add_sample_media(&self) { + self.add_media(&[ + (SAMPLE_JPG, JPG_DATA), + (SAMPLE_MP3, MP3_DATA), + (SAMPLE_JS, JS_DATA), + ]); + } + + fn add_conflicting_media(&mut self) { + let mut file = File::create(self.media_folder.join(SAMPLE_MP3)).unwrap(); + file.write_all(OTHER_MP3_DATA).unwrap(); + } + + fn assert_decks(&mut self) { + let existing_decks: HashSet<_> = self + .get_all_deck_names(true) + .unwrap() + .into_iter() + .map(|(_, name)| name) + .collect(); + for deck in ["parent", "parent::sample", "siblings"] { + assert!(existing_decks.contains(deck)); + } + assert!(!existing_decks.contains("parent::sample::child")); + } + + fn assert_notetype(&mut self, notetype: &Notetype) { + assert!(self.get_notetype(notetype.id).unwrap().is_some()); + } + + fn assert_note_and_media(&mut self, note: &Note) { + let sha1 = sha1_of_data(MP3_DATA); + let new_mp3_name = format!("sample-{}.mp3", hex::encode(&sha1)); + + for file in [SAMPLE_JPG, SAMPLE_JS, &new_mp3_name] { + assert!(self.media_folder.join(file).exists()) + } + + let imported_note = self.storage.get_note(note.id).unwrap().unwrap(); + assert!(imported_note.fields()[0].contains(&new_mp3_name)); + } + + fn assert_empty(&self) { + assert!(self.get_all_deck_names(true).unwrap().is_empty()); + assert!(self.storage.get_all_note_ids().unwrap().is_empty()); + assert!(self.storage.get_all_card_ids().unwrap().is_empty()); + assert!(self.storage.all_tags().unwrap().is_empty()); + } } diff --git a/rslib/src/lib.rs b/rslib/src/lib.rs index 9e03edc38..dc43db87e 100644 --- a/rslib/src/lib.rs +++ b/rslib/src/lib.rs @@ -40,6 +40,7 @@ mod sync; pub mod tags; pub mod template; pub mod template_filters; +pub(crate) mod tests; pub mod text; pub mod timestamp; pub mod types;