use grpctestify::execution::ExecutionPlan;
use grpctestify::parser::{parse_gctf, parse_gctf_from_str};
use std::assert_matches;
use std::fs;
use std::path::Path;
#[test]
fn test_explain_rpc_mode_unary() {
let test_cases = vec![
"tests/gctf/basic/unary.gctf",
"examples/basic/unary.gctf",
"examples/basic/partial-match.gctf",
"examples/basic/tolerance.gctf",
];
for path in test_cases {
if !Path::new(path).exists() {
continue;
}
let doc = parse_gctf(Path::new(path));
assert!(doc.is_ok(), "Failed to parse {}", path);
let plan = ExecutionPlan::from_document(&doc.unwrap());
assert_matches!(
plan.rpc_mode,
grpctestify::execution::RpcMode::Unary,
"Expected Unary mode for {}, got {:?}",
path,
plan.rpc_mode
);
}
}
#[test]
fn test_explain_rpc_mode_server_streaming() {
let test_cases = vec![
"tests/gctf/streaming/server-streaming.gctf",
"examples/streaming/server-streaming.gctf",
];
for path in test_cases {
if !Path::new(path).exists() {
continue;
}
let doc = parse_gctf(Path::new(path));
assert!(doc.is_ok(), "Failed to parse {}", path);
let plan = ExecutionPlan::from_document(&doc.unwrap());
assert_matches!(
plan.rpc_mode,
grpctestify::execution::RpcMode::ServerStreaming { .. },
"Expected ServerStreaming mode for {}, got {:?}",
path,
plan.rpc_mode
);
}
}
#[test]
fn test_explain_rpc_mode_client_streaming() {
let test_cases = vec![
"tests/gctf/streaming/client-streaming.gctf",
"examples/streaming/client-streaming.gctf",
];
for path in test_cases {
if !Path::new(path).exists() {
continue;
}
let doc = parse_gctf(Path::new(path));
assert!(doc.is_ok(), "Failed to parse {}", path);
let plan = ExecutionPlan::from_document(&doc.unwrap());
assert_matches!(
plan.rpc_mode,
grpctestify::execution::RpcMode::ClientStreaming { .. },
"Expected ClientStreaming mode for {}, got {:?}",
path,
plan.rpc_mode
);
}
}
#[test]
fn test_explain_rpc_mode_unary_error() {
let test_cases = vec![
"tests/gctf/error-handling/expected-error.gctf",
"examples/error-handling/expected-error.gctf",
];
for path in test_cases {
if !Path::new(path).exists() {
continue;
}
let doc = parse_gctf(Path::new(path));
assert!(doc.is_ok(), "Failed to parse {}", path);
let plan = ExecutionPlan::from_document(&doc.unwrap());
assert_matches!(
plan.rpc_mode,
grpctestify::execution::RpcMode::UnaryError,
"Expected UnaryError mode for {}, got {:?}",
path,
plan.rpc_mode
);
}
}
#[test]
fn test_explain_against_fixture() {
let fixture_path = "tests/fixtures/explain/basic-unary.json";
let gctf_path = "tests/gctf/basic/unary.gctf";
if !Path::new(fixture_path).exists() || !Path::new(gctf_path).exists() {
return;
}
let doc = parse_gctf(Path::new(gctf_path)).unwrap();
let plan = ExecutionPlan::from_document(&doc);
let expected_json = fs::read_to_string(fixture_path).unwrap();
let expected: serde_json::Value = serde_json::from_str(&expected_json).unwrap();
let actual_json = serde_json::to_value(&plan).unwrap();
assert_eq!(
actual_json["rpc_mode"], expected["rpc_mode"],
"RPC mode mismatch"
);
assert_eq!(
actual_json["summary"]["total_requests"], expected["summary"]["total_requests"],
"Total requests mismatch"
);
assert_eq!(
actual_json["summary"]["total_responses"], expected["summary"]["total_responses"],
"Total responses mismatch"
);
}
#[test]
fn test_explain_multiple_requests() {
let test_cases = vec![
(
"examples/streaming/client-streaming.gctf",
"ClientStreaming",
),
(
"examples/streaming/server-streaming.gctf",
"ServerStreaming",
),
];
for (path, expected_mode) in test_cases {
if !Path::new(path).exists() {
continue;
}
let doc = parse_gctf(Path::new(path));
assert!(doc.is_ok(), "Failed to parse {}", path);
let plan = ExecutionPlan::from_document(&doc.unwrap());
let mode_str = format!("{:?}", plan.rpc_mode);
assert!(
mode_str.contains(expected_mode),
"Expected mode '{}' in '{}', got '{}'",
expected_mode,
path,
mode_str
);
}
}
#[test]
fn test_explain_with_extractions() {
let path = "examples/variables/extract-basic.gctf";
if !Path::new(path).exists() {
return;
}
let doc = match parse_gctf(Path::new(path)) {
Ok(d) => d,
Err(_) => return,
};
let plan = ExecutionPlan::from_document(&doc);
assert!(!plan.extractions.is_empty(), "Extractions should exist");
}
#[test]
fn test_explain_with_assertions() {
let path = "examples/assertions/response-with-asserts.gctf";
if !Path::new(path).exists() {
return;
}
let doc = parse_gctf(Path::new(path)).unwrap();
let plan = ExecutionPlan::from_document(&doc);
assert!(!plan.assertions.is_empty(), "Expected assertions, got none");
}
#[test]
fn test_explain_summary_accuracy() {
let test_cases = vec![
("examples/basic/unary.gctf", 1, 1, false, 0),
("examples/basic/with-headers.gctf", 1, 1, false, 0),
("examples/error-handling/expected-error.gctf", 1, 0, true, 0),
];
for (path, expected_requests, expected_responses, expected_error, _expected_asserts) in
test_cases
{
if !Path::new(path).exists() {
continue;
}
let doc = match parse_gctf(Path::new(path)) {
Ok(d) => d,
Err(_) => continue,
};
let plan = ExecutionPlan::from_document(&doc);
assert_eq!(
plan.summary.total_requests, expected_requests,
"Total requests mismatch for {}",
path
);
assert_eq!(
plan.summary.total_responses, expected_responses,
"Total responses mismatch for {}",
path
);
assert_eq!(
plan.summary.error_expected, expected_error,
"Error expected mismatch for {}",
path
);
}
}
#[test]
fn test_explain_error_partial_and_with_asserts_via_ast() {
let content = r#"--- ENDPOINT ---
tasktracker.TaskService/CompleteTask
--- REQUEST ---
{
"task_id": "task-42"
}
--- ERROR partial=true with_asserts=true ---
{
"code": 5
}
--- ASSERTS ---
.message contains "Can't find stub"
"#;
let doc = parse_gctf_from_str(content, "issue-40-error-options.gctf").unwrap();
let plan = ExecutionPlan::from_document(&doc);
assert_eq!(plan.summary.total_errors, 1);
assert!(plan.summary.error_expected);
assert_eq!(plan.assertions.len(), 1);
let error = plan
.expectations
.iter()
.find(|e| e.expectation_type == "error")
.expect("error expectation");
assert!(error.comparison_options.partial);
assert!(error.comparison_options.with_asserts);
}