def test_macro_var_scope(self): """Test macro variable scope.""" script = ("macro (foo VAR)\n" "endmacro ()") global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].set_vars[0].node, MatchesStructure(contents=Equals("VAR")))
def test_no_use_by_foreach_var(self): """Test that there is no use for a foreach var.""" script = ("foreach (VAR ${LIST})\n" "endforeach ()") global_scope = find_variables_in_scopes.used_in_tree(ast.parse(script)) self.assertThat(global_scope.used_vars[0].node, MatchesStructure(contents=Not(Equals("VAR"))))
def test_parse_arg_for_col(self, col, statement): """Parse for column number of argument.""" function_call_len = len("function_call (") script = " " * (col - 1) + statement parse_result = ast.parse(script) self.assertEqual(parse_result.statements[0].arguments[0].col, col + function_call_len)
def test_global_scope(self, matcher): """Test setting and finding vars with {} at global scope.""" script = "{0}".format(gen_source_line(matcher)) global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.set_vars[0].node, MatchesStructure(contents=Equals("VALUE")))
def test_exclude_foreach_kws(self, keyword): """Test that there is no use for a foreach keyword.""" script = ("foreach (VAR {0} LIST)\n" "endforeach ()").format(keyword) global_scope = find_variables_in_scopes.used_in_tree(ast.parse(script)) self.assertThat(global_scope.used_vars[0].node, MatchesStructure(contents=Not(Equals(keyword))))
def test_exclude_if_kws(self, keyword): """Test that there is no use for an if keyword.""" script = ("if ({0} OTHER)\n" "endif ()").format(keyword) global_scope = find_variables_in_scopes.used_in_tree(ast.parse(script)) self.assertThat(global_scope.used_vars[0].node, MatchesStructure(contents=Not(Equals(keyword))))
def test_function_call_args(self, contents): """Parse for FunctionCall args.""" body = ast.parse(contents) self.assertTrue(isinstance(body.statements[0].arguments[0], ast.Word)) self.assertTrue(isinstance(body.statements[0].arguments[1], ast.Word))
def test_elseif_statement_has_body(self): """First element of ElseIfStatement body should be FunctionCall.""" body = ast.parse(self.if_else_if_block) elseif_statement = body.statements[0].elseif_statements[0] self.assertTrue(isinstance(elseif_statement.body[0], ast.FunctionCall)) self.assertEqual(elseif_statement.body[0].arguments[0].contents, "ELSEIF")
def lint(contents, whitelist=None, blacklist=None, **kwargs): r"""Actually lints some file contents. Contents should be a raw string with \n. whitelist is a list of checks to only perform, blacklist is list of checks to never perform. """ abstract_syntax_tree = ast.parse(contents) contents_lines = contents.splitlines(True) linter_functions = LINTER_FUNCTIONS def _keyvalue_pair_if(dictionary, condition): """Return a key-value pair in dictionary if condition matched.""" return {k: v for (k, v) in dictionary.items() if condition(k)} def _check_list(check_list, cond): """Return filter function for cond.""" def _check_against_list(key): """Return true if list exists and condition passes.""" return cond(check_list, key) if check_list is not None else True return _check_against_list linter_functions = _keyvalue_pair_if( linter_functions, _check_list(whitelist, lambda l, k: k in l)) linter_functions = _keyvalue_pair_if( linter_functions, _check_list(blacklist, lambda l, k: k not in l)) linter_errors = [] for (code, function) in linter_functions.items(): errors = function(contents_lines, abstract_syntax_tree, **kwargs) for error in errors: linter_errors.append((code, error)) return linter_errors
def test_used_in_macro(self, call): """Test that a variable is marked as used in a macro.""" script = ("macro (name)\n" " f ({0})\n" "endmacro ()\n").format(call) global_scope = find_variables_in_scopes.used_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].used_vars[0], MatchesStructure(source=Equals(VarSrc.MacroVar)))
def test_arguments_depth(self): """Test arguments to a function call have depth.""" tree = ast.parse("function_call (ARGUMENT)") listener = MagicMock() wrapper = _ast_args_to_kwargs_wrapper(listener) ast_visitor.recurse(tree, word=wrapper) self.assertThat(listener.call_args_list[-1][1].items(), Contains(("depth", 2)))
def test_body_depth(self): """Test node body has depth.""" tree = ast.parse("function_call (ARGUMENT)") listener = MagicMock() wrapper = _ast_args_to_kwargs_wrapper(listener) ast_visitor.recurse(tree, function_call=wrapper) self.assertThat(listener.call_args_list[-1][1].items(), Contains(("depth", 1)))
def test_suppress_extraneous_parens(self): """Convert unquoted parens in function arguments to CompoundLiteral.""" parse_result = ast.parse("f ( ( ABC ) )") arguments = parse_result.statements[0].arguments self.assertEqual(arguments[0].type, WordType.CompoundLiteral) self.assertEqual(arguments[1].type, WordType.Variable) self.assertEqual(arguments[2].type, WordType.CompoundLiteral)
def test_used_in_func_foreach(self, call): """Test that a variable is marked as used in a function when nested.""" script = ("function (name)\n" " foreach (VAR {0})" " endforeach ()" "endfunction ()\n").format(call) global_scope = find_variables_in_scopes.used_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].used_vars[0], MatchesStructure(source=Equals(VarSrc.FunctionVar)))
def test_visit(self, node_type, keyword, script): """Visit a node.""" tree = ast.parse(script) listener = MagicMock() wrapper = _ast_args_to_kwargs_wrapper(listener) keywords = {keyword: wrapper} ast_visitor.recurse(tree, **keywords) self.assertThat(listener.call_args_list[-1][1].items(), Contains(("name", node_type)))
def test_in_func_scope(self, matcher): """Test setting and finding vars with {} in function scope.""" script = ("function (foo)\n" " {0}\n" "endfunction ()\n").format(gen_source_line(matcher)) global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].set_vars[0].node, MatchesStructure(contents=Equals("VALUE")))
def test_foreach_in_func(self, matcher): """Test that using {} in an foreach statements propagates variable.""" script = ("function (foo)\n" " foreach (VAR LISTVAR)\n" " {0}\n" " endforeach ()\n" "endfunction ()\n").format(gen_source_line(matcher)) global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].set_vars[0].node, MatchesStructure(contents=Equals("VALUE")))
def test_global_setprop_scope(self): """Test that setting a variable in the set_property scope is global.""" script = ("function (foo)\n" " function (other)\n" " set_property (GLOBAL PROPERTY VARIABLE OTHER)\n" " endfunction ()\n" "endfunction ()\n") global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.set_vars[0].node, MatchesStructure(contents=Equals("VARIABLE")))
def test_parent_scope(self): """Test that setting a variable in the parent scope propagates.""" script = ("function (foo)\n" " function (other)\n" " set (VARIABLE OTHER PARENT_SCOPE)\n" " endfunction ()\n" "endfunction ()\n") global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].set_vars[0].node, MatchesStructure(contents=Equals("VARIABLE")))
def test_while_in_func(self, matcher): """Test that using {} in a while block propagates variable to func.""" script = ("function (foo)\n" " while (CONDITION)\n" " {0}\n" " endwhile (CONDITION)\n" "endfunction ()\n").format(gen_source_line(matcher)) global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].set_vars[0].node, MatchesStructure(contents=Equals("VALUE")))
def test_foreach_scope(self): """Test that setting a variable in an foreach statements propagates.""" script = ("function (foo)\n" " foreach (VAR LISTVAR)\n" " endforeach ()\n" "endfunction ()\n") global_scope = find_variables_in_scopes.set_in_tree(ast.parse(script)) self.assertThat(global_scope.scopes[0].scopes[0].set_vars[0].node, MatchesStructure(contents=Equals("VAR"))) foreach_type = find_variables_in_scopes.ScopeType.Foreach self.assertThat(global_scope.scopes[0].scopes[0].info, MatchesStructure(type=Equals(foreach_type)))
def test_parse_multi_multilines(self): """Parse a multiple multiline strings from arguments.. There should only be two arguments to the passed function and their type should be string """ multiline_string = "\"MULTI\nLINE\nSTRING\"" script_contents = "f ({0} {1})".format(multiline_string, multiline_string) parse_result = ast.parse(script_contents) arguments = parse_result.statements[0].arguments self.assertEqual(len(arguments), 2) self.assertEqual(arguments[0].type, WordType.String) self.assertEqual(arguments[0].contents, multiline_string) self.assertEqual(arguments[1].type, WordType.String) self.assertEqual(arguments[1].contents, multiline_string)
def test_if_block_in_function(self): """Check if block detected inside of function call.""" script = """ function (my_function FOO)\n \n if (FOO)\n \n message (BAR)\n \n endif (FOO)\n \n message (FOO)\n endfunction ()\n """ body = ast.parse(script) function_definition = body.statements[0] self.assertTrue(isinstance(function_definition.body[0], ast.IfBlock))
def do_print(filename): """Print the AST of filename.""" with open(filename) as cmake_file: body = ast.parse(cmake_file.read()) word_print = _print_details( lambda n: "{0} {1}".format(n.type, n.contents)) ast_visitor.recurse(body, while_stmnt=_print_details(), foreach=_print_details(), function_def=_print_details(), macro_def=_print_details(), if_block=_print_details(), if_stmnt=_print_details(), elseif_stmnt=_print_details(), else_stmnt=_print_details(), function_call=_print_details(lambda n: n.name), word=word_print)
def do_print(filename): """Print the AST of filename.""" with open(filename) as cmake_file: body = ast.parse(cmake_file.read()) word_print = _print_details(lambda n: "{0} {1}".format(n.type, n.contents)) ast_visitor.recurse(body, while_stmnt=_print_details(), foreach=_print_details(), function_def=_print_details(), macro_def=_print_details(), if_block=_print_details(), if_stmnt=_print_details(), elseif_stmnt=_print_details(), else_stmnt=_print_details(), function_call=_print_details(lambda n: n.name), word=word_print)
def lint(contents, whitelist=None, blacklist=None, **kwargs): r"""Actually lints some file contents. Contents should be a raw string with \n. whitelist is a list of checks to only perform, blacklist is list of checks to never perform. """ abstract_syntax_tree = ast.parse(contents) contents_lines = contents.splitlines(True) linter_functions = LINTER_FUNCTIONS def _keyvalue_pair_if(dictionary, condition): """Return a key-value pair in dictionary if condition matched.""" return { k: v for (k, v) in dictionary.items() if condition(k) } def _check_list(check_list, cond): """Return filter function for cond.""" def _check_against_list(key): """Return true if list exists and condition passes.""" return cond(check_list, key) if check_list is not None else True return _check_against_list linter_functions = _keyvalue_pair_if(linter_functions, _check_list(whitelist, lambda l, k: k in l)) linter_functions = _keyvalue_pair_if(linter_functions, _check_list(blacklist, lambda l, k: k not in l)) linter_errors = [] for (code, function) in linter_functions.items(): errors = function(contents_lines, abstract_syntax_tree, **kwargs) for error in errors: linter_errors.append((code, error)) return linter_errors
def test_parse_for_col(self, col, statement): """Parse for column number.""" script = " " * (col - 1) + statement parse_result = ast.parse(script) self.assertEqual(parse_result.statements[0].col, col)
def test_macro_footer_name(self): """Parse for macro footer, check if has name endmacro.""" body = ast.parse(self.macro_definition) self.assertEqual(body.statements[0].footer.name, "endmacro")
def test_macro_body(self): """Check that the macro body is a FunctionCall with name message.""" body = ast.parse(self.macro_definition) self.assertEqual(body.statements[0].body[0].name, "message")
import os import os.path import sys import subprocess from glob import glob from cmakeast import ast as cmakeast os.chdir(os.path.dirname(sys.argv[0])) os.chdir('..') ctests = [] test_decs = ['add_unittest', 'add_fulltest'] with open('test/unit/CMakeLists.txt', 'r') as f: ast = cmakeast.parse(f.read()) for s in ast.statements: if isinstance(s, cmakeast.FunctionCall): if s.name in test_decs: args = list(map(lambda x: x.contents, s.arguments)) suit = args[0] tests = args[1:] for t in tests: ctests.append(suit + '_' + t) os.chdir('build') uttests = [] for suit in glob('test/unit/ut-*'): suitname = suit.split('/ut-')[1]
def test_parse_for_if_statement(self): """Parse for IfStatement.""" body = ast.parse(self.if_else_if_block) self.assertTrue(isinstance(body.statements[0].if_statement, ast.IfStatement))
def test_else_statement_has_body(self): """Parse for ElseStatement, first element should be FunctionCall.""" body = ast.parse(self.if_else_if_block) else_statement = body.statements[0].else_statement self.assertTrue(isinstance(else_statement.body[0], ast.FunctionCall)) self.assertEqual(else_statement.body[0].arguments[0].contents, "ELSE")
def test_if_statement_has_body(self): """Parse for IfStatement body first element should be FunctionCall.""" body = ast.parse(self.if_else_if_block) if_statement = body.statements[0].if_statement self.assertTrue(isinstance(if_statement.body[0], ast.FunctionCall)) self.assertEqual(if_statement.body[0].arguments[0].contents, "IF")
def test_elseif_has_header(self): """Parse for ElseIfStatement header - should be a FunctionCall.""" body = ast.parse(self.if_else_if_block) elseif_statement = body.statements[0].elseif_statements[0] self.assertTrue(isinstance(elseif_statement.header, ast.FunctionCall))
def test_parse_for_endif_footer(self): """Parse for footer (endif).""" body = ast.parse(self.if_else_if_block) self.assertTrue(isinstance(body.statements[0].footer, ast.FunctionCall)) self.assertEqual(body.statements[0].footer.name, "endif")
def test_parse_for_line(self, line, statement): """Parse for line numbers.""" script = "\n" * (line - 1) + statement parse_result = ast.parse(script) self.assertEqual(parse_result.statements[0].line, line)
def test_use_at_toplevel(self, call): """Test that a variable is marked as used at the toplevel.""" script = "f ({0})".format(call) global_scope = find_variables_in_scopes.used_in_tree(ast.parse(script)) self.assertThat(global_scope.used_vars[0], MatchesStructure(source=Equals(VarSrc.GlobalVar)))
def test_not_used_in_function_hdr(self): """Test that there is no use in a function header.""" script = ("function (name ARGUMENT)\n" "endfunction ()") global_scope = find_variables_in_scopes.used_in_tree(ast.parse(script)) self.assertEqual(len(global_scope.scopes[0].used_vars), 0)