use super::*;
use crate::autocomplete::jq_functions::JQ_FUNCTION_METADATA;
use proptest::prelude::*;
fn get_functions_requiring_args() -> Vec<&'static crate::autocomplete::jq_functions::JqFunction> {
JQ_FUNCTION_METADATA
.iter()
.filter(|f| f.needs_parens)
.collect()
}
fn get_functions_not_requiring_args() -> Vec<&'static crate::autocomplete::jq_functions::JqFunction>
{
JQ_FUNCTION_METADATA
.iter()
.filter(|f| !f.needs_parens)
.collect()
}
#[test]
fn test_all_functions_requiring_args_get_parenthesis() {
let funcs = get_functions_requiring_args();
assert!(
!funcs.is_empty(),
"Should have functions requiring arguments"
);
for func in funcs {
let suggestion = Suggestion::new(func.name, SuggestionType::Function)
.with_needs_parens(true)
.with_signature(func.signature);
let partial = &func.name[..func.name.len().min(3)];
let (mut textarea, mut query_state) = setup_insertion_test(partial);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
let expected_suffix = format!("{}(", func.name);
assert!(
result.ends_with(&expected_suffix),
"Function '{}' with needs_parens=true should result in '{}' but got '{}'",
func.name,
expected_suffix,
result
);
}
}
#[test]
fn test_all_functions_not_requiring_args_get_no_parenthesis() {
let funcs = get_functions_not_requiring_args();
assert!(
!funcs.is_empty(),
"Should have functions not requiring arguments"
);
for func in funcs {
let suggestion = Suggestion::new(func.name, SuggestionType::Function)
.with_needs_parens(false)
.with_signature(func.signature);
let partial = &func.name[..func.name.len().min(3)];
let (mut textarea, mut query_state) = setup_insertion_test(partial);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
assert!(
result.ends_with(func.name),
"Function '{}' with needs_parens=false should end with '{}' but got '{}'",
func.name,
func.name,
result
);
assert!(
!result.ends_with(&format!("{}(", func.name)),
"Function '{}' with needs_parens=false should NOT have '(' appended, but got '{}'",
func.name,
result
);
}
}
#[test]
fn test_all_functions_cursor_positioned_correctly() {
let funcs = get_functions_requiring_args();
assert!(
!funcs.is_empty(),
"Should have functions requiring arguments"
);
for func in funcs {
let suggestion = Suggestion::new(func.name, SuggestionType::Function)
.with_needs_parens(true)
.with_signature(func.signature);
let partial = &func.name[..func.name.len().min(3)];
let (mut textarea, mut query_state) = setup_insertion_test(partial);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
let cursor_col = textarea.cursor().1;
let expected_cursor_pos = result.len();
assert_eq!(
cursor_col, expected_cursor_pos,
"Cursor should be at position {} (end of '{}') but was at {}",
expected_cursor_pos, result, cursor_col
);
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_object_key_context_insertion_replaces_partial(
has_prefix in prop::bool::ANY, prefix_key in "[a-z]{2,6}", partial in "[a-z]{1,4}", suffix in "[a-z]{1,6}", ) {
let suggestion = format!("{}{}", partial, suffix);
let prefix = if has_prefix {
format!("{{{}: .{}, ", prefix_key, prefix_key)
} else {
"{".to_string()
};
let initial_query = format!("{}{}", prefix, partial);
let (mut textarea, mut query_state) = setup_insertion_test(&initial_query);
let suggestion_obj = Suggestion::new(&suggestion, SuggestionType::Field);
insert_suggestion(&mut textarea, &mut query_state, &suggestion_obj);
let result = textarea.lines()[0].clone();
let expected = format!("{}{}", prefix, suggestion);
prop_assert_eq!(
result.clone(),
expected.clone(),
"ObjectKeyContext insertion should replace partial '{}' with suggestion '{}'. Initial: '{}', Expected: '{}', Got: '{}'",
partial,
suggestion,
initial_query,
expected,
result
);
let cursor_col = textarea.cursor().1;
let expected_cursor_pos = expected.len();
prop_assert_eq!(
cursor_col,
expected_cursor_pos,
"Cursor should be at position {} (end of '{}') but was at {}",
expected_cursor_pos,
result,
cursor_col
);
}
}
#[test]
fn test_object_key_context_insertion_simple() {
let initial_query = "{na";
let (mut textarea, mut query_state) = setup_insertion_test(initial_query);
let suggestion = Suggestion::new("name", SuggestionType::Field);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
assert_eq!(
result, "{name",
"ObjectKeyContext insertion should replace 'na' with 'name'. Got: '{}'",
result
);
let cursor_col = textarea.cursor().1;
assert_eq!(
cursor_col, 5,
"Cursor should be at position 5 (end of '{{name')"
);
}
#[test]
fn test_object_key_context_insertion_after_comma() {
let initial_query = "{name: .name, ag";
let (mut textarea, mut query_state) = setup_insertion_test(initial_query);
let suggestion = Suggestion::new("age", SuggestionType::Field);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
assert_eq!(
result, "{name: .name, age",
"ObjectKeyContext insertion should replace 'ag' with 'age'. Got: '{}'",
result
);
let cursor_col = textarea.cursor().1;
assert_eq!(
cursor_col, 17,
"Cursor should be at position 17 (end of '{{name: .name, age')"
);
}
#[test]
fn test_object_key_context_insertion_with_space_after_comma() {
let initial_query = "{name: .name, ag";
let (mut textarea, mut query_state) = setup_insertion_test(initial_query);
let suggestion = Suggestion::new("age", SuggestionType::Field);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
assert_eq!(result, "{name: .name, age");
}
#[test]
fn test_object_key_context_insertion_nested_object() {
let initial_query = "{outer: {in";
let (mut textarea, mut query_state) = setup_insertion_test(initial_query);
let suggestion = Suggestion::new("inner", SuggestionType::Field);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
assert_eq!(
result, "{outer: {inner",
"ObjectKeyContext insertion in nested object should work. Got: '{}'",
result
);
}
#[test]
fn test_object_key_context_insertion_longer_partial() {
let initial_query = "{servi";
let (mut textarea, mut query_state) = setup_insertion_test(initial_query);
let suggestion = Suggestion::new("services", SuggestionType::Field);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
assert_eq!(
result, "{services",
"ObjectKeyContext insertion with longer partial should work. Got: '{}'",
result
);
}
#[test]
fn test_object_key_context_insertion_single_char_partial() {
let initial_query = "{n";
let (mut textarea, mut query_state) = setup_insertion_test(initial_query);
let suggestion = Suggestion::new("name", SuggestionType::Field);
insert_suggestion(&mut textarea, &mut query_state, &suggestion);
let result = textarea.lines()[0].clone();
assert_eq!(
result, "{name",
"ObjectKeyContext insertion with single char partial should work. Got: '{}'",
result
);
}