obj-cli 1.0.0

Command-line tools (dump, check, stat, backup) for the obj embedded document database.
Documentation
//! `obj dump` acceptance tests (issue #99).

use assert_cmd::Command;
use obj::{Db, Document};
use predicates::str::contains;
use serde::{Deserialize, Serialize};
use tempfile::TempDir;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct Note {
    title: String,
    body: String,
}

impl Document for Note {
    const COLLECTION: &'static str = "notes";
    const VERSION: u32 = 1;
}

#[test]
fn dump_default_header_format() {
    let dir = TempDir::new().expect("tmp");
    let path = dir.path().join("dump.obj");
    let db = Db::open(&path).expect("open");
    for i in 0..5u32 {
        db.insert(Note {
            title: format!("note-{i}"),
            body: format!("body-{i}"),
        })
        .expect("insert");
    }
    drop(db);

    Command::cargo_bin("obj")
        .expect("binary")
        .arg("dump")
        .arg(&path)
        .arg("--collection")
        .arg("notes")
        .assert()
        .success()
        .stdout(contains("## notes"))
        .stdout(contains("- id:"))
        .stdout(contains("collection_id:"))
        .stdout(contains("type_version:"))
        .stdout(contains("payload_len:"))
        .stdout(contains("payload_crc32c: 0x"))
        .stdout(contains("# emitted: 5"));
}

#[test]
fn dump_limit_truncates_output() {
    let dir = TempDir::new().expect("tmp");
    let path = dir.path().join("dump-limit.obj");
    let db = Db::open(&path).expect("open");
    for i in 0..10u32 {
        db.insert(Note {
            title: format!("note-{i}"),
            body: format!("body-{i}"),
        })
        .expect("insert");
    }
    drop(db);

    Command::cargo_bin("obj")
        .expect("binary")
        .arg("dump")
        .arg(&path)
        .arg("--collection")
        .arg("notes")
        .arg("--limit")
        .arg("3")
        .assert()
        .success()
        .stdout(contains("# emitted: 3"));
}

#[test]
fn dump_hex_format_includes_payload_bytes() {
    let dir = TempDir::new().expect("tmp");
    let path = dir.path().join("dump-hex.obj");
    let db = Db::open(&path).expect("open");
    db.insert(Note {
        title: "t".into(),
        body: "b".into(),
    })
    .expect("insert");
    drop(db);

    Command::cargo_bin("obj")
        .expect("binary")
        .arg("dump")
        .arg(&path)
        .arg("--collection")
        .arg("notes")
        .arg("--format")
        .arg("hex")
        .assert()
        .success()
        .stdout(contains("payload_hex:"));
}

#[test]
fn dump_missing_collection_exits_two() {
    let dir = TempDir::new().expect("tmp");
    let path = dir.path().join("dump-missing.obj");
    let db = Db::open(&path).expect("open");
    db.insert(Note {
        title: "t".into(),
        body: "b".into(),
    })
    .expect("insert");
    drop(db);

    Command::cargo_bin("obj")
        .expect("binary")
        .arg("dump")
        .arg(&path)
        .arg("--collection")
        .arg("does-not-exist")
        .assert()
        .code(2)
        .stderr(contains("error:"));
}