exec_tests.py 6.11 KB
Newer Older
1
import hashlib
2 3 4
import logging
import os
import shutil
5
import signal
6 7 8 9
from os import path
from mjtest.environment import TestMode, Environment
from mjtest.test.syntax_tests import BasicSyntaxTest
from mjtest.test.tests import TestCase, BasicDiffTestResult, BasicTestResult
10
from mjtest.util.shell import SigKill
11
from mjtest.util.utils import get_main_class_name
12 13 14 15 16 17 18 19

_LOG = logging.getLogger("exec_tests")

class JavaExecTest(BasicSyntaxTest):
    """
    The MiniJava compiler should behave the same as javac
    """

20 21
    FILE_ENDINGS = [".java", ".mj"]
    INVALID_FILE_ENDINGS = [".inf.java", ".inf.mj"]
22
    OUTPUT_FILE_ENDING = ".out"
23
    MODE = TestMode.compile_firm
24 25 26 27

    def __init__(self, env: Environment, type: str, file: str, preprocessed_file: str):
        super().__init__(env, type, file, preprocessed_file)
        self._expected_output_file = file + self.OUTPUT_FILE_ENDING
28 29 30 31
        prev_out_dir = path.join(path.dirname(file), ".java_output")
        if not path.exists(prev_out_dir):
            os.mkdir(prev_out_dir)
        self._prev_out_file = path.join(prev_out_dir, path.basename(self._expected_output_file))
32
        self._prev_out_hash_file = self._prev_out_file + "_hash"
33
        self._has_expected_output_file = path.exists(self._expected_output_file)
34
        if not self._has_expected_output_file:
35 36
            if path.exists(self._prev_out_file) and path.exists(self._prev_out_hash_file) \
                    and self._check_hash_sum(self.preprocessed_file, self._prev_out_hash_file):
37 38 39
                self._has_expected_output_file = True
                self._expected_output_file = self._prev_out_file
                _LOG.info("Reuse old java output file \"{}\"".format(path.relpath(self._prev_out_file)))
40 41 42 43
        self._should_succeed = True

    def run(self) -> BasicDiffTestResult:
        base_filename = path.basename(self.file).split(".")[0]
44
        tmp_dir = self.env.create_pid_local_tmpdir()
45 46 47 48
        shutil.copy(self.preprocessed_file, path.join(tmp_dir, base_filename + ".java"))
        cwd = os.getcwd()
        os.chdir(tmp_dir)
        exp_out = None
49
        #print(base_filename, get_main_class_name(base_filename + ".java"))
50 51 52 53 54
        if not self._has_expected_output_file:
            _, _, javac_rtcode = \
                self.env.run_command("javac", base_filename + ".java")
            if javac_rtcode != 0:
                _LOG.error("File \"{}\" isn't valid Java".format(self.preprocessed_file))
55
                os.chdir(cwd)
56 57
                raise InterruptedError()
            exp_out, _, _ = \
58
                self.env.run_command("java", get_main_class_name(base_filename + ".java"))
59
            exp_out = exp_out.decode().strip()
60 61 62
            with open(self._prev_out_file, "w") as f:
                f.write(exp_out)
                f.flush()
63 64 65
            with open(self._prev_out_hash_file, "w") as f:
                f.write(self._hash_sum_for_file(base_filename + ".java"))
                f.flush()
66 67 68
        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:
                exp_out = f.read()
69 70 71 72 73 74 75
        try:
            _, err, rtcode = self.env.run_mj_command(self.MODE, base_filename + ".java")
            out, _, _ = self.env.run_command("./" + base_filename)
            out = out.decode().strip()
            os.chdir(cwd)
            if self.type == self.MODE and self.env.mode == self.MODE:
                return BasicDiffTestResult(self, rtcode, out, err.decode(), exp_out)
Johannes Bechberger's avatar
Johannes Bechberger committed
76
            return BasicTestResult(self, rtcode, out, err.decode())
77 78 79
        except SigKill as sig:
            os.chdir(cwd)
            return BasicTestResult(self, sig.retcode, "", exp_out, sig.name)
80 81 82
        except:
            os.chdir(cwd)
            raise
83

84 85 86 87 88
    def _check_hash_sum(self, file: str, hash_sum_file: str) -> bool:
        old_hash = ""
        with open(hash_sum_file, "r") as f:
            old_hash = f.readline().strip()
        return self._hash_sum_for_file(file) == old_hash
89

90 91 92
    def _hash_sum_for_file(self, file: str) -> str:
        with open(file, "r") as f:
            return hashlib.sha256(f.read().encode()).hexdigest()
93

94 95 96 97 98
TestCase.TEST_CASE_CLASSES[TestMode.compile_firm].append(JavaExecTest)


class JavaInfiniteLoopTest(BasicSyntaxTest):

99 100
    FILE_ENDINGS = [".inf.java", ".inf.mj"]
    OUTPUT_FILE_ENDING = ".out"
101 102 103 104
    MODE = TestMode.compile_firm

    def __init__(self, env: Environment, type: str, file: str, preprocessed_file: str):
        super().__init__(env, type, file, preprocessed_file)
105 106
        self._output_file = self.file + self.OUTPUT_FILE_ENDING
        self._has_output_file = path.exists(self._output_file)
107 108 109 110 111 112 113 114

    def run(self) -> BasicTestResult:
        base_filename = path.basename(self.file).split(".")[0]
        tmp_dir = self.env.create_pid_local_tmpdir()
        shutil.copy(self.preprocessed_file, path.join(tmp_dir, base_filename + ".java"))
        cwd = os.getcwd()
        os.chdir(tmp_dir)
        timeout = 1
115 116 117
        err = ""
        out = ""
        out2 = ""
118
        try:
119
            out2, err, rtcode = self.env.run_mj_command(self.MODE, base_filename + ".java")
120 121 122 123
            out, _, _ = self.env.run_command("./" + base_filename, timeout=timeout)
        except SigKill as kill:
            os.chdir(cwd)
            if kill.retcode == signal.SIGXCPU:
124 125 126 127 128 129 130 131 132
                if self._has_output_file:
                    out = out.decode().strip()
                    exp_out = ""
                    with open(self._output_file, "r") as f:
                        exp_out = f.read().strip()
                    if not out.startswith(exp_out):
                        return BasicDiffTestResult(self, 1, out, err.decode(), exp_out,
                                                   "Output doesn't start like expected")
                return BasicTestResult(self, 0, err.decode(), out.decode())
133
            else:
134
                return BasicTestResult(self, kill.retcode, "", err.decode(), "No timeout, got " + kill.name)
135 136 137 138
        except:
            os.chdir(cwd)
            raise
        os.chdir(cwd)
139
        return BasicTestResult(self, 1, "", err.decode(), "No timeout")
140 141 142


TestCase.TEST_CASE_CLASSES[TestMode.compile_firm].append(JavaInfiniteLoopTest)