关于robotframework4版本源码中词法解析部分的分析

  robot通过解析测试用例文件,对测试用例进行后续操作。在robot3.2.2版本之前直接是将文件内容用list解析为类似于表格的一种格式。词法解析部分从3.2.2版本开始就利用了编译原理当中的token和抽象语法树进行了重写。
  token可以理解为一个字段,在robot需要处理的测试用例文件中,每一行中的每一个“单词”,都可以看作一个字段,例如下面这一行:

[Tags]    ID=1    ANIMAL=cat    COLOR=red    SIZE=big   

在源码robot/parsing/lexer/tokenizer.py文件中

_space_splitter = re.compile(r'(\s{2,}|\t)', re.UNICODE)
self._space_splitter.split(line)

主要由这两行来分离每一个字段
所以词法解析给出的9个token为

['[Tags]', '    ', 'ID=1','    ','ANIMAL=cat','    ','COLOR=red','    ','SIZE=big']

  当然,此处并没有详细描述形成token的过程,不过详情可参考文档:Robot Framework Documentation
  文档中的第18页记录获取token的方法,如果想了解详细过程,可以按照文档中的提示写如下测试代码进行调试

from robot.api.parsing import get_tokens
path = 'example.robot'
for token in get_tokens(path):
	print(repr(token))

假如example.robot为以下内容:

*** Test Cases ***
Example
    Keyword    argument
Second example
    Keyword    xxx
*** Keywords ***
Keyword
    [Arguments]    ${arg}
    Log    ${arg}

解析完成生成的token为:

Token(TESTCASE_HEADER, '*** Test Cases ***', 1, 0)
Token(EOL, '\n', 1, 18)
Token(EOS, '', 1, 19)
Token(TESTCASE_NAME, 'Example', 2, 0)
Token(EOL, '\n', 2, 7)
Token(EOS, '', 2, 8)
Token(SEPARATOR, ' ', 3, 0)
Token(KEYWORD, 'Keyword', 3, 4)
Token(SEPARATOR, ' ', 3, 11)
Token(ARGUMENT, 'argument', 3, 15)
Token(EOL, '\n', 3, 23)
Token(EOS, '', 3, 24)
Token(EOL, '\n', 4, 0)
Token(EOS, '', 4, 1)

  创建完token之后,接着就要利用抽象语法树去构建model对象了,构建model是为了将文件中测试套件、测试用例、settings、variables、resource、keywords等信息用类似于tree的结构表现出来,便于后续对用例的其他操作。
  model中包含block和statement。statement只是存放相应的token值。block可以简单理解为json串中的key,作为一个标识。而每一个block和statement也可以作为block的value。例:

  图中的block有TestCaseSection、TestCase、If,statement有SectionHeader、EmptyLine、TestCaseName,block标识的是测试文件中相应的部分,如:TestCaseSection标识测试文件中的***TestCases***。
  每一个block中都包含header和body这两个属性,header存放标识名称,例如:***TestCases***、example case等等。而statement中存放着具体的token。当然也有其他的属性,例如lineno等,其他属性表示此block或statement在文件中对应的位置或者此处有无其他的errors(主要是不存在的section或无法识别的数据)。

robot/parsing/parser/fileparser.py文件中

    def parse(self, statement):
        parser_class = {
            Token.SETTING_HEADER: SettingSectionParser,
            Token.VARIABLE_HEADER: VariableSectionParser,
            Token.TESTCASE_HEADER: TestCaseSectionParser,
            Token.KEYWORD_HEADER: KeywordSectionParser,
            Token.COMMENT_HEADER: CommentSectionParser,
            Token.ORTHOGONAL_HEADER: OrthogonalSectionParser,
            Token.COMMENT: ImplicitCommentSectionParser,
            Token.ERROR: ImplicitCommentSectionParser,
            Token.EOL: ImplicitCommentSectionParser
        }[statement.type]
        parser = parser_class(statement)
        self.model.sections.append(parser.model)
        return parser

  定义并创建block,这些block对应文件中*** XXX ***的部分,然后由每一个block再去创建生成block中相应的block或着statement,例如 TestCaseSectionParser,其中header存放testcase的名字,body存放***testcases***中的内容,而其中可能会有多个testcase,每一个testcase又是一个block,以此类推,直至出现具体的token值,把token存放到statement中。

  由于本人时间问题,不在这里详细描述创建过程,不过详情可参考文档:Robot Framework Documentation
文档中第19页有一段测试代码,运行调试,进行分析后可以了解详细过程:

import astpretty
from robot.api.parsing import get_model
model = get_model('example.robot')
astpretty.pprint(model)

本人是新手小白,博客中如有讲解不到的地方请多包含。也可以在下方留言,以便及时更正,谢谢。
我是MySoul,期待和你一起进步。

最后附上生成的model示例:

File(
    source='F:\\robot4\\demos\\if.robot',
    lineno=1,
    col_offset=0,
    end_lineno=33,
    end_col_offset=4,
    errors=(),
    sections=[
        OrthogonalSection(
            lineno=1,
            col_offset=0,
            end_lineno=5,
            end_col_offset=1,
            errors=(),
            header=SectionHeader(lineno=1, col_offset=0, end_lineno=1, end_col_offset=27, errors=(), type='ORTHOGONAL_HEADER', tokens=(Token(ORTHOGONAL_HEADER, '*** Orthogonal Factors ***', 1, 0), Token(EOL, '\n', 1, 26))),
            body=[
                OrthogonalFactor(lineno=2, col_offset=0, end_lineno=2, end_col_offset=28, errors=(), type='NAME', tokens=(Token(NAME, 'ANIMAL', 2, 0), Token(SEPARATOR, '       ', 2, 6), Token(ARGUMENT, '["cat", "dog"]', 2, 13), Token(EOL, '\n', 2, 27))),
                OrthogonalFactor(lineno=3, col_offset=0, end_lineno=3, end_col_offset=38, errors=(), type='NAME', tokens=(Token(NAME, 'COLOR', 3, 0), Token(SEPARATOR, '        ', 3, 5), Token(ARGUMENT, '["red", "green", "blue"]', 3, 13), Token(EOL, '\n', 3, 37))),
                OrthogonalFactor(lineno=4, col_offset=0, end_lineno=4, end_col_offset=29, errors=(), type='NAME', tokens=(Token(NAME, 'SIZE', 4, 0), Token(SEPARATOR, '        ', 4, 4), Token(ARGUMENT, '["big", "small"]', 4, 12), Token(EOL, '\n', 4, 28))),
                EmptyLine(lineno=5, col_offset=0, end_lineno=5, end_col_offset=1, errors=(), type='EOL', tokens=(Token(EOL, '\n', 5, 0),)),
            ],
        ),
        VariableSection(
            lineno=6,
            col_offset=0,
            end_lineno=9,
            end_col_offset=1,
            errors=(),
            header=SectionHeader(lineno=6, col_offset=0, end_lineno=6, end_col_offset=18, errors=(), type='VARIABLE HEADER', tokens=(Token(VARIABLE_HEADER, '*** Variables ***', 6, 0), Token(EOL, '\n', 6, 17))),
            body=[
                Variable(lineno=7, col_offset=0, end_lineno=7, end_col_offset=16, errors=(), type='VARIABLE', tokens=(Token(VARIABLE, '${AGE}', 7, 0), Token(SEPARATOR, '        ', 7, 6), Token(ARGUMENT, '5', 7, 14), Token(EOL, '\n', 7, 15))),
                Variable(lineno=8, col_offset=0, end_lineno=8, end_col_offset=18, errors=(), type='VARIABLE', tokens=(Token(VARIABLE, '${NAME}', 8, 0), Token(SEPARATOR, '       ', 8, 7), Token(ARGUMENT, 'dog', 8, 14), Token(EOL, '\n', 8, 17))),
                EmptyLine(lineno=9, col_offset=0, end_lineno=9, end_col_offset=1, errors=(), type='EOL', tokens=(Token(EOL, '\n', 9, 0),)),
            ],
        ),
        TestCaseSection(
            lineno=10,
            col_offset=0,
            end_lineno=29,
            end_col_offset=1,
            errors=(),
            header=SectionHeader(lineno=10, col_offset=0, end_lineno=10, end_col_offset=19, errors=(), type='TESTCASE HEADER', tokens=(Token(TESTCASE_HEADER, '*** Test Cases ***', 10, 0), Token(EOL, '\n', 10, 18))),
            body=[
                EmptyLine(lineno=11, col_offset=0, end_lineno=11, end_col_offset=1, errors=(), type='EOL', tokens=(Token(EOL, '\n', 11, 0),)),
                TestCase(
                    lineno=12,
                    col_offset=0,
                    end_lineno=20,
                    end_col_offset=1,
                    errors=(),
                    header=TestCaseName(lineno=12, col_offset=0, end_lineno=12, end_col_offset=8, errors=(), type='TESTCASE NAME', tokens=(Token(TESTCASE_NAME, 'if case', 12, 0), Token(EOL, '\n', 12, 7))),
                    body=[
                        If(
                            lineno=13,
                            col_offset=0,
                            end_lineno=19,
                            end_col_offset=8,
                            errors=(),
                            header=IfHeader(lineno=13, col_offset=0, end_lineno=13, end_col_offset=32, errors=(), type='IF', tokens=(Token(SEPARATOR, '    ', 13, 0), Token(IF, 'IF', 13, 4), Token(SEPARATOR, '    ', 13, 6), Token(ARGUMENT, '"$${ANIMAL}" == "dog"', 13, 10), Token(EOL, '\n', 13, 31))),
                            body=[KeywordCall(lineno=14, col_offset=0, end_lineno=14, end_col_offset=43, errors=(), type='KEYWORD', tokens=(Token(SEPARATOR, '        ', 14, 0), Token(KEYWORD, 'Log', 14, 8), Token(SEPARATOR, '    ', 14, 11), Token(ARGUMENT, '$${SIZE}$${COLOR}$${ANIMAL}', 14, 15), Token(EOL, '\n', 14, 42)))],
                            orelse=If(
                                lineno=15,
                                col_offset=0,
                                end_lineno=18,
                                end_col_offset=23,
                                errors=(),
                                header=ElseIfHeader(lineno=15, col_offset=0, end_lineno=15, end_col_offset=36, errors=(), type='ELSE IF', tokens=(Token(SEPARATOR, '    ', 15, 0), Token(ELSE_IF, 'ELSE IF', 15, 4), Token(SEPARATOR, '   ', 15, 11), Token(ARGUMENT, '"$${ANIMAL}" == "cat"', 15, 14), Token(EOL, '\n', 15, 35))),
                                body=[KeywordCall(lineno=16, col_offset=0, end_lineno=16, end_col_offset=19, errors=(), type='KEYWORD', tokens=(Token(SEPARATOR, '        ', 16, 0), Token(KEYWORD, 'Log', 16, 8), Token(SEPARATOR, '    ', 16, 11), Token(ARGUMENT, 'mew', 16, 15), Token(EOL, '\n', 16, 18)))],
                                orelse=If(
                                    lineno=17,
                                    col_offset=0,
                                    end_lineno=18,
                                    end_col_offset=23,
                                    errors=(),
                                    header=ElseHeader(lineno=17, col_offset=0, end_lineno=17, end_col_offset=9, errors=(), type='ELSE', tokens=(Token(SEPARATOR, '    ', 17, 0), Token(ELSE, 'ELSE', 17, 4), Token(EOL, '\n', 17, 8))),
                                    body=[KeywordCall(lineno=18, col_offset=0, end_lineno=18, end_col_offset=23, errors=(), type='KEYWORD', tokens=(Token(SEPARATOR, '        ', 18, 0), Token(KEYWORD, 'Log', 18, 8), Token(SEPARATOR, '    ', 18, 11), Token(ARGUMENT, 'unknown', 18, 15), Token(EOL, '\n', 18, 22)))],
                                    orelse=None,
                                    end=None,
                                ),
                                end=None,
                            ),
                            end=End(lineno=19, col_offset=0, end_lineno=19, end_col_offset=8, errors=(), type='END', tokens=(Token(SEPARATOR, '    ', 19, 0), Token(END, 'END', 19, 4), Token(EOL, '\n', 19, 7))),
                        ),
                        EmptyLine(lineno=20, col_offset=0, end_lineno=20, end_col_offset=1, errors=(), type='EOL', tokens=(Token(EOL, '\n', 20, 0),)),
                    ],
                ),
                TestCase(
                    lineno=21,
                    col_offset=0,
                    end_lineno=29,
                    end_col_offset=1,
                    errors=(),
                    header=TestCaseName(lineno=21, col_offset=0, end_lineno=21, end_col_offset=9, errors=(), type='TESTCASE NAME', tokens=(Token(TESTCASE_NAME, 'if case2', 21, 0), Token(EOL, '\n', 21, 8))),
                    body=[
                        If(
                            lineno=22,
                            col_offset=0,
                            end_lineno=28,
                            end_col_offset=8,
                            errors=(),
                            header=IfHeader(lineno=22, col_offset=0, end_lineno=22, end_col_offset=32, errors=(), type='IF', tokens=(Token(SEPARATOR, '    ', 22, 0), Token(IF, 'IF', 22, 4), Token(SEPARATOR, '    ', 22, 6), Token(ARGUMENT, '"$${ANIMAL}" == "dog"', 22, 10), Token(EOL, '\n', 22, 31))),
                            body=[KeywordCall(lineno=23, col_offset=0, end_lineno=23, end_col_offset=20, errors=(), type='KEYWORD', tokens=(Token(SEPARATOR, '        ', 23, 0), Token(KEYWORD, 'Log', 23, 8), Token(SEPARATOR, '    ', 23, 11), Token(ARGUMENT, 'wang', 23, 15), Token(EOL, '\n', 23, 19)))],
                            orelse=If(
                                lineno=24,
                                col_offset=0,
                                end_lineno=27,
                                end_col_offset=23,
                                errors=(),
                                header=ElseIfHeader(lineno=24, col_offset=0, end_lineno=24, end_col_offset=36, errors=(), type='ELSE IF', tokens=(Token(SEPARATOR, '    ', 24, 0), Token(ELSE_IF, 'ELSE IF', 24, 4), Token(SEPARATOR, '   ', 24, 11), Token(ARGUMENT, '"$${ANIMAL}" == "cat"', 24, 14), Token(EOL, '\n', 24, 35))),
                                body=[KeywordCall(lineno=25, col_offset=0, end_lineno=25, end_col_offset=19, errors=(), type='KEYWORD', tokens=(Token(SEPARATOR, '        ', 25, 0), Token(KEYWORD, 'Log', 25, 8), Token(SEPARATOR, '    ', 25, 11), Token(ARGUMENT, 'mew', 25, 15), Token(EOL, '\n', 25, 18)))],
                                orelse=If(
                                    lineno=26,
                                    col_offset=0,
                                    end_lineno=27,
                                    end_col_offset=23,
                                    errors=(),
                                    header=ElseHeader(lineno=26, col_offset=0, end_lineno=26, end_col_offset=9, errors=(), type='ELSE', tokens=(Token(SEPARATOR, '    ', 26, 0), Token(ELSE, 'ELSE', 26, 4), Token(EOL, '\n', 26, 8))),
                                    body=[KeywordCall(lineno=27, col_offset=0, end_lineno=27, end_col_offset=23, errors=(), type='KEYWORD', tokens=(Token(SEPARATOR, '        ', 27, 0), Token(KEYWORD, 'Log', 27, 8), Token(SEPARATOR, '    ', 27, 11), Token(ARGUMENT, 'unknown', 27, 15), Token(EOL, '\n', 27, 22)))],
                                    orelse=None,
                                    end=None,
                                ),
                                end=None,
                            ),
                            end=End(lineno=28, col_offset=0, end_lineno=28, end_col_offset=8, errors=(), type='END', tokens=(Token(SEPARATOR, '    ', 28, 0), Token(END, 'END', 28, 4), Token(EOL, '\n', 28, 7))),
                        ),
                        EmptyLine(lineno=29, col_offset=0, end_lineno=29, end_col_offset=1, errors=(), type='EOL', tokens=(Token(EOL, '\n', 29, 0),)),
                    ],
                ),
            ],
        ),
        KeywordSection(
            lineno=30,
            col_offset=0,
            end_lineno=33,
            end_col_offset=4,
            errors=(),
            header=SectionHeader(lineno=30, col_offset=0, end_lineno=30, end_col_offset=17, errors=(), type='KEYWORD HEADER', tokens=(Token(KEYWORD_HEADER, '*** Keywords ***', 30, 0), Token(EOL, '\n', 30, 16))),
            body=[
                Keyword(
                    lineno=31,
                    col_offset=0,
                    end_lineno=33,
                    end_col_offset=4,
                    errors=(),
                    header=KeywordName(lineno=31, col_offset=0, end_lineno=31, end_col_offset=5, errors=(), type='KEYWORD NAME', tokens=(Token(KEYWORD_NAME, 'Test', 31, 0), Token(EOL, '\n', 31, 4))),
                    body=[
                        KeywordCall(lineno=32, col_offset=0, end_lineno=32, end_col_offset=21, errors=(), type='KEYWORD', tokens=(Token(SEPARATOR, '    ', 32, 0), Token(KEYWORD, 'Log', 32, 4), Token(SEPARATOR, '   ', 32, 7), Token(ARGUMENT, 'Test begin', 32, 10), Token(EOL, '\n', 32, 20))),
                        EmptyLine(lineno=33, col_offset=0, end_lineno=33, end_col_offset=4, errors=(), type='EOL', tokens=(Token(EOL, '    ', 33, 0),)),
                    ],
                ),
            ],
        ),
    ],
)



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值