rusty-fmp 0.3.0

JSON CLI and client library for Financial Modeling Prep
Documentation
use std::process::Command;

use httpmock::Method::GET;
use httpmock::MockServer;
use serde_json::json;

#[test]
fn bare_command_prints_help() {
    let output = Command::new(env!("CARGO_BIN_EXE_fmp-agent"))
        .env("CLAP_COLOR", "never")
        .env("FMP_BASE_URL", "")
        .env("NO_COLOR", "1")
        .output()
        .unwrap();

    let help = String::from_utf8(output.stdout).unwrap();
    let stderr = String::from_utf8(output.stderr).unwrap();

    assert!(
        output.status.success(),
        "expected bare command to succeed, got status {:?}\nstdout:\n{}\nstderr:\n{}",
        output.status.code(),
        help,
        stderr
    );
    assert!(stderr.is_empty(), "expected empty stderr, got:\n{stderr}");
    assert!(
        help.contains("Usage: fmp-agent [OPTIONS] <COMMAND>"),
        "expected help usage in stdout, got:\n{help}"
    );
    assert!(
        help.contains("Commands:"),
        "expected commands section in stdout, got:\n{help}"
    );
    assert!(!help.contains("requires a subcommand"));
}

#[test]
fn invalid_argument_uses_clap_error_path() {
    let output = Command::new(env!("CARGO_BIN_EXE_fmp-agent"))
        .arg("--definitely-invalid")
        .env("CLAP_COLOR", "never")
        .env("NO_COLOR", "1")
        .output()
        .unwrap();

    let stdout = String::from_utf8(output.stdout).unwrap();
    let stderr = String::from_utf8(output.stderr).unwrap();

    assert!(!output.status.success());
    assert!(stdout.is_empty(), "expected empty stdout, got:\n{stdout}");
    assert!(
        stderr.contains("unexpected argument '--definitely-invalid'"),
        "expected Clap error in stderr, got:\n{stderr}"
    );
}

#[test]
fn command_invocation_prints_compact_json() {
    let server = MockServer::start();
    let mock = server.mock(|when, then| {
        when.method(GET)
            .path("/search-symbol")
            .query_param("query", "Apple")
            .query_param("apikey", "test-key");
        then.status(200).json_body(json!([{ "symbol": "AAPL" }]));
    });

    let output = Command::new(env!("CARGO_BIN_EXE_fmp-agent"))
        .args([
            "--api-key",
            "test-key",
            "--base-url",
            &format!("{}/", server.base_url()),
            "search",
            "Apple",
        ])
        .output()
        .unwrap();

    mock.assert();

    let stdout = String::from_utf8(output.stdout).unwrap();
    let stderr = String::from_utf8(output.stderr).unwrap();

    assert!(
        output.status.success(),
        "expected command to succeed, got status {:?}\nstdout:\n{}\nstderr:\n{}",
        output.status.code(),
        stdout,
        stderr
    );
    assert!(stderr.is_empty(), "expected empty stderr, got:\n{stderr}");
    assert_eq!(
        stdout.lines().count(),
        1,
        "expected one JSON line, got:\n{stdout}"
    );

    let output: serde_json::Value = serde_json::from_str(stdout.trim_end()).unwrap();
    assert_eq!(output["ok"], true);
    assert_eq!(output["endpoint"], "search-symbol");
    assert_eq!(output["query"], json!({ "query": "Apple" }));
    assert_eq!(output["data"], json!([{ "symbol": "AAPL" }]));
}