openmoat 0.10.0

Policy checks for AI coding agents: decides allow, defer, ask or deny for every tool call from Claude Code, Codex, Cursor, OpenClaw, GitHub Copilot CLI, pi and Gemini CLI, configures Claude Code's, Codex's and Cursor's own OS sandboxes from the same policy, and keeps a local audit log.
use serde_json::json;

use super::parse;

#[test]
fn plain_json_reads_as_serde_json_does() {
    let text = r#"{"a": [1, -2, 3.5, 1e3, true, null], "b": {"c": "dé\n"}}"#;
    let parsed = parse(text).unwrap();
    assert_eq!(
        parsed.value,
        serde_json::from_str::<serde_json::Value>(text).unwrap()
    );
    assert!(!parsed.comments);
}

#[test]
fn json5_syntax_reads_as_its_json_value() {
    let text = "\u{feff}// OpenClaw\n{\n  gateway: { port: 18789, },\n  /* plugins */\n  \
                plugins: { allow: ['a', \"b\",], $x_1: .5, y: 5., z: +1, h: 0xFF, n: -0x10 },\n  \
                'quoted key': 'it\\'s \\x41\\u00e9 \\\n done',\n}\n";
    let parsed = parse(text).unwrap();
    assert!(parsed.comments);
    assert_eq!(
        parsed.value,
        json!({
            "gateway": {"port": 18789},
            "plugins": {"allow": ["a", "b"], "$x_1": 0.5, "y": 5.0, "z": 1, "h": 255, "n": -16},
            "quoted key": "it's A\u{e9}  done",
        })
    );
}

#[test]
fn comment_marks_inside_strings_are_text() {
    let parsed = parse(r#"{"url": "https://x/*y*/", 'p': '//not'}"#).unwrap();
    assert!(!parsed.comments);
    assert_eq!(parsed.value["url"], "https://x/*y*/");
}

#[test]
fn the_last_of_duplicate_keys_wins() {
    assert_eq!(parse("{a: 1, a: 2}").unwrap().value, json!({"a": 2}));
}

#[test]
fn escapes_in_keys_and_surrogate_pairs() {
    let parsed = parse(r#"{ab: "😀"}"#).unwrap();
    assert_eq!(parsed.value, json!({"ab": "\u{1F600}"}));
    assert!(parse(r#"{"x": "\uD83D"}"#).is_err());
}

#[test]
fn what_json_cannot_hold_or_json5_does_not_allow_is_refused() {
    for text in [
        "{a: Infinity}",
        "{a: -Infinity}",
        "{a: NaN}",
        "{a: 01}",
        "{a: 1,,}",
        "{,}",
        "[1 2]",
        "{a 1}",
        "{a: undefined}",
        "{a: 'x\ny'}",
        "{a: '\\1'}",
        "{a: 1} x",
        "/* open",
        "{a: 0x}",
        "{a: 1e}",
        "{a: .}",
        "{a: 12abc}",
        "",
    ] {
        assert!(parse(text).is_err(), "{text:?} should be refused");
    }
}

#[test]
fn deep_nesting_is_refused_not_recursed() {
    let deep = "[".repeat(10_000);
    assert!(parse(&deep).is_err());
    let fine = format!("{}{}", "[".repeat(100), "]".repeat(100));
    assert!(parse(&fine).is_ok());
}

#[test]
fn errors_name_the_line() {
    let error = parse("{\n  a: 1,\n  b: ?\n}").unwrap_err().to_string();
    assert!(error.contains("line 3"), "{error}");
}