mod common;
use crate::common::{collection_file, tests_dir};
use itertools::Itertools;
use predicates::{
prelude::{PredicateBooleanExt, predicate},
str::PredicateStrExt,
};
use rstest::rstest;
use slumber_core::{
collection::{CollectionFile, ProfileId, RecipeId},
database::Database,
http::{Exchange, RequestId},
};
use slumber_util::Factory;
use std::{fs, path::Path};
use uuid::Uuid;
const RECIPE1_NO_PROFILE_ID: RequestId =
id("00000000-0000-0000-0000-000000000000");
const RECIPE1_PROFILE1_ID: RequestId =
id("00000000-0000-0000-0000-000000000001");
const RECIPE2_ID: RequestId = id("00000000-0000-0000-0000-000000000002");
const OTHER_COLLECTION_ID: RequestId =
id("00000000-0000-0000-0000-000000000003");
#[test]
fn test_print_path() {
let (mut command, data_dir) = common::slumber();
command.args(["db", "--path"]);
let expected = data_dir.join("state.sqlite").display().to_string();
command
.assert()
.success()
.stdout(predicate::eq(expected).trim());
}
#[rstest]
fn test_collection_list() {
let (mut command, data_dir) = common::slumber();
init_db(&data_dir);
command
.args(["db", "collection", "list"])
.assert()
.success()
.stdout(
predicates::str::contains("slumber.yml")
.and(predicates::str::contains("other.yml")),
);
}
#[test]
fn test_collection_migrate_paths() {
let (mut command, data_dir) = common::slumber();
let database = init_db(&data_dir);
let collections = database.get_collections().unwrap();
assert_eq!(collections.len(), 2);
let first_collection = &collections[0];
assert!(
first_collection.path.ends_with("slumber.yml"),
"Expected target collection to be first in list"
);
command
.args(["db", "collection", "migrate", "other.yml", "slumber.yml"])
.assert()
.success()
.stdout("Migrated other.yml into slumber.yml\n");
let collections = database.get_collections().unwrap();
assert_eq!(collections.len(), 1);
assert_eq!(collections[0].id, first_collection.id);
assert_eq!(database.get_all_requests().unwrap().len(), 4);
}
#[test]
fn test_collection_migrate_ids() {
let (mut command, data_dir) = common::slumber();
let database = init_db(&data_dir);
let collections = database.get_collections().unwrap();
assert_eq!(collections.len(), 2);
let id1 = collections[0].id;
let id2 = collections[1].id;
command
.args([
"db",
"collection",
"migrate",
&id2.to_string(),
&id1.to_string(),
])
.assert()
.success()
.stdout(format!("Migrated {id2} into {id1}\n"));
let collections = database.get_collections().unwrap();
assert_eq!(collections.len(), 1);
assert_eq!(collections[0].id, id1);
assert_eq!(database.get_all_requests().unwrap().len(), 4);
}
#[test]
fn test_collection_delete() {
let (mut command, data_dir) = common::slumber();
let database = init_db(&data_dir);
let collections = database.get_collections().unwrap();
assert_eq!(collections.len(), 2);
let id = collections[0].id;
assert_eq!(database.get_all_requests().unwrap().len(), 4);
command
.args(["db", "collection", "delete", &id.to_string()])
.assert()
.success()
.stdout(format!("Deleted collection {id}\n"));
let collections = database.get_collections().unwrap();
assert_eq!(collections.len(), 1);
assert_ne!(collections[0].id, id); assert_eq!(database.get_all_requests().unwrap().len(), 1);
}
#[test]
fn test_collection_delete_file_missing() {
let (mut command, data_dir) = common::slumber();
let database = Database::from_directory(&data_dir).unwrap();
let collection_path = data_dir.join("slumber.yml");
fs::write(&collection_path, "").unwrap();
let collection_path = collection_path.canonicalize().unwrap();
let collection_file =
CollectionFile::new(Some(collection_path.clone())).unwrap();
let id = database
.clone()
.into_collection(&collection_file)
.unwrap()
.collection_id();
assert_eq!(
database
.get_collections()
.unwrap()
.into_iter()
.map(|collection| collection.id)
.collect::<Vec<_>>(),
[id]
);
fs::remove_file(&collection_path).unwrap();
command
.args([
"db",
"collection",
"delete",
collection_path.to_str().unwrap(),
])
.assert()
.success();
assert_eq!(database.get_collections().unwrap(), []);
}
#[test]
fn test_collection_delete_bad_id() {
let (mut command, _) = common::slumber();
let id = Uuid::new_v4().to_string();
command
.args(["db", "collection", "delete", &id])
.assert()
.failure()
.stderr(format!("Unknown collection `{id}`\n"));
}
#[rstest]
#[case::recipe(
&["db", "request", "list", "recipe1"],
&[RECIPE1_NO_PROFILE_ID, RECIPE1_PROFILE1_ID],
)]
#[case::no_profile(
&["db", "request", "list", "recipe1", "-p"], &[RECIPE1_NO_PROFILE_ID],
)]
#[case::profile(
&["db", "request", "list", "recipe1", "-p", "profile1"], &[RECIPE1_PROFILE1_ID],
)]
#[case::collection(
&["db", "request", "list"],
&[RECIPE1_NO_PROFILE_ID, RECIPE1_PROFILE1_ID, RECIPE2_ID],
)]
#[case::different_collection(
&["-f", "./other.yml", "db", "request", "list"],
&[OTHER_COLLECTION_ID],
)]
#[case::all(
&["db", "request", "list", "--all"],
&[RECIPE1_NO_PROFILE_ID, RECIPE1_PROFILE1_ID, RECIPE2_ID, OTHER_COLLECTION_ID],
)]
fn test_request_list(
#[case] arguments: &[&str],
#[case] expected_requests: &[RequestId],
) {
let (mut command, data_dir) = common::slumber();
init_db(&data_dir);
command.args(arguments).assert().success().stdout(
predicates::function::function(|stdout: &str| {
expected_requests
.iter()
.all(|expected_id| stdout.contains(&expected_id.to_string()))
}),
);
}
#[rstest]
fn test_request_delete() {
let (mut command, data_dir) = common::slumber();
let database = init_db(&data_dir);
command
.args([
"db",
"request",
"delete",
&RECIPE1_PROFILE1_ID.to_string(),
&RECIPE1_NO_PROFILE_ID.to_string(),
])
.assert()
.success();
let remaining = database
.get_all_requests()
.unwrap()
.into_iter()
.map(|exchange| exchange.id)
.sorted()
.collect_vec();
assert_eq!(&remaining, &[RECIPE2_ID, OTHER_COLLECTION_ID]);
}
const fn id(s: &str) -> RequestId {
let Ok(uuid) = Uuid::try_parse(s) else {
panic!("Bad value") };
RequestId(uuid)
}
fn init_db(data_dir: &Path) -> Database {
let database = Database::from_directory(data_dir).unwrap();
let collection1_db = database
.clone()
.into_collection(&collection_file())
.unwrap();
let profile_id: ProfileId = "profile1".into();
let recipe_id: RecipeId = "recipe1".into();
collection1_db
.insert_exchange(&Exchange::factory((
RECIPE1_NO_PROFILE_ID,
None,
recipe_id.clone(),
)))
.unwrap();
collection1_db
.insert_exchange(&Exchange::factory((
RECIPE1_PROFILE1_ID,
Some(profile_id),
recipe_id,
)))
.unwrap();
collection1_db
.insert_exchange(&Exchange::factory((
RECIPE2_ID,
None,
"recipe2".into(),
)))
.unwrap();
let collection2_db = database
.clone()
.into_collection(
&CollectionFile::new(Some(tests_dir().join("other.yml"))).unwrap(),
)
.unwrap();
collection2_db
.insert_exchange(&Exchange::factory(OTHER_COLLECTION_ID))
.unwrap();
database
}