Add History::clear() function (#536)

* Add History::clear() function

* Add file-backed history test
This commit is contained in:
Reilly Wood 2023-02-09 04:33:12 -08:00 committed by GitHub
parent 829a1a9f49
commit d83cc56cb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 0 deletions

View File

@ -165,6 +165,8 @@ pub trait History: Send {
id: HistoryItemId,
updater: &dyn Fn(HistoryItem) -> HistoryItem,
) -> Result<()>;
/// delete all history items
fn clear(&mut self) -> Result<()>;
/// remove an item from this history
fn delete(&mut self, h: HistoryItemId) -> Result<()>;
/// ensure that this history is written to disk
@ -322,4 +324,52 @@ mod test {
Ok(())
}
#[test]
fn clear_history() -> Result<()> {
let mut history = create_filled_example_history()?;
assert_ne!(history.count_all()?, 0);
history.clear().unwrap();
assert_eq!(history.count_all()?, 0);
Ok(())
}
// test that clear() works as expected across multiple instances of History
#[test]
fn clear_history_with_backing_file() -> Result<()> {
#[cfg(any(feature = "sqlite", feature = "sqlite-dynlib"))]
fn open_history() -> Box<dyn History> {
Box::new(
crate::SqliteBackedHistory::with_file("target/test-history.db".into()).unwrap(),
)
}
#[cfg(not(any(feature = "sqlite", feature = "sqlite-dynlib")))]
fn open_history() -> Box<dyn History> {
Box::new(
crate::FileBackedHistory::with_file(100, "target/test-history.txt".into()).unwrap(),
)
}
// create history, add a few entries
let mut history = open_history();
history.save(create_item(1, "/home/me", "cd ~/Downloads", 0))?; // 1
history.save(create_item(1, "/home/me/Downloads", "unzp foo.zip", 1))?; // 2
assert_eq!(history.count_all()?, 2);
drop(history);
// open it again and clear it
let mut history = open_history();
assert_eq!(history.count_all()?, 2);
history.clear().unwrap();
assert_eq!(history.count_all()?, 0);
drop(history);
// open it once more and confirm that the cleared data is gone forever
let history = open_history();
assert_eq!(history.count_all()?, 0);
Ok(())
}
}

View File

@ -178,6 +178,19 @@ impl History for FileBackedHistory {
))
}
fn clear(&mut self) -> Result<()> {
self.entries.clear();
self.len_on_disk = 0;
if let Some(file) = &self.file {
if let Err(err) = std::fs::remove_file(file) {
return Err(ReedlineError(ReedlineErrorVariants::IOError(err)));
}
}
Ok(())
}
fn delete(&mut self, _h: super::HistoryItemId) -> Result<()> {
Err(ReedlineError(
ReedlineErrorVariants::HistoryFeatureUnsupported {

View File

@ -136,6 +136,14 @@ impl History for SqliteBackedHistory {
Ok(())
}
fn clear(&mut self) -> Result<()> {
self.db
.execute("delete from history", params![])
.map_err(map_sqlite_err)?;
Ok(())
}
fn delete(&mut self, h: HistoryItemId) -> Result<()> {
let changed = self
.db

View File

@ -15,6 +15,8 @@ pub(crate) enum ReedlineErrorVariants {
history: &'static str,
feature: &'static str,
},
#[error("I/O error: {0}")]
IOError(std::io::Error),
}
/// separate struct to not expose anything to the public (for now)