blob: 0670627c3c07a973615f371d909126ac5a301464 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/usr/bin/env python
2
3import sys
4import os
5import re
Patrick Williamsc0f7c042017-02-23 20:41:17 -06006from . import ftools
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007
8
9# A parser that can be used to identify weather a line is a test result or a section statement.
10class Lparser(object):
11
Brad Bishopd7bf8c12018-02-25 22:55:05 -050012 def __init__(self, test_0_pass_regex, test_0_fail_regex, test_0_skip_regex, section_0_begin_regex=None, section_0_end_regex=None, **kwargs):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050013 # Initialize the arguments dictionary
14 if kwargs:
15 self.args = kwargs
16 else:
17 self.args = {}
18
19 # Add the default args to the dictionary
20 self.args['test_0_pass_regex'] = test_0_pass_regex
21 self.args['test_0_fail_regex'] = test_0_fail_regex
Brad Bishopd7bf8c12018-02-25 22:55:05 -050022 self.args['test_0_skip_regex'] = test_0_skip_regex
Patrick Williamsc124f4f2015-09-15 14:41:29 -050023 if section_0_begin_regex:
24 self.args['section_0_begin_regex'] = section_0_begin_regex
25 if section_0_end_regex:
26 self.args['section_0_end_regex'] = section_0_end_regex
27
Brad Bishopd7bf8c12018-02-25 22:55:05 -050028 self.test_possible_status = ['pass', 'fail', 'error', 'skip']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029 self.section_possible_status = ['begin', 'end']
30
31 self.initialized = False
32
33
34 # Initialize the parser with the current configuration
35 def init(self):
36
37 # extra arguments can be added by the user to define new test and section categories. They must follow a pre-defined pattern: <type>_<category_name>_<status>_regex
38 self.test_argument_pattern = "^test_(.+?)_(%s)_regex" % '|'.join(map(str, self.test_possible_status))
39 self.section_argument_pattern = "^section_(.+?)_(%s)_regex" % '|'.join(map(str, self.section_possible_status))
40
41 # Initialize the test and section regex dictionaries
42 self.test_regex = {}
43 self.section_regex ={}
44
45 for arg, value in self.args.items():
46 if not value:
47 raise Exception('The value of provided argument %s is %s. Should have a valid value.' % (key, value))
48 is_test = re.search(self.test_argument_pattern, arg)
49 is_section = re.search(self.section_argument_pattern, arg)
50 if is_test:
51 if not is_test.group(1) in self.test_regex:
52 self.test_regex[is_test.group(1)] = {}
53 self.test_regex[is_test.group(1)][is_test.group(2)] = re.compile(value)
54 elif is_section:
55 if not is_section.group(1) in self.section_regex:
56 self.section_regex[is_section.group(1)] = {}
57 self.section_regex[is_section.group(1)][is_section.group(2)] = re.compile(value)
58 else:
59 # TODO: Make these call a traceback instead of a simple exception..
60 raise Exception("The provided argument name does not correspond to any valid type. Please give one of the following types:\nfor tests: %s\nfor sections: %s" % (self.test_argument_pattern, self.section_argument_pattern))
61
62 self.initialized = True
63
64 # Parse a line and return a tuple containing the type of result (test/section) and its category, status and name
65 def parse_line(self, line):
66 if not self.initialized:
67 raise Exception("The parser is not initialized..")
68
69 for test_category, test_status_list in self.test_regex.items():
70 for test_status, status_regex in test_status_list.items():
71 test_name = status_regex.search(line)
72 if test_name:
73 return ['test', test_category, test_status, test_name.group(1)]
74
75 for section_category, section_status_list in self.section_regex.items():
76 for section_status, status_regex in section_status_list.items():
77 section_name = status_regex.search(line)
78 if section_name:
79 return ['section', section_category, section_status, section_name.group(1)]
80 return None
81
82
83class Result(object):
84
85 def __init__(self):
86 self.result_dict = {}
87
88 def store(self, section, test, status):
89 if not section in self.result_dict:
90 self.result_dict[section] = []
91
92 self.result_dict[section].append((test, status))
93
94 # sort tests by the test name(the first element of the tuple), for each section. This can be helpful when using git to diff for changes by making sure they are always in the same order.
95 def sort_tests(self):
96 for package in self.result_dict:
97 sorted_results = sorted(self.result_dict[package], key=lambda tup: tup[0])
98 self.result_dict[package] = sorted_results
99
100 # Log the results as files. The file name is the section name and the contents are the tests in that section.
101 def log_as_files(self, target_dir, test_status):
102 status_regex = re.compile('|'.join(map(str, test_status)))
103 if not type(test_status) == type([]):
104 raise Exception("test_status should be a list. Got " + str(test_status) + " instead.")
105 if not os.path.exists(target_dir):
106 raise Exception("Target directory does not exist: %s" % target_dir)
107
108 for section, test_results in self.result_dict.items():
109 prefix = ''
110 for x in test_status:
111 prefix +=x+'.'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500112 if section:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500113 prefix += section
114 section_file = os.path.join(target_dir, prefix)
115 # purge the file contents if it exists
116 open(section_file, 'w').close()
117 for test_result in test_results:
118 (test_name, status) = test_result
119 # we log only the tests with status in the test_status list
120 match_status = status_regex.search(status)
121 if match_status:
122 ftools.append_file(section_file, status + ": " + test_name)
123
124 # Not yet implemented!
125 def log_to_lava(self):
126 pass