exec_tests.py 5.41 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 20

_LOG = logging.getLogger("exec_tests")

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

    FILE_ENDINGS = [".java"]
21
    INVALID_FILE_ENDINGS = [".inf.java"]
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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
TestCase.TEST_CASE_CLASSES[TestMode.compile_firm].append(JavaExecTest)


class JavaInfiniteLoopTest(BasicSyntaxTest):

    FILE_ENDINGS = [".inf.java"]
    MODE = TestMode.compile_firm

    def __init__(self, env: Environment, type: str, file: str, preprocessed_file: str):
        super().__init__(env, type, file, preprocessed_file)

    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
        try:
            _, err, rtcode = self.env.run_mj_command(self.MODE, base_filename + ".java")
            out, _, _ = self.env.run_command("./" + base_filename, timeout=timeout)
        except SigKill as kill:
            os.chdir(cwd)
            if kill.retcode == signal.SIGXCPU:
                return BasicTestResult(self, err.decode(), 0, out.decode())
            else:
                return BasicTestResult(self, kill.retcode, "", "", "No timeout, got " + kill.name)
        except:
            os.chdir(cwd)
            raise
        os.chdir(cwd)
        return BasicTestResult(self, 1, "", "", "No timeout")


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