obj-cli 1.0.0

Command-line tools (dump, check, stat, backup) for the obj embedded document database.
Documentation
//! `obj stat` acceptance tests (issue #99).
//!
//! Populates a small DB via the public `obj` API, invokes the CLI,
//! and asserts on the markdown-section output shape + exit code.

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

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct User {
    email: String,
    handle: String,
}

impl Document for User {
    const COLLECTION: &'static str = "users";
    const VERSION: u32 = 1;

    fn indexes() -> Vec<IndexSpec> {
        vec![IndexSpec::unique("by_email", "email").expect("static spec")]
    }
}

#[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 stat_prints_header_and_collection_sections() {
    let dir = TempDir::new().expect("tmp");
    let path = dir.path().join("stat.obj");
    let db = Db::open(&path).expect("open");
    for i in 0..8u32 {
        db.insert(User {
            email: format!("user{i}@example.com"),
            handle: format!("u{i}"),
        })
        .expect("insert user");
    }
    for i in 0..3u32 {
        db.insert(Note {
            title: format!("note-{i}"),
            body: format!("body-{i}"),
        })
        .expect("insert note");
    }
    drop(db);

    Command::cargo_bin("obj")
        .expect("binary")
        .arg("stat")
        .arg(&path)
        .assert()
        .success()
        .stdout(contains("## file"))
        .stdout(contains("page_size:"))
        .stdout(contains("page_count:"))
        .stdout(contains("format: 0.0"))
        .stdout(contains("collection_count: 2"))
        .stdout(contains("## users"))
        .stdout(contains("## notes"))
        .stdout(contains("doc_count: 8"))
        .stdout(contains("doc_count: 3"))
        .stdout(contains("active_index_count: 1"));
}

#[test]
fn stat_missing_path_exits_two() {
    let dir = TempDir::new().expect("tmp");
    let missing = dir.path().join("no-such-dir").join("never.obj");
    Command::cargo_bin("obj")
        .expect("binary")
        .arg("stat")
        .arg(&missing)
        .assert()
        .code(2)
        .stderr(contains("error:"));
}