use assert_cmd::prelude::*;
use indoc::indoc;
use predicates::prelude::*;
use conserve::test_fixtures::{ScratchArchive, TreeFixture};
use serde_json::Value;
use crate::run_conserve;
fn setup() -> (ScratchArchive, TreeFixture) {
let af = ScratchArchive::new();
let tf = TreeFixture::new();
tf.create_file_with_contents("hello.c", b"void main() {}");
tf.create_dir("subdir");
run_conserve()
.arg("backup")
.arg(af.path())
.arg(tf.path())
.assert()
.success();
(af, tf)
}
#[test]
fn no_changes() {
let (af, tf) = setup();
run_conserve()
.arg("diff")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(predicate::str::is_empty())
.stderr(predicate::str::is_empty());
run_conserve()
.arg("diff")
.arg("--include-unchanged")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(". /\n. /hello.c\n. /subdir\n")
.stderr(predicate::str::is_empty());
}
#[test]
fn add_entries() {
let (af, tf) = setup();
tf.create_dir("src");
let new_rs_content = b"pub fn main() {}";
tf.create_file_with_contents("src/new.rs", new_rs_content);
run_conserve()
.arg("diff")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(indoc! {"
+ /src
+ /src/new.rs
"})
.stderr(predicate::str::is_empty());
let command = run_conserve()
.args(["diff", "-j"])
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stderr(predicate::str::is_empty());
let diff_json = &command.get_output().stdout;
println!("{}", std::str::from_utf8(diff_json).unwrap());
let diff = serde_json::Deserializer::from_slice(diff_json)
.into_iter::<Value>()
.collect::<Result<Vec<Value>, _>>()
.unwrap();
println!("{diff:#?}");
assert_eq!(diff.len(), 2);
assert_eq!(diff[0]["apath"], "/src");
assert_eq!(diff[0]["added"]["kind"], "Dir");
assert_eq!(diff[0]["added"]["size"], Value::Null);
assert!(diff[0]["added"]["mtime"].is_string());
assert_eq!(diff[1]["apath"], "/src/new.rs");
assert_eq!(diff[1]["added"]["kind"], "File");
assert_eq!(diff[1]["added"]["size"], new_rs_content.len());
assert!(diff[1]["added"]["mtime"].is_string());
}
#[test]
fn remove_file() {
let (af, tf) = setup();
std::fs::remove_file(tf.path().join("hello.c")).unwrap();
run_conserve()
.arg("diff")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout("- /hello.c\n")
.stderr(predicate::str::is_empty());
run_conserve()
.arg("diff")
.arg("--include-unchanged")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(". /\n- /hello.c\n. /subdir\n")
.stderr(predicate::str::is_empty());
}
#[test]
fn change_kind() {
let (af, tf) = setup();
std::fs::remove_dir(tf.path().join("subdir")).unwrap();
tf.create_file_with_contents("subdir", b"used to be a directory, no longer");
run_conserve()
.arg("diff")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(indoc! {"
* /subdir
"})
.stderr(predicate::str::is_empty());
run_conserve()
.arg("diff")
.arg("--include-unchanged")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(indoc! {"
. /
. /hello.c
* /subdir
"})
.stderr(predicate::str::is_empty());
}
#[test]
fn change_file_content() {
let (af, tf) = setup();
tf.create_file_with_contents("hello.c", b"int main() { abort(); }");
run_conserve()
.arg("diff")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(indoc! {"
* /hello.c
"})
.stderr(predicate::str::is_empty());
run_conserve()
.arg("diff")
.arg("--include-unchanged")
.arg(af.path())
.arg(tf.path())
.assert()
.success()
.stdout(indoc! {"
. /
* /hello.c
. /subdir
"})
.stderr(predicate::str::is_empty());
}