# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ast import NodeVisitor
from robot.variables import VariableIterator
from .testsettings import TestSettings
[docs]class SettingsBuilder(NodeVisitor):
def __init__(self, suite, test_defaults):
self.suite = suite
self.test_defaults = test_defaults
[docs] def visit_Documentation(self, node):
self.suite.doc = node.value
[docs] def visit_SuiteSetup(self, node):
self.suite.setup.config(name=node.name, args=node.args,
lineno=node.lineno)
[docs] def visit_SuiteTeardown(self, node):
self.suite.teardown.config(name=node.name, args=node.args,
lineno=node.lineno)
[docs] def visit_TestSetup(self, node):
self.test_defaults.setup = {
'name': node.name, 'args': node.args, 'lineno': node.lineno
}
[docs] def visit_TestTeardown(self, node):
self.test_defaults.teardown = {
'name': node.name, 'args': node.args, 'lineno': node.lineno
}
[docs] def visit_TestTimeout(self, node):
self.test_defaults.timeout = node.value
[docs] def visit_TestTemplate(self, node):
self.test_defaults.template = node.value
[docs] def visit_ResourceImport(self, node):
self.suite.resource.imports.create(type='Resource', name=node.name,
lineno=node.lineno)
[docs] def visit_LibraryImport(self, node):
self.suite.resource.imports.create(type='Library', name=node.name,
args=node.args, alias=node.alias,
lineno=node.lineno)
[docs] def visit_VariablesImport(self, node):
self.suite.resource.imports.create(type='Variables', name=node.name,
args=node.args, lineno=node.lineno)
[docs] def visit_VariableSection(self, node):
pass
[docs] def visit_TestCaseSection(self, node):
pass
[docs] def visit_KeywordSection(self, node):
pass
[docs]class SuiteBuilder(NodeVisitor):
def __init__(self, suite, test_defaults):
self.suite = suite
self.test_defaults = test_defaults
[docs] def visit_SettingSection(self, node):
pass
[docs] def visit_Variable(self, node):
self.suite.resource.variables.create(name=node.name,
value=node.value,
lineno=node.lineno,
error=format_error(node.errors))
[docs] def visit_TestCase(self, node):
TestCaseBuilder(self.suite, self.test_defaults).visit(node)
[docs] def visit_Keyword(self, node):
KeywordBuilder(self.suite.resource).visit(node)
[docs]class ResourceBuilder(NodeVisitor):
def __init__(self, resource):
self.resource = resource
[docs] def visit_Documentation(self, node):
self.resource.doc = node.value
[docs] def visit_LibraryImport(self, node):
self.resource.imports.create(type='Library', name=node.name,
args=node.args, alias=node.alias,
lineno=node.lineno)
[docs] def visit_ResourceImport(self, node):
self.resource.imports.create(type='Resource', name=node.name,
lineno=node.lineno)
[docs] def visit_VariablesImport(self, node):
self.resource.imports.create(type='Variables', name=node.name,
args=node.args, lineno=node.lineno)
[docs] def visit_Variable(self, node):
self.resource.variables.create(name=node.name,
value=node.value,
lineno=node.lineno,
error=format_error(node.errors))
[docs] def visit_Keyword(self, node):
KeywordBuilder(self.resource).visit(node)
[docs]class TestCaseBuilder(NodeVisitor):
def __init__(self, suite, defaults):
self.suite = suite
self.settings = TestSettings(defaults)
self.test = None
[docs] def visit_TestCase(self, node):
self.test = self.suite.tests.create(name=node.name, lineno=node.lineno)
self.generic_visit(node)
self._set_settings(self.test, self.settings)
def _set_settings(self, test, settings):
if settings.setup:
test.setup.config(**settings.setup)
if settings.teardown:
test.teardown.config(**settings.teardown)
if settings.timeout:
test.timeout = settings.timeout
if settings.tags:
test.tags = settings.tags
if settings.template:
test.template = settings.template
self._set_template(test, settings.template)
def _set_template(self, parent, template):
for item in parent.body:
if item.type == item.FOR:
self._set_template(item, template)
elif item.type == item.IF_ELSE_ROOT:
for branch in item.body:
self._set_template(branch, template)
elif item.type == item.KEYWORD:
name, args = self._format_template(template, item.args)
item.name = name
item.args = args
def _format_template(self, template, arguments):
variables = VariableIterator(template, identifiers='$')
count = len(variables)
if count == 0 or count != len(arguments):
return template, arguments
temp = []
for (before, _, after), arg in zip(variables, arguments):
temp.extend([before, arg])
temp.append(after)
return ''.join(temp), ()
[docs] def visit_For(self, node):
ForBuilder(self.test).build(node)
[docs] def visit_If(self, node):
IfBuilder(self.test).build(node)
[docs] def visit_TemplateArguments(self, node):
self.test.body.create_keyword(args=node.args, lineno=node.lineno)
[docs] def visit_Documentation(self, node):
self.test.doc = node.value
[docs] def visit_Setup(self, node):
self.settings.setup = {
'name': node.name, 'args': node.args, 'lineno': node.lineno
}
[docs] def visit_Teardown(self, node):
self.settings.teardown = {
'name': node.name, 'args': node.args, 'lineno': node.lineno
}
[docs] def visit_Timeout(self, node):
self.settings.timeout = node.value
[docs] def visit_Template(self, node):
self.settings.template = node.value
[docs] def visit_KeywordCall(self, node):
self.test.body.create_keyword(name=node.keyword, args=node.args,
assign=node.assign, lineno=node.lineno)
[docs]class KeywordBuilder(NodeVisitor):
def __init__(self, resource):
self.resource = resource
self.kw = None
self.teardown = None
[docs] def visit_Keyword(self, node):
self.kw = self.resource.keywords.create(name=node.name,
lineno=node.lineno)
self.generic_visit(node)
if self.teardown is not None:
self.kw.teardown.config(**self.teardown)
[docs] def visit_Documentation(self, node):
self.kw.doc = node.value
[docs] def visit_Arguments(self, node):
self.kw.args = node.values
if node.errors:
self.kw.error = ('Invalid argument specification: %s'
% format_error(node.errors))
[docs] def visit_Return(self, node):
self.kw.return_ = node.values
[docs] def visit_Timeout(self, node):
self.kw.timeout = node.value
[docs] def visit_Teardown(self, node):
self.teardown = {
'name': node.name, 'args': node.args, 'lineno': node.lineno
}
[docs] def visit_KeywordCall(self, node):
self.kw.body.create_keyword(name=node.keyword, args=node.args,
assign=node.assign, lineno=node.lineno)
[docs] def visit_For(self, node):
ForBuilder(self.kw).build(node)
[docs] def visit_If(self, node):
IfBuilder(self.kw).build(node)
[docs]class ForBuilder(NodeVisitor):
def __init__(self, parent):
self.parent = parent
self.model = None
[docs] def build(self, node):
error = format_error(self._get_errors(node))
self.model = self.parent.body.create_for(
node.variables, node.flavor, node.values, lineno=node.lineno, error=error
)
for step in node.body:
self.visit(step)
return self.model
def _get_errors(self, node):
errors = node.header.errors + node.errors
if node.end:
errors += node.end.errors
return errors
[docs] def visit_KeywordCall(self, node):
self.model.body.create_keyword(name=node.keyword, args=node.args,
assign=node.assign, lineno=node.lineno)
[docs] def visit_TemplateArguments(self, node):
self.model.body.create_keyword(args=node.args, lineno=node.lineno)
[docs] def visit_For(self, node):
ForBuilder(self.model).build(node)
[docs] def visit_If(self, node):
IfBuilder(self.model).build(node)
[docs]class IfBuilder(NodeVisitor):
def __init__(self, parent):
self.parent = parent
self.model = None
[docs] def build(self, node):
model = self.parent.body.create_if(lineno=node.lineno,
error=format_error(self._get_errors(node)))
while node:
self.model = model.body.create_branch(node.type, node.condition,
lineno=node.lineno)
for step in node.body:
self.visit(step)
node = node.orelse
return model
def _get_errors(self, node):
errors = node.header.errors + node.errors
if node.orelse:
errors += self._get_errors(node.orelse)
if node.end:
errors += node.end.errors
return errors
[docs] def visit_KeywordCall(self, node):
self.model.body.create_keyword(name=node.keyword, args=node.args,
assign=node.assign, lineno=node.lineno)
[docs] def visit_TemplateArguments(self, node):
self.model.body.create_keyword(args=node.args, lineno=node.lineno)
[docs] def visit_If(self, node):
IfBuilder(self.model).build(node)
[docs] def visit_For(self, node):
ForBuilder(self.model).build(node)