From: Joe Wreschnig Date: Sat, 20 Mar 2010 09:14:40 +0000 (-0700) Subject: Integration and coverage tests. (Fixes issue #2) X-Git-Url: https://git.yukkurigames.com/?p=python-bulletml.git;a=commitdiff_plain;h=781dc628702361a759834ca5fdf117679d33f76a Integration and coverage tests. (Fixes issue #2) --- diff --git a/MANIFEST.in b/MANIFEST.in index 9b06366..ea8405a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include examples/*.xml include examples/*/*.xml +include tests/*.py include README.txt diff --git a/bulletml/parser.py b/bulletml/parser.py index 9d515a2..5435925 100644 --- a/bulletml/parser.py +++ b/bulletml/parser.py @@ -361,9 +361,6 @@ class Accel(object): class BulletDef(object): """Bullet definition.""" - direction = None - speed = None - def __init__(self, actions=(), direction=None, speed=None, tags=()): self.direction = direction self.speed = speed @@ -557,7 +554,9 @@ class Offset(object): def __setstate__(self, state): state = dict(state) - self.__init__(state["type"], state.get("x"), state.get("y")) + x = NumberDef(state["x"]) if "x" in state else None + y = NumberDef(state["y"]) if "y" in state else None + self.__init__(state["type"], x, y) @classmethod def FromXML(cls, doc, element): diff --git a/setup.py b/setup.py index 1b383c2..5784907 100755 --- a/setup.py +++ b/setup.py @@ -3,9 +3,11 @@ import glob import os import shutil +import sys -from distutils.core import setup +from distutils.core import setup, Command from distutils.command.clean import clean as distutils_clean +from distutils.command.sdist import sdist as distutils_sdist class clean(distutils_clean): def run(self): @@ -22,8 +24,8 @@ class clean(distutils_clean): for pathname, dirs, files in os.walk(os.path.dirname(__file__)): for filename in filter(should_remove, files): try: os.unlink(os.path.join(pathname, filename)) - except EnvironmentError, err: - print str(err) + except EnvironmentError as err: + print(str(err)) try: os.unlink("MANIFEST") except OSError: pass @@ -33,10 +35,77 @@ class clean(distutils_clean): if os.path.isdir(path): shutil.rmtree(path) +class coverage_cmd(Command): + description = "generate test coverage data" + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + import trace + tracer = trace.Trace( + count=True, trace=False, + ignoredirs=[sys.prefix, sys.exec_prefix]) + def run_tests(): + import bulletml + try: + reload(bulletml) + except NameError: + pass + self.run_command("test") + tracer.runfunc(run_tests) + results = tracer.results() + coverage = os.path.join(os.path.dirname(__file__), "coverage") + results.write_results(show_missing=True, coverdir=coverage) + map(os.unlink, glob.glob(os.path.join(coverage, "[!b]*.cover"))) + try: os.unlink(os.path.join(coverage, "..setup.cover")) + except OSError: pass + + total_lines = 0 + bad_lines = 0 + for filename in glob.glob(os.path.join(coverage, "*.cover")): + lines = open(filename, "rU").readlines() + total_lines += len(lines) + bad_lines += len( + [line for line in lines if + (line.startswith(">>>>>>") and + "finally:" not in line and '"""' not in line)]) + pct = 100.0 * (total_lines - bad_lines) / float(total_lines) + print("Coverage data written to %s (%d/%d, %0.2f%%)" % ( + coverage, total_lines - bad_lines, total_lines, pct)) + +class sdist(distutils_sdist): + def run(self): + self.run_command("test") + distutils_sdist.run(self) + +class test_cmd(Command): + description = "run automated tests" + user_options = [ + ("to-run=", None, "list of tests to run (default all)"), + ] + + def initialize_options(self): + self.to_run = [] + self.quick = False + + def finalize_options(self): + if self.to_run: + self.to_run = self.to_run.split(",") + + def run(self): + import tests + if tests.unit(self.to_run): + raise SystemExit("Test failures are listed above.") + if __name__ == "__main__": - from bulletml import VERSION_STRING - setup(cmdclass=dict(clean=clean), - name="python-bulletml", version=VERSION_STRING, + setup(cmdclass=dict( + clean=clean, test=test_cmd, coverage=coverage_cmd, sdist=sdist), + name="python-bulletml", version="0.1", url="http://code.google.com/p/python-bulletml/", description="parse and run BulletML scripts", author="Joe Wreschnig", diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..8640d5a --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,72 @@ +"""Generic test runner. + +This module scans for filenames begining with test_ and runs the tests +in them. It is less noisy than the default Python test runners. +""" + +from __future__ import division +from __future__ import print_function + +import glob +import os +import sys +import unittest + +from unittest import TestCase + +suites = [] +add = suites.append + +for name in glob.glob(os.path.join(os.path.dirname(__file__), "test_*.py")): + module = "tests." + os.path.basename(name) + __import__(module[:-3], {}, {}, []) + +class Result(unittest.TestResult): + + separator1 = '=' * 70 + separator2 = '-' * 70 + + def addSuccess(self, test): + unittest.TestResult.addSuccess(self, test) + sys.stdout.write('.') + + def addError(self, test, err): + unittest.TestResult.addError(self, test, err) + sys.stdout.write('E') + + def addFailure(self, test, err): + unittest.TestResult.addFailure(self, test, err) + sys.stdout.write('F') + + def printErrors(self): + succ = self.testsRun - (len(self.errors) + len(self.failures)) + v = "%3d" % succ + count = 50 - self.testsRun + sys.stdout.write((" " * count) + v + "\n") + self.printErrorList('ERROR', self.errors) + self.printErrorList('FAIL', self.failures) + + def printErrorList(self, flavour, errors): + for test, err in errors: + sys.stdout.write(self.separator1 + "\n") + sys.stdout.write("%s: %s\n" % (flavour, str(test))) + sys.stdout.write(self.separator2 + "\n") + sys.stdout.write("%s\n" % err) + +class Runner(object): + def run(self, test): + suite = unittest.makeSuite(test) + pref = '%s (%d): ' % (test.__name__, len(suite._tests)) + print(pref + " " * (25 - len(pref)), end=" ") + result = Result() + suite(result) + result.printErrors() + return bool(result.failures + result.errors) + +def unit(run=[]): + runner = Runner() + failures = False + for test in suites: + if not run or test.__name__ in run or test.__name__.lstrip("T") in run: + failures |= runner.run(test) + return failures diff --git a/tests/test_examples.py b/tests/test_examples.py new file mode 100644 index 0000000..d9d59d7 --- /dev/null +++ b/tests/test_examples.py @@ -0,0 +1,54 @@ +import os +import glob + +from bulletml import BulletML, Bullet, bulletyaml +from tests import TestCase, add + +class Texamples_xml(TestCase): + pass + +class Texamples_yaml(TestCase): + pass + +class Texamples_repr(TestCase): + pass + +class Texamples_run(TestCase): + pass + +for filename in glob.glob("examples/*/*.xml"): + basename = os.path.basename(filename)[:-4].replace("-", "_") + + def test_xml(self, filename=filename): + BulletML.FromDocument(open(filename, "rU")) + setattr(Texamples_xml, "test_" + basename, test_xml) + + try: + import yaml + except ImportError: + pass + else: + def test_yaml(self, filename=filename): + doc = BulletML.FromDocument(open(filename, "rU")) + doc = yaml.load(yaml.dump(doc)) + doc = yaml.load(yaml.dump(doc)) + setattr(Texamples_yaml, "test_" + basename, test_yaml) + + def test_repr(self, filename=filename): + doc = BulletML.FromDocument(open(filename, "rU")) + repr(doc) + setattr(Texamples_repr, "test_" + basename, test_repr) + + def test_run(self, filename=filename): + doc = BulletML.FromDocument(open(filename, "rU")) + bullets = [Bullet.FromDocument(doc)] + for i in range(100): + for bullet in bullets: + bullets.extend(bullet.step()) + setattr(Texamples_run, "test_" + basename, test_run) + + +add(Texamples_xml) +add(Texamples_yaml) +add(Texamples_repr) +add(Texamples_run)