197 lines
5.8 KiB
Python
197 lines
5.8 KiB
Python
#!/usr/bin/env python
|
|
|
|
import tempfile
|
|
import sys
|
|
import subprocess
|
|
import shutil
|
|
import os
|
|
import hashlib
|
|
import contextlib
|
|
import gzip
|
|
import fnmatch
|
|
|
|
|
|
def generate_file_list(directory):
|
|
for dirpath, dirnames, filenames in os.walk(directory):
|
|
for filename in filenames:
|
|
yield os.path.join(dirpath, filename)
|
|
|
|
|
|
def sha1_file(name, checksum=None):
|
|
CHUNKSIZE = 1024
|
|
if checksum is None:
|
|
checksum = hashlib.sha1()
|
|
if fnmatch.fnmatch(name, "*.dat"):
|
|
opener = gzip.open
|
|
else:
|
|
opener = open
|
|
|
|
with contextlib.closing(opener(name, 'rb')) as data:
|
|
chunk = data.read(CHUNKSIZE)
|
|
while len(chunk) == CHUNKSIZE:
|
|
checksum.update(chunk)
|
|
chunk = data.read(CHUNKSIZE)
|
|
else:
|
|
checksum.update(chunk)
|
|
return checksum
|
|
|
|
|
|
def calculate_result(directory):
|
|
checksum = hashlib.sha1()
|
|
for filename in sorted(generate_file_list(directory)):
|
|
if filename.endswith("session.lock"):
|
|
continue
|
|
sha1_file(filename, checksum)
|
|
return checksum.hexdigest()
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def temporary_directory(prefix='regr'):
|
|
name = tempfile.mkdtemp(prefix)
|
|
try:
|
|
yield name
|
|
finally:
|
|
shutil.rmtree(name)
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def directory_clone(src):
|
|
with temporary_directory('regr') as name:
|
|
subdir = os.path.join(name, "subdir")
|
|
shutil.copytree(src, subdir)
|
|
yield subdir
|
|
|
|
|
|
def launch_subprocess(directory, arguments, env=None):
|
|
#my python breaks with an empty environ, i think it wants PATH
|
|
#if sys.platform == "win32":
|
|
if env is None:
|
|
env = {}
|
|
|
|
newenv = {}
|
|
newenv.update(os.environ)
|
|
newenv.update(env)
|
|
|
|
proc = subprocess.Popen((["python.exe"] if sys.platform == "win32" else []) + [
|
|
"./mce.py",
|
|
directory] + arguments, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=newenv)
|
|
|
|
return proc
|
|
|
|
|
|
class RegressionError(Exception):
|
|
pass
|
|
|
|
|
|
def do_test(test_data, result_check, arguments=()):
|
|
"""Run a regression test on the given world.
|
|
|
|
result_check - sha1 of the recursive tree generated
|
|
arguments - arguments to give to mce.py on execution
|
|
"""
|
|
result_check = result_check.lower()
|
|
|
|
env = {
|
|
'MCE_RANDOM_SEED': '42',
|
|
'MCE_LAST_PLAYED': '42',
|
|
}
|
|
|
|
if 'MCE_PROFILE' in os.environ:
|
|
env['MCE_PROFILE'] = os.environ['MCE_PROFILE']
|
|
|
|
with directory_clone(test_data) as directory:
|
|
proc = launch_subprocess(directory, arguments, env)
|
|
proc.stdin.close()
|
|
proc.wait()
|
|
|
|
if proc.returncode:
|
|
raise RegressionError("Program execution failed!")
|
|
|
|
checksum = calculate_result(directory).lower()
|
|
if checksum != result_check.lower():
|
|
raise RegressionError("Checksum mismatch: {0!r} != {1!r}".format(checksum, result_check))
|
|
print "[OK] (sha1sum of result is {0!r}, as expected)".format(result_check)
|
|
|
|
|
|
def do_test_match_output(test_data, result_check, arguments=()):
|
|
result_check = result_check.lower()
|
|
|
|
env = {
|
|
'MCE_RANDOM_SEED': '42',
|
|
'MCE_LAST_PLAYED': '42'
|
|
}
|
|
|
|
with directory_clone(test_data) as directory:
|
|
proc = launch_subprocess(directory, arguments, env)
|
|
proc.stdin.close()
|
|
output = proc.stdout.read()
|
|
proc.wait()
|
|
|
|
if proc.returncode:
|
|
raise RegressionError("Program execution failed!")
|
|
|
|
print "Output\n{0}".format(output)
|
|
|
|
checksum = hashlib.sha1()
|
|
checksum.update(output)
|
|
checksum = checksum.hexdigest()
|
|
|
|
if checksum != result_check.lower():
|
|
raise RegressionError("Checksum mismatch: {0!r} != {1!r}".format(checksum, result_check))
|
|
|
|
print "[OK] (sha1sum of result is {0!r}, as expected)".format(result_check)
|
|
|
|
|
|
alpha_tests = [
|
|
(do_test, 'baseline', '2bf250ec4e5dd8bfd73b3ccd0a5ff749569763cf', []),
|
|
(do_test, 'degrief', '2b7eecd5e660f20415413707b4576b1234debfcb', ['degrief']),
|
|
(do_test_match_output, 'analyze', '9cb4aec2ed7a895c3a5d20d6e29e26459e00bd53', ['analyze']),
|
|
(do_test, 'relight', 'f3b3445b0abca1fe2b183bc48b24fb734dfca781', ['relight']),
|
|
(do_test, 'replace', '4e816038f9851817b0d75df948d058143708d2ec', ['replace', 'Water (active)', 'with', 'Lava (active)']),
|
|
(do_test, 'fill', '94566d069edece4ff0cc52ef2d8f877fbe9720ab', ['fill', 'Water (active)']),
|
|
(do_test, 'heightmap', '71c20e7d7e335cb64b3eb0e9f6f4c9abaa09b070', ['heightmap', 'regression_test/mars.png']),
|
|
]
|
|
|
|
import optparse
|
|
|
|
parser = optparse.OptionParser()
|
|
parser.add_option("--profile", help="Perform profiling on regression tests", action="store_true")
|
|
|
|
|
|
def main(argv):
|
|
options, args = parser.parse_args(argv)
|
|
|
|
if len(args) <= 1:
|
|
do_these_regressions = ['*']
|
|
else:
|
|
do_these_regressions = args[1:]
|
|
|
|
with directory_clone("testfiles/AnvilWorld") as directory:
|
|
test_data = directory
|
|
passes = []
|
|
fails = []
|
|
|
|
for func, name, sha, args in alpha_tests:
|
|
print "Starting regression {0} ({1})".format(name, args)
|
|
|
|
if any(fnmatch.fnmatch(name, x) for x in do_these_regressions):
|
|
if options.profile:
|
|
print >> sys.stderr, "Starting to profile to %s.profile" % name
|
|
os.environ['MCE_PROFILE'] = '%s.profile' % name
|
|
try:
|
|
func(test_data, sha, args)
|
|
except RegressionError as e:
|
|
fails.append("Regression {0} failed: {1}".format(name, e))
|
|
print fails[-1]
|
|
else:
|
|
passes.append("Regression {0!r} complete.".format(name))
|
|
print passes[-1]
|
|
|
|
print "{0} tests passed.".format(len(passes))
|
|
for line in fails:
|
|
print line
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv))
|