Skip to content

Commit

Permalink
Add to_dict to running side TestSuite structure.
Browse files Browse the repository at this point in the history
TestSuite.resource is not yet implemented and roundtrip with
`from_dict` doesn't work properly yet. Also need to decide how to
handle result side TestSuite structure.

Part of #3902.
  • Loading branch information
pekkaklarck committed Jan 9, 2023
1 parent c1534b7 commit 9df3a6c
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 10 deletions.
5 changes: 4 additions & 1 deletion src/robot/model/body.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,14 @@ def has_setup(self):
def has_teardown(self):
return False

def to_dict(self):
raise NotImplementedError


class BaseBody(ItemList):
"""Base class for Body and Branches objects."""
__slots__ = []
# Set using 'Body.register' when these classes are created.
# Set using 'BaseBody.register' when these classes are created.
keyword_class = None
for_class = None
if_class = None
Expand Down
46 changes: 46 additions & 0 deletions src/robot/model/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ def __str__(self):
values = ' '.join(self.values)
return 'FOR %s %s %s' % (variables, self.flavor, values)

def to_dict(self):
return {'type': self.type,
'variables': list(self.variables),
'flavor': self.flavor,
'values': list(self.values)}


@Body.register
class While(BodyItem):
Expand All @@ -78,6 +84,12 @@ def visit(self, visitor):
def __str__(self):
return f'WHILE {self.condition}' + (f' {self.limit}' if self.limit else '')

def to_dict(self):
data = {'type': self.type, 'condition': self.condition}
if self.limit:
data['limit'] = self.limit
return data


class IfBranch(BodyItem):
body_class = Body
Expand Down Expand Up @@ -113,6 +125,14 @@ def __str__(self):
def visit(self, visitor):
visitor.visit_if_branch(self)

def to_dict(self):
data = {'type': self.type,
'condition': self.condition,
'body': self.body.to_dicts()}
if self.type == self.ELSE:
data.pop('condition')
return data


@Body.register
class If(BodyItem):
Expand All @@ -138,6 +158,9 @@ def id(self):
def visit(self, visitor):
visitor.visit_if(self)

def to_dict(self):
return {'type': self.type, 'body': self.body.to_dicts()}


class TryBranch(BodyItem):
body_class = Body
Expand Down Expand Up @@ -185,6 +208,17 @@ def __repr__(self):
def visit(self, visitor):
visitor.visit_try_branch(self)

def to_dict(self):
data = {'type': self.type}
if self.type == self.EXCEPT:
data['patterns'] = list(self.patterns)
if self.pattern_type:
data['pattern_type'] = self.pattern_type
if self.variable:
data['variable'] = self.variable
data['body'] = self.body.to_dicts()
return data


@Body.register
class Try(BodyItem):
Expand Down Expand Up @@ -233,6 +267,9 @@ def id(self):
def visit(self, visitor):
visitor.visit_try(self)

def to_dict(self):
return {'type': self.type, 'body': self.body.to_dicts()}


@Body.register
class Return(BodyItem):
Expand All @@ -247,6 +284,9 @@ def __init__(self, values=(), parent=None):
def visit(self, visitor):
visitor.visit_return(self)

def to_dict(self):
return {'type': self.type, 'values': list(self.values)}


@Body.register
class Continue(BodyItem):
Expand All @@ -259,6 +299,9 @@ def __init__(self, parent=None):
def visit(self, visitor):
visitor.visit_continue(self)

def to_dict(self):
return {'type': self.type}


@Body.register
class Break(BodyItem):
Expand All @@ -270,3 +313,6 @@ def __init__(self, parent=None):

def visit(self, visitor):
visitor.visit_break(self)

def to_dict(self):
return {'type': self.type}
3 changes: 3 additions & 0 deletions src/robot/model/itemlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,6 @@ def __imul__(self, other):

def __rmul__(self, other):
return self * other

def to_dicts(self):
return [item.to_dict() for item in self]
8 changes: 8 additions & 0 deletions src/robot/model/keyword.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ def __str__(self):
parts = list(self.assign) + [self.name] + list(self.args)
return ' '.join(str(p) for p in parts)

def to_dict(self):
data = {'name': self.name}
if self.args:
data['args'] = list(self.args)
if self.assign:
data['assign'] = list(self.assign)
return data


class Keywords(ItemList):
"""A list-like object representing keywords in a suite, a test or a keyword.
Expand Down
6 changes: 6 additions & 0 deletions src/robot/model/modelobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ def from_dict(cls, data):
def from_json(cls, data):
return cls.from_dict(json.loads(data))

def to_dict(self):
raise NotImplementedError

def to_json(self):
return json.dumps(self.to_dict())

def config(self, **attributes):
"""Configure model object with given attributes.
Expand Down
17 changes: 17 additions & 0 deletions src/robot/model/testcase.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,23 @@ def visit(self, visitor):
def __str__(self):
return self.name

def to_dict(self):
data = {'name': self.name}
if self.doc:
data['doc'] = self.doc
if self.tags:
data['tags'] = list(self.tags)
if self.timeout:
data['timeout'] = self.timeout
if self.lineno:
data['lineno'] = self.lineno
if self.has_setup:
data['setup'] = self.setup.to_dict()
if self.has_teardown:
data['teardown'] = self.teardown.to_dict()
data['body'] = self.body.to_dicts()
return data


class TestCases(ItemList):
__slots__ = []
Expand Down
22 changes: 21 additions & 1 deletion src/robot/model/testsuite.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,29 @@ def visit(self, visitor):
def __str__(self):
return self.name

def to_dict(self):
data = {'name': self.name}
if self.doc:
data['doc'] = self.doc
if self.metadata:
data['metadata'] = dict(self.metadata)
if self.source:
data['source'] = self.source
if self.rpa:
data['rpa'] = self.rpa
if self.has_setup:
data['setup'] = self.setup.to_dict()
if self.has_teardown:
data['teardown'] = self.teardown.to_dict()
if self.tests:
data['tests'] = self.tests.to_dicts()
if self.suites:
data['suites'] = self.suites.to_dicts()
return data


class TestSuites(ItemList):
__slots__ = []

def __init__(self, suite_class=TestSuite, parent=None, suites=None):
ItemList.__init__(self, suite_class, {'parent': parent}, suites)
super().__init__(suite_class, {'parent': parent}, suites)
85 changes: 83 additions & 2 deletions src/robot/running/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ def __init__(self, name='', args=(), assign=(), type=BodyItem.KEYWORD, parent=No
def source(self):
return self.parent.source if self.parent is not None else None

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
return data

def run(self, context, run=True, templated=None):
return KeywordRunner(context, run).run(self)

Expand All @@ -86,7 +92,8 @@ class For(model.For):
__slots__ = ['lineno', 'error']
body_class = Body

def __init__(self, variables, flavor, values, parent=None, lineno=None, error=None):
def __init__(self, variables=(), flavor='IN', values=(), parent=None,
lineno=None, error=None):
super().__init__(variables, flavor, values, parent)
self.lineno = lineno
self.error = error
Expand All @@ -95,6 +102,14 @@ def __init__(self, variables, flavor, values, parent=None, lineno=None, error=No
def source(self):
return self.parent.source if self.parent is not None else None

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
if self.error:
data['error'] = self.error
return data

def run(self, context, run=True, templated=False):
return ForRunner(context, self.flavor, run, templated).run(self)

Expand All @@ -113,6 +128,14 @@ def __init__(self, condition=None, limit=None, parent=None, lineno=None, error=N
def source(self):
return self.parent.source if self.parent is not None else None

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
if self.error:
data['error'] = self.error
return data

def run(self, context, run=True, templated=False):
return WhileRunner(context, run, templated).run(self)

Expand All @@ -129,6 +152,12 @@ def __init__(self, type=BodyItem.IF, condition=None, parent=None, lineno=None):
def source(self):
return self.parent.source if self.parent is not None else None

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
return data


@Body.register
class If(model.If):
Expand All @@ -147,6 +176,14 @@ def source(self):
def run(self, context, run=True, templated=False):
return IfRunner(context, run, templated).run(self)

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
if self.error:
data['error'] = self.error
return data


class TryBranch(model.TryBranch):
__slots__ = ['lineno']
Expand All @@ -161,6 +198,12 @@ def __init__(self, type=BodyItem.TRY, patterns=(), pattern_type=None,
def source(self):
return self.parent.source if self.parent is not None else None

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
return data


@Body.register
class Try(model.Try):
Expand All @@ -179,6 +222,14 @@ def source(self):
def run(self, context, run=True, templated=False):
return TryRunner(context, run, templated).run(self)

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
if self.error:
data['error'] = self.error
return data


@Body.register
class Return(model.Return):
Expand All @@ -201,6 +252,14 @@ def run(self, context, run=True, templated=False):
if not context.dry_run:
raise ReturnFromKeyword(self.values)

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
if self.error:
data['error'] = self.error
return data


@Body.register
class Continue(model.Continue):
Expand All @@ -223,6 +282,14 @@ def run(self, context, run=True, templated=False):
if not context.dry_run:
raise ContinueLoop()

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
if self.error:
data['error'] = self.error
return data


@Body.register
class Break(model.Break):
Expand All @@ -245,6 +312,14 @@ def run(self, context, run=True, templated=False):
if not context.dry_run:
raise BreakLoop()

def to_dict(self):
data = super().to_dict()
if self.lineno:
data['lineno'] = self.lineno
if self.error:
data['error'] = self.error
return data


class TestCase(model.TestCase):
"""Represents a single executable test case.
Expand All @@ -266,6 +341,12 @@ def __init__(self, name='', doc='', tags=None, timeout=None, template=None,
def source(self):
return self.parent.source if self.parent is not None else None

def to_dict(self):
data = super().to_dict()
if self.template:
data['template'] = self.template
return data


class TestSuite(model.TestSuite):
"""Represents a single executable test suite.
Expand Down Expand Up @@ -344,7 +425,7 @@ def randomize(self, suites=True, tests=True, seed=None):
self.visit(Randomizer(suites, tests, seed))

def run(self, settings=None, **options):
"""Executes the suite based based the given ``settings`` or ``options``.
"""Executes the suite based on the given ``settings`` or ``options``.
:param settings: :class:`~robot.conf.settings.RobotSettings` object
to configure test execution.
Expand Down

0 comments on commit 9df3a6c

Please sign in to comment.