Skip to content

Commit

Permalink
Merge pull request #37 from melexis/variables
Browse files Browse the repository at this point in the history
Resolve RF variables in Documentation
  • Loading branch information
Letme authored Apr 25, 2023
2 parents 136442a + d133b08 commit 99265c9
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 31 deletions.
9 changes: 6 additions & 3 deletions doc/source/robot/example.robot
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ Documentation Example using the space separated plain text format.
Library OperatingSystem

*** Variables ***
${MESSAGE} Hello, world!
${NAD} ${0x63}
${MESSAGE} Hello,
... world!

*** Test Cases ***
First Test
[Documentation] Thorough and relatively lengthy documentation for the first example
... test case.
[Documentation] Thorough and relatively lengthy documentation for the example test case that
... logs ${MESSAGE} and ${NAD}.
[Tags] SWRQT-SOME_RQT ANOTHER-TAG SWRQT-OTHER_RQT SYSRQT-SOME_SYSTEM_RQT
Log ${MESSAGE}
Log ${NAD}
My Keyword /tmp

Undocumented Test
Expand Down
5 changes: 4 additions & 1 deletion mlx/robot2rst.mako
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def generate_body(input_string):
indent = ' ' * 4
newline = '\n'
line_separator = newline + indent
for variable, value in parser.variables.items():
if variable in input_string:
input_string = input_string.replace(variable, value)
input_string = input_string.replace(r'\r', '').strip()
lines = input_string.split(newline)
intermediate_output = indent
Expand All @@ -63,7 +66,7 @@ ${'='*len(title)}
:local:


% for test in tests:
% for test in parser.tests:
.. item:: ${to_traceable_item(test.name, prefix)} ${test.name}
% for relationship, tag_regex, _ in relationship_config:
<%
Expand Down
12 changes: 7 additions & 5 deletions mlx/robot2rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from mako.exceptions import RichTraceback
from mako.template import Template

from .robot_parser import extract_tests
from .robot_parser import ParserApplication

TEMPLATE_FILE = Path(__file__).parent.joinpath('robot2rst.mako')
LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -43,20 +43,20 @@ def render_template(destination, only="", **kwargs):
return 0


def generate_robot_2_rst(robot_file, rst_file, prefix, relationship_config, gen_matrix, **kwargs):
def generate_robot_2_rst(parser, rst_file, prefix, relationship_config, gen_matrix, **kwargs):
"""
Calls mako template function and passes all needed parameters.
Args:
robot_file (Path): Path to the input file (.robot).
parser (ParserApplication): Parser with data extracted from the .robot file
rst_file (Path): Path to the output file (.rst).
prefix (str): Prefix of generated item IDs.
relationship_config (list): List of tuples that contain a relationship, tag_regex and coverage percentage
gen_matrix (bool): True if traceability matrices are to be generated, False if not.
"""
return render_template(
rst_file,
tests=extract_tests(str(robot_file.resolve(strict=True))),
parser=parser,
suite=rst_file.stem,
prefix=prefix,
relationship_config=relationship_config,
Expand Down Expand Up @@ -137,7 +137,9 @@ def main():
f"percentages ({len(coverages)}).")
relationship_config = [(relationships[i], tag_regexes[i], coverages[i]) for i in range(len(relationships))]

return generate_robot_2_rst(Path(args.robot_file), Path(args.rst_file), prefix, relationship_config,
parser = ParserApplication(Path(args.robot_file))
parser.run()
return generate_robot_2_rst(parser, Path(args.rst_file), prefix, relationship_config,
gen_matrix, test_type=test_type, only=args.expression, coverages=coverages)


Expand Down
53 changes: 31 additions & 22 deletions mlx/robot_parser.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
from ast import NodeVisitor
import re
from collections import namedtuple

from robot.api import get_model, Token
from robot.parsing import ModelVisitor


def extract_tests(robot_file):
""" Extracts all useful information from the tests in the .robot file.
class ParserApplication(ModelVisitor):
""" Class used to extract all useful info from the .robot file.
Args:
robot_file (str): Path to the .robot file.
See https://robot-framework.readthedocs.io/en/v6.0.2/autodoc/robot.api.html#inspecting-model
Returns:
list: List of objects with attributes name (str), doc (str) and tags (list).
"""
model = get_model(robot_file)
parser = TestCaseParser()
parser.visit(model)
return parser.tests


class TestCaseParser(NodeVisitor):
""" Class used to extract all useful info from test cases.
See https://robot-framework.readthedocs.io/en/latest/autodoc/robot.parsing.html#parsing-data-to-model
Attributes:
tests (list): List of objects with attributes name (str), doc (str) and tags (list).
variables (dict): Dictionary mapping variables, e.g. '${MESSAGE}', to their values
"""
TestAttributes = namedtuple('TestAttributes', 'name doc tags')

def __init__(self, *args, **kwargs):
def __init__(self, robot_file, *args, **kwargs):
""" Constructor
Args:
robot_file (Path): Path to the .robot file.
"""
super().__init__(*args, **kwargs)
self.robot_file = str(robot_file.resolve(strict=True))
self.model = get_model(self.robot_file)
self.tests = []
self.variables = {}

def run(self):
self.visit(self.model)

def visit_VariableSection(self, node):
for element in node.body:
if getattr(element, 'type') == Token.VARIABLE:
name = element.get_value(Token.VARIABLE)
value = ' '.join(element.get_values(Token.ARGUMENT))
match = re.fullmatch(r"\${(.+)}", value)
if match:
value = match.group(1)
self.variables[name] = value

def visit_TestCase(self, node):
doc = ''
tags = []
for element in node.body:
if not hasattr(element, 'type'):
continue
if element.type == Token.DOCUMENTATION:
if getattr(element, 'type') == Token.DOCUMENTATION:
in_docstring = False
previous_token = None
for token in element.tokens:
Expand Down

0 comments on commit 99265c9

Please sign in to comment.