summaryrefslogtreecommitdiff
path: root/test/signatures/run_test.py
blob: df612e20a92d72c792fd9fb6c738c3813ad4af4c (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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python

import argparse
import re
import os.path
import sys
import subprocess


class TestConfiguration(object):
    """Represents a test to run."""
    def __init__(self):
        """Initialized from program arguments.
        Exists with code 2 and prints usage message on invalid arguments."""
        parser = argparse.ArgumentParser(
            description='Runs `lfscc on a test file.')
        parser.add_argument('lfscc_binary')
        parser.add_argument('input')
        parser.add_argument('include_dirs', nargs='*')
        args = parser.parse_args()

        self.lfscc = args.lfscc_binary
        self.dep_graph = DepGraph(args.input, args.include_dirs)


class DepGraph(object):
    """Represents a dependency graph of LFSC input files"""
    def __init__(self, root_path, include_dirs):
        """Creates a dependency graph rooted a `root_path`.
        Computes a root-last topological sort.
        Exits with exitcode 1 on cyclic dependencies"""

        # Root of the graph
        self._r = root_path

        # Nodes (paths) that have been visited
        self._visited = set()

        # Nodes (paths) that have been ordered
        self._ordered_set = set()

        # The order of nodes (paths). Root is last.
        self._ordered_paths = []

        self.include_dirs = include_dirs

        # Start DFS topo-order
        self._visit(root_path)

    def _visit(self, p):
        """Puts the descendents of p in the order, parent-last"""
        node = TestFile(p, self.include_dirs)
        self._visited.add(p)
        for n in node.dep_paths:
            if n not in self._ordered_set:
                if n in self._visited:
                    # Our child is is an ancestor our ours!?
                    print("{} and {} are in a dependency cycle".format(p, n))
                    sys.exit(1)
                else:
                    self._visit(n)
        self._ordered_paths.append(p)
        self._ordered_set.add(p)

    def getPathsInOrder(self):
        return self._ordered_paths


class TestFile(object):
    """Represents a testable input file to LFSC"""
    def __init__(self, path, include_dirs):
        """Read the file at `path` and determine its immediate dependencies"""
        self.path = path
        self._get_config_map()
        self.deps = self.config_map['deps'].split() if (
            'deps' in self.config_map) else []
        self.dir = os.path.dirname(self.path)
        self.dep_paths = []
        include_paths = include_dirs + [self.dir]
        for dep in self.deps:
            found_dep = False
            for include_path in include_paths:
                dep_path = os.path.join(include_path, dep)
                if os.path.isfile(dep_path):
                    self.dep_paths.append(dep_path)
                    found_dep = True
                    break
            assert found_dep

    def _get_comment_lines(self):
        """Return an iterator over comment lines, ;'s included"""
        with open(self.path, 'r') as test_file:
            return (line for line in test_file.readlines() if \
                    re.match(r'^\s*;.*$', line) is not None)

    def _get_config_map(self):
        """Populate self.config_map.
        Config variables are set using the syntax
        ; Var Name Spaces Okay: space separated values"""
        m = {}
        for l in self._get_comment_lines():
            match = re.match(r'^.*;\s*(\w+(?:\s+\w+)*)\s*:(.*)$', l)
            if match is not None:
                m[match.group(1).replace(' ', '').lower()] = match.group(2)
        self.config_map = m


def main():
    configuration = TestConfiguration()
    cmd = [configuration.lfscc] + configuration.dep_graph.getPathsInOrder()
    result = subprocess.Popen(cmd,
                              stderr=subprocess.STDOUT,
                              stdout=subprocess.PIPE)
    (stdout, _) = result.communicate()
    if 0 != result.returncode:
        if stdout:
            print(stdout.decode())
    return result.returncode


if __name__ == '__main__':
    sys.exit(main())
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback