def test_ast_NodevVisitor(self): class Visitor(ast.NodeVisitor): def __init__(self): self.test_names = [] self.kw_names = [] self.names = None def visit_TestCaseSection(self, node): self.names = self.test_names self.generic_visit(node) def visit_KeywordSection(self, node): self.names = self.kw_names self.generic_visit(node) def visit_Name(self, node): self.names.append(node.name) def visit_Block(self, node): raise RuntimeError('Should not be executed.') def visit_Statement(self, node): raise RuntimeError('Should not be executed.') visitor = Visitor() visitor.visit(get_model(DATA)) assert_equal(visitor.test_names, ['Example']) assert_equal(visitor.kw_names, ['Keyword'])
def test_continue(self): model = get_model('''\ *** Keywords *** Name FOR ${x} IN @{stuff} Continue CONTINUE CONTINUE END ''', data_only=True) expected = KeywordSection( header=SectionHeader( tokens=[Token(Token.KEYWORD_HEADER, '*** Keywords ***', 1, 0)] ), body=[ Keyword( header=KeywordName( tokens=[Token(Token.KEYWORD_NAME, 'Name', 2, 0)] ), body=[ For( header=ForHeader([Token(Token.FOR, 'FOR', 3, 4), Token(Token.VARIABLE, '${x}', 3, 11), Token(Token.FOR_SEPARATOR, 'IN', 3, 19), Token(Token.ARGUMENT, '@{stuff}', 3, 25)]), body=[KeywordCall([Token(Token.KEYWORD, 'Continue', 4, 8), Token(Token.ARGUMENT, 'CONTINUE', 4, 20)]), Continue([Token(Token.CONTINUE, 'CONTINUE', 5, 8)])], end=End([Token(Token.END, 'END', 6, 4)]) ) ], ) ] ) assert_model(model.sections[0], expected)
def test_ModelVisitor(self): class Visitor(ModelVisitor): def __init__(self): self.test_names = [] self.kw_names = [] self.blocks = [] self.statements = [] def visit_TestCaseName(self, node): self.test_names.append(node.name) self.visit_Statement(node) def visit_KeywordName(self, node): self.kw_names.append(node.name) self.visit_Statement(node) def visit_Block(self, node): self.blocks.append(type(node).__name__) self.generic_visit(node) def visit_Statement(self, node): self.statements.append(node.type) visitor = Visitor() visitor.visit(get_model(DATA)) assert_equal(visitor.test_names, ['Example']) assert_equal(visitor.kw_names, ['Keyword']) assert_equal(visitor.blocks, [ 'File', 'CommentSection', 'Body', 'TestCaseSection', 'Body', 'TestCase', 'Body', 'KeywordSection', 'Body', 'Keyword', 'Body' ]) assert_equal(visitor.statements, [ 'EOL', 'TESTCASE_HEADER', 'TESTCASE_NAME', 'KEYWORD', 'EOL', 'KEYWORD_HEADER', 'KEYWORD_NAME', 'ARGUMENTS', 'KEYWORD' ])
def test_nested(self): model = get_model('''\ *** Test Cases *** Example IF ${x} IF ${y} K1 ELSE IF ${z} K2 ''', data_only=True) node = model.sections[0].body[0].body[0] expected = If( header=InlineIfHeader([Token(Token.INLINE_IF, 'IF', 3, 4), Token(Token.ARGUMENT, '${x}', 3, 10)]), body=[If( header=InlineIfHeader([Token(Token.INLINE_IF, 'IF', 3, 18), Token(Token.ARGUMENT, '${y}', 3, 24)]), body=[KeywordCall([Token(Token.KEYWORD, 'K1', 3, 32)])], orelse=If( header=ElseHeader([Token(Token.ELSE, 'ELSE', 3, 38)]), body=[If( header=InlineIfHeader([Token(Token.INLINE_IF, 'IF', 3, 46), Token(Token.ARGUMENT, '${z}', 3, 52)]), body=[KeywordCall([Token(Token.KEYWORD, 'K2', 3, 60)])], end=End([Token(Token.END, '', 3, 62)]), )], ), errors=('Inline IF cannot be nested.',), )], errors=('Inline IF cannot be nested.',), ) assert_model(node, expected)
def test_valid(self): model = get_model('''\ *** Test Cases *** Example FOR ${x} IN a b c Log ${x} END ''', data_only=True) loop = model.sections[0].body[0].body[0] expected = ForLoop(header=ForLoopHeader([ Token(Token.FOR, 'FOR', 3, 4), Token(Token.VARIABLE, '${x}', 3, 11), Token(Token.FOR_SEPARATOR, 'IN', 3, 19), Token(Token.ARGUMENT, 'a', 3, 25), Token(Token.ARGUMENT, 'b', 3, 30), Token(Token.ARGUMENT, 'c', 3, 35), ]), body=[ KeywordCall([ Token(Token.KEYWORD, 'Log', 4, 8), Token(Token.ARGUMENT, '${x}', 4, 15) ]) ], end=End([Token(Token.END, 'END', 5, 4)])) assert_model(loop, expected)
def test_model_error(self): model = get_model('''\ *** Invalid *** *** Settings *** Invalid Documentation ''', data_only=True) inv_header = ( "Unrecognized section header '*** Invalid ***'. Valid sections: " "'Settings', 'Variables', 'Test Cases', 'Tasks', 'Keywords' and 'Comments'." ) inv_setting = "Non-existing setting 'Invalid'." expected = File([ CommentSection(body=[ Error([Token('ERROR', '*** Invalid ***', 1, 0, inv_header)]) ]), SettingSection( header=SectionHeader( [Token('SETTING HEADER', '*** Settings ***', 2, 0)]), body=[ Error([Token('ERROR', 'Invalid', 3, 0, inv_setting)]), Documentation( [Token('DOCUMENTATION', 'Documentation', 4, 0)]) ]) ]) assert_model(model, expected)
def inplace(self, *paths): """Tidy file(s) in-place. :param paths: Paths of the files to to process. """ for path in paths: self._tidy(get_model(path), output=self._get_writer(path))
def test_in_test_case_body_inside_if_else(self): for data_only in [True, False]: with self.subTest(data_only=data_only): model = get_model('''\ *** Test Cases *** Example IF True RETURN ELSE IF False RETURN ELSE RETURN END ''', data_only=data_only) ifroot = model.sections[0].body[0].body[0] node = ifroot.body[0] expected = ReturnStatement( [Token(Token.RETURN_STATEMENT, 'RETURN', 4, 8)], errors=('RETURN can only be used inside a user keyword.',) ) remove_non_data_nodes_and_assert(node, expected, data_only) expected.tokens[0].lineno = 6 remove_non_data_nodes_and_assert(ifroot.orelse.body[0], expected, data_only) expected.tokens[0].lineno = 8 remove_non_data_nodes_and_assert(ifroot.orelse.orelse.body[0], expected, data_only)
def test_valid(self): model = get_model('''\ *** Variables *** ${x} value @{y}= two values &{z} = one=item ''', data_only=True) expected = VariableSection(header=SectionHeader( tokens=[Token(Token.VARIABLE_HEADER, '*** Variables ***', 1, 0)]), body=[ Variable([ Token(Token.VARIABLE, '${x}', 2, 0), Token(Token.ARGUMENT, 'value', 2, 10) ]), Variable([ Token(Token.VARIABLE, '@{y}=', 3, 0), Token(Token.ARGUMENT, 'two', 3, 10), Token(Token.ARGUMENT, 'values', 3, 17) ]), Variable([ Token(Token.VARIABLE, '&{z} =', 4, 0), Token(Token.ARGUMENT, 'one=item', 4, 10) ]), ]) assert_model(model.sections[0], expected)
def test_in_test_case_body_inside_try_except(self): for data_only in [True, False]: with self.subTest(data_only=data_only): model = get_model('''\ *** Test Cases *** Example TRY RETURN EXCEPT RETURN ELSE RETURN FINALLY RETURN END ''', data_only=data_only) tryroot = model.sections[0].body[0].body[0] node = tryroot.body[0] expected = ReturnStatement( [Token(Token.RETURN_STATEMENT, 'RETURN', 4, 8)], errors=('RETURN can only be used inside a user keyword.',) ) remove_non_data_nodes_and_assert(node, expected, data_only) expected.tokens[0].lineno = 6 remove_non_data_nodes_and_assert(tryroot.next.body[0], expected, data_only) expected.tokens[0].lineno = 8 remove_non_data_nodes_and_assert(tryroot.next.next.body[0], expected, data_only) expected.tokens[0].lineno = 10 remove_non_data_nodes_and_assert(tryroot.next.next.next.body[0], expected, data_only)
def test_break(self): model = get_model('''\ *** Keywords *** Name WHILE True Break BREAK BREAK END ''', data_only=True) expected = KeywordSection( header=SectionHeader( tokens=[Token(Token.KEYWORD_HEADER, '*** Keywords ***', 1, 0) ]), body=[ Keyword( header=KeywordName( tokens=[Token(Token.KEYWORD_NAME, 'Name', 2, 0)]), body=[ While(header=WhileHeader([ Token(Token.WHILE, 'WHILE', 3, 4), Token(Token.ARGUMENT, 'True', 3, 13) ]), body=[ KeywordCall([ Token(Token.KEYWORD, 'Break', 4, 8), Token(Token.ARGUMENT, 'BREAK', 4, 17) ]), Break([Token(Token.BREAK, 'BREAK', 5, 8)]) ], end=End([Token(Token.END, 'END', 6, 4)])) ], ) ]) assert_model(model.sections[0], expected)
def test_invalid(self): model = get_model('''\ *** Test Cases *** Example FOR END ooops FOR wrong IN ''', data_only=True) loop1, loop2 = model.sections[0].body[0].body expected1 = For(header=ForHeader( tokens=[Token(Token.FOR, 'FOR', 3, 4)], errors=('FOR loop has no loop variables.', "FOR loop has no 'IN' or other valid separator."), ), end=End(tokens=[ Token(Token.END, 'END', 4, 4), Token(Token.ARGUMENT, 'ooops', 4, 11) ], errors=('END does not accept arguments.', )), errors=('FOR loop has empty body.', )) expected2 = For(header=ForHeader( tokens=[ Token(Token.FOR, 'FOR', 6, 4), Token(Token.VARIABLE, 'wrong', 6, 11), Token(Token.FOR_SEPARATOR, 'IN', 6, 20) ], errors=("FOR loop has invalid loop variable 'wrong'.", "FOR loop has no loop values."), ), errors=('FOR loop has empty body.', 'FOR loop has no closing END.')) assert_model(loop1, expected1) assert_model(loop2, expected2)
def test_return(self): model = get_model('''\ *** Keywords *** Name Return RETURN RETURN RETURN ''', data_only=True) expected = KeywordSection( header=SectionHeader( tokens=[Token(Token.KEYWORD_HEADER, '*** Keywords ***', 1, 0) ]), body=[ Keyword( header=KeywordName( tokens=[Token(Token.KEYWORD_NAME, 'Name', 2, 0)]), body=[ KeywordCall([ Token(Token.KEYWORD, 'Return', 3, 4), Token(Token.ARGUMENT, 'RETURN', 3, 14) ]), ReturnStatement([ Token(Token.RETURN_STATEMENT, 'RETURN', 4, 4), Token(Token.ARGUMENT, 'RETURN', 4, 14) ]) ], ) ]) assert_model(model.sections[0], expected)
def test_if_else_if_else(self): model = get_model('''\ *** Test Cases *** Example IF True K1 ELSE IF False K2 ELSE K3 END ''', data_only=True) node = model.sections[0].body[0].body[0] expected = If( header=IfHeader([ Token(Token.IF, 'IF', 3, 4), Token(Token.ARGUMENT, 'True', 3, 10), ]), body=[KeywordCall([Token(Token.KEYWORD, 'K1', 4, 8)])], orelse=If( header=ElseIfHeader([ Token(Token.ELSE_IF, 'ELSE IF', 5, 4), Token(Token.ARGUMENT, 'False', 5, 15), ]), body=[KeywordCall([Token(Token.KEYWORD, 'K2', 6, 8)])], orelse=If( header=ElseHeader([ Token(Token.ELSE, 'ELSE', 7, 4), ]), body=[KeywordCall([Token(Token.KEYWORD, 'K3', 8, 8)])], )), end=End([Token(Token.END, 'END', 9, 4)])) assert_model(node, expected)
def test_invalid(self): model = get_model('''\ *** Test Cases *** Example IF too many ELSE ooops ELSE IF ''', data_only=True) node = model.sections[0].body[0].body[0] expected = If( header=IfHeader([ Token(Token.IF, 'IF', 3, 4), Token(Token.ARGUMENT, 'too', 3, 10), Token(Token.ARGUMENT, 'many', 3, 17), ]), orelse=If(header=ElseHeader([ Token(Token.ELSE, 'ELSE', 4, 4), Token(Token.ARGUMENT, 'ooops', 4, 12) ]), orelse=If(header=ElseIfHeader( [Token(Token.ELSE_IF, 'ELSE IF', 5, 4)]), errors=[ 'ELSE IF has no condition.', 'ELSE IF has empty body.' ]), errors=['ELSE has condition.', 'ELSE has empty body.']), errors=[ 'IF has more than one condition.', 'IF has empty body.', 'ELSE IF after ELSE.', 'IF has no closing END.' ]) assert_model(node, expected)
def inplace(self, *paths): """Tidy file(s) in-place. :param paths: Paths of the files to to process. """ for path in paths: model = get_model(path) with self._get_output(path) as output: self._tidy(model, output)
def get_and_assert_model(data, expected, depth=2): for data_only in True, False: model = get_model(data.strip(), data_only=data_only) if not data_only: remove_non_data(model) node = model.sections[0] for _ in range(depth): node = node.body[0] assert_model(node, expected)
def _build(self, suite, source, defaults): model = get_model(self._get_source(source), data_only=True, curdir=self._get_curdir(source)) ErrorLogger(source).visit(model) SettingsBuilder(suite, defaults).visit(model) SuiteBuilder(suite, defaults).visit(model) suite.rpa = self._get_rpa_mode(model) return suite
def test_ast_NodeTransformer(self): class Transformer(ast.NodeTransformer): def visit_Tags(self, node): return None def visit_TestCaseSection(self, node): self.generic_visit(node) node.body.append( TestCase( TestCaseName([ Token('TESTCASE_NAME', 'Added'), Token('EOL', '\n') ]))) return node def visit_TestCase(self, node): self.generic_visit(node) return node if node.name != 'REMOVE' else None def visit_TestCaseName(self, node): name_token = node.get_token(Token.TESTCASE_NAME) name_token.value = name_token.value.upper() return node def visit_Block(self, node): raise RuntimeError('Should not be executed.') def visit_Statement(self, node): raise RuntimeError('Should not be executed.') model = get_model('''\ *** Test Cases *** Example [Tags] to be removed Remove ''') Transformer().visit(model) expected = File(sections=[ TestCaseSection(header=TestCaseSectionHeader([ Token('TESTCASE_HEADER', '*** Test Cases ***', 1, 0), Token('EOL', '\n', 1, 18) ]), body=[ TestCase( TestCaseName([ Token('TESTCASE_NAME', 'EXAMPLE', 2, 0), Token('EOL', '\n', 2, 7) ])), TestCase( TestCaseName([ Token('TESTCASE_NAME', 'Added'), Token('EOL', '\n') ])) ]) ]) assert_model(model, expected)
def test_invalid(self): model = get_model('''\ *** Variables *** Ooops I did it again ${} invalid ${x}== invalid ${not closed invalid &{dict} invalid ${invalid} ''', data_only=True) expected = VariableSection( header=SectionHeader(tokens=[ Token(Token.VARIABLE_HEADER, '*** Variables ***', 1, 0) ]), body=[ Variable(tokens=[ Token(Token.VARIABLE, 'Ooops', 2, 0), Token(Token.ARGUMENT, 'I did it again', 2, 10) ], errors=("Invalid variable name 'Ooops'.", )), Variable(tokens=[ Token(Token.VARIABLE, '${}', 3, 0), Token(Token.ARGUMENT, 'invalid', 3, 10) ], errors=("Invalid variable name '${}'.", )), Variable(tokens=[ Token(Token.VARIABLE, '${x}==', 4, 0), Token(Token.ARGUMENT, 'invalid', 4, 10) ], errors=("Invalid variable name '${x}=='.", )), Variable(tokens=[ Token(Token.VARIABLE, '${not', 5, 0), Token(Token.ARGUMENT, 'closed', 5, 10) ], errors=("Invalid variable name '${not'.", )), Variable(tokens=[ Token(Token.VARIABLE, '', 6, 0), Token(Token.ARGUMENT, 'invalid', 6, 10) ], errors=("Invalid variable name ''.", )), Variable( tokens=[ Token(Token.VARIABLE, '&{dict}', 7, 0), Token(Token.ARGUMENT, 'invalid', 7, 10), Token(Token.ARGUMENT, '${invalid}', 7, 21) ], errors= ("Invalid dictionary variable item 'invalid'. " "Items must use 'name=value' syntax or be dictionary variables themselves.", "Invalid dictionary variable item '${invalid}'. " "Items must use 'name=value' syntax or be dictionary variables themselves." )), ]) assert_model(model.sections[0], expected)
def _build(self, suite, source, defaults, model=None, get_model=get_model): if defaults is None: defaults = TestDefaults() if model is None: model = get_model(self._get_source(source), data_only=True, curdir=self._get_curdir(source)) ErrorReporter(source).visit(model) SettingsBuilder(suite, defaults).visit(model) SuiteBuilder(suite, defaults).visit(model) suite.rpa = self._get_rpa_mode(model) return suite
def test_invalid(self): model = get_model('''\ *** Test Cases *** Example IF too many ELSE ooops ELSE IF END ooops IF ''', data_only=True) if1, if2 = model.sections[0].body[0].body expected1 = If( header=IfHeader( tokens=[Token(Token.IF, 'IF', 3, 4), Token(Token.ARGUMENT, 'too', 3, 10), Token(Token.ARGUMENT, 'many', 3, 17)], errors=('IF has more than one condition.',) ), orelse=If( header=ElseHeader( tokens=[Token(Token.ELSE, 'ELSE', 4, 4), Token(Token.ARGUMENT, 'ooops', 4, 12)], errors=('ELSE has condition.',) ), orelse=If( header=ElseIfHeader( tokens=[Token(Token.ELSE_IF, 'ELSE IF', 5, 4)], errors=('ELSE IF has no condition.',) ), errors=('ELSE IF has empty body.',) ), errors=('ELSE has empty body.',) ), end=End( tokens=[Token(Token.END, 'END', 6, 4), Token(Token.ARGUMENT, 'ooops', 6, 11)], errors=('END does not accept arguments.',) ), errors=('IF has empty body.', 'ELSE IF after ELSE.') ) expected2 = If( header=IfHeader( tokens=[Token(Token.IF, 'IF', 8, 4)], errors=('IF has no condition.',) ), errors=('IF has empty body.', 'IF has no closing END.') ) assert_model(if1, expected1) assert_model(if2, expected2)
def file(self, path, outpath=None): """Tidy a file. :param path: Path of the input file. :param outpath: Path of the output file. If not given, output is returned. Use :func:`inplace` to tidy files in-place. """ with self._get_output(outpath) as writer: self._tidy(get_model(path), writer) if not outpath: return writer.getvalue().replace('\r\n', '\n')
def test_in_uk_body(self): for data_only in [True, False]: with self.subTest(data_only=data_only): model = get_model('''\ *** Keywords *** Example CONTINUE''', data_only=data_only) node = model.sections[0].body[0].body[0] expected = Continue( [Token(Token.CONTINUE, 'CONTINUE', 3, 4)], errors=('CONTINUE can only be used inside a loop.',) ) remove_non_data_nodes_and_assert(node, expected, data_only)
def test_in_test_case_body(self): for data_only in [True, False]: with self.subTest(data_only=data_only): model = get_model('''\ *** Test Cases *** Example BREAK''', data_only=data_only) node = model.sections[0].body[0].body[0] expected = Break( [Token(Token.BREAK, 'BREAK', 3, 4)], errors=('BREAK can only be used inside a loop.',) ) remove_non_data_nodes_and_assert(node, expected, data_only)
def test_in_test_case_body(self): for data_only in [True, False]: with self.subTest(data_only=data_only): model = get_model('''\ *** Test Cases *** Example RETURN''', data_only=data_only) node = model.sections[0].body[0].body[0] expected = ReturnStatement( [Token(Token.RETURN_STATEMENT, 'RETURN', 3, 4)], errors=('RETURN can only be used inside a user keyword.',) ) remove_non_data_nodes_and_assert(node, expected, data_only)
def test_nested(self): model = get_model('''\ *** Test Cases *** Example IF ${x} Log ${x} IF ${y} Log ${y} ELSE Log ${z} END END ''', data_only=True) node = model.sections[0].body[0].body[0] expected = If( header=IfHeader([ Token(Token.IF, 'IF', 3, 4), Token(Token.ARGUMENT, '${x}', 3, 10), ]), body=[ KeywordCall([Token(Token.KEYWORD, 'Log', 4, 8), Token(Token.ARGUMENT, '${x}', 4, 15)]), If( header=IfHeader([ Token(Token.IF, 'IF', 5, 8), Token(Token.ARGUMENT, '${y}', 5, 14), ]), body=[ KeywordCall([Token(Token.KEYWORD, 'Log', 6, 12), Token(Token.ARGUMENT, '${y}', 6, 19)]) ], orelse=If( header=ElseHeader([ Token(Token.ELSE, 'ELSE', 7, 8) ]), body=[ KeywordCall([Token(Token.KEYWORD, 'Log', 8, 12), Token(Token.ARGUMENT, '${z}', 8, 19)]) ] ), end=End([ Token(Token.END, 'END', 9, 8) ]) ) ], end=End([ Token(Token.END, 'END', 10, 4) ]) ) assert_model(node, expected)
def build_suite(source, datapath=None, parent_defaults=None, process_curdir=True): suite = TestSuite(name=format_name(source), source=source) defaults = TestDefaults(parent_defaults) if datapath: model = get_model(datapath, data_only=True, process_curdir=process_curdir) ErrorLogger(datapath).visit(model) SettingsBuilder(suite, defaults).visit(model) SuiteBuilder(suite, defaults).visit(model) if not suite.tests: LOGGER.info("Data source '%s' has no tests or tasks." % datapath) suite.rpa = _get_rpa_mode(model) return suite, defaults
def test_if(self): model = get_model('''\ *** Test Cases *** Example IF True Keyword ''', data_only=True) node = model.sections[0].body[0].body[0] expected = If( header=InlineIfHeader([Token(Token.INLINE_IF, 'IF', 3, 4), Token(Token.ARGUMENT, 'True', 3, 10)]), body=[KeywordCall([Token(Token.KEYWORD, 'Keyword', 3, 18)])], end=End([Token(Token.END, '', 3, 25)]) ) assert_model(node, expected)
def test_in_try_test_case_body(self): for data_only in [True, False]: with self.subTest(data_only=data_only): model = get_model('''\ *** Test Cases *** Example TRY CONTINUE EXCEPT no operation END''', data_only=data_only) node = model.sections[0].body[0].body[0].body[0] expected = Continue( [Token(Token.CONTINUE, 'CONTINUE', 4, 8)], errors=('CONTINUE can only be used inside a loop.',) ) remove_non_data_nodes_and_assert(node, expected, data_only)