mirror of
https://github.com/ankitects/anki.git
synced 2025-12-12 14:26:55 -05:00
add tests for the other checks, and fix new card due limiting
This commit is contained in:
parent
9b1eee85d5
commit
8af475ac6f
3 changed files with 144 additions and 10 deletions
|
|
@ -22,7 +22,7 @@ pub struct CheckDatabaseOutput {
|
||||||
card_properties_invalid: usize,
|
card_properties_invalid: usize,
|
||||||
card_position_too_high: usize,
|
card_position_too_high: usize,
|
||||||
cards_missing_note: usize,
|
cards_missing_note: usize,
|
||||||
deck_ids_missing: usize,
|
decks_missing: usize,
|
||||||
revlog_properties_invalid: usize,
|
revlog_properties_invalid: usize,
|
||||||
templates_missing: usize,
|
templates_missing: usize,
|
||||||
card_ords_duplicated: usize,
|
card_ords_duplicated: usize,
|
||||||
|
|
@ -51,10 +51,10 @@ impl CheckDatabaseOutput {
|
||||||
tr_args!["count"=>self.cards_missing_note],
|
tr_args!["count"=>self.cards_missing_note],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if self.deck_ids_missing > 0 {
|
if self.decks_missing > 0 {
|
||||||
probs.push(i18n.trn(
|
probs.push(i18n.trn(
|
||||||
TR::DatabaseCheckMissingDecks,
|
TR::DatabaseCheckMissingDecks,
|
||||||
tr_args!["count"=>self.deck_ids_missing],
|
tr_args!["count"=>self.decks_missing],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if self.field_count_mismatch > 0 {
|
if self.field_count_mismatch > 0 {
|
||||||
|
|
@ -123,8 +123,7 @@ impl Collection {
|
||||||
self.check_revlog(&mut out)?;
|
self.check_revlog(&mut out)?;
|
||||||
|
|
||||||
debug!(self.log, "missing decks");
|
debug!(self.log, "missing decks");
|
||||||
let names = self.storage.get_all_deck_names()?;
|
self.check_missing_deck_names(&mut out)?;
|
||||||
self.add_missing_deck_names(&names)?;
|
|
||||||
|
|
||||||
self.update_next_new_position()?;
|
self.update_next_new_position()?;
|
||||||
|
|
||||||
|
|
@ -157,7 +156,7 @@ impl Collection {
|
||||||
fn check_missing_deck_ids(&mut self, out: &mut CheckDatabaseOutput) -> Result<()> {
|
fn check_missing_deck_ids(&mut self, out: &mut CheckDatabaseOutput) -> Result<()> {
|
||||||
for did in self.storage.missing_decks()? {
|
for did in self.storage.missing_decks()? {
|
||||||
self.recover_missing_deck(did)?;
|
self.recover_missing_deck(did)?;
|
||||||
out.deck_ids_missing += 1;
|
out.decks_missing += 1;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -311,6 +310,12 @@ impl Collection {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_missing_deck_names(&mut self, out: &mut CheckDatabaseOutput) -> Result<()> {
|
||||||
|
let names = self.storage.get_all_deck_names()?;
|
||||||
|
out.decks_missing += self.add_missing_deck_names(&names)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn update_next_new_position(&self) -> Result<()> {
|
fn update_next_new_position(&self) -> Result<()> {
|
||||||
let pos = self.storage.max_new_card_position().unwrap_or(0);
|
let pos = self.storage.max_new_card_position().unwrap_or(0);
|
||||||
self.set_next_card_position(pos)
|
self.set_next_card_position(pos)
|
||||||
|
|
@ -353,7 +358,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
out,
|
out,
|
||||||
CheckDatabaseOutput {
|
CheckDatabaseOutput {
|
||||||
deck_ids_missing: 1,
|
decks_missing: 1,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -362,6 +367,58 @@ mod test {
|
||||||
"recovered123"
|
"recovered123"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// missing note
|
||||||
|
col.storage.remove_note(note.id)?;
|
||||||
|
let out = col.check_database()?;
|
||||||
|
assert_eq!(
|
||||||
|
out,
|
||||||
|
CheckDatabaseOutput {
|
||||||
|
cards_missing_note: 1,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
col.storage.db_scalar::<u32>("select count(*) from cards")?,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn revlog() -> Result<()> {
|
||||||
|
let mut col = open_test_collection();
|
||||||
|
|
||||||
|
col.storage.db.execute_batch(
|
||||||
|
"
|
||||||
|
insert into revlog (id,cid,usn,ease,ivl,lastIvl,factor,time,type)
|
||||||
|
values (0,0,0,0,1.5,1.5,0,0,0)",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let out = col.check_database()?;
|
||||||
|
assert_eq!(
|
||||||
|
out,
|
||||||
|
CheckDatabaseOutput {
|
||||||
|
revlog_properties_invalid: 1,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
col.storage
|
||||||
|
.db_scalar::<bool>("select ivl = lastIvl = 1 from revlog")?,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn note_card_link() -> Result<()> {
|
||||||
|
let mut col = open_test_collection();
|
||||||
|
let nt = col.get_notetype_by_name("Basic")?.unwrap();
|
||||||
|
let mut note = nt.new_note();
|
||||||
|
col.add_note(&mut note, DeckID(1))?;
|
||||||
|
|
||||||
// duplicate ordinals
|
// duplicate ordinals
|
||||||
let cid = col.search_cards("", SortMode::NoOrder)?[0];
|
let cid = col.search_cards("", SortMode::NoOrder)?[0];
|
||||||
let mut card = col.storage.get_card(cid)?.unwrap();
|
let mut card = col.storage.get_card(cid)?.unwrap();
|
||||||
|
|
@ -403,4 +460,78 @@ mod test {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn note_fields() -> Result<()> {
|
||||||
|
let mut col = open_test_collection();
|
||||||
|
let nt = col.get_notetype_by_name("Basic")?.unwrap();
|
||||||
|
let mut note = nt.new_note();
|
||||||
|
col.add_note(&mut note, DeckID(1))?;
|
||||||
|
|
||||||
|
// excess fields get joined into the last one
|
||||||
|
col.storage
|
||||||
|
.db
|
||||||
|
.execute_batch("update notes set flds = 'a\x1fb\x1fc\x1fd'")?;
|
||||||
|
let out = col.check_database()?;
|
||||||
|
assert_eq!(
|
||||||
|
out,
|
||||||
|
CheckDatabaseOutput {
|
||||||
|
field_count_mismatch: 1,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let note = col.storage.get_note(note.id)?.unwrap();
|
||||||
|
assert_eq!(¬e.fields, &["a", "b; c; d"]);
|
||||||
|
|
||||||
|
// missing fields get filled with blanks
|
||||||
|
col.storage
|
||||||
|
.db
|
||||||
|
.execute_batch("update notes set flds = 'a'")?;
|
||||||
|
let out = col.check_database()?;
|
||||||
|
assert_eq!(
|
||||||
|
out,
|
||||||
|
CheckDatabaseOutput {
|
||||||
|
field_count_mismatch: 1,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let note = col.storage.get_note(note.id)?.unwrap();
|
||||||
|
assert_eq!(¬e.fields, &["a", ""]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deck_names() -> Result<()> {
|
||||||
|
let mut col = open_test_collection();
|
||||||
|
|
||||||
|
let deck = col.get_or_create_normal_deck("foo::bar::baz")?;
|
||||||
|
// includes default
|
||||||
|
assert_eq!(col.storage.get_all_deck_names()?.len(), 4);
|
||||||
|
|
||||||
|
col.storage
|
||||||
|
.db
|
||||||
|
.prepare("delete from decks where id != ? and id != 1")?
|
||||||
|
.execute(&[deck.id])?;
|
||||||
|
assert_eq!(col.storage.get_all_deck_names()?.len(), 2);
|
||||||
|
|
||||||
|
let out = col.check_database()?;
|
||||||
|
assert_eq!(
|
||||||
|
out,
|
||||||
|
CheckDatabaseOutput {
|
||||||
|
decks_missing: 1, // only counts the immediate parent that was missing
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
&col.storage
|
||||||
|
.get_all_deck_names()?
|
||||||
|
.iter()
|
||||||
|
.map(|(_, name)| name)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&["Default", "foo", "foo::bar", "foo::bar::baz"]
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -215,8 +215,9 @@ impl Collection {
|
||||||
Ok(LegacyDueCounts::from(tree))
|
Ok(LegacyDueCounts::from(tree))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_missing_deck_names(&mut self, names: &[(DeckID, String)]) -> Result<()> {
|
pub(crate) fn add_missing_deck_names(&mut self, names: &[(DeckID, String)]) -> Result<usize> {
|
||||||
let mut parents = HashSet::new();
|
let mut parents = HashSet::new();
|
||||||
|
let mut missing = 0;
|
||||||
for (_id, name) in names {
|
for (_id, name) in names {
|
||||||
parents.insert(UniCase::new(name.as_str()));
|
parents.insert(UniCase::new(name.as_str()));
|
||||||
if let Some(immediate_parent) = name.rsplitn(2, "::").nth(1) {
|
if let Some(immediate_parent) = name.rsplitn(2, "::").nth(1) {
|
||||||
|
|
@ -224,10 +225,11 @@ impl Collection {
|
||||||
if !parents.contains(&immediate_parent_uni) {
|
if !parents.contains(&immediate_parent_uni) {
|
||||||
self.get_or_create_normal_deck(immediate_parent)?;
|
self.get_or_create_normal_deck(immediate_parent)?;
|
||||||
parents.insert(immediate_parent_uni);
|
parents.insert(immediate_parent_uni);
|
||||||
|
missing += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(missing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,5 @@ where
|
||||||
and queue != 4 then 1000000 + due % 1000000
|
and queue != 4 then 1000000 + due % 1000000
|
||||||
else due
|
else due
|
||||||
end
|
end
|
||||||
);
|
)
|
||||||
|
and due >= 1000000;
|
||||||
Loading…
Reference in a new issue