Commit fbbd2749 authored by Johannes Bucher's avatar Johannes Bucher

Update mjtest and mjtest-tests

Merge remote-tracking branch 'gitlab-original/master'
parents d771772b 529180eb
...@@ -23,8 +23,10 @@ The test cases are divided in 6 'modes': ...@@ -23,8 +23,10 @@ The test cases are divided in 6 'modes':
them. them.
- __ast__: Test cases that check the generated ast by using the pretty printing functionality. - __ast__: Test cases that check the generated ast by using the pretty printing functionality.
- __semantic__: Test cases that check semantic checking of MiniJava programs - __semantic__: Test cases that check semantic checking of MiniJava programs
- __compile-firm__: Test cases that check the correct compilation and execution of MiniJava programs with the libfirm backend. - __compile-firm-only__: Test cases that check the compilation of MiniJava programs with the libfirm backend.
- __compile__: Test cases that check the correct compilation and execution of MiniJava programs with the self implemented backend. - __compile-firm__ (alias `exec-firm`): Test cases that check the correct compilation and execution of MiniJava programs with the libfirm backend.
- __compile-only__: Test cases that check the compilation MiniJava programs with the self implemented backend.
- __compile__ (alias `exec`): Test cases that check the correct compilation and execution of MiniJava programs with the self implemented backend.
The test different test cases for each mode are located in a folder with the same name. The test different test cases for each mode are located in a folder with the same name.
Except the compile-firm test cases which are located in the `exec` folder. Except the compile-firm test cases which are located in the `exec` folder.
...@@ -103,6 +105,19 @@ Test types for the semantic mode ...@@ -103,6 +105,19 @@ Test types for the semantic mode
__All semantic mode tests have to be syntactically correct__ __All semantic mode tests have to be syntactically correct__
Test types for the compile-firm-only and compile-only mode
----------------------------------------------------------
<table>
<tr><th>File ending(s) of test cases</th><th>Expected behaviour to complete a test of this type</th></tr>
<tr>
<td><code>.valid.mj</code> <code>.mj</code> <code>.valid.java</code> <code>.java</code></td>
<td>Return code is <code>0</code> and the compiler produces an `a.out` file, i.e. the MiniJava code can be compiled</td>
</tr>
</table>
__All valid semantic test-cases are also used, the non-semantic compile-(firm)-only
should be placed into the `compile-only` folder__
Test types for the compile-firm and compile mode Test types for the compile-firm and compile mode
------------------------------------------------ ------------------------------------------------
...@@ -112,7 +127,7 @@ Test types for the compile-firm and compile mode ...@@ -112,7 +127,7 @@ Test types for the compile-firm and compile mode
<tr> <tr>
<td><code>.java</code> <code>.mj</code></td> <td><code>.java</code> <code>.mj</code></td>
<td>The test file should compile. The resulting binary should be runnable and its output should be:<br/> <td>The test file should compile. The resulting binary should be runnable and its output should be:<br/>
if a <code>[test file].out</code> exists: the content of this file<br/> if a <code>[input file].out</code> (for test cases with input) or <code>[test file].out</code> (else) exists: the content of this file<br/>
if no such file exists: the same as the execution of the file with <code>java</code></td> if no such file exists: the same as the execution of the file with <code>java</code></td>
</tr> </tr>
<tr> <tr>
...@@ -171,12 +186,13 @@ usage: mjt.py [-h] [--only_incorrect_tests] [--all_exec_tests] ...@@ -171,12 +186,13 @@ usage: mjt.py [-h] [--only_incorrect_tests] [--all_exec_tests]
[--produce_no_reports] [--produce_all_reports] [--parallel] [--produce_no_reports] [--produce_all_reports] [--parallel]
[--output_no_incorrect_reports] [--color] [--ci_testing] [--output_no_incorrect_reports] [--color] [--ci_testing]
[--log_level LOG_LEVEL] [--log_level LOG_LEVEL]
{all,lexer,syntax,ast,semantic,compile-firm,compile} MJ_RUN {all,lexer,syntax,ast,semantic,compile-firm-only,compile-only,
compile-firm,compile,exec,exec-firm} MJ_RUN
MiniJava test runner MiniJava test runner
positional arguments: positional arguments:
{all,lexer,syntax,ast,semantic,compile-firm,exec} {all,lexer,syntax,ast,semantic,compile-firm-only,compile-only,compile-firm,exec,exec-firm}
What do you want to test? What do you want to test?
MJ_RUN Command to run your MiniJava implementation, e.g. MJ_RUN Command to run your MiniJava implementation, e.g.
`mj/run`, can be omitted by assigning the environment `mj/run`, can be omitted by assigning the environment
......
...@@ -27,7 +27,7 @@ class LogLevelChoices(argparse.Action): ...@@ -27,7 +27,7 @@ class LogLevelChoices(argparse.Action):
if True:#__name__ == '__main__': if True:#__name__ == '__main__':
parser = argparse.ArgumentParser(description="MiniJava test runner", add_help=True) parser = argparse.ArgumentParser(description="MiniJava test runner", add_help=True)
parser.add_argument("mode", parser.add_argument("mode",
choices=["all"] + TEST_MODES, choices=["all"] + TEST_MODES + ["exec-firm"],
help="What do you want to test?") help="What do you want to test?")
if os.getenv("MJ_RUN", None) is None: if os.getenv("MJ_RUN", None) is None:
parser.add_argument("mj_run", parser.add_argument("mj_run",
...@@ -84,9 +84,16 @@ if True:#__name__ == '__main__': ...@@ -84,9 +84,16 @@ if True:#__name__ == '__main__':
if ret is not None: if ret is not None:
failed += ret.failed failed += ret.failed
count += ret.count count += ret.count
if args["mode"] in ["exec", "exec-firm"]:
new_mode = args["mode"].replace("exec", "compile")
print(colored("\"{}\" is just an alias for \"{}\", using the latter instead"
.format(args["mode"], new_mode),
"yellow"))
args["mode"] = new_mode
if args["mode"] == "all": if args["mode"] == "all":
report_subdir = datetime.now().strftime("%d-%m-%y_%H-%M-%S") report_subdir = datetime.now().strftime("%d-%m-%y_%H-%M-%S")
for mode in [TestMode.lexer, TestMode.syntax, TestMode.ast, TestMode.semantic, for mode in [TestMode.lexer, TestMode.syntax, TestMode.ast, TestMode.semantic,
TestMode.compile_firm_only, TestMode.compile_only,
TestMode.compile_firm, TestMode.compile]: TestMode.compile_firm, TestMode.compile]:
args["all_exec_tests"] = True args["all_exec_tests"] = True
args["report_subdir"] = report_subdir + "_" + mode args["report_subdir"] = report_subdir + "_" + mode
......
...@@ -34,6 +34,10 @@ class TestMode: ...@@ -34,6 +34,10 @@ class TestMode:
compile = "compile" compile = "compile"
compile_firm_only = "compile-firm-only"
compile_only = "compile-only"
exec = "exec" exec = "exec"
bench = "bench" bench = "bench"
...@@ -42,12 +46,14 @@ class TestMode: ...@@ -42,12 +46,14 @@ class TestMode:
ast: [syntax], ast: [syntax],
compile_firm: [exec], compile_firm: [exec],
compile: [exec], compile: [exec],
compile_firm_only: [semantic, compile_only],
compile_only: [semantic],
bench: [exec] bench: [exec]
} }
""" All 'success' tests of the n.th mode can used as 'success' tests for the n-1.th mode""" """ All 'success' tests of the n.th mode can used as 'success' tests for the n-1.th mode"""
TEST_MODES = [TestMode.lexer, TestMode.syntax, TestMode.ast, TestMode.semantic, TestMode.compile_firm, TEST_MODES = [TestMode.lexer, TestMode.syntax, TestMode.ast, TestMode.semantic, TestMode.compile_firm_only,
TestMode.exec, TestMode.bench, TestMode.compile] TestMode.compile_only, TestMode.compile_firm, TestMode.exec, TestMode.bench, TestMode.compile]
def get_test_dirname(mode: str) -> str: def get_test_dirname(mode: str) -> str:
...@@ -163,8 +169,10 @@ class Environment: ...@@ -163,8 +169,10 @@ class Environment:
TestMode.syntax: "--parsetest", TestMode.syntax: "--parsetest",
TestMode.ast: "--print-ast", TestMode.ast: "--print-ast",
TestMode.semantic: "--check", TestMode.semantic: "--check",
TestMode.compile_only: None,
TestMode.compile_firm_only: "--compile-firm",
TestMode.compile_firm: "--compile-firm", TestMode.compile_firm: "--compile-firm",
TestMode.compile: None TestMode.compile: None,
}[mode] }[mode]
cmd = [self.mj_run_cmd] cmd = [self.mj_run_cmd]
if mode_flag: if mode_flag:
...@@ -172,13 +180,13 @@ class Environment: ...@@ -172,13 +180,13 @@ class Environment:
cmd.extend(list(args)) cmd.extend(list(args))
return execute(cmd, timeout=timeout or self.timeout) return execute(cmd, timeout=timeout or self.timeout)
def run_command(self, cmd: str, *args: Tuple[str], timeout: float = None, input_str: Optional[str] = None) -> Tuple[bytes, bytes, int]: def run_command(self, cmd: str, *args: Tuple[str], timeout: float = None, input_bytes: Optional[bytes] = None) -> Tuple[bytes, bytes, int]:
""" """
Execute the passend command with its arguments Execute the passend command with its arguments
:return: (out, err, return code) :return: (out, err, return code)
""" """
return execute([cmd] + list(args), timeout=timeout or self.timeout, input_str=input_str) return execute([cmd] + list(args), timeout=timeout or self.timeout, input_bytes=input_bytes)
def has_to_preprocess(self, file: str) -> bool: def has_to_preprocess(self, file: str) -> bool:
return os.path.relpath(file, self.test_dir).startswith("exec") return os.path.relpath(file, self.test_dir).startswith("exec")
...@@ -241,4 +249,4 @@ class Environment: ...@@ -241,4 +249,4 @@ class Environment:
timer.cancel() timer.cancel()
else: else:
stdout, stderr = proc.communicate() stdout, stderr = proc.communicate()
return stdout, stderr, proc.returncode, timeouted return stdout, stderr, proc.returncode, timeouted
\ No newline at end of file
...@@ -7,6 +7,8 @@ from mjtest.test.syntax_tests import BasicSyntaxTest ...@@ -7,6 +7,8 @@ from mjtest.test.syntax_tests import BasicSyntaxTest
from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult
from os import path from os import path
from mjtest.util.utils import decode
_LOG = logging.getLogger("tests") _LOG = logging.getLogger("tests")
...@@ -59,6 +61,6 @@ class ASTPrettyPrintTest(BasicSyntaxTest): ...@@ -59,6 +61,6 @@ class ASTPrettyPrintTest(BasicSyntaxTest):
with open(output_file, "wb") as f: with open(output_file, "wb") as f:
f.write(out) f.write(out)
f.flush() f.flush()
return rtcode, out.decode(), err.decode() return rtcode, decode(out), decode(err)
TestCase.TEST_CASE_CLASSES["ast"].append(ASTPrettyPrintTest) TestCase.TEST_CASE_CLASSES["ast"].append(ASTPrettyPrintTest)
...@@ -16,7 +16,7 @@ from mjtest.environment import TestMode, Environment ...@@ -16,7 +16,7 @@ from mjtest.environment import TestMode, Environment
from mjtest.test.syntax_tests import BasicSyntaxTest from mjtest.test.syntax_tests import BasicSyntaxTest
from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult, ExtensibleTestResult from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult, ExtensibleTestResult
from mjtest.util.shell import SigKill from mjtest.util.shell import SigKill
from mjtest.util.utils import get_main_class_name, InsertionTimeOrderedDict from mjtest.util.utils import get_main_class_name, InsertionTimeOrderedDict, decode
_LOG = logging.getLogger("bench_tests") _LOG = logging.getLogger("bench_tests")
...@@ -49,8 +49,8 @@ class BenchExecTest(BasicSyntaxTest): ...@@ -49,8 +49,8 @@ class BenchExecTest(BasicSyntaxTest):
INVALID_FILE_ENDINGS = [".inf.java", ".inf.mj"] INVALID_FILE_ENDINGS = [".inf.java", ".inf.mj"]
MODE = TestMode.compile_firm MODE = TestMode.compile_firm
def __init__(self, env: Environment, type: str, file: str, preprocessed_file: str): def __init__(self, env: Environment, type: str, file: str, preprocessed_file: str, log_file_mode: str = ""):
super().__init__(env, type, file, preprocessed_file) super().__init__(env, type, file, preprocessed_file, log_file_mode)
self._should_succeed = True self._should_succeed = True
def _bench_command(self, cmd: str, *args: Tuple[str]) -> _RunResult: def _bench_command(self, cmd: str, *args: Tuple[str]) -> _RunResult:
...@@ -85,7 +85,7 @@ class BenchExecTest(BasicSyntaxTest): ...@@ -85,7 +85,7 @@ class BenchExecTest(BasicSyntaxTest):
_LOG.error("File \"{}\" isn't valid Java".format(self.preprocessed_file)) _LOG.error("File \"{}\" isn't valid Java".format(self.preprocessed_file))
test_result.incorrect_msg = "invalid java code, but output file missing" test_result.incorrect_msg = "invalid java code, but output file missing"
test_result.set_error_code(javac_rtcode) test_result.set_error_code(javac_rtcode)
test_result.add_long_text("Javac error message", err.decode()) test_result.add_long_text("Javac error message", decode(err))
test_result.add_file("Source file", self.preprocessed_file) test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd) os.chdir(cwd)
return test_result return test_result
...@@ -102,8 +102,8 @@ class BenchExecTest(BasicSyntaxTest): ...@@ -102,8 +102,8 @@ class BenchExecTest(BasicSyntaxTest):
if rtcode != 0: if rtcode != 0:
test_result.incorrect_msg = "file can't be compiled" test_result.incorrect_msg = "file can't be compiled"
test_result.set_error_code(rtcode) test_result.set_error_code(rtcode)
test_result.add_long_text("Error output", err.decode()) test_result.add_long_text("Error output", decode(err))
test_result.add_long_text("Output", out.decode()) test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file) test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd) os.chdir(cwd)
return test_result return test_result
......
This diff is collapsed.
...@@ -3,6 +3,8 @@ from mjtest.environment import Environment, TestMode, TEST_MODES, get_test_dirna ...@@ -3,6 +3,8 @@ from mjtest.environment import Environment, TestMode, TEST_MODES, get_test_dirna
from mjtest.test.tests import TestCase, BasicTestResult from mjtest.test.tests import TestCase, BasicTestResult
from os import path from os import path
from mjtest.util.utils import decode
class BasicSyntaxTest(TestCase): class BasicSyntaxTest(TestCase):
...@@ -35,7 +37,7 @@ class BasicSyntaxTest(TestCase): ...@@ -35,7 +37,7 @@ class BasicSyntaxTest(TestCase):
def run(self) -> BasicTestResult: def run(self) -> BasicTestResult:
out, err, rtcode = self.env.run_mj_command(self.MODE, self.preprocessed_file) out, err, rtcode = self.env.run_mj_command(self.MODE, self.preprocessed_file)
return BasicTestResult(self, rtcode, out.decode(), err.decode()) return BasicTestResult(self, rtcode, decode(out), decode(err))
TestCase.TEST_CASE_CLASSES[TestMode.syntax].append(BasicSyntaxTest) TestCase.TEST_CASE_CLASSES[TestMode.syntax].append(BasicSyntaxTest)
...@@ -53,7 +55,7 @@ class JavaCompileTest(BasicSyntaxTest): ...@@ -53,7 +55,7 @@ class JavaCompileTest(BasicSyntaxTest):
tmp_dir = self.env.create_pid_local_tmpdir() tmp_dir = self.env.create_pid_local_tmpdir()
_, self.javac_err, self.javac_rtcode = \ _, self.javac_err, self.javac_rtcode = \
self.env.run_command("javac", path.relpath(preprocessed_file), "-d", tmp_dir, "-verbose") self.env.run_command("javac", path.relpath(preprocessed_file), "-d", tmp_dir, "-verbose")
self.javac_err = self.javac_err.decode() # type: str self.javac_err = decode(self.javac_err) # type: str
self._should_succeed = self._is_file_syntactically_correct() if self.SYNTAX_TEST else self.javac_rtcode == 0 self._should_succeed = self._is_file_syntactically_correct() if self.SYNTAX_TEST else self.javac_rtcode == 0
def _is_file_syntactically_correct(self): def _is_file_syntactically_correct(self):
......
from collections import namedtuple from collections import namedtuple
import shutil import shutil
from typing import Optional, List, Tuple, T, Union, Dict from typing import Optional, List, Tuple, Union, Dict
import collections import collections
from mjtest.environment import Environment, TestMode, TEST_MODES, get_test_dirname from mjtest.environment import Environment, TestMode, TEST_MODES, get_test_dirname
from os.path import join, exists, basename from os.path import join, exists, basename
...@@ -8,7 +8,7 @@ import logging ...@@ -8,7 +8,7 @@ import logging
import os import os
import multiprocessing import multiprocessing
from mjtest.util.parallelism import available_cpu_count from mjtest.util.parallelism import available_cpu_count
from mjtest.util.utils import cprint, colored from mjtest.util.utils import cprint, colored, decode
from pprint import pprint from pprint import pprint
import shutil import shutil
import difflib import difflib
...@@ -50,7 +50,7 @@ class TestSuite: ...@@ -50,7 +50,7 @@ class TestSuite:
correct_test_cases = set() correct_test_cases = set()
log_file = self._log_file_for_type(mode) log_file = self._log_file_for_type(mode)
if exists(log_file): if exists(log_file):
with open(log_file) as f: with open(log_file, errors="backslashreplace") as f:
correct_test_cases = set() correct_test_cases = set()
for t in f.readlines(): for t in f.readlines():
t = t.strip() t = t.strip()
...@@ -223,7 +223,7 @@ class TestSuite: ...@@ -223,7 +223,7 @@ class TestSuite:
os.mkdir(os.path.dirname(log_file)) os.mkdir(os.path.dirname(log_file))
except IOError: except IOError:
pass pass
with open(log_file, "w") as f: with open(log_file, "w", errors="backslashreplace") as f:
f.write("\n".join(self.correct_test_cases[mode])) f.write("\n".join(self.correct_test_cases[mode]))
except IOError as e: except IOError as e:
_LOG.exception("Caught i/o error while storing {}".format(log_file)) _LOG.exception("Caught i/o error while storing {}".format(log_file))
...@@ -314,7 +314,7 @@ class TestResult: ...@@ -314,7 +314,7 @@ class TestResult:
def store_at(self, file: str): def store_at(self, file: str):
os.makedirs(os.path.dirname(file), exist_ok=True) os.makedirs(os.path.dirname(file), exist_ok=True)
with open(file, "w") as f: with open(file, "w", errors="backslashreplace") as f:
print(self.long_message(), file=f) print(self.long_message(), file=f)
def short_message(self) -> str: def short_message(self) -> str:
...@@ -348,8 +348,8 @@ class ExtensibleTestResult(TestResult): ...@@ -348,8 +348,8 @@ class ExtensibleTestResult(TestResult):
self.messages.append(TestResultMessage(title, content, multiline=False, with_line_numbers=False)) self.messages.append(TestResultMessage(title, content, multiline=False, with_line_numbers=False))
def add_file(self, title: str, file_name: str, with_line_numbers: bool = True): def add_file(self, title: str, file_name: str, with_line_numbers: bool = True):
with open(file_name, "r") as f: with open(file_name, "r", errors="backslashreplace") as f:
file_content = os.linesep.join([line.rstrip() for line in f]) file_content = os.linesep.join([line.rstrip() for line in f.readlines()])
self.add_long_text(title, file_content, with_line_numbers) self.add_long_text(title, file_content, with_line_numbers)
def succeeded(self): def succeeded(self):
...@@ -461,7 +461,7 @@ class BasicTestResult(TestResult): ...@@ -461,7 +461,7 @@ class BasicTestResult(TestResult):
def long_message(self) -> str: def long_message(self) -> str:
file_content = [] file_content = []
with open(self.test_case.preprocessed_file, "r") as f: with open(self.test_case.preprocessed_file, "r", errors="backslashreplace") as f:
file_content = [line.rstrip() for line in f] file_content = [line.rstrip() for line in f]
others = [] others = []
for title, content, long_text in self.other_texts: for title, content, long_text in self.other_texts:
...@@ -563,13 +563,13 @@ class DiffTest(TestCase): ...@@ -563,13 +563,13 @@ class DiffTest(TestCase):
exp_out = "" exp_out = ""
if rtcode == 0 and self.should_succeed(): if rtcode == 0 and self.should_succeed():
if self._has_expected_output_file and self.type == self.MODE and self.env.mode == self.MODE: if self._has_expected_output_file and self.type == self.MODE and self.env.mode == self.MODE:
with open(self._expected_output_file, "r") as f: with open(self._expected_output_file, "r", errors="backslashreplace") as f:
exp_out = f.read() exp_out = f.read()
#else: #else:
# _LOG.error("Expected output file for test case {}:{} is missing.".format(self.MODE, self.short_name())) # _LOG.error("Expected output file for test case {}:{} is missing.".format(self.MODE, self.short_name()))
if self.type == self.MODE and self.env.mode == self.MODE: if self.type == self.MODE and self.env.mode == self.MODE:
return BasicDiffTestResult(self, rtcode, out.decode(), err.decode(), exp_out) return BasicDiffTestResult(self, rtcode, decode(out), decode(err), exp_out)
return BasicTestResult(self, rtcode, out.decode(), err.decode()) return BasicTestResult(self, rtcode, decode(out), decode(err))
class LexerDiffTest(DiffTest): class LexerDiffTest(DiffTest):
...@@ -582,4 +582,4 @@ import mjtest.test.syntax_tests ...@@ -582,4 +582,4 @@ import mjtest.test.syntax_tests
import mjtest.test.ast_tests import mjtest.test.ast_tests
import mjtest.test.semantic_tests import mjtest.test.semantic_tests
import mjtest.test.exec_tests import mjtest.test.exec_tests
import mjtest.test.bench import mjtest.test.bench
\ No newline at end of file
...@@ -16,7 +16,7 @@ try: ...@@ -16,7 +16,7 @@ try:
except ImportError: except ImportError:
has_resource_module = False has_resource_module = False
pass pass
import sys import sys
import signal import signal
import threading import threading
...@@ -46,14 +46,14 @@ def _lower_rlimit(res, limit): ...@@ -46,14 +46,14 @@ def _lower_rlimit(res, limit):
class _Execute(object): class _Execute(object):
def __init__(self, cmd, timeout, env, rlimit, input_str): def __init__(self, cmd, timeout, env, rlimit, input_bytes):
self.cmd = cmd self.cmd = cmd
self.timeout = timeout self.timeout = timeout
self.env = env self.env = env
self.proc = None self.proc = None
self.exception = None self.exception = None
self.rlimit = rlimit self.rlimit = rlimit
self.input_str = input_str self.input_bytes = input_bytes
MB = 1024 * 1024 MB = 1024 * 1024
if not 'RLIMIT_CORE' in rlimit: if not 'RLIMIT_CORE' in rlimit:
rlimit['RLIMIT_CORE'] = 0 rlimit['RLIMIT_CORE'] = 0
...@@ -80,14 +80,13 @@ class _Execute(object): ...@@ -80,14 +80,13 @@ class _Execute(object):
self.proc = subprocess.Popen(self.cmd, self.proc = subprocess.Popen(self.cmd,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE if self.input_str else None, stdin=subprocess.PIPE if self.input_bytes else None,
env=self.env, env=self.env,
shell=True, shell=True,
**prexec_args) **prexec_args)
#if self.input_str: #if self.input_bytes:
# self.proc.stdin.write(self.input_str.decode) # self.proc.stdin.write(self.input_bytes.decode)
input_bytes = self.input_str.encode() if self.input_str else None x = self.proc.communicate(input=self.input_bytes, timeout=self.timeout if self.timeout > 0.0 else None)
x = self.proc.communicate(input=input_bytes, timeout=self.timeout if self.timeout > 0.0 else None)
self.out, self.err = x self.out, self.err = x
self.returncode = self.proc.returncode self.returncode = self.proc.returncode
except subprocess.TimeoutExpired as t: except subprocess.TimeoutExpired as t:
...@@ -110,7 +109,7 @@ class _Execute(object): ...@@ -110,7 +109,7 @@ class _Execute(object):
raise SigKill(-self.returncode, _EXIT_CODES[self.returncode] + ": " + os.strerror(-self.returncode)) raise SigKill(-self.returncode, _EXIT_CODES[self.returncode] + ": " + os.strerror(-self.returncode))
return (self.out, self.err, self.returncode) return (self.out, self.err, self.returncode)
def execute(cmd, env=None, timeout=0, rlimit=None, propagate_sigint=True, input_str = None): def execute(cmd, env=None, timeout=0, rlimit=None, propagate_sigint=True, input_bytes = None):
"""Execute a command and return stderr and stdout data""" """Execute a command and return stderr and stdout data"""
if not rlimit: if not rlimit:
rlimit = dict() rlimit = dict()
...@@ -120,7 +119,7 @@ def execute(cmd, env=None, timeout=0, rlimit=None, propagate_sigint=True, input_ ...@@ -120,7 +119,7 @@ def execute(cmd, env=None, timeout=0, rlimit=None, propagate_sigint=True, input_
else: else:
#cmd = shlex.split(cmd[0]) + cmd[1:] #cmd = shlex.split(cmd[0]) + cmd[1:]
cmd = " ".join(shlex.quote(c) for c in cmd) cmd = " ".join(shlex.quote(c) for c in cmd)
exc = _Execute(cmd, timeout, env, rlimit, input_str) exc = _Execute(cmd, timeout, env, rlimit, input_bytes)
(out, err, returncode) = exc.run() (out, err, returncode) = exc.run()
if returncode == -signal.SIGINT: if returncode == -signal.SIGINT:
raise KeyboardInterrupt raise KeyboardInterrupt
......
...@@ -47,7 +47,7 @@ def cprint(text: str, *args, **kwargs): ...@@ -47,7 +47,7 @@ def cprint(text: str, *args, **kwargs):
def get_main_class_name(file: str) -> Optional[str]: def get_main_class_name(file: str) -> Optional[str]:
current_class = None current_class = None
with open(file, "r") as f: with open(file, "r", errors="backslashreplace") as f:
for line in f: for line in f:
if line.startswith("class ") or line.startswith("/*public*/ class "): if line.startswith("class ") or line.startswith("/*public*/ class "):
match = re.search("[A-Za-z_0-9]+", line.replace("class ", "").replace("/*public*/", "")) match = re.search("[A-Za-z_0-9]+", line.replace("class ", "").replace("/*public*/", ""))
...@@ -113,4 +113,11 @@ class InsertionTimeOrderedDict: ...@@ -113,4 +113,11 @@ class InsertionTimeOrderedDict:
ret = InsertionTimeOrderedDict() ret = InsertionTimeOrderedDict()
for item in items: for item in items:
ret[key_func(item)] = item ret[key_func(item)] = item
return ret return ret
\ No newline at end of file
def decode(arr: bytes) -> str:
"""
Decodes the passed byte array as UTF8 and handles invalid characters
"""
return arr.decode("utf-8", "backslashreplace")
\ No newline at end of file
...@@ -48,7 +48,7 @@ class PreProcessor: ...@@ -48,7 +48,7 @@ class PreProcessor:
def add_commented(line: str): def add_commented(line: str):
middle_lines.append("/*{}*/".format(line)) middle_lines.append("/*{}*/".format(line))
with open(file, "r") as f: with open(file, "r", errors="backslashreplace") as f:
for line in f: for line in f:
line = line.rstrip() line = line.rstrip()
if self._import_regexp.match(line): if self._import_regexp.match(line):
...@@ -108,7 +108,7 @@ class PreProcessor: ...@@ -108,7 +108,7 @@ class PreProcessor:
print() print()
print(text) print(text)
else: else:
with open(self.dst_file, "w") as f: with open(self.dst_file, "w", errors="backslashreplace") as f:
for text in reversed(self.imported_strs): for text in reversed(self.imported_strs):
f.write(text) f.write(text)
f.write("\n\n") f.write("\n\n")
...@@ -122,7 +122,7 @@ def is_importable_file(file: str) -> bool: ...@@ -122,7 +122,7 @@ def is_importable_file(file: str) -> bool:
has_package = False has_package = False
has_public_class = False has_public_class = False
has_main_method = False has_main_method = False
with open(file, "r") as f: with open(file, "r", errors="backslashreplace") as f:
for line in f: for line in f:
if line.startswith("package "): if line.startswith("package "):
has_package = True has_package = True
......
Subproject commit 541910c3730523949b1b309e457f9cfdff7808b3 Subproject commit 9e7b9291db05fa7049738b435b2f818ed2aa29e1