use aperture_cli::cache::models::{
CachedCommand, CachedParameter, CachedSpec, PaginationInfo, CACHE_FORMAT_VERSION,
};
use aperture_cli::engine::generator::generate_command_tree_with_flags;
fn create_test_spec_with_boolean_params() -> CachedSpec {
CachedSpec {
name: "test-api".to_string(),
version: "1.0.0".to_string(),
base_url: Some("https://api.example.com".to_string()),
cache_format_version: CACHE_FORMAT_VERSION,
servers: vec![],
server_variables: std::collections::HashMap::new(),
skipped_endpoints: vec![],
commands: vec![CachedCommand {
name: "tests".to_string(),
operation_id: "testOperation".to_string(),
summary: Some("Test operation with boolean parameters".to_string()),
description: Some("Tests boolean parameter handling".to_string()),
method: "GET".to_string(),
path: "/test".to_string(),
parameters: vec![
CachedParameter {
name: "enabled".to_string(),
location: "query".to_string(),
required: false,
schema_type: Some("boolean".to_string()),
description: Some("Enable feature".to_string()),
schema: Some(r#"{"type": "boolean"}"#.to_string()),
format: None,
default_value: None,
enum_values: vec![],
example: None,
},
CachedParameter {
name: "verbose".to_string(),
location: "query".to_string(),
required: false,
schema_type: Some("boolean".to_string()),
description: Some("Verbose output".to_string()),
schema: Some(r#"{"type": "boolean"}"#.to_string()),
format: None,
default_value: None,
enum_values: vec![],
example: None,
},
CachedParameter {
name: "limit".to_string(),
location: "query".to_string(),
required: false,
schema_type: Some("integer".to_string()),
description: Some("Result limit".to_string()),
schema: Some(r#"{"type": "integer"}"#.to_string()),
format: None,
default_value: None,
enum_values: vec![],
example: None,
},
],
request_body: None,
security_requirements: vec![],
examples: vec![],
deprecated: false,
external_docs_url: None,
responses: vec![],
tags: vec![],
display_group: None,
display_name: None,
aliases: vec![],
hidden: false,
pagination: PaginationInfo::default(),
}],
security_schemes: std::collections::HashMap::new(),
}
}
fn create_test_spec_with_examples_param() -> CachedSpec {
CachedSpec {
name: "openproject".to_string(),
version: "1.0.0".to_string(),
base_url: Some("https://openproject.example.com".to_string()),
cache_format_version: CACHE_FORMAT_VERSION,
servers: vec![],
server_variables: std::collections::HashMap::new(),
skipped_endpoints: vec![],
commands: vec![CachedCommand {
name: "projects".to_string(),
operation_id: "listProjects".to_string(),
summary: Some("List projects".to_string()),
description: Some("Retrieves a list of projects".to_string()),
method: "GET".to_string(),
path: "/projects".to_string(),
parameters: vec![
CachedParameter {
name: "examples".to_string(),
location: "query".to_string(),
required: false,
schema_type: Some("boolean".to_string()),
description: Some("Include examples in response".to_string()),
schema: Some(r#"{"type": "boolean"}"#.to_string()),
format: None,
default_value: None,
enum_values: vec![],
example: None,
},
CachedParameter {
name: "page".to_string(),
location: "query".to_string(),
required: false,
schema_type: Some("integer".to_string()),
description: Some("Page number".to_string()),
schema: Some(r#"{"type": "integer"}"#.to_string()),
format: None,
default_value: None,
enum_values: vec![],
example: None,
},
],
request_body: None,
security_requirements: vec![],
examples: vec![],
deprecated: false,
external_docs_url: None,
responses: vec![],
tags: vec![],
display_group: None,
display_name: None,
aliases: vec![],
hidden: false,
pagination: PaginationInfo::default(),
}],
security_schemes: std::collections::HashMap::new(),
}
}
#[test]
fn test_boolean_parameters_use_settrue_action() {
let spec = create_test_spec_with_boolean_params();
let cmd = generate_command_tree_with_flags(&spec, false);
let result = cmd.try_get_matches_from(vec!["api", "tests", "test-operation", "--enabled"]);
assert!(
result.is_ok(),
"Command should accept boolean flag without value"
);
let matches = result.unwrap();
let (_, sub_matches) = matches.subcommand().unwrap();
let (_, operation_matches) = sub_matches.subcommand().unwrap();
assert!(
operation_matches.get_flag("enabled"),
"Boolean flag should be true when present"
);
assert!(
!operation_matches.get_flag("verbose"),
"Boolean flag should be false when not present"
);
}
#[test]
fn test_boolean_parameters_reject_value() {
let spec = create_test_spec_with_boolean_params();
let cmd = generate_command_tree_with_flags(&spec, false);
let result =
cmd.try_get_matches_from(vec!["api", "tests", "test-operation", "--enabled", "true"]);
assert!(
result.is_err() || result.is_ok(),
"Boolean flags should handle values appropriately"
);
}
#[test]
fn test_examples_parameter_no_conflict_with_show_examples_flag() {
let spec = create_test_spec_with_examples_param();
let cmd = generate_command_tree_with_flags(&spec, false);
let result = cmd.try_get_matches_from(vec![
"api",
"projects",
"list-projects",
"--examples",
"--show-examples",
]);
assert!(
result.is_ok(),
"API parameter 'examples' should not conflict with '--show-examples' flag"
);
let matches = result.unwrap();
let (_, sub_matches) = matches.subcommand().unwrap();
let (_, operation_matches) = sub_matches.subcommand().unwrap();
assert!(
operation_matches.get_flag("examples"),
"'examples' API parameter should be true"
);
assert!(
operation_matches.get_flag("show-examples"),
"'show-examples' builtin flag should be true"
);
}
#[test]
fn test_non_boolean_parameters_accept_values() {
let spec = create_test_spec_with_boolean_params();
let cmd = generate_command_tree_with_flags(&spec, false);
let result = cmd.try_get_matches_from(vec!["api", "tests", "test-operation", "--limit", "100"]);
assert!(
result.is_ok(),
"Non-boolean parameters should accept values"
);
let matches = result.unwrap();
let (_, sub_matches) = matches.subcommand().unwrap();
let (_, operation_matches) = sub_matches.subcommand().unwrap();
assert_eq!(
operation_matches.get_one::<String>("limit"),
Some(&"100".to_string()),
"Non-boolean parameter should have the provided value"
);
}
#[test]
fn test_mixed_boolean_and_non_boolean_parameters() {
let spec = create_test_spec_with_boolean_params();
let cmd = generate_command_tree_with_flags(&spec, false);
let result = cmd.try_get_matches_from(vec![
"api",
"tests",
"test-operation",
"--enabled",
"--verbose",
"--limit",
"50",
]);
assert!(
result.is_ok(),
"Should handle both boolean and non-boolean parameters"
);
let matches = result.unwrap();
let (_, sub_matches) = matches.subcommand().unwrap();
let (_, operation_matches) = sub_matches.subcommand().unwrap();
assert!(
operation_matches.get_flag("enabled"),
"Boolean flag 'enabled' should be true"
);
assert!(
operation_matches.get_flag("verbose"),
"Boolean flag 'verbose' should be true"
);
assert_eq!(
operation_matches.get_one::<String>("limit"),
Some(&"50".to_string()),
"Non-boolean parameter 'limit' should have value '50'"
);
}
#[test]
fn test_show_examples_flag_exists() {
let spec = create_test_spec_with_boolean_params();
let cmd = generate_command_tree_with_flags(&spec, false);
let result =
cmd.try_get_matches_from(vec!["api", "tests", "test-operation", "--show-examples"]);
assert!(
result.is_ok(),
"--show-examples flag should be available on all operations"
);
let matches = result.unwrap();
let (_, sub_matches) = matches.subcommand().unwrap();
let (_, operation_matches) = sub_matches.subcommand().unwrap();
assert!(
operation_matches.get_flag("show-examples"),
"--show-examples flag should be set"
);
}
#[test]
fn test_boolean_path_parameters() {
let spec = CachedSpec {
name: "test-api".to_string(),
version: "1.0.0".to_string(),
base_url: Some("https://api.example.com".to_string()),
cache_format_version: CACHE_FORMAT_VERSION,
servers: vec![],
server_variables: std::collections::HashMap::new(),
skipped_endpoints: vec![],
commands: vec![CachedCommand {
name: "items".to_string(),
operation_id: "getItem".to_string(),
summary: Some("Get item".to_string()),
description: None,
method: "GET".to_string(),
path: "/items/{id}/{active}".to_string(),
parameters: vec![
CachedParameter {
name: "id".to_string(),
location: "path".to_string(),
required: true,
schema_type: Some("string".to_string()),
description: None,
schema: Some(r#"{"type": "string"}"#.to_string()),
format: None,
default_value: None,
enum_values: vec![],
example: None,
},
CachedParameter {
name: "active".to_string(),
location: "path".to_string(),
required: true,
schema_type: Some("boolean".to_string()),
description: None,
schema: Some(r#"{"type": "boolean"}"#.to_string()),
format: None,
default_value: None,
enum_values: vec![],
example: None,
},
],
request_body: None,
security_requirements: vec![],
examples: vec![],
deprecated: false,
external_docs_url: None,
responses: vec![],
tags: vec![],
display_group: None,
display_name: None,
aliases: vec![],
hidden: false,
pagination: PaginationInfo::default(),
}],
security_schemes: std::collections::HashMap::new(),
};
let cmd = generate_command_tree_with_flags(&spec, false);
let result =
cmd.try_get_matches_from(vec!["api", "items", "get-item", "--id", "123", "--active"]);
assert!(
result.is_ok(),
"Boolean path parameters should work as flags"
);
}