You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bddisasm/bdshemu_test/test_all.py

179 lines
4.9 KiB

#
# Copyright (c) 2020 Bitdefender
# SPDX-License-Identifier: Apache-2.0
#
import os
import sys
import glob
import shutil
from zipfile import ZipFile
from pathlib import Path
TEMP_PATH = "!temp"
# A test file-name contains some indicators as to how the emulation should be done:
# - If '_16' is present in the name, emulation will be done on 16 bit
# - If '_32' is present in the name, emulation will be done on 32 bit
# - If '_64' is present in the name, emulation will be done on 64 bit
# - If '_r0' is present in the name, emulation will be done as kernel code
# A test case consists of minimum two files:
# - An '.test' file, containing the binary code to be emulated
# - An '.result' file, containing the emulation output
# A test is considered passed if the output produced during emulation is identical to the
# output containted in the '.result' file.
#
# test_dir
#
# Runs the tests inside the provided directory.
# Returns a tuplecontaining the total number of tests run and the number of failed tests.
#
def test_dir(dir, arch='x86'):
total_tests = 0
failed_tests = 0
for f in glob.glob('%s\\*.test' % dir):
base, _ = os.path.splitext(f)
tst_file = f
res_file = base + '.result'
tmp_file = base + '.temp'
if 0 < tst_file.find('_16'):
mod = '-b16'
elif 0 < tst_file.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < tst_file.find('_r0'):
mod += ' -k'
print(' * Running test case %s...' % tst_file)
os.system('disasm shemu %s -f %s >%s' % (mod, tst_file, tmp_file))
try:
res = open(res_file).read()
except:
print(' ! No result file provided for test %s!' % tst_file)
try:
tmp = open(tmp_file).read()
except:
print(' ! No result produced by test %s!' % tst_file)
total_tests += 1
if res != tmp:
print(' **** FAILED! ****')
failed_tests += 1
else:
print(' * Passed.')
# Cleanup.
os.remove(tmp_file)
os.remove(tst_file + "_decoded.bin")
return (total_tests, failed_tests)
#
# regenerate
#
def regenerate(dir, arch='x86'):
for f in glob.glob('%s\\*.test' % dir):
base, _ = os.path.splitext(f)
tst_file = f
res_file = base + '.result'
if 0 < f.find('_16'):
mod = '-b16'
elif 0 < f.find('_32'):
mod = '-b32'
else:
mod = '-b64'
if 0 < f.find('_r0'):
mod += ' -k'
print(' * Regenerating test case %s...' % tst_file)
os.system('disasm -exi shemu %s -f %s >%s' % (mod, tst_file, res_file))
# Cleanup.
os.remove(tst_file + "_decoded.bin")
#
# parse_dir_rec
#
def parse_dir_rec(dir, arch, handler):
for f in glob.glob(dir + "\\*"):
path, name = os.path.split(f)
if name in ['.', '..']:
continue
if os.path.isdir(f):
parse_dir_rec(f, arch, handler)
handler(f, arch)
#
# test_archive
#
def test_archive(filename, arch='x86'):
cleanup_files = []
# Run the x86 test.
print("Extracting test archive...")
with ZipFile(filename) as zf:
cleanup_files = zf.namelist()
zf.extractall(path=TEMP_PATH)
zf.close()
print("Running tests...")
total_tests, failed_tests = 0, 0
for dn in glob.glob(os.path.join(TEMP_PATH, "*")):
if not os.path.isdir(dn):
continue
print('Testing %s...' % dn)
cnt_tests, cnt_failed = test_dir(dn, arch)
total_tests += cnt_tests
failed_tests += cnt_failed
print("========================================================================")
print("Summary:")
print("Ran %d tests, %d failed" % (total_tests, failed_tests))
print("========================================================================")
print()
shutil.rmtree(TEMP_PATH)
if __name__ == "__main__":
# No arguments provided, auto-run all tests.
if len(sys.argv) == 1:
print("Running x86 tests...")
test_archive("x86\\bdshemu_test_x86.zip")
sys.exit(0)
opt_dir = ""
opt_regen = False
opt_arch = 'x86'
for arg in sys.argv[1:]:
if os.path.isdir(arg):
print("Will test directory", arg)
opt_dir = arg
if arg == "regenerate":
print("Will regenerate tests...")
opt_regen = True
print("Identified architecture: ", opt_arch)
# Single directory test.
if not opt_dir:
print("A directory containing tests must be supplied!")
sys.exit(-1)
if opt_regen:
parse_dir_rec(opt_dir, opt_arch, regenerate)
else:
parse_dir_rec(opt_dir, opt_arch, test_dir)