149 lines
5.1 KiB
Rust
149 lines
5.1 KiB
Rust
use super::*;
|
|
use crate::pull_requests::{Direction, ReviewFilter, SortField, SortRule};
|
|
|
|
struct Fixture(PathBuf);
|
|
|
|
impl Fixture {
|
|
fn new() -> Self {
|
|
let path = std::env::temp_dir().join(format!(
|
|
"vamp-pr-preferences-{}-{}",
|
|
std::process::id(),
|
|
NEXT_TEMP.fetch_add(1, Ordering::Relaxed)
|
|
));
|
|
fs::create_dir(&path).unwrap();
|
|
Self(path)
|
|
}
|
|
|
|
fn path(&self) -> PathBuf {
|
|
self.0.join("state/vamp/pull_requests.json")
|
|
}
|
|
}
|
|
|
|
impl Drop for Fixture {
|
|
fn drop(&mut self) {
|
|
let _ = fs::remove_dir_all(&self.0);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn paths_use_absolute_xdg_state_or_home_without_reading_environment() {
|
|
assert_eq!(
|
|
path_from(Some(OsStr::new("/state")), Some(OsStr::new("/home"))).unwrap(),
|
|
PathBuf::from("/state/vamp/pull_requests.json")
|
|
);
|
|
for xdg in [None, Some(OsStr::new("")), Some(OsStr::new("relative"))] {
|
|
assert_eq!(
|
|
path_from(xdg, Some(OsStr::new("/home"))).unwrap(),
|
|
PathBuf::from("/home/.local/state/vamp/pull_requests.json")
|
|
);
|
|
}
|
|
assert!(path_from(None, None).is_err());
|
|
assert!(path_from(None, Some(OsStr::new("relative"))).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn loading_is_lazy_and_applied_preferences_round_trip_atomically() {
|
|
let fixture = Fixture::new();
|
|
let path = fixture.path();
|
|
let (store, mut preferences, notice) = Store::load(Ok(path.clone()));
|
|
assert_eq!(preferences, Preferences::default());
|
|
assert!(notice.is_none());
|
|
assert!(!path.parent().unwrap().exists());
|
|
preferences.filters = vec![ReviewFilter::Approved];
|
|
preferences.sort.insert(
|
|
SortField::UpdatedAt,
|
|
SortRule {
|
|
precedence: Some(1),
|
|
direction: Direction::Asc,
|
|
},
|
|
);
|
|
store.save(&preferences).unwrap();
|
|
let (_, loaded, notice) = Store::load(Ok(path.clone()));
|
|
assert_eq!(loaded.sort, preferences.sort);
|
|
assert_eq!(loaded.filters, Preferences::default().filters);
|
|
assert!(!fs::read_to_string(&path).unwrap().contains("filters"));
|
|
assert!(notice.is_none());
|
|
preferences.filters.clear();
|
|
preferences.sort.clear();
|
|
store.save(&preferences).unwrap();
|
|
assert_eq!(Store::load(Ok(path)).1, Preferences::default());
|
|
assert_eq!(
|
|
fs::read_dir(fixture.0.join("state/vamp")).unwrap().count(),
|
|
1
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn previously_saved_filters_are_ignored_without_changing_sort_or_file() {
|
|
let fixture = Fixture::new();
|
|
let path = fixture.path();
|
|
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
|
for filters in [
|
|
r#"[]"#,
|
|
r#"["approved"]"#,
|
|
r#"["unknown"]"#,
|
|
r#"{"invalid":true}"#,
|
|
] {
|
|
let bytes = format!(
|
|
r#"{{"version":1,"preferences":{{"sort":{{"created_at":{{"precedence":1,"direction":"asc"}}}},"filters":{filters}}}}}"#
|
|
);
|
|
fs::write(&path, &bytes).unwrap();
|
|
let (_, loaded, notice) = Store::load(Ok(path.clone()));
|
|
assert!(notice.is_none());
|
|
assert_eq!(loaded.filters, Preferences::default().filters);
|
|
assert_eq!(loaded.sort[&SortField::CreatedAt].direction, Direction::Asc);
|
|
assert_eq!(fs::read_to_string(&path).unwrap(), bytes);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn corrupt_incompatible_and_invalid_data_is_preserved_even_after_apply() {
|
|
let fixture = Fixture::new();
|
|
let path = fixture.path();
|
|
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
|
for bytes in [
|
|
"not json",
|
|
r#"{"version":2,"preferences":{}}"#,
|
|
r#"{"version":1,"preferences":{"sort":{"unknown":{}}}}"#,
|
|
r#"{"version":1,"preferences":{"sort":{"updated_at":{"direction":"up"}}}}"#,
|
|
r#"{"version":1,"preferences":{"sort":{"updated_at":{"precedence":0}}}}"#,
|
|
r#"{"version":1,"preferences":{"sort":{"updated_at":{"precedence":1},"created_at":{"precedence":1}}}}"#,
|
|
] {
|
|
fs::write(&path, bytes).unwrap();
|
|
let (store, loaded, notice) = Store::load(Ok(path.clone()));
|
|
assert_eq!(loaded, Preferences::default());
|
|
assert!(notice.unwrap().contains("session-only"));
|
|
assert!(store.save(&loaded).unwrap_err().contains("preserved"));
|
|
assert_eq!(fs::read_to_string(&path).unwrap(), bytes);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn failed_writes_and_newly_incompatible_data_are_reported_without_replacement() {
|
|
let fixture = Fixture::new();
|
|
let path = fixture.path();
|
|
let (store, preferences, _) = Store::load(Ok(path.clone()));
|
|
fs::write(fixture.0.join("state"), "keep this file").unwrap();
|
|
assert!(
|
|
store
|
|
.save(&preferences)
|
|
.unwrap_err()
|
|
.contains("session-only")
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(fixture.0.join("state")).unwrap(),
|
|
"keep this file"
|
|
);
|
|
fs::remove_file(fixture.0.join("state")).unwrap();
|
|
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
|
let incompatible = r#"{"version":9,"preferences":{}}"#;
|
|
fs::write(&path, incompatible).unwrap();
|
|
assert!(
|
|
store
|
|
.save(&preferences)
|
|
.unwrap_err()
|
|
.contains("unsupported")
|
|
);
|
|
assert_eq!(fs::read_to_string(path).unwrap(), incompatible);
|
|
}
|