use unilang_parser:: { Parser, config::UnilangParserOptions };
fn get_arg_value( instruction: &unilang_parser::instruction::GenericInstruction, name: &str ) -> String
{
instruction
.named_arguments
.get( name )
.and_then( | args | args.first() )
.map_or_else( || panic!( "Argument '{name}' not found" ), | arg | arg.value.clone() )
}
#[ test ]
fn test_hash_in_value()
{
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( ".search query::\"Bug #003\"" );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert_eq!( instruction.named_arguments.len(), 1, "Expected 1 named argument" );
let value = get_arg_value( &instruction, "query" );
assert_eq!( value, "Bug #003", "Hash character should be part of value" );
}
#[ test ]
fn test_question_mark_in_value()
{
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( ".cmd arg::test?" );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "arg" );
assert_eq!( value, "test?", "Question mark should be part of value" );
assert!( !instruction.help_requested, "? in value should not trigger help" );
}
#[ test ]
fn test_multiple_values_with_special_chars()
{
let input = ".search query::\"Bug #003\" status::open? max::100";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert_eq!( instruction.named_arguments.len(), 3, "Expected 3 named arguments" );
assert_eq!( get_arg_value( &instruction, "query" ), "Bug #003" );
assert_eq!( get_arg_value( &instruction, "status" ), "open?" );
assert_eq!( get_arg_value( &instruction, "max" ), "100" );
}
#[ test ]
fn test_value_with_path_containing_hash()
{
let input = ".cmd file::path/to/file#123";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "file" );
assert_eq!( value, "path/to/file#123", "Path with # should be preserved" );
}
#[ test ]
fn test_empty_value()
{
let input = ".cmd query::\"\"";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "query" );
assert_eq!( value, "", "Empty value should be preserved" );
}
#[ test ]
fn test_whitespace_terminates_value()
{
let input = ".cmd query::val1 val2";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert_eq!( get_arg_value( &instruction, "query" ), "val1" );
assert_eq!( instruction.positional_arguments.len(), 1, "Expected 1 positional arg" );
assert_eq!( instruction.positional_arguments[0].value, "val2" );
}
#[ test ]
fn test_help_operator_after_value()
{
let input = ".cmd query::\"Bug #003\" ?";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert_eq!( get_arg_value( &instruction, "query" ), "Bug #003" );
assert!( instruction.help_requested, "? operator should trigger help" );
}
#[ test ]
fn test_dot_delimiter_in_value()
{
let input = ".cmd path::file.name.ext";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "path" );
assert_eq!( value, "file.name.ext", "Dots in value should be preserved" );
}
#[ test ]
fn test_slash_in_value()
{
let input = ".cmd path::dir/subdir/file";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "path" );
assert_eq!( value, "dir/subdir/file", "Slashes in value should be preserved" );
}
#[ test ]
fn test_operator_spacing_variant_with_spaces()
{
let input = ".cmd query :: \"Bug #003\"";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "query" );
assert_eq!( value, "Bug #003", "Spaced operator should work identically" );
}
#[ test ]
fn test_parse_from_argv_api_consistency()
{
let parser = Parser::new( UnilangParserOptions::default() );
let argv = vec![
".search".to_string(),
"query::Bug #003".to_string(),
];
let result = parser.parse_from_argv( &argv );
assert!( result.is_ok(), "parse_from_argv failed: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "query" );
assert_eq!( value, "Bug #003", "parse_from_argv should protect special chars" );
}
#[ test ]
fn test_complex_value_with_multiple_delimiters()
{
let input = ".cmd arg::path/to#file.ext?query";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "arg" );
assert_eq!( value, "path/to#file.ext?query", "All delimiters should be preserved in value" );
}
#[ test ]
fn test_value_at_eof()
{
let input = ".cmd query::value#123";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
let value = get_arg_value( &instruction, "query" );
assert_eq!( value, "value#123", "Value at EOF should be fully captured" );
}
#[ test ]
fn test_value_with_tab_delimiter()
{
let input = ".cmd query::val1\tval2";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert_eq!( get_arg_value( &instruction, "query" ), "val1" );
assert_eq!( instruction.positional_arguments.len(), 1 );
assert_eq!( instruction.positional_arguments[0].value, "val2" );
}
#[ test ]
fn test_regression_hash_outside_value_still_errors()
{
let input = ".cmd arg::test #";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_err(), "Expected parse error for # outside value context" );
if let Err( e ) = result
{
let error_msg = format!( "{e:?}" );
assert!(
error_msg.contains( '#' ) || error_msg.contains( "Unexpected token" ),
"Error should mention # or unexpected token, got: {error_msg}"
);
}
}
#[ test ]
fn test_regression_help_operator_alone_still_works()
{
let input = ".cmd ?";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert!( instruction.help_requested, "? alone should trigger help" );
}
#[ test ]
fn test_value_with_newline_delimiter()
{
let input = ".cmd query::val1\nval2";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert_eq!( get_arg_value( &instruction, "query" ), "val1" );
}
#[ test ]
fn test_consecutive_operators_in_value()
{
let input = ".cmd arg1::val1 arg2::val2";
let parser = Parser::new( UnilangParserOptions::default() );
let result = parser.parse_repl_input( input );
assert!( result.is_ok(), "Failed to parse: {:?}", result.err() );
let instruction = result.unwrap();
assert_eq!( get_arg_value( &instruction, "arg1" ), "val1" );
assert_eq!( get_arg_value( &instruction, "arg2" ), "val2" );
}