Fix wrong module name in test helper
[idea/community.git] / python / educational-python / resources / fileTemplates / internal / test_helper.py.ft
1 import sys
2
3
4 def get_file_text(path):
5     """ Returns file text by path"""
6     file_io = open(path, "r")
7     text = file_io.read()
8     file_io.close()
9     return text
10
11
12 def get_file_output(encoding="utf-8", path=sys.argv[-1], arg_string=""):
13     """
14     Returns answer file output
15     :param encoding: to decode output in python3
16     :param path: path of file to execute
17     :return: list of strings
18     """
19     import subprocess
20
21     proc = subprocess.Popen([sys.executable, path], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
22                             stderr=subprocess.STDOUT)
23     if arg_string:
24         for arg in arg_string.split("\n"):
25             proc.stdin.write(bytearray(str(arg) + "\n", encoding))
26             proc.stdin.flush()
27
28     return list(map(lambda x: str(x.decode(encoding)), proc.communicate()[0].splitlines()))
29
30
31 def test_file_importable():
32     """ Tests there is no obvious syntax errors"""
33     path = sys.argv[-1]
34     if not path.endswith(".py"):
35         import os
36
37         parent = os.path.abspath(os.path.join(path, os.pardir))
38         python_files = [f for f in os.listdir(parent) if os.path.isfile(os.path.join(parent, f)) and f.endswith(".py")]
39         for python_file in python_files:
40             if python_file == "tests.py":
41                 continue
42             check_importable_path(os.path.join(parent, python_file))
43         return
44     check_importable_path(path)
45
46
47 def check_importable_path(path):
48     """ Checks that file is importable.
49         Reports failure otherwise.
50     """
51     saved_input = patch_input()
52     try:
53         import_file(path)
54     except:
55         failed("The file contains syntax errors", test_file_importable.__name__)
56         return
57     finally:
58         revert_input(saved_input)
59
60     passed(test_file_importable.__name__)
61
62
63 def patch_input():
64     def mock_fun(_m=""):
65         return "mock"
66
67     if sys.version_info[0] == 3:
68         import builtins
69         save_input = builtins.input
70         builtins.input = mock_fun
71         return save_input
72     elif sys.version_info[0] == 2:
73         import __builtin__
74         save_input = __builtin__.raw_input
75         __builtin__.raw_input = mock_fun
76         __builtin__.input = mock_fun
77         return save_input
78
79
80 def revert_input(saved_input):
81     if sys.version_info[0] == 3:
82         import builtins
83         builtins.input = saved_input
84     elif sys.version_info[0] == 2:
85         import __builtin__
86         __builtin__.raw_input = saved_input
87         __builtin__.input = saved_input
88
89
90 def import_file(path):
91     """ Returns imported file """
92     if sys.version_info[0] == 2 or sys.version_info[1] < 3:
93         import imp
94
95         return imp.load_source("tmp", path)
96     elif sys.version_info[0] == 3:
97         import importlib.machinery
98
99         return importlib.machinery.SourceFileLoader("tmp", path).load_module("tmp")
100
101
102 def import_task_file():
103     """ Returns imported file.
104         Imports file from which check action was run
105     """
106     path = sys.argv[-1]
107     return import_file(path)
108
109
110 def test_is_not_empty():
111     """
112         Checks that file is not empty
113     """
114     path = sys.argv[-1]
115     file_text = get_file_text(path)
116
117     if len(file_text) > 0:
118         passed()
119     else:
120         failed("The file is empty. Please, reload the task and try again.")
121
122
123 def test_is_initial_text(error_text="You should modify the file"):
124     """
125         Checks that file was modified
126     """
127     path = sys.argv[-1]
128     text = get_initial_text(path)
129     file_text = get_file_text(path)
130
131     if file_text.strip() == text.strip():
132         failed(error_text)
133     else:
134         passed()
135
136
137 def get_initial_text(path):
138     """
139         Returns the initial task text
140     """
141     course_lib = sys.argv[-2]
142
143     import os
144     # path format is "project_root/lessonX/taskY/file.py"
145     task_index = path.rfind(os.sep, 0, path.rfind(os.sep))
146     index = path.rfind(os.sep, 0, task_index)
147     relative_path = path[index + 1:]
148     initial_file_path = os.path.join(course_lib, relative_path)
149     return get_file_text(initial_file_path)
150
151
152 def test_text_equals(text, error_text):
153     """
154         Checks that answer equals text.
155     """
156     path = sys.argv[-1]
157     file_text = get_file_text(path)
158
159     if file_text.strip() == text:
160         passed()
161     else:
162         failed(error_text)
163
164
165 def test_answer_placeholders_text_deleted(error_text="Don't just delete task text"):
166     """
167         Checks that all answer placeholders are not empty
168     """
169     windows = get_answer_placeholders()
170
171     for window in windows:
172         if len(window) == 0:
173             failed(error_text)
174             return
175     passed()
176
177
178 def set_congratulation_message(message):
179     """ Overrides default 'Congratulations!' message """
180     print("#educational_plugin CONGRATS_MESSAGE " + message)
181
182
183 def failed(message="Please, reload the task and try again.", name=None):
184     """ Reports failure """
185     if not name:
186         name = sys._getframe().f_back.f_code.co_name
187     print("#educational_plugin " + name + " FAILED + " + message)
188
189
190 def passed(name=None):
191     """ Reports success """
192     if not name:
193         name = sys._getframe().f_back.f_code.co_name
194     print("#educational_plugin " + name + " test OK")
195
196
197 def get_answer_placeholders():
198     """
199         Returns all answer placeholders text
200     """
201     prefix = "#educational_plugin_window = "
202     path = sys.argv[-1]
203     import os
204
205     file_name_without_extension = os.path.splitext(path)[0]
206     windows_path = file_name_without_extension + "_windows"
207     windows = []
208     f = open(windows_path, "r")
209     window_text = ""
210     first = True
211     for line in f.readlines():
212         if line.startswith(prefix):
213             if not first:
214                 windows.append(window_text.strip())
215             else:
216                 first = False
217             window_text = line[len(prefix):]
218         else:
219             window_text += line
220
221     if window_text:
222         windows.append(window_text.strip())
223
224     f.close()
225     return windows
226
227
228 def check_samples(samples=()):
229     """
230       Check script output for all samples. Sample is a two element list, where the first is input and
231       the second is output.
232     """
233     for sample in samples:
234         if len(sample) == 2:
235             output = get_file_output(arg_string=str(sample[0]))
236             if "\n".join(output) != sample[1]:
237                 failed(
238                     "Test from samples failed: \n \n"
239                     "Input:\n{}"
240                     "\n \n"
241                     "Expected:\n{}"
242                     "\n \n"
243                     "Your result:\n{}".format(str.strip(sample[0]), str.strip(sample[1]), "\n".join(output)))
244                 return
245         set_congratulation_message("All test from samples passed. Now we are checking your solution on Stepic server.")
246
247     passed()
248
249
250 def run_common_tests(error_text="Please, reload file and try again"):
251     test_is_initial_text()
252     test_is_not_empty()
253     test_answer_placeholders_text_deleted()
254     test_file_importable()