from os import environ
from shutil import copy
from subprocess import check_call


def _dotest(self, cpu_vm, cpu_vm_dpmi):

    if not getattr(self.__class__, 'cpumade', False):
        check_call(["make", "--quiet", "-C", "test/cpu", "clean", "all"])
        self.__class__.cpumade = True

    if (('jit' in cpu_vm and 'sim' in cpu_vm_dpmi) or
            ('sim' in cpu_vm and 'jit' in cpu_vm_dpmi)):
        raise ValueError("Invalid JIT/SIM combination")

    if ('sim' in cpu_vm) or ('sim' in cpu_vm_dpmi):
        cpu_emu = 1
    else:
        cpu_emu = 0

    if ('jit' in cpu_vm) or ('sim' in cpu_vm):
        cpu_vm = 'emulated'
    if ('jit' in cpu_vm_dpmi) or ('sim' in cpu_vm_dpmi):
        cpu_vm_dpmi = 'emulated'

    if ('kvm' in cpu_vm or 'kvm' in cpu_vm_dpmi) and not self.have_kvm:
        self.skipTest("requires KVM")

    if cpu_vm == 'native' and not self.have_vm86:
        self.skipTest("native vm86() only on 32bit x86")

    if cpu_vm_dpmi == 'native' and environ.get("SKIP_NATIVE_DPMI"):
        self.skipTest("no native dpmi")

    edir = self.topdir / "test" / "cpu"

    # Native reference file is now checked in to git and will
    # only need to be updated if the test source changes.
    reffile = edir / "reffile.log"

    # DOS test binary is built as part of normal build process
    copy(edir / "dosbin.exe", self.workdir / "dosbin.exe")
    dosfile = self.workdir / "dosfile.log"

    # output from DOS under test
    self.mkfile("testit.bat", """\
dosbin > %s
rem end
""" % dosfile.name, newline="\r\n")

    self.runDosemu("testit.bat", timeout=20, config="""\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
$_cpu_vm = "%s"
$_cpu_vm_dpmi = "%s"
$_cpuemu = (%i)
$_ignore_djgpp_null_derefs = (off)
"""%(cpu_vm, cpu_vm_dpmi, cpu_emu))

    self.assertFilesEqual(reffile, dosfile)

EMU_TESTS = (
    ('jit',    'native'), #  CPU JIT vm86 + native DPMI
    ('sim',    'native'), #  CPU simulated vm86 + native DPMI

    ('jit',    'jit'),    #  CPU JIT vm86 + JIT DPMI
    ('sim',    'sim'),    #  CPU simulated vm86 + simulated DPMI
)

KVM_TESTS = (
    ('kvm',    'native'), #  CPU KVM vm86 + native DPMI
    ('kvm',    'kvm'),    #  CPU KVM vm86 + KVM DPMI
    ('kvm',    'jit'),    #  CPU KVM vm86 + JIT DPMI
    ('kvm',    'sim'),    #  CPU KVM vm86 + simulated DPMI

    ('jit',    'kvm'),    #  CPU JIT vm86 + KVM DPMI
    ('sim',    'kvm'),    #  CPU simulated vm86 + KVM DPMI
)

VM86_TESTS = (
    ('native', 'native'), #  CPU native vm86(i386 only) + native DPMI
)


def create_test(test):
    def do_test(self):
        _dotest(self, *test)

    if test[0] == 'native':
        d1 = 'native vm86(i386 only)'
    elif test[0] == 'sim':
        d1 = 'simulated vm86'
    else:
        d1 = '%s vm86' % test[0].upper()

    if test[1] == 'native':
        d2 = 'native DPMI';
    elif test[1] == 'sim':
        d2 = 'simulated DPMI'
    else:
        d2 = '%s DPMI' % test[1].upper()
    setattr(do_test, '__doc__', 'CPU %s + %s' % (d1, d2))
    setattr(do_test, 'cputest', True)
    return do_test


def cpu_create_items(testcase):
    tests = {
        'emu': EMU_TESTS,
        'kvm': KVM_TESTS,
        'vm86': VM86_TESTS,
    }[testcase.use_cpu]


    # Insert each test into the testcase
    for test in tests:
        name = 'test_cpu_method_%s_%s' % test
        setattr(testcase, name, create_test(test))

    testcase.attrs.add('cputest')
