From 5e589d47009fdeea86b5363ef27d26559c7d820a Mon Sep 17 00:00:00 2001 From: Liana Bakradze Date: Tue, 14 Oct 2014 17:43:48 +0400 Subject: [PATCH] EDU-205 Write meaningful information to the output of a test run --- .../fileTemplates/internal/test_helper.py.ft | 97 +++++++++++++----- .../resources/courses/introduction_course.zip | Bin 95292 -> 95411 bytes .../jetbrains/python/edu/StudyTestRunner.java | 22 ++-- .../python/edu/actions/StudyCheckAction.java | 2 +- 4 files changed, 89 insertions(+), 32 deletions(-) diff --git a/python/edu/course-creator/resources/fileTemplates/internal/test_helper.py.ft b/python/edu/course-creator/resources/fileTemplates/internal/test_helper.py.ft index 9dc07f2e219a..4b1d9660714b 100644 --- a/python/edu/course-creator/resources/fileTemplates/internal/test_helper.py.ft +++ b/python/edu/course-creator/resources/fileTemplates/internal/test_helper.py.ft @@ -1,5 +1,6 @@ import sys + def get_file_text(path): """ get file text by path""" file_io = open(path, "r") @@ -7,41 +8,65 @@ def get_file_text(path): file_io.close() return text -def get_file_output(path): - # TODO: get file output by path - return "" + +def get_file_output(): + saved_stdout = sys.stdout + try: + from StringIO import StringIO + + out = StringIO() + sys.stdout = out + import_task_file() + output = out.getvalue().strip() + return output + finally: + sys.stdout = saved_stdout + def test_file_importable(): """ tests there is no obvious syntax errors""" path = sys.argv[-1] + if not path.endswith(".py"): + import os + + parent = os.path.abspath(os.path.join(path, os.pardir)) + python_files = [f for f in os.listdir(parent) if os.path.isfile(os.path.join(parent, f)) and f.endswith(".py")] + for python_file in python_files: + if python_file == "tests.py": continue + check_importable_path(os.path.join(parent, python_file)) + return + check_importable_path(path) + + +def check_importable_path(path): try: import_file(path) - except ImportError: - failed("File contains syntax errors") - return - except SyntaxError: - failed("File contains syntax errors") - return - except NameError: - failed("File contains syntax errors") + except: + failed("File contains syntax errors", test_file_importable.func_name) return + passed(test_file_importable.func_name) - passed() def import_file(path): """ returns imported file """ if sys.version_info[0] == 2: - import imp - return imp.load_source("tmp", path) + import imp + + return imp.load_source("tmp", path) elif sys.version_info[0] == 3: - import importlib.machinery - return importlib.machinery.SourceFileLoader("tmp", path).load_module("tmp") + import importlib.machinery + + return importlib.machinery.SourceFileLoader("tmp", path).load_module("tmp") + def import_task_file(): - """ returns imported file """ + """ returns imported file + imports file from which check action was run + """ path = sys.argv[-1] return import_file(path) + def test_is_not_empty(): path = sys.argv[-1] file_text = get_file_text(path) @@ -51,6 +76,7 @@ def test_is_not_empty(): else: failed("The file is empty. Please, reload the task and try again.") + def test_is_initial_text(error_text="You should modify the file"): path = sys.argv[-1] text = get_initial_text(path) @@ -61,6 +87,7 @@ def test_is_initial_text(error_text="You should modify the file"): else: passed() + def get_initial_text(path): course_lib = sys.argv[-2] @@ -68,7 +95,7 @@ def get_initial_text(path): # path format is "project_root/lessonX/taskY/file.py" task_index = path.rfind(os.sep, 0, path.rfind(os.sep)) index = path.rfind(os.sep, 0, task_index) - relative_path = path[index+1:] + relative_path = path[index + 1:] initial_file_path = os.path.join(course_lib, relative_path) return get_file_text(initial_file_path) @@ -82,6 +109,7 @@ def test_text_equals(text, error_text): else: failed(error_text) + def test_window_text_deleted(error_text="Don't just delete task text"): windows = get_task_windows() @@ -92,17 +120,35 @@ def test_window_text_deleted(error_text="Don't just delete task text"): passed() -def failed(message="Please, reload the task and try again."): - print("#educational_plugin FAILED + " + message) +def failed(message="Please, reload the task and try again.", name=None): + if not name: + name = sys._getframe().f_back.f_code.co_name + print("#educational_plugin " + name + " FAILED + " + message) -def passed(): - print("#educational_plugin test OK") -def get_task_windows(): +def passed(name=None): + if not name: + name = sys._getframe().f_back.f_code.co_name + print("#educational_plugin " + name + " test OK") + + +def get_task_windows(file_name=None): prefix = "#educational_plugin_window = " - path = sys.argv[-1] import os - windows_path = os.path.splitext(path)[0] + "_windows" + + parent = os.path.abspath(os.path.join(sys.argv[-1], os.pardir)) + if not file_name: + path = sys.argv[-1] + else: + path = os.path.join(parent, file_name) + import os + + file_name_without_extension = os.path.splitext(path)[0] + windows_path = file_name_without_extension + "_windows" + smart_test_files = [f for f in os.listdir(parent) if + os.path.join(parent, f) == file_name_without_extension + "_answers_window_windows"] + if len(smart_test_files) == 1: + windows_path = os.path.join(parent, smart_test_files[0]) windows = [] f = open(windows_path, "r") window_text = "" @@ -123,6 +169,7 @@ def get_task_windows(): f.close() return windows + def run_common_tests(error_text="Please, reload file and try again"): test_file_importable() test_is_not_empty() diff --git a/python/edu/learn-python/resources/courses/introduction_course.zip b/python/edu/learn-python/resources/courses/introduction_course.zip index 0d76bc8d2d13efc94fb146ba0fa1d651e2503547..d6578cafb773cf03b68b3be96d1a86d7f731257a 100644 GIT binary patch delta 8799 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

+PkY~WpBmk3Lc-A=;KZ5S)OClNk?F5#v`cy09D zqHOIK?jrg>CTyxE delta 8726 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

TvQ3Ez*A= z+|OTD=>6y3p0t7zdaTqW2SgC1a3zgm=nrKy@?eHP^!yV(Be?AEIAFPkg4h5kC1NcF z^#R~>fCv2pfp!@_55NZ(t=A%Ez2IKB7YN6%aXrdt?k<+Q;KC=%e#Ks;%DFl@w1xM&yG5(jdcw zV682xWDYD@Du%HX{-*dThS4ZdVHvI+P$(XT!(;T5gnL)9B4H!JfA~QPj*kTD z=tEL~wGZ?6^_U1Kr|2-HtcpOxnN3G1(2fM>4j#a>KZprEMlH>e5GnjPjii1;m!yn> zp=O_;)+?jH?+OoK$LbKD(P%JwM07{PGOGI`O>z(vOvY)-?-B)TnR$kSk|=P#OaU&c zHXtg|5L&f{<~mu!pNi$tFe#^6>T@p|%5gi(0UHt=1FKLe1)0pga|DfnH=Bd!rAC~7 zp$pkH29Dldk~0RG;`n+M(m56~YSeKPG~pEZOdUU(9kDQ)jEiy$c@YbVN-oJ2c*tcP zk`f06ZoDj4k}Gi#@Yin&7#GYS9%k^J=*Ghg@*`1ieEI5sU!;azm50FJuIh59mVSW| zQ35nO@|w)7MoJT)$Nh4J9{H63HDq3wGqCLqeUg_5N~N1Jr8;?-2-lt(sTd18JY+1q z|0Qv90du%P#!(@Cl3<-*+)^mkCqd8OZ*%XsR=Da8OS+7Mu#tDDLbH*d)vj?cE4ERp zC9lSTPv~6=qQ;|0X4*XpZjFc8+~&dHWXPp;pIY`LgOAPw3d~aAp*rdz1En0hi~p`qmlrhA8|Db`#( diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java index 0c4e97f1cbf7..0994967fd087 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java @@ -16,8 +16,9 @@ import java.io.*; import java.util.Map; public class StudyTestRunner { - public static final String TEST_OK = "#educational_plugin test OK"; - private static final String TEST_FAILED = "#educational_plugin FAILED + "; + public static final String STUDY_PREFIX="#educational_plugin"; + public static final String TEST_OK = "test OK"; + private static final String TEST_FAILED = "FAILED + "; private static final String PYTHONPATH = "PYTHONPATH"; private static final Logger LOG = Logger.getInstance(StudyTestRunner.class); private final Task myTask; @@ -32,7 +33,7 @@ public class StudyTestRunner { Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]); File testRunner = new File(myTaskDir.getPath(), myTask.getTestFile()); GeneralCommandLine commandLine = new GeneralCommandLine(); - commandLine.setWorkDirectory(myTaskDir.getPath()); + commandLine.withWorkDirectory(myTaskDir.getPath()); final Map env = commandLine.getEnvironment(); final VirtualFile courseDir = project.getBaseDir(); if (courseDir != null) { @@ -45,7 +46,12 @@ public class StudyTestRunner { commandLine.addParameter(testRunner.getPath()); final Course course = StudyTaskManager.getInstance(project).getCourse(); assert course != null; - commandLine.addParameter(new File(course.getResourcePath()).getParent()); + File resourceFile = new File(course.getResourcePath()); + String resourceFolder = resourceFile.getParent(); + if (resourceFolder == null) { + return null; + } + commandLine.addParameter(resourceFolder); commandLine.addParameter(FileUtil.toSystemDependentName(executablePath)); return commandLine.createProcess(); } @@ -60,8 +66,12 @@ public class StudyTestRunner { String line; try { while ((line = testOutputReader.readLine()) != null) { - if (line.contains(TEST_FAILED)) { - String res = line.substring(TEST_FAILED.length(), line.length()); + if (line.contains(STUDY_PREFIX)) { + if (line.contains(TEST_OK)) { + continue; + } + int messageStart = line.indexOf(TEST_FAILED); + String res = line.substring(messageStart + TEST_FAILED.length()); StudyUtils.closeSilently(testOutputReader); return res; } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java index 04fc72a150a1..9741a240b0ec 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java @@ -127,7 +127,7 @@ public class StudyCheckAction extends DumbAwareAction { return; } String failedMessage = testRunner.getPassedTests(testProcess); - if (failedMessage.equals(StudyTestRunner.TEST_OK)) { + if (failedMessage != null && failedMessage.equals(StudyTestRunner.TEST_OK)) { task.setStatus(StudyStatus.Solved, oldStatus); createTestResultPopUp("Congratulations!", MessageType.INFO.getPopupBackground(), project); }