diff --git a/fish_tests.cpp b/fish_tests.cpp index 35b1a7ff3..8e7c09ebb 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -511,6 +511,20 @@ static void test_iothread(void) delete int_ptr; } +static parser_test_error_bits_t detect_argument_errors(const wcstring &src) +{ + parse_node_tree_t tree; + if (! parse_tree_from_string(src, parse_flag_none, &tree, NULL, symbol_argument_list)) + { + return PARSER_TEST_ERROR; + } + + assert(! tree.empty()); + const parse_node_t *first_arg = tree.next_node_in_node_list(tree.at(0), symbol_argument, NULL); + assert(first_arg != NULL); + return parse_util_detect_errors_in_argument(*first_arg, first_arg->get_source(src)); +} + /** Test the parser */ @@ -592,12 +606,57 @@ static void test_parser() err(L"'and' command in pipeline not reported as error"); } + if (! parse_util_detect_errors(L"cat | or cat")) + { + err(L"'or' command in pipeline not reported as error"); + } + if (! parse_util_detect_errors(L"cat | exec") || ! parse_util_detect_errors(L"exec | cat")) { err(L"'exec' command in pipeline not reported as error"); } + if (detect_argument_errors(L"foo")) + { + err(L"simple argument reported as error"); + } + if (detect_argument_errors(L"''")) + { + err(L"Empty string reported as error"); + } + + + if (! (detect_argument_errors(L"foo$$") & PARSER_TEST_ERROR)) + { + err(L"Bad variable expansion not reported as error"); + } + + if (! (detect_argument_errors(L"foo$@") & PARSER_TEST_ERROR)) + { + err(L"Bad variable expansion not reported as error"); + } + + /* Within command substitutions, we should be able to detect everything that parse_util_detect_errors can detect */ + if (! (detect_argument_errors(L"foo(cat | or cat)") & PARSER_TEST_ERROR)) + { + err(L"Bad command substitution not reported as error"); + } + + if (! (detect_argument_errors(L"foo\\xFF9") & PARSER_TEST_ERROR)) + { + err(L"Bad escape not reported as error"); + } + + if (! (detect_argument_errors(L"foo(echo \\xFF9)") & PARSER_TEST_ERROR)) + { + err(L"Bad escape in command substitution not reported as error"); + } + + if (! (detect_argument_errors(L"foo(echo (echo (echo \\xFF9)))") & PARSER_TEST_ERROR)) + { + err(L"Bad escape in nested command substitution not reported as error"); + } say(L"Testing basic evaluation"); diff --git a/parse_util.cpp b/parse_util.cpp index 2fcb24aa3..e7c1873de 100644 --- a/parse_util.cpp +++ b/parse_util.cpp @@ -1091,6 +1091,8 @@ void parse_util_expand_variable_error(const parse_node_t &node, const wcstring & */ parser_test_error_bits_t parse_util_detect_errors_in_argument(const parse_node_t &node, const wcstring &arg_src, parse_error_list_t *out_errors) { + assert(node.type == symbol_argument); + int err=0; wchar_t *paran_begin, *paran_end; diff --git a/parse_util.h b/parse_util.h index cf885e050..e6ba16536 100644 --- a/parse_util.h +++ b/parse_util.h @@ -171,6 +171,11 @@ std::vector parse_util_compute_indents(const wcstring &src); parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors = NULL); +/** + Test if this argument contains any errors. Detected errors include syntax errors in command substitutions, improperly escaped characters and improper use of the variable expansion operator. + + This does NOT currently detect unterminated quotes. +*/ parser_test_error_bits_t parse_util_detect_errors_in_argument(const parse_node_t &node, const wcstring &arg_src, parse_error_list_t *out_errors = NULL); #endif