示例#1
0
def test_no_tags_implies_notice():
    code = """
'''
Because there is no tag, this docstring is handled as a notice.
'''
@public
def foo():
    '''
    This one too!
    '''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    userdoc, devdoc = parse_natspec(srilang_ast, global_ctx)

    assert userdoc == {
        "methods": {
            "foo()": {
                "notice": "This one too!"
            }
        },
        "notice":
        "Because there is no tag, this docstring is handled as a notice.",
    }
    assert not devdoc
示例#2
0
def test_whitespace():
    code = """
'''
        @dev

  Whitespace    gets  cleaned
    up,
            people can use


         awful formatting.


We don't mind!

@author Mr No-linter
                '''
"""
    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    _, devdoc = parse_natspec(srilang_ast, global_ctx)

    assert devdoc == {
        "author":
        "Mr No-linter",
        "details":
        "Whitespace gets cleaned up, people can use awful formatting. We don't mind!",
    }
示例#3
0
def test_returns():
    code = """
@public
def foo(bar: int128, baz: uint256) -> (int128, uint256):
    '''
    @return value of bar
    @return value of baz
    '''
    return bar, baz
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    _, devdoc = parse_natspec(srilang_ast, global_ctx)

    assert devdoc == {
        "methods": {
            "foo(int128,uint256)": {
                "returns": {
                    "_0": "value of bar",
                    "_1": "value of baz"
                }
            }
        }
    }
示例#4
0
def test_params():
    code = """
@public
def foo(bar: int128, baz: uint256, potato: bytes32):
    '''
    @param bar a number
    @param baz also a number
    @dev we didn't document potato, but that's ok
    '''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    _, devdoc = parse_natspec(srilang_ast, global_ctx)

    assert devdoc == {
        "methods": {
            "foo(int128,uint256,bytes32)": {
                "details": "we didn't document potato, but that's ok",
                "params": {
                    "bar": "a number",
                    "baz": "also a number"
                },
            }
        }
    }
示例#5
0
def test_documentation_example_output():
    srilang_ast = parse_to_ast(test_code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    userdoc, devdoc = parse_natspec(srilang_ast, global_ctx)

    assert userdoc == expected_userdoc
    assert devdoc == expected_devdoc
示例#6
0
def generate_inline_function(code, variables, memory_allocator):
    ast_code = parse_to_ast(code)
    new_context = Context(vars=variables,
                          global_ctx=GlobalContext(),
                          memory_allocator=memory_allocator,
                          origcode=code)
    generated_lll = parse_body(ast_code.body, new_context)
    return new_context, generated_lll
示例#7
0
def test_empty_param(bad_docstring):
    code = f"""
@public
def foo(a: int128):
    '''{bad_docstring}'''
    pass
    """
    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="No description given for parameter 'a'"):
        parse_natspec(srilang_ast, global_ctx)
示例#8
0
def test_too_many_returns_no_return_type():
    code = """
@public
def foo():
    '''@return should fail, the function does not include a return value'''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="Method does not return any values"):
        parse_natspec(srilang_ast, global_ctx)
示例#9
0
def test_unknown_param():
    code = """
@public
def foo(bar: int128, baz: uint256):
    '''@param hotdog not a number'''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="Method has no parameter 'hotdog'"):
        parse_natspec(srilang_ast, global_ctx)
示例#10
0
def test_invalid_field():
    code = """
@public
def foo():
    '''@title function level docstrings cannot have titles'''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="'@title' is not a valid field"):
        parse_natspec(srilang_ast, global_ctx)
示例#11
0
def parse_to_lll(
        source_code: str,
        runtime_only: bool = False,
        interface_codes: Optional[InterfaceImports] = None) -> LLLnode:
    srilang_module = sri_ast.parse_to_ast(source_code)
    global_ctx = GlobalContext.get_global_context(
        srilang_module, interface_codes=interface_codes)
    lll_nodes, lll_runtime = parse_tree_to_lll(source_code, global_ctx)

    if runtime_only:
        return lll_runtime
    else:
        return lll_nodes
示例#12
0
def test_duplicate_param():
    code = """
@public
def foo(bar: int128, baz: uint256):
    '''
    @param bar a number
    @param bar also a number
    '''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="Parameter 'bar' documented more than once"):
        parse_natspec(srilang_ast, global_ctx)
示例#13
0
def test_unknown_field():
    code = """
@public
def foo():
    '''
    @notice this is ok
    @thing this is bad
    '''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="Unknown NatSpec field '@thing'"):
        parse_natspec(srilang_ast, global_ctx)
示例#14
0
def test_partial_natspec():
    code = """
@public
def foo():
    '''
    Regular comments preceeding natspec is not allowed
    @notice this is natspec
    '''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="NatSpec docstring opens with untagged comment"):
        parse_natspec(srilang_ast, global_ctx)
示例#15
0
def extract_sigs(sig_code):
    if sig_code['type'] == 'srilang':
        interface_ast = [
            i for i in sri_ast.parse_to_ast(sig_code['code']) if
            isinstance(i, sri_ast.FunctionDef) or
            (isinstance(i, sri_ast.AnnAssign) and i.target.id != "implements")
        ]
        global_ctx = GlobalContext.get_global_context(interface_ast)
        return sig_utils.mk_full_signature(global_ctx, sig_formatter=lambda x: x)
    elif sig_code['type'] == 'json':
        return mk_full_signature_from_json(sig_code['code'])
    else:
        raise Exception(
            (f"Unknown interface signature type '{sig_code['type']}' supplied. "
             "'srilang' & 'json' are supported")
        )
示例#16
0
def test_duplicate_fields():
    code = """
@public
def foo():
    '''
    @notice It's fine to have one notice, but....
    @notice a second one, not so much
    '''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="Duplicate NatSpec field '@notice'"):
        parse_natspec(srilang_ast, global_ctx)
示例#17
0
def test_too_many_returns_single_return_type():
    code = """
@public
def foo() -> int128:
    '''
    @return int128
    @return this should fail
    '''
    return 1
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    with pytest.raises(
            NatSpecSyntaxException,
            match="Number of documented return values exceeds actual number",
    ):
        parse_natspec(srilang_ast, global_ctx)
示例#18
0
def generate_global_context(
    srilang_module: sri_ast.Module, interface_codes: Optional[InterfaceImports],
) -> GlobalContext:
    """
    Generate a contextualized AST from the srilang AST.

    Arguments
    ---------
    srilang_module : sri_ast.Module
        Top-level srilang AST node
    interface_codes: Dict, optional
        Interfaces that may be imported by the contracts.

    Returns
    -------
    GlobalContext
        Sorted, contextualized representation of the srilang AST
    """
    return GlobalContext.get_global_context(
        srilang_module, interface_codes=interface_codes
    )
示例#19
0
def test_ignore_private_methods():
    code = """
@public
def foo(bar: int128, baz: uint256):
    '''@dev I will be parsed.'''
    pass

@private
def notfoo(bar: int128, baz: uint256):
    '''@dev I will not be parsed.'''
    pass
    """

    srilang_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(srilang_ast)
    _, devdoc = parse_natspec(srilang_ast, global_ctx)

    assert devdoc["methods"] == {
        "foo(int128,uint256)": {
            "details": "I will be parsed."
        }
    }