diff --git a/rslib/src/import_export/package/apkg/import/notes.rs b/rslib/src/import_export/package/apkg/import/notes.rs index 6a8c4b990..9f3a15537 100644 --- a/rslib/src/import_export/package/apkg/import/notes.rs +++ b/rslib/src/import_export/package/apkg/import/notes.rs @@ -252,3 +252,91 @@ impl Notetype { hasher.digest().bytes() } } + +#[cfg(test)] +mod test { + use super::*; + use crate::{collection::open_test_collection, import_export::package::media::SafeMediaEntry}; + + #[test] + fn notes() { + let mut col = open_test_collection(); + let mut media_map = MediaUseMap::default(); + let basic_ntid = col.get_notetype_by_name("basic").unwrap().unwrap().id; + + // a note with a remapped media reference + let mut note_with_media = col.new_note("basic"); + note_with_media.fields_mut()[0] = "".to_string(); + let entry = SafeMediaEntry::from_legacy(("0", "bar.jpg".to_string())).unwrap(); + media_map.add_checked("foo.jpg", entry); + // a note with an id existing in the target, but a unique guid + let mut note_with_existing_id = col.add_new_note("basic"); + note_with_existing_id.guid = "other".to_string(); + // a note of which a later version exists in the target + let mut outdated_note = col.add_new_note("basic"); + outdated_note.mtime.0 -= 1; + outdated_note.fields_mut()[0] = "outdated".to_string(); + // an updated version of a target note, but with a different id + let mut updated_note = col.add_new_note("basic"); + let updated_note_id = updated_note.id; + updated_note.id.0 = 42; + updated_note.mtime.0 += 1; + updated_note.fields_mut()[0] = "updated".to_string(); + // an updated version of a target note, but with a different notetype + let mut updated_note_with_new_nt = col.add_new_note("basic"); + updated_note_with_new_nt.notetype_id.0 = 42; + updated_note_with_new_nt.mtime.0 += 1; + updated_note_with_new_nt.fields_mut()[0] = "updated".to_string(); + // a new note with a remapped notetype + let mut note_with_remapped_nt = col.new_note("basic"); + note_with_remapped_nt.notetype_id.0 = 123; + // a note existing in the target with a remapped notetype + let mut updated_note_with_remapped_nt = col.add_new_note("basic"); + updated_note_with_remapped_nt.notetype_id.0 = 123; + updated_note_with_remapped_nt.mtime.0 += 1; + updated_note_with_remapped_nt.fields_mut()[0] = "updated".to_string(); + + let notes = vec![ + note_with_media.clone(), + note_with_existing_id.clone(), + outdated_note.clone(), + updated_note.clone(), + updated_note_with_new_nt.clone(), + note_with_remapped_nt.clone(), + updated_note_with_remapped_nt.clone(), + ]; + let mut ctx = NoteContext::new(Usn(1), &mut col, &mut media_map).unwrap(); + ctx.remapped_notetypes.insert(NotetypeId(123), basic_ntid); + ctx.import_notes(notes).unwrap(); + + // media is remapped + assert_eq!( + col.get_note_field(note_with_media.id, 0), + "" + ); + // conflicting note id is remapped + assert_ne!(col.note_id_for_guid("other"), note_with_existing_id.id); + // note doesn't overwrite more recent version in target + assert_eq!(col.get_note_field(outdated_note.id, 0), ""); + // note with same guid is updated, regardless of id + assert_eq!(col.get_note_field(updated_note_id, 0), "updated"); + // note is not updated if notetype is different + assert_eq!(col.get_note_field(updated_note_with_new_nt.id, 0), ""); + // notetype id is remapped + assert_eq!( + col.get_note_unwrapped(note_with_remapped_nt.id).notetype_id, + basic_ntid + ); + // note with remapped notetype is not updated + assert_eq!(col.get_note_field(updated_note_with_remapped_nt.id, 0), ""); + } + + impl Collection { + fn note_id_for_guid(&self, guid: &str) -> NoteId { + self.storage + .db + .query_row("SELECT id FROM notes WHERE guid = ?", [guid], |r| r.get(0)) + .unwrap() + } + } +} diff --git a/rslib/src/tests.rs b/rslib/src/tests.rs index 5c1be1818..4400e3453 100644 --- a/rslib/src/tests.rs +++ b/rslib/src/tests.rs @@ -3,6 +3,8 @@ #![cfg(test)] +use std::mem; + use tempfile::{tempdir, TempDir}; use crate::{collection::CollectionBuilder, media::MediaManager, prelude::*}; @@ -35,6 +37,20 @@ impl Collection { .new_note() } + pub(crate) fn add_new_note(&mut self, notetype: &str) -> Note { + let mut note = self.new_note(notetype); + self.add_note(&mut note, DeckId(1)).unwrap(); + note + } + + pub(crate) fn get_note_unwrapped(&self, nid: NoteId) -> Note { + self.storage.get_note(nid).unwrap().unwrap() + } + + pub(crate) fn get_note_field(&self, nid: NoteId, field: usize) -> String { + mem::take(&mut self.get_note_unwrapped(nid).fields_mut()[field]) + } + pub(crate) fn add_deck_with_machine_name(&mut self, name: &str, filtered: bool) -> Deck { let mut deck = new_deck_with_machine_name(name, filtered); self.add_deck_inner(&mut deck, Usn(1)).unwrap();