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();