summaryrefslogtreecommitdiff
path: root/tests/test_typestubs.py
blob: 6a8d75f30c7ea21ac6e5bc5d84b3c0aadbcd1acc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import ast
import re


def read_stubfile():
    with open("adblock/adblock.pyi", encoding="utf-8") as file:
        node = ast.parse(file.read())
    return node


def get_functions_and_methods(node):
    functions = [n for n in node.body if isinstance(n, ast.FunctionDef)]
    classes = [n for n in node.body if isinstance(n, ast.ClassDef)]

    methods = {}
    for c in classes:
        methods[c.name] = [n for n in c.body if isinstance(n, ast.FunctionDef)]

    return functions, methods


def pattern_exists_in_file(filename, regex):
    """
    Checks if the given regex is present in the given file
    """
    with open(filename, "r", encoding="utf-8") as f:
        for line in f:
            if re.search(regex, line):
                return True
    return False


def test_functions_and_methods_exist_in_rust():
    """
    Check that for each of the functions and methods present in the Python
    typestub file, there is a line in `src/lib.rs` containing a matching
    definition. Since we're doing a naive grep search, without access to the
    Rust AST, there may be false negatives.
    """
    stubfile_node = read_stubfile()
    functions, methods = get_functions_and_methods(stubfile_node)

    methods_flattened = []
    for class_methods in methods.values():
        methods_flattened += class_methods

    for f in functions + methods_flattened:
        if f.name.startswith("__"):
            # Skip dunder methods since their names are the same for every
            # class, making the test not particularly useful. They are also not
            # marked `pub` in Rust.
            continue
        assert pattern_exists_in_file("src/lib.rs", r"pub fn {}".format(f.name))