# mceditlib.run_regression_test — mceditlib 0.1 documentation

### Navigation

- index
- modules |
- mceditlib 0.1 documentation »
- Module code »

# Source code for mceditlib.run_regression_test

    #!/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))

### Navigation

- index
- modules |
- mceditlib 0.1 documentation »
- Module code »