1import os
2import sys
3import argparse
4import re
5
6class Checks(object):
7    class CheckError(Exception):
8        pass
9
10    def __init__(self, filename, prefix):
11        self.checks = []
12        self.lines = []
13        self.check_no_output = False
14        self.filename = filename
15        self.prefix = prefix
16    def readStdin(self):
17        self.lines = [l.rstrip('\r\n') for l in sys.stdin.readlines()]
18    def readChecks(self):
19        with open(self.filename) as f:
20            for line in f:
21                match = re.search('{}: NO_OUTPUT'.format(self.prefix), line)
22                if match is not None:
23                    self.check_no_output = True
24                    return
25                match = re.search('{}: num_threads=([0-9]+) (.*)$'.format(self.prefix), line)
26                if match is not None:
27                    num_threads = int(match.group(1))
28                    for i in range(num_threads):
29                        self.checks.append(match.group(2))
30                    continue
31    def check(self):
32        # If no checks at all, then nothing to do
33        if len(self.checks) == 0 and not self.check_no_output:
34            print('Nothing to check for')
35            return
36        # Check if we are expecting no output
37        if self.check_no_output:
38            if len(self.lines) == 0:
39                return
40            else:
41                raise Checks.CheckError('{}: Output was found when expecting none.'.format(self.prefix))
42        # Run through each check line and see if it exists in the output
43        # If it does, then delete the line from output and look for the
44        # next check line.
45        # If you don't find the line then raise Checks.CheckError
46        # If there are extra lines of output then raise Checks.CheckError
47        for c in self.checks:
48            found = False
49            index = -1
50            for idx, line in enumerate(self.lines):
51                if re.search(c, line) is not None:
52                    found = True
53                    index = idx
54                    break
55            if not found:
56                raise Checks.CheckError('{}: Did not find: {}'.format(self.prefix, c))
57            else:
58                del self.lines[index]
59        if len(self.lines) != 0:
60            raise Checks.CheckError('{}: Extra output: {}'.format(self.prefix, self.lines))
61
62# Setup argument parsing
63parser = argparse.ArgumentParser(description='''This script checks output of
64    a program against "CHECK" lines in filename''')
65parser.add_argument('filename', default=None, help='filename to check against')
66parser.add_argument('-c', '--check-prefix', dest='prefix',
67                    default='CHECK', help='check prefix token default: %(default)s')
68command_args = parser.parse_args()
69# Do the checking
70checks = Checks(command_args.filename, command_args.prefix)
71checks.readStdin()
72checks.readChecks()
73checks.check()
74