osp-cli 1.5.1

CLI and REPL for querying and managing OSP infrastructure data
Documentation
use crate::core::output_model::Group;
use serde_json::json;

use super::{apply, apply_groups, compile};

#[test]
fn project_basic_selection_variants_cover_columns_droppers_and_quoted_terms_unit() {
    let rows = vec![
        json!({"uid": "oistes", "cn": "Oistein", "mail": "o@uio.no"})
            .as_object()
            .cloned()
            .expect("object"),
    ];
    let projected = apply(rows, "uid cn").expect("project should work");
    assert!(projected[0].contains_key("uid"));
    assert!(projected[0].contains_key("cn"));
    assert!(!projected[0].contains_key("mail"));

    let rows = vec![
        json!({"uid": "oistes", "status": "active"})
            .as_object()
            .cloned()
            .expect("object"),
    ];
    let projected = apply(rows, "!status").expect("project should work");
    assert!(projected[0].contains_key("uid"));
    assert!(!projected[0].contains_key("status"));

    let rows = vec![
        json!({"display,name": "Alice", "display": "wrong", "name": "wrong"})
            .as_object()
            .cloned()
            .expect("object"),
    ];
    let projected = apply(rows, "\"display,name\"").expect("project should work");
    assert_eq!(
        projected,
        vec![
            json!({"display,name": "Alice"})
                .as_object()
                .cloned()
                .expect("object")
        ]
    );
}

#[test]
fn project_nested_path_variants_cover_exact_relative_and_absolute_matching_unit() {
    let rows = vec![
        json!({
            "id": 55753,
            "txts": {"id": 27994},
            "ipaddresses": [{"id": 57171}, {"id": 57172}],
            "metadata": {"asset": {"id": 42}}
        })
        .as_object()
        .cloned()
        .expect("object"),
    ];
    let projected = apply(rows, "id").expect("project should work");
    assert_eq!(
        projected,
        vec![
            json!({
                "id": 55753,
                "txts": {"id": 27994},
                "ipaddresses": [{"id": 57171}, {"id": 57172}],
                "metadata": {"asset": {"id": 42}}
            })
            .as_object()
            .cloned()
            .expect("object")
        ]
    );

    let rows = vec![
        json!({"id": 1, "nested": {"id": 2}, "other": {"id": 3}})
            .as_object()
            .cloned()
            .expect("object"),
    ];
    let projected = apply(rows, ".nested.id").expect("project should work");
    assert_eq!(
        projected,
        vec![
            json!({"nested": {"id": 2}})
                .as_object()
                .cloned()
                .expect("object")
        ]
    );

    let rows = vec![
        json!({"metadata": {"asset": {"id": 42}}})
            .as_object()
            .cloned()
            .expect("object"),
    ];
    let projected = apply(rows, "asset.id").expect("project should work");
    assert!(projected.is_empty());
}

#[test]
fn project_fanout_and_dynamic_label_rules_cover_projection_drop_and_ambiguity_unit() {
    let rows = vec![
        json!({
            "interfaces": [
                {"mac": "aa:bb"},
                {"mac": "cc:dd"}
            ]
        })
        .as_object()
        .cloned()
        .expect("object"),
    ];
    let projected = apply(rows, "interfaces[].mac").expect("project should work");
    assert_eq!(projected.len(), 2);
    assert_eq!(projected[0].get("mac"), Some(&json!("aa:bb")));
    assert_eq!(projected[1].get("mac"), Some(&json!("cc:dd")));

    let rows = vec![
        json!({
            "uid": "alice",
            "interfaces": [{"mac": "aa:bb"}, {"mac": "cc:dd"}]
        })
        .as_object()
        .cloned()
        .expect("object"),
    ];
    let projected = apply(rows, "uid interfaces[].mac !mac").expect("project should work");
    assert_eq!(
        projected,
        vec![
            json!({"uid": "alice"})
                .as_object()
                .cloned()
                .expect("object")
        ]
    );

    let rows = vec![
        json!({
            "users": [{"name": "alice"}],
            "groups": [{"name": "ops"}]
        })
        .as_object()
        .cloned()
        .expect("object"),
    ];
    let err = apply(rows, "users[].name groups[].name").expect_err("project should fail");
    assert!(
        err.to_string()
            .contains("ambiguous dynamic projection label `name`")
    );
    assert!(err.to_string().contains("users[].name"));
    assert!(err.to_string().contains("groups[].name"));
}

#[test]
fn project_group_retention_and_compile_guards_cover_empty_specs_and_structural_droppers_unit() {
    let groups = vec![Group {
        groups: json!({"dept": "eng"}).as_object().cloned().expect("object"),
        aggregates: json!({"count": 2}).as_object().cloned().expect("object"),
        rows: vec![
            json!({"uid": "alice"})
                .as_object()
                .cloned()
                .expect("object"),
            json!({"uid": "bob"}).as_object().cloned().expect("object"),
        ],
    }];
    let projected = apply_groups(groups, "missing").expect("group project should work");
    assert_eq!(projected.len(), 1);
    assert!(projected[0].rows.is_empty());
    assert_eq!(projected[0].aggregates.get("count"), Some(&json!(2)));

    let err = apply(
        vec![
            json!({"uid": "alice"})
                .as_object()
                .cloned()
                .expect("object"),
        ],
        "   ",
    )
    .expect_err("empty spec should fail");
    assert!(err.to_string().contains("requires one or more keys"));

    let plan = compile("!sections[0].entries[0]").expect("project should compile");
    assert_eq!(plan.droppers.len(), 1);
    assert!(plan.droppers[0].is_structural());
}