Test Failed
Pull Request — master (#807)
by
unknown
03:38
created

doc.create_individual_doc_test.create_unittest()   B

Complexity

Conditions 6

Size

Total Lines 47
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 22
nop 4
dl 0
loc 47
rs 8.4186
c 0
b 0
f 0
1
# Copyright 2020 Diamond Light Source Ltd.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
6
#
7
#     http://www.apache.org/licenses/LICENSE-2.0
8
#
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14
15
"""
16
.. module:: create_individual_doc_test
17
   :platform: Unix
18
   :synopsis: A module to automatically create plugin documentation
19
.. moduleauthor:: Jessica Verschoyle
20
21
"""
22
import os
23
24
import savu.plugins.utils as pu
25
26
27
def create_plugin_doc_testing_file(savu_base_path, module_name, file_path):
28
    """Open the provided file path. Read the lines beginning with a command
29
    prompt and save these to a list. Write these lines to a unittest file.
30
31
    :param savu_base_path:
32
    :param module_name: plugin module name
33
    :param file_path: plugin documentation file path
34
    """
35
    # Read the testing lines from the plugin documentation file
36
    doc_file_path = f"{savu_base_path}{module_name}/{file_path}"
37
    testing_lines, process_lists = read_test_file(doc_file_path)
38
39
    # If there are testing lines and/or process lists inside the plugin
40
    # documentation, then append the configurator end lines for use with
41
    # the unittest
42
    plugin_dir = module_name.split("plugins")[1]
43
    if testing_lines:
44
        file_name = file_path.split(".")[0]
45
        create_unittest(file_name, testing_lines, process_lists, plugin_dir)
46
47
48
def create_unittest(file_name, testing_lines, process_lists, plugin_dir):
49
    """Create a unittest file
50
51
    :param file_name: Plugin file name
52
    :param testing_lines: Command lines to test
53
    :param process_lists: List of process list file paths to check
54
    :param plugin_dir: Plugin directory to save the log files inside
55
    """
56
    unittest_file_path = f"{savu_base_path}doc/doc_tests//plugins/" \
57
                        f"{plugin_dir}/{file_name}_test.py"
58
    pu.create_dir(unittest_file_path)
59
    unittest_setup = get_unittest_setup(plugin_dir, file_name)
60
61
    if testing_lines:
62
        unittest_config_start, unittest_config_end, test_list \
63
            = get_unittest_commands(testing_lines, process_lists, file_name)
64
65
    # If there are process lists inside the doc file, create a refresh function
66
    if process_lists:
67
        unittest_process_start, unittest_process_end, process_list_format = \
68
            get_unittest_process_list_function(process_lists)
69
70
    unittest_end = '''
71
    
72
    def tearDown(self):
73
        # End the logging session
74
        dtu.end_logging(logger, logger_rst, fh, ch, fh_rst)
75
        logging.shutdown()
76
77
if __name__ == "__main__":
78
    unittest.main()
79
    '''
80
81
    with open(unittest_file_path, "w") as unittest_file:
82
        unittest_file.write(unittest_setup)
83
84
        if process_lists:
85
            unittest_file.write(unittest_process_start)
0 ignored issues
show
introduced by
The variable unittest_process_start does not seem to be defined in case process_lists on line 66 is False. Are you sure this can never be the case?
Loading history...
86
            unittest_file.writelines(process_list_format)
0 ignored issues
show
introduced by
The variable process_list_format does not seem to be defined in case process_lists on line 66 is False. Are you sure this can never be the case?
Loading history...
87
            unittest_file.write(unittest_process_end)
0 ignored issues
show
introduced by
The variable unittest_process_end does not seem to be defined in case process_lists on line 66 is False. Are you sure this can never be the case?
Loading history...
88
89
        if testing_lines:
90
            unittest_file.write(unittest_config_start)
0 ignored issues
show
introduced by
The variable unittest_config_start does not seem to be defined in case testing_lines on line 61 is False. Are you sure this can never be the case?
Loading history...
91
            unittest_file.writelines(test_list)
0 ignored issues
show
introduced by
The variable test_list does not seem to be defined in case testing_lines on line 61 is False. Are you sure this can never be the case?
Loading history...
92
            unittest_file.write(unittest_config_end)
0 ignored issues
show
introduced by
The variable unittest_config_end does not seem to be defined in case testing_lines on line 61 is False. Are you sure this can never be the case?
Loading history...
93
94
        unittest_file.write(unittest_end)
95
96
97
def create_init_file(plugin_directory):
98
    """Create a an init file for the unit test
99
100
    :param plugin_directory: Plugin directory to save the log files inside
101
    """
102
    template_init_file_path = f"{savu_base_path}doc/doc_tests/__init__.py"
103
    init_file_path = f"{plugin_directory}/__init__.py"
104
    if not os.path.isfile(init_file_path):
105
        with open(init_file_path, "w+") as init_file:
106
            append_file(init_file, template_init_file_path)
107
108
109
def append_file(f, additional_file):
110
    """ Append the additional_file on to main file f """
111
    with open(additional_file) as add_file:
112
        f.write(add_file.read())
113
114
115
def get_unittest_process_list_function(process_lists):
116
    """Create function to refresh process lists
117
118
    :param process_lists: List of process list file paths
119
    :return: refresh_process_start, refresh_process_end, process_list_format
120
    """
121
    # Set up the indentation for the proces list
122
    indent = 25 * " "
123
    newline_str = ",\n" + indent
124
    # Create the list as a string
125
    process_list_format = list(map(lambda x: '\"' + x + '\"', process_lists))
126
    process_list_format = \
127
        (newline_str.join(list(map(str, process_list_format))))
128
129
    refresh_process_start = '''
130
    def refresh_process_lists(self):
131
        """ Run through the process list files and refresh them to update
132
        any inconsistent parameter values.
133
        If there is a value which cannot be used, that parameter will 
134
        be set to the default value.
135
        """
136
        process_lists = ['''
137
    refresh_process_end = ''']
138
        output_checks = ["Exception","Error","ERROR"]
139
        for process_list_path in process_lists:
140
            file_exists = os.path.exists(savu_base_path + process_list_path)
141
            error_msg = f"The process list at {process_list_path}" \\
142
                        f"does not exist."
143
            
144
            self.assertTrue(file_exists, msg=error_msg)
145
            if file_exists:
146
                # Write the process list being tested to the logger
147
                logger.debug(f"REFRESH PROCESS LIST: " \\
148
                             f"{savu_base_path}{process_list_path}")
149
                saved_stdout = sys.stdout
150
                try:
151
                    out = StringIO()
152
                    sys.stdout = out
153
                    refresh.generate_test(savu_base_path \\
154
                                              + process_list_path)
155
                    output_value = out.getvalue().strip()
156
                    for check in output_checks:
157
                        error_msg = f"Refresh failed: {check} in the output."
158
                        assert check not in output_value, error_msg
159
                finally:
160
                    sys.stdout = saved_stdout
161
        '''
162
    return refresh_process_start, refresh_process_end, process_list_format
163
164
165
def get_unittest_commands(testing_lines, process_lists, file_name):
166
    """Set up the method for testing savu configurator commands
167
168
    :param testing_lines: The command lines to test
169
    :return: unittest_function_start, unittest_function_end, test_list
170
    """
171
172
    # Set up the indentation for the command list
173
    indent = 22 * " "
174
    newline_str = '",\n' + indent
175
    # Create the list as a string
176
    test_list = list(map(lambda x: '"' + x + newline_str, testing_lines))
177
178
    # Set up the unittest
179
    unittest_function_start = '''    
180
    def test_''' + file_name + '''(self):
181
        """ Run the input commands with savu_config
182
        """
183
        '''
184
    if process_lists:
185
        unittest_function_start += "self.refresh_process_lists()"
186
187
    unittest_function_start += '''
188
        input_list = ['''
189
    unittest_function_end = '''"exit", "y"]
190
        output_checks = ["Exception","Error","ERROR"]
191
        sctu.savu_config_runner(input_list, output_checks, 
192
                                error_str=True)'''
193
    return unittest_function_start, unittest_function_end, test_list
194
195
196
def read_test_file(doc_file_path):
197
    """Read the command prompt lines from the doc file and append to list
198
199
    :param doc_file_path:
200
    :return: testing_lines, process_lists
201
    """
202
    testing_lines = []
203
    process_lists = []
204
    with open(doc_file_path, "r") as doc_file:
205
        for line in doc_file:
206
            if ">>>" in line:
207
                line = line.replace(">>>", "")
208
                if "open " in line:
209
                    # Replace file path with the correct full path
210
                    line = line.replace("open ", "open " + savu_base_path)
0 ignored issues
show
introduced by
The variable savu_base_path does not seem to be defined in case __name__ == "__main__" on line 271 is False. Are you sure this can never be the case?
Loading history...
211
                testing_lines.append(line.strip())
212
            if ".. ::process_list::" in line:
213
                # Documentation must include this line in order to update
214
                # the plugin list before running it in the example
215
                # '.. ' indicates a rst file comment
216
                line = line.replace(".. ::process_list::", "")
217
                process_lists.append(line.strip())
218
    return testing_lines, process_lists
219
220
221
def get_unittest_setup(dir_name, file_name):
222
    """Setup unittest
223
224
    :param dir_name: Directory name
225
    :param file_name: Plugin name
226
    :return: unittest_setup
227
    """
228
    folder_name = file_name.replace("_doc", "")
229
230
    unittest_name = file_name.replace('_', ' ').title().replace(' ','')
231
    unittest_setup='''
232
"""
233
.. module:: ''' + file_name + '''_test
234
   :platform: Unix
235
   :synopsis: unittest test for plugin restructured text file documentation
236
.. moduleauthor: Jessica Verschoyle
237
238
"""
239
240
import os
241
import sys
242
import unittest
243
import logging
244
import logging.config
245
246
from io import StringIO
247
248
import doc.doc_tests.doc_test_utils as dtu
249
import scripts.configurator_tests.savu_config_test_utils as sctu
250
import scripts.configurator_tests.refresh_process_lists_test as refresh
251
252
# Determine Savu base path
253
main_dir = \\
254
    os.path.dirname(os.path.realpath(__file__)).split("/Savu/")[0]
255
savu_base_path = f"{main_dir}/Savu/"
256
257
# Reset the args for command line input
258
dtu.setup_argparser()
259
260
# Start logging
261
logger, logger_rst = dtu.get_loggers()
262
fh, ch, fh_rst = dtu.setup_log_files(logger, logger_rst,
263
                                     "'''+f"{dir_name}/{folder_name}/"\
264
                                         +'''")
265
                                     
266
class '''+unittest_name+'''Test(unittest.TestCase):
267
'''
268
    return unittest_setup
269
270
271
if __name__ == "__main__":
272
    # determine Savu base path
273
    main_dir = os.path.dirname(os.path.realpath(__file__)).split("/Savu/")[0]
274
    savu_base_path = f"{main_dir}/Savu/"
275
    plugin_doc_file_path = \
276
        f"{savu_base_path}doc/source/plugin_guides/plugins/"
277
    doc_test_path = f"{savu_base_path}doc/doc_tests/"
278
    for root, dirs, files in os.walk(plugin_doc_file_path, topdown=True):
279
        pkg_path = root.split("Savu/")[1]
280
        module_name = pkg_path.replace("savu/", "")
281
        for file in files:
282
            file_name = file.split(".")[0]
283
            unittest_file_path = f"{doc_test_path}{file_name}_test.py"
284
285
            # Read the testing lines from the plugin documentation file
286
            create_plugin_doc_testing_file(savu_base_path, module_name, file)
287
    for root, dirs, files in os.walk(f"{doc_test_path}plugins", topdown=True):
288
        create_init_file(root)
289