diff --git a/README.md b/README.md
index 1fcfea187d7b237352cad53fca121458101ed702..092a62478e23e9fcc138b60a8b8023e6636a45ea 100644
--- a/README.md
+++ b/README.md
@@ -23,8 +23,10 @@ The test cases are divided in 6 'modes':
them.
- __ast__: Test cases that check the generated ast by using the pretty printing functionality.
- __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__: Test cases that check the correct compilation and execution of MiniJava programs with the self implemented backend.
+- __compile-firm-only__: Test cases that check the compilation of MiniJava programs with the libfirm 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.
Except the compile-firm test cases which are located in the `exec` folder.
@@ -103,6 +105,19 @@ Test types for the semantic mode
__All semantic mode tests have to be syntactically correct__
+Test types for the compile-firm-only and compile-only mode
+----------------------------------------------------------
+
+
+File ending(s) of test cases | Expected behaviour to complete a test of this type |
+
+ .valid.mj .mj .valid.java .java |
+ Return code is 0 and the compiler produces an `a.out` file, i.e. the MiniJava code can be compiled |
+
+
+
+__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
------------------------------------------------
@@ -112,7 +127,7 @@ Test types for the compile-firm and compile mode
.java .mj |
The test file should compile. The resulting binary should be runnable and its output should be:
- if a [test file].out exists: the content of this file
+ if a [input file].out (for test cases with input) or [test file].out (else) exists: the content of this file
if no such file exists: the same as the execution of the file with java |
@@ -171,12 +186,13 @@ usage: mjt.py [-h] [--only_incorrect_tests] [--all_exec_tests]
[--produce_no_reports] [--produce_all_reports] [--parallel]
[--output_no_incorrect_reports] [--color] [--ci_testing]
[--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
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?
MJ_RUN Command to run your MiniJava implementation, e.g.
`mj/run`, can be omitted by assigning the environment
diff --git a/mjtest/cli.py b/mjtest/cli.py
index 3746be2d19d49a489be2e247de4d1d4405dd528f..fa8b0e87222bc3b32d292d4a01f1dc13f9414b68 100644
--- a/mjtest/cli.py
+++ b/mjtest/cli.py
@@ -27,7 +27,7 @@ class LogLevelChoices(argparse.Action):
if True:#__name__ == '__main__':
parser = argparse.ArgumentParser(description="MiniJava test runner", add_help=True)
parser.add_argument("mode",
- choices=["all"] + TEST_MODES,
+ choices=["all"] + TEST_MODES + ["exec-firm"],
help="What do you want to test?")
if os.getenv("MJ_RUN", None) is None:
parser.add_argument("mj_run",
@@ -84,9 +84,16 @@ if True:#__name__ == '__main__':
if ret is not None:
failed += ret.failed
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":
report_subdir = datetime.now().strftime("%d-%m-%y_%H-%M-%S")
for mode in [TestMode.lexer, TestMode.syntax, TestMode.ast, TestMode.semantic,
+ TestMode.compile_firm_only, TestMode.compile_only,
TestMode.compile_firm, TestMode.compile]:
args["all_exec_tests"] = True
args["report_subdir"] = report_subdir + "_" + mode
diff --git a/mjtest/environment.py b/mjtest/environment.py
index b7f50cefc15e9a881c3c803192d12a03d8c7d3c2..d6bf1653060672770df441f0ac32bc7d7d536d53 100644
--- a/mjtest/environment.py
+++ b/mjtest/environment.py
@@ -34,6 +34,10 @@ class TestMode:
compile = "compile"
+ compile_firm_only = "compile-firm-only"
+
+ compile_only = "compile-only"
+
exec = "exec"
bench = "bench"
@@ -42,12 +46,14 @@ class TestMode:
ast: [syntax],
compile_firm: [exec],
compile: [exec],
+ compile_firm_only: [semantic, compile_only],
+ compile_only: [semantic],
bench: [exec]
}
""" 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,
- TestMode.exec, TestMode.bench, TestMode.compile]
+TEST_MODES = [TestMode.lexer, TestMode.syntax, TestMode.ast, TestMode.semantic, TestMode.compile_firm_only,
+ TestMode.compile_only, TestMode.compile_firm, TestMode.exec, TestMode.bench, TestMode.compile]
def get_test_dirname(mode: str) -> str:
@@ -163,8 +169,10 @@ class Environment:
TestMode.syntax: "--parsetest",
TestMode.ast: "--print-ast",
TestMode.semantic: "--check",
+ TestMode.compile_only: None,
+ TestMode.compile_firm_only: "--compile-firm",
TestMode.compile_firm: "--compile-firm",
- TestMode.compile: None
+ TestMode.compile: None,
}[mode]
cmd = [self.mj_run_cmd]
if mode_flag:
@@ -172,13 +180,13 @@ class Environment:
cmd.extend(list(args))
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
: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:
return os.path.relpath(file, self.test_dir).startswith("exec")
@@ -241,4 +249,4 @@ class Environment:
timer.cancel()
else:
stdout, stderr = proc.communicate()
- return stdout, stderr, proc.returncode, timeouted
\ No newline at end of file
+ return stdout, stderr, proc.returncode, timeouted
diff --git a/mjtest/test/ast_tests.py b/mjtest/test/ast_tests.py
index 201c20bc863f698c6d3001405e6ab1306ff55c3a..1252527571e5ad2d9f910f5d1143e9b94cf3978b 100644
--- a/mjtest/test/ast_tests.py
+++ b/mjtest/test/ast_tests.py
@@ -7,6 +7,8 @@ from mjtest.test.syntax_tests import BasicSyntaxTest
from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult
from os import path
+from mjtest.util.utils import decode
+
_LOG = logging.getLogger("tests")
@@ -59,6 +61,6 @@ class ASTPrettyPrintTest(BasicSyntaxTest):
with open(output_file, "wb") as f:
f.write(out)
f.flush()
- return rtcode, out.decode(), err.decode()
+ return rtcode, decode(out), decode(err)
TestCase.TEST_CASE_CLASSES["ast"].append(ASTPrettyPrintTest)
diff --git a/mjtest/test/bench.py b/mjtest/test/bench.py
index 55b8f463aa9cd656c285f387f45217d5de6f52b0..824ab8d89b222c8287459535cbd94c29f290f48e 100644
--- a/mjtest/test/bench.py
+++ b/mjtest/test/bench.py
@@ -16,7 +16,7 @@ from mjtest.environment import TestMode, Environment
from mjtest.test.syntax_tests import BasicSyntaxTest
from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult, ExtensibleTestResult
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")
@@ -49,8 +49,8 @@ class BenchExecTest(BasicSyntaxTest):
INVALID_FILE_ENDINGS = [".inf.java", ".inf.mj"]
MODE = TestMode.compile_firm
- def __init__(self, env: Environment, type: str, file: str, preprocessed_file: str):
- super().__init__(env, type, file, preprocessed_file)
+ def __init__(self, env: Environment, type: str, file: str, preprocessed_file: str, log_file_mode: str = ""):
+ super().__init__(env, type, file, preprocessed_file, log_file_mode)
self._should_succeed = True
def _bench_command(self, cmd: str, *args: Tuple[str]) -> _RunResult:
@@ -85,7 +85,7 @@ class BenchExecTest(BasicSyntaxTest):
_LOG.error("File \"{}\" isn't valid Java".format(self.preprocessed_file))
test_result.incorrect_msg = "invalid java code, but output file missing"
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)
os.chdir(cwd)
return test_result
@@ -102,8 +102,8 @@ class BenchExecTest(BasicSyntaxTest):
if rtcode != 0:
test_result.incorrect_msg = "file can't be compiled"
test_result.set_error_code(rtcode)
- test_result.add_long_text("Error output", err.decode())
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Error output", decode(err))
+ test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd)
return test_result
diff --git a/mjtest/test/exec_tests.py b/mjtest/test/exec_tests.py
index 9c24b9541d8ce64fe2c92a674f62158a4bac3e93..8e2a95863577938225ed810f9d86110ebaf8c154 100644
--- a/mjtest/test/exec_tests.py
+++ b/mjtest/test/exec_tests.py
@@ -14,7 +14,7 @@ from mjtest.environment import TestMode, Environment
from mjtest.test.syntax_tests import BasicSyntaxTest
from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult, ExtensibleTestResult
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("exec_tests")
@@ -48,6 +48,7 @@ class JavaExecTest(BasicSyntaxTest):
self._expected_output_file = self._prev_out_file
_LOG.info("Reuse old java output file \"{}\"".format(path.relpath(self._prev_out_file)))
self._should_succeed = True
+ self._only_compile = self.MODE.endswith("-only")
def run(self) -> BasicDiffTestResult:
is_big_testcase = "big" in self.file
@@ -58,33 +59,32 @@ class JavaExecTest(BasicSyntaxTest):
cwd = os.getcwd()
os.chdir(tmp_dir)
exp_out = None
- input_str = None
+ input_bytes = None
#print(base_filename, get_main_class_name(base_filename + ".java"))
test_result = ExtensibleTestResult(self)
if self._has_input_file:
if self._has_character_input:
- with open(self._input_file, "r") as f:
- input_str = f.read()
+ with open(self._input_file, "rb") as f:
+ input_bytes = f.read()
else:
- with open(self._input_file, "r") as f:
- chars = bytearray('ascii', 'ignore') # type: bytearray
+ with open(self._input_file, "r", errors="backslashreplace") as f:
+ input_bytes = bytearray(encoding='ascii', errors='ignore') # type: bytearray
for line in f.readlines():
for part in line.split(" "):
part = part.strip()
if len(part) > 0:
chars.append(int(part))
- input_str = chars.decode()
- if not self._has_expected_output_file:
+ if not self._has_expected_output_file and not self._only_compile:
_, err, javac_rtcode = \
self.env.run_command("javac", base_filename + ".java", timeout=timeout)
if javac_rtcode != 0:
_LOG.error("File \"{}\" isn't valid Java".format(self.preprocessed_file))
test_result.incorrect_msg = "invalid java code, but output file missing"
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)
os.chdir(cwd)
return test_result
@@ -92,30 +92,31 @@ class JavaExecTest(BasicSyntaxTest):
if not main_class:
_LOG.debug("Can't find a main class, using the file name instead")
main_class = base_filename
- exp_out, err, java_rtcode = \
- self.env.run_command("java", get_main_class_name(base_filename + ".java"), timeout=timeout, input_str=input_str)
- if javac_rtcode != 0:
- test_result.add_long_text("Java output: ", exp_out.decode())
- test_result.incorrect_msg = "java runtime error"
- test_result.set_error_code(java_rtcode)
- test_result.add_long_text("Java error message", err.decode())
- test_result.add_file("Source file", self.preprocessed_file)
- if self._input_file:
- test_result.add_file("Input file", self.file)
- os.chdir(cwd)
- return test_result
- exp_out = exp_out.decode()
-
- with open(self._prev_out_file, "w") as f:
- f.write(exp_out)
- f.flush()
- with open(self._prev_out_hash_file, "w") as f:
- f.write(self._hash_sum_for_file(base_filename + ".java"))
- f.flush()
- 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:
+ if not self._only_compile:
+ exp_out, err, java_rtcode = \
+ self.env.run_command("java", get_main_class_name(base_filename + ".java"), timeout=timeout, input_bytes=input_bytes)
+ if javac_rtcode != 0:
+ test_result.add_long_text("Java output: ", decode(exp_out))
+ test_result.incorrect_msg = "java runtime error"
+ test_result.set_error_code(java_rtcode)
+ test_result.add_long_text("Java error message", decode(err))
+ test_result.add_file("Source file", self.preprocessed_file)
+ if self._input_file:
+ test_result.add_file("Input file", self.file)
+ os.chdir(cwd)
+ return test_result
+ exp_out = decode(exp_out)
+
+ with open(self._prev_out_file, "w", errors="backslashreplace") as f:
+ f.write(exp_out)
+ f.flush()
+ with open(self._prev_out_hash_file, "w", errors="backslashreplace") as f:
+ f.write(self._hash_sum_for_file(base_filename + ".java"))
+ f.flush()
+ if self._has_expected_output_file and self.type == self.MODE and self.env.mode == self.MODE \
+ and not self._only_compile:
+ with open(self._expected_output_file, "r", errors="backslashreplace") as f:
exp_out = f.read()
-
try:
out, err, rtcode = None, None, None
try:
@@ -123,8 +124,8 @@ class JavaExecTest(BasicSyntaxTest):
if rtcode != 0:
test_result.incorrect_msg = "file can't be compiled"
test_result.set_error_code(rtcode)
- test_result.add_long_text("Error output", err.decode())
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Error output", decode(err))
+ test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd)
return test_result
@@ -137,13 +138,19 @@ class JavaExecTest(BasicSyntaxTest):
except:
os.chdir(cwd)
raise
+ if self._only_compile:
+ if not os.path.exists("a.out"):
+ test_result.incorrect_msg = "binary cannot be found"
+ test_result.set_error_code(1)
+ test_result.add_file("Source file", self.preprocessed_file)
+ return test_result
try:
- out, err, rtcode = self.env.run_command("./a.out", timeout=timeout, input_str=input_str)
+ out, err, rtcode = self.env.run_command("./a.out", timeout=timeout, input_bytes=input_bytes)
if rtcode != 0:
test_result.incorrect_msg = "binary can't be run, non zero error code"
test_result.set_error_code(rtcode)
- test_result.add_long_text("Error output", err.decode())
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Error output", decode(err))
+ test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file)
if self._input_file:
test_result.add_file("Input file", self.file)
@@ -160,7 +167,7 @@ class JavaExecTest(BasicSyntaxTest):
except:
os.chdir(cwd)
raise
- out = out.decode()
+ out = decode(out)
if self.type == self.MODE and self.env.mode == self.MODE:
if exp_out.strip() != out.strip():
test_result.incorrect_msg = "incorrect output"
@@ -176,7 +183,7 @@ class JavaExecTest(BasicSyntaxTest):
test_result.add_long_text("Output", out)
os.chdir(cwd)
return test_result
- return BasicTestResult(self, rtcode, out, err.decode())
+ return BasicTestResult(self, rtcode, out, decode(err))
except SigKill as sig:
os.chdir(cwd)
assert False
@@ -186,7 +193,7 @@ class JavaExecTest(BasicSyntaxTest):
def _check_hash_sum(self, file: str, hash_sum_file: str) -> bool:
old_hash = ""
- with open(hash_sum_file, "r") as f:
+ with open(hash_sum_file, "r", errors="backslashreplace") as f:
try:
old_hash = f.readline().strip()
except UnicodeDecodeError:
@@ -195,7 +202,7 @@ class JavaExecTest(BasicSyntaxTest):
@classmethod
def _hash_sum_for_file(self, file: str) -> str:
- with open(file, "r") as f:
+ with open(file, "r", errors="backslashreplace") as f:
return hashlib.sha256(f.read().encode()).hexdigest()
@classmethod
@@ -228,6 +235,16 @@ class JavaCompileExecTest(JavaExecTest):
TestCase.TEST_CASE_CLASSES[TestMode.compile].append(JavaCompileExecTest)
+class JavaCompileOnlyTest(JavaExecTest):
+ MODE = TestMode.compile_only
+
+TestCase.TEST_CASE_CLASSES[TestMode.compile_only].append(JavaCompileOnlyTest)
+
+class JavaCompileFirmOnlyTest(JavaExecTest):
+ MODE = TestMode.compile_firm_only
+
+TestCase.TEST_CASE_CLASSES[TestMode.compile_firm_only].append(JavaCompileFirmOnlyTest)
+
class JavaInfiniteLoopTest(BasicSyntaxTest):
FILE_ENDINGS = [".inf.java", ".inf.mj"]
@@ -255,8 +272,8 @@ class JavaInfiniteLoopTest(BasicSyntaxTest):
if rtcode != 0:
test_result.incorrect_msg = "file can't be compiled"
test_result.set_error_code(rtcode)
- test_result.add_long_text("Error output", err.decode())
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Error output", decode(err))
+ test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd)
return test_result
@@ -264,19 +281,19 @@ class JavaInfiniteLoopTest(BasicSyntaxTest):
if rtcode != 0:
test_result.incorrect_msg = "binary can't be run, non zero error code"
test_result.set_error_code(rtcode)
- test_result.add_long_text("Error output", err.decode())
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Error output", decode(err))
+ test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd)
return test_result
except SigKill as sig:
if sig.retcode == signal.SIGXCPU:
out, _, _, _ = self.env.run_command_till_timeout("./a.out", timeout=1)
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Output", decode(out))
if self._has_output_file:
- out = out.decode().strip()
+ out = decode(out).strip()
exp_out = ""
- with open(self._output_file, "r") as f:
+ with open(self._output_file, "r", errors="backslashreplace") as f:
exp_out = f.read().strip()
test_result.add_long_text("Expected output start", exp_out)
if not out.startswith(exp_out):
@@ -342,8 +359,8 @@ class InvalidJavaExecTest(BasicSyntaxTest):
if rtcode != 0:
test_result.incorrect_msg = "file can't be compiled"
test_result.set_error_code(-rtcode)
- test_result.add_long_text("Error output", err.decode())
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Error output", decode(err))
+ test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd)
return test_result
@@ -361,8 +378,8 @@ class InvalidJavaExecTest(BasicSyntaxTest):
if rtcode != 0:
test_result.incorrect_msg = "binary can't be run, non zero error code"
test_result.set_error_code(rtcode)
- test_result.add_long_text("Error output", err.decode())
- test_result.add_long_text("Output", out.decode())
+ test_result.add_long_text("Error output", decode(err))
+ test_result.add_long_text("Output", decode(out))
test_result.add_file("Source file", self.preprocessed_file)
os.chdir(cwd)
return test_result
@@ -375,7 +392,7 @@ class InvalidJavaExecTest(BasicSyntaxTest):
except:
os.chdir(cwd)
raise
- test_result = BasicTestResult(self, rtcode, out.decode(), err.decode())
+ test_result = BasicTestResult(self, rtcode, decode(out), decode(err))
test_result.require_error_string_in_error_case = False
return test_result
except SigKill as sig:
diff --git a/mjtest/test/syntax_tests.py b/mjtest/test/syntax_tests.py
index 8d16904bd1b4162c82b65edaec164f1a5bde9332..45178363337b117aac92ebc609b785f802606859 100644
--- a/mjtest/test/syntax_tests.py
+++ b/mjtest/test/syntax_tests.py
@@ -3,6 +3,8 @@ from mjtest.environment import Environment, TestMode, TEST_MODES, get_test_dirna
from mjtest.test.tests import TestCase, BasicTestResult
from os import path
+from mjtest.util.utils import decode
+
class BasicSyntaxTest(TestCase):
@@ -35,7 +37,7 @@ class BasicSyntaxTest(TestCase):
def run(self) -> BasicTestResult:
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)
@@ -53,7 +55,7 @@ class JavaCompileTest(BasicSyntaxTest):
tmp_dir = self.env.create_pid_local_tmpdir()
_, self.javac_err, self.javac_rtcode = \
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
def _is_file_syntactically_correct(self):
diff --git a/mjtest/test/tests.py b/mjtest/test/tests.py
index 1710eeff2ef8cbc62be0a1f43494b6b09bc819d7..ba3ffaed7e2c1b5a18351b3779ce0fc0d968544e 100644
--- a/mjtest/test/tests.py
+++ b/mjtest/test/tests.py
@@ -1,6 +1,6 @@
from collections import namedtuple
import shutil
-from typing import Optional, List, Tuple, T, Union, Dict
+from typing import Optional, List, Tuple, Union, Dict
import collections
from mjtest.environment import Environment, TestMode, TEST_MODES, get_test_dirname
from os.path import join, exists, basename
@@ -8,7 +8,7 @@ import logging
import os
import multiprocessing
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
import shutil
import difflib
@@ -50,7 +50,7 @@ class TestSuite:
correct_test_cases = set()
log_file = self._log_file_for_type(mode)
if exists(log_file):
- with open(log_file) as f:
+ with open(log_file, errors="backslashreplace") as f:
correct_test_cases = set()
for t in f.readlines():
t = t.strip()
@@ -223,7 +223,7 @@ class TestSuite:
os.mkdir(os.path.dirname(log_file))
except IOError:
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]))
except IOError as e:
_LOG.exception("Caught i/o error while storing {}".format(log_file))
@@ -314,7 +314,7 @@ class TestResult:
def store_at(self, file: str):
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)
def short_message(self) -> str:
@@ -348,8 +348,8 @@ class ExtensibleTestResult(TestResult):
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):
- with open(file_name, "r") as f:
- file_content = os.linesep.join([line.rstrip() for line in f])
+ with open(file_name, "r", errors="backslashreplace") as f:
+ file_content = os.linesep.join([line.rstrip() for line in f.readlines()])
self.add_long_text(title, file_content, with_line_numbers)
def succeeded(self):
@@ -461,7 +461,7 @@ class BasicTestResult(TestResult):
def long_message(self) -> str:
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]
others = []
for title, content, long_text in self.other_texts:
@@ -563,13 +563,13 @@ class DiffTest(TestCase):
exp_out = ""
if rtcode == 0 and self.should_succeed():
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()
#else:
# _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:
- return BasicDiffTestResult(self, rtcode, out.decode(), err.decode(), exp_out)
- return BasicTestResult(self, rtcode, out.decode(), err.decode())
+ return BasicDiffTestResult(self, rtcode, decode(out), decode(err), exp_out)
+ return BasicTestResult(self, rtcode, decode(out), decode(err))
class LexerDiffTest(DiffTest):
@@ -582,4 +582,4 @@ import mjtest.test.syntax_tests
import mjtest.test.ast_tests
import mjtest.test.semantic_tests
import mjtest.test.exec_tests
-import mjtest.test.bench
\ No newline at end of file
+import mjtest.test.bench
diff --git a/mjtest/util/shell.py b/mjtest/util/shell.py
index 9620ee4812d1ae56b920e3607eed1a195a4d692f..442d8532a22edb5a4024e9b6ff77e16165b3f365 100644
--- a/mjtest/util/shell.py
+++ b/mjtest/util/shell.py
@@ -16,7 +16,7 @@ try:
except ImportError:
has_resource_module = False
pass
-
+
import sys
import signal
import threading
@@ -46,14 +46,14 @@ def _lower_rlimit(res, limit):
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.timeout = timeout
self.env = env
self.proc = None
self.exception = None
self.rlimit = rlimit
- self.input_str = input_str
+ self.input_bytes = input_bytes
MB = 1024 * 1024
if not 'RLIMIT_CORE' in rlimit:
rlimit['RLIMIT_CORE'] = 0
@@ -80,14 +80,13 @@ class _Execute(object):
self.proc = subprocess.Popen(self.cmd,
stdout=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,
shell=True,
**prexec_args)
- #if self.input_str:
- # self.proc.stdin.write(self.input_str.decode)
- input_bytes = self.input_str.encode() if self.input_str else None
- x = self.proc.communicate(input=input_bytes, timeout=self.timeout if self.timeout > 0.0 else None)
+ #if self.input_bytes:
+ # self.proc.stdin.write(self.input_bytes.decode)
+ x = self.proc.communicate(input=self.input_bytes, timeout=self.timeout if self.timeout > 0.0 else None)
self.out, self.err = x
self.returncode = self.proc.returncode
except subprocess.TimeoutExpired as t:
@@ -110,7 +109,7 @@ class _Execute(object):
raise SigKill(-self.returncode, _EXIT_CODES[self.returncode] + ": " + os.strerror(-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"""
if not rlimit:
rlimit = dict()
@@ -120,7 +119,7 @@ def execute(cmd, env=None, timeout=0, rlimit=None, propagate_sigint=True, input_
else:
#cmd = shlex.split(cmd[0]) + cmd[1:]
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()
if returncode == -signal.SIGINT:
raise KeyboardInterrupt
diff --git a/mjtest/util/utils.py b/mjtest/util/utils.py
index ba9a430441a0f8750822df4b22a55fd1e172ac34..9d4d77ffa0fd1b082acff7b5fa31ca9699a7c67f 100644
--- a/mjtest/util/utils.py
+++ b/mjtest/util/utils.py
@@ -47,7 +47,7 @@ def cprint(text: str, *args, **kwargs):
def get_main_class_name(file: str) -> Optional[str]:
current_class = None
- with open(file, "r") as f:
+ with open(file, "r", errors="backslashreplace") as f:
for line in f:
if line.startswith("class ") or line.startswith("/*public*/ class "):
match = re.search("[A-Za-z_0-9]+", line.replace("class ", "").replace("/*public*/", ""))
@@ -113,4 +113,11 @@ class InsertionTimeOrderedDict:
ret = InsertionTimeOrderedDict()
for item in items:
ret[key_func(item)] = item
- return ret
\ No newline at end of file
+ return ret
+
+
+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
diff --git a/preproc/preproc/preprocessor.py b/preproc/preproc/preprocessor.py
index b79088c65b954697cf80336b06137822335f48df..e02c0da6be32fedea782e3fe1475a0ab3839e095 100644
--- a/preproc/preproc/preprocessor.py
+++ b/preproc/preproc/preprocessor.py
@@ -48,7 +48,7 @@ class PreProcessor:
def add_commented(line: str):
middle_lines.append("/*{}*/".format(line))
- with open(file, "r") as f:
+ with open(file, "r", errors="backslashreplace") as f:
for line in f:
line = line.rstrip()
if self._import_regexp.match(line):
@@ -108,7 +108,7 @@ class PreProcessor:
print()
print(text)
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):
f.write(text)
f.write("\n\n")
@@ -122,7 +122,7 @@ def is_importable_file(file: str) -> bool:
has_package = False
has_public_class = False
has_main_method = False
- with open(file, "r") as f:
+ with open(file, "r", errors="backslashreplace") as f:
for line in f:
if line.startswith("package "):
has_package = True
diff --git a/tests b/tests
index 541910c3730523949b1b309e457f9cfdff7808b3..9e7b9291db05fa7049738b435b2f818ed2aa29e1 160000
--- a/tests
+++ b/tests
@@ -1 +1 @@
-Subproject commit 541910c3730523949b1b309e457f9cfdff7808b3
+Subproject commit 9e7b9291db05fa7049738b435b2f818ed2aa29e1