cadmpeg 0.6.6

Convert and inspect native CAD files.
// SPDX-License-Identifier: Apache-2.0
//! `cadmpeg query join` integration tests.

#![allow(clippy::unwrap_used)]

use predicates::prelude::{predicate, PredicateBooleanExt};
use tempfile::tempdir;

mod query_support;
mod support;

use crate::query_support::write;
use crate::support::cadmpeg;

const CHECK_REPORT: &str = r#"{
  "ir_version": "8",
  "command": "check",
  "status": "ok",
  "refusal": null
}"#;

const JOIN_DOC: &str = r#"{
  "ir_version": "8",
  "model": {
    "features": [
      {"id": "f1", "native_ref": "n1"},
      {"id": "f2", "native_ref": "missing"}
    ]
  },
  "native": {
    "rhino": {
      "unknowns": [
        {"id": "n1", "kind": "curve"},
        {"id": "n2", "kind": "other"}
      ]
    }
  }
}"#;

const RIGHT_DOC: &str = r#"{
  "ir_version": "8",
  "native": {
    "rhino": {
      "unknowns": [
        {"id": "other-id", "name": "n1"}
      ]
    }
  }
}"#;

#[test]
fn join_help_mentions_left_key() {
    cadmpeg()
        .args(["query", "join", "--help"])
        .assert()
        .success()
        .stdout(
            predicate::str::contains("--left-key")
                .and(predicate::str::contains("--right-key"))
                .and(predicate::str::contains("--mode"))
                .and(predicate::str::contains("--right-file"))
                .and(predicate::str::contains("left.id,right.links")),
        );
}

#[test]
fn join_unknown_arena_teaches() {
    let dir = tempdir().unwrap();
    let doc = write(dir.path(), "doc.json", JOIN_DOC);
    let missing = cadmpeg()
        .args([
            "query",
            "join",
            doc.to_str().unwrap(),
            "model.bogus",
            "native.rhino.unknowns",
            "--left-key",
            "native_ref",
            "--right-key",
            "id",
        ])
        .output()
        .unwrap();
    assert_eq!(missing.status.code(), Some(2));
    let stderr = String::from_utf8_lossy(&missing.stderr);
    assert!(stderr.contains("unknown arena model.bogus"), "{stderr}");
    assert!(stderr.contains("addressable arenas"), "{stderr}");
}

#[test]
fn join_rejects_report() {
    let dir = tempdir().unwrap();
    let report = write(dir.path(), "report.json", CHECK_REPORT);
    cadmpeg()
        .args([
            "query",
            "join",
            report.to_str().unwrap(),
            "model.features",
            "native.rhino.unknowns",
            "--left-key",
            "native_ref",
            "--right-key",
            "id",
        ])
        .assert()
        .code(2)
        .stderr(
            predicate::str::contains("command report").and(predicate::str::contains("dump SOURCE")),
        );
}

#[test]
fn join_json_envelope_matched_native_ref() {
    let dir = tempdir().unwrap();
    let doc = write(dir.path(), "doc.json", JOIN_DOC);
    let output = cadmpeg()
        .args([
            "query",
            "join",
            "--json",
            doc.to_str().unwrap(),
            "model.features",
            "native.rhino.unknowns",
            "--left-key",
            "native_ref",
            "--right-key",
            "id",
        ])
        .output()
        .unwrap();
    assert!(
        output.status.success(),
        "{}",
        String::from_utf8_lossy(&output.stderr)
    );
    let value: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
    assert_eq!(value["command"], "query");
    let rows = value["payload"].as_array().unwrap();
    assert_eq!(rows.len(), 1);
    assert_eq!(rows[0]["key"], "n1");
    assert_eq!(rows[0]["left"]["id"], "f1");
    assert_eq!(rows[0]["right"]["id"], "n1");
    assert_eq!(rows[0]["left_arena"], "model.features");
    assert_eq!(rows[0]["right_arena"], "native.rhino.unknowns");
}

#[test]
fn join_unmatched_and_right_file() {
    let dir = tempdir().unwrap();
    let left = write(dir.path(), "left.json", JOIN_DOC);
    let right = write(dir.path(), "right.json", RIGHT_DOC);

    let unmatched = cadmpeg()
        .args([
            "query",
            "join",
            "--json",
            left.to_str().unwrap(),
            "model.features",
            "native.rhino.unknowns",
            "--left-key",
            "native_ref",
            "--right-key",
            "id",
            "--mode",
            "unmatched",
        ])
        .output()
        .unwrap();
    assert!(unmatched.status.success());
    let value: serde_json::Value = serde_json::from_slice(&unmatched.stdout).unwrap();
    let rows = value["payload"].as_array().unwrap();
    assert_eq!(rows.len(), 1);
    assert_eq!(rows[0]["left"]["id"], "f2");
    assert_eq!(rows[0]["right"], serde_json::Value::Null);

    let cross = cadmpeg()
        .args([
            "query",
            "join",
            "--json",
            left.to_str().unwrap(),
            "model.features",
            "native.rhino.unknowns",
            "--left-key",
            "native_ref",
            "--right-key",
            "name",
            "--right-file",
            right.to_str().unwrap(),
        ])
        .output()
        .unwrap();
    assert!(
        cross.status.success(),
        "{}",
        String::from_utf8_lossy(&cross.stderr)
    );
    let value: serde_json::Value = serde_json::from_slice(&cross.stdout).unwrap();
    let rows = value["payload"].as_array().unwrap();
    assert_eq!(rows.len(), 1);
    assert_eq!(rows[0]["key"], "n1");
    assert_eq!(rows[0]["left"]["id"], "f1");
    assert_eq!(rows[0]["right"]["id"], "other-id");
    assert_eq!(rows[0]["left_file"], left.to_str().unwrap());
    assert_eq!(rows[0]["right_file"], right.to_str().unwrap());
}

#[test]
fn join_requires_keys() {
    let dir = tempdir().unwrap();
    let doc = write(dir.path(), "doc.json", JOIN_DOC);
    cadmpeg()
        .args([
            "query",
            "join",
            doc.to_str().unwrap(),
            "model.features",
            "native.rhino.unknowns",
        ])
        .assert()
        .failure()
        .stderr(predicate::str::contains("left-key"));
}