diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..1d64705 --- /dev/null +++ b/conftest.py @@ -0,0 +1,21 @@ + +# Configuration for the tests. +# Use `py.test` to run the tests. + +# (This file needs to be in or above the directory where py.test is called) + +import pytest +import os + +def pytest_addoption(parser): + parser.addoption("--media-root", action="store", + default=None, + help="Root for the media files (if not specified and pokedex/data/media doesn't exist, tests are skipped)") + parser.addoption("--all", action="store_true", default=False, + help="Run all tests, even those that take a lot of time") + +def pytest_generate_tests(metafunc): + for funcargs in getattr(metafunc.function, 'funcarglist', ()): + metafunc.addcall(funcargs=funcargs) + for posargs in getattr(metafunc.function, 'posarglist', ()): + metafunc.addcall(funcargs=dict(zip(metafunc.funcargnames, posargs))) diff --git a/pokedex/tests/__init__.py b/pokedex/tests/__init__.py index 8343e61..3bc8d3c 100644 --- a/pokedex/tests/__init__.py +++ b/pokedex/tests/__init__.py @@ -1,6 +1,45 @@ -def setup(): - # XXX This needs to recreate the database, someday. :( - pass -def teardown(): - pass +import inspect +from functools import wraps + +# test support code +def params(funcarglist): + """Basic list-of-dicts test parametrization + + From: http://pytest.org/funcargs.html + + Example: + @params([dict(a=1, b=2), dict(a=3, b=4)]) + def test_lt(a, b): + assert a < b + """ + def decorator(function): + function.funcarglist = funcarglist + return function + return decorator + +def positional_params(*paramlist): + """Magic list-of-lists parametrization + + Example: + @params([(1, 2), (3, 4)]) + def test_lt(a, b): + assert a < b + """ + def decorator(function): + function.posarglist = paramlist + return function + return decorator + +def single_params(*paramlist): + """Magic list-of-lists parametrization + + Example: + @params('1', '2', '3', '4']) + def test_int(k): + assert int(k) + """ + def decorator(function): + function.posarglist = [[param] for param in paramlist] + return function + return decorator diff --git a/pokedex/tests/test_database_sanity.py b/pokedex/tests/test_database_sanity.py index ff897a4..40c6241 100644 --- a/pokedex/tests/test_database_sanity.py +++ b/pokedex/tests/test_database_sanity.py @@ -1,5 +1,6 @@ -from nose.tools import * -import unittest + +import pytest + from sqlalchemy.orm import aliased from sqlalchemy.orm.exc import NoResultFound @@ -21,8 +22,8 @@ def test_encounter_slots(): .join((version_group_b, tables.Version.version_group)) \ .filter(version_group_a.id != version_group_b.id) - assert_equal(sanity_q.count(), 0, - "Encounter slots all match the encounters they belong to") + # Encounter slots all match the encounters they belong to + assert sanity_q.count() == 0 def test_nonzero_autoincrement_ids(): """Check that autoincrementing ids don't contain zeroes @@ -34,8 +35,8 @@ def test_nonzero_autoincrement_ids(): for cls in tables.mapped_classes: if 'id' in cls.__table__.c: if cls.__table__.c.id.autoincrement: - @raises(NoResultFound) def nonzero_id(cls): - util.get(session, cls, id=0) + with pytest.raises(NoResultFound): + util.get(session, cls, id=0) nonzero_id.description = "No zero id in %s" % cls.__name__ yield nonzero_id, cls diff --git a/pokedex/tests/test_lookup.py b/pokedex/tests/test_lookup.py index 3da916d..48b773e 100644 --- a/pokedex/tests/test_lookup.py +++ b/pokedex/tests/test_lookup.py @@ -1,18 +1,12 @@ -# encoding: utf8 -from nose.tools import * -import unittest +# Encoding: UTF-8 + +from pokedex.tests import * from pokedex.lookup import PokedexLookup -lookup = None +lookup = PokedexLookup() -def setup(): - # Recreate data - global lookup - lookup = PokedexLookup() - -def test_exact_lookup(): - tests = [ +@positional_params( # Simple lookups (u'Eevee', 'pokemon_species',133), (u'Scratch', 'moves', 10), @@ -37,68 +31,61 @@ def test_exact_lookup(): (u'이브이', 'pokemon_species', 133), (u'伊布', 'pokemon_species', 133), (u'Evoli', 'pokemon_species', 133), - ] + ) +def test_exact_lookup(input, table, id): + results = lookup.lookup(input) + assert len(results) == 1 + assert results[0].exact == True - for input, table, id in tests: - results = lookup.lookup(input) - assert_equal(len(results), 1, u"'%s' returns one result" % input) - assert_equal(results[0].exact, True, u"'%s' match exactly" % input) - - row = results[0].object - assert_equal(row.__tablename__, table, u"'%s' is in the right table" % input) - assert_equal(row.id, id, u"'%s' returns the right id" % input) + row = results[0].object + assert row.__tablename__ == table + assert row.id == id def test_id_lookup(): results = lookup.lookup(u'1') - assert_true(len(results) >= 5, u'At least five things have id 1') - assert_true(all(_.object.id == 1 for _ in results), - u'All results have id 1') + assert len(results) >= 5 + assert all(result.object.id == 1 for result in results) + def test_multi_lookup(): results = lookup.lookup(u'Metronome') - assert_equal(len(results), 2, u'Two things called "Metronome"') - assert_true(results[0].exact, u'Metronome matches are exact') + assert len(results) == 2 + assert results[0].exact def test_type_lookup(): results = lookup.lookup(u'pokemon:1') - assert_equal(results[0].object.__tablename__, 'pokemon_species', - u'Type restriction works correctly') - assert_equal(len(results), 1, u'Only one id result when type is specified') - assert_equal(results[0].object.name, u'Bulbasaur', - u'Type + id returns the right result') + assert results[0].object.__tablename__ == 'pokemon_species' + assert len(results) == 1 + assert results[0].object.name == u'Bulbasaur' results = lookup.lookup(u'1', valid_types=['pokemon_species']) - assert_equal(results[0].object.name, u'Bulbasaur', - u'valid_types works as well as type: prefix') + assert results[0].object.name == u'Bulbasaur' + def test_language_lookup(): # There are two objects named "charge": the move Charge, and the move # Tackle, which is called "Charge" in French. results = lookup.lookup(u'charge') - assert_true(len(results) > 1, u'There are multiple "charge"s') + assert len(results) > 1 results = lookup.lookup(u'@fr:charge') - assert_equal(results[0].iso639, u'fr', u'Language restriction works correctly') - assert_equal(len(results), 1, u'Only one "charge" result when language is specified') - assert_equal(results[0].object.name, u'Tackle', - u'Language + vague name returns the right result') + assert results[0].iso639 == u'fr' + assert len(results) == 1 + assert results[0].object.name == u'Tackle' results = lookup.lookup(u'charge', valid_types=['@fr']) - assert_equal(results[0].object.name, u'Tackle', - u'valid_types works as well as @lang: prefix') + assert results[0].object.name == u'Tackle' results = lookup.lookup(u'@fr,move:charge') - assert_equal(results[0].object.name, u'Tackle', - u'Languages and types both work together') + assert results[0].object.name == u'Tackle' results = lookup.lookup(u'@fr:charge', valid_types=['move']) - assert_equal(results[0].object.name, u'Tackle', - u'valid_types and language prefixes get along') + assert results[0].object.name, u'Tackle' -def test_fuzzy_lookup(): - tests = [ + +@positional_params( # Regular English names (u'chamander', u'Charmander'), (u'pokeball', u'Poké Ball'), @@ -110,44 +97,51 @@ def test_fuzzy_lookup(): # Sufficiently long foreign names (u'カクレオ', u'Kecleon'), (u'Yamikrasu', u'Murkrow'), - ] + ) +def test_fuzzy_lookup(misspelling, name): + results = lookup.lookup(misspelling) + first_result = results[0] + assert first_result.object.name == name - for misspelling, name in tests: - results = lookup.lookup(misspelling) - first_result = results[0] - assert_equal(first_result.object.name, name, - u'Simple misspellings are corrected') +def test_nidoran(): results = lookup.lookup(u'Nidoran') - top_names = [_.object.name for _ in results[0:2]] - assert_true(u'Nidoran♂' in top_names, u'Nidoran♂ is a top result for "Nidoran"') - assert_true(u'Nidoran♀' in top_names, u'Nidoran♀ is a top result for "Nidoran"') + top_names = [result.object.name for result in results[0:2]] + assert u'Nidoran♂' in top_names + assert u'Nidoran♀' in top_names -def test_wildcard_lookup(): - tests = [ + +@positional_params( (u'pokemon:*meleon', u'Charmeleon'), (u'item:master*', u'Master Ball'), (u'ee?ee', u'Eevee'), - ] + ) +def test_wildcard_lookup(wildcard, name): + results = lookup.lookup(wildcard) + first_result = results[0] + assert first_result.object.name == name - for wildcard, name in tests: - results = lookup.lookup(wildcard) - first_result = results[0] - assert_equal(first_result.object.name, name, - u'Wildcards work correctly') -def test_random_lookup(): - for _ in xrange(5): +def test_bare_random(): + for i in range(5): results = lookup.lookup(u'random') - assert_equal(len(results), 1, u'Random returns one result') + assert len(results) == 1 + + +@positional_params( + [u'pokemon_species'], + [u'moves'], + [u'items'], + [u'abilities'], + [u'types'], + ) +def test_qualified_random(table_name): + results = lookup.lookup(u'random', valid_types=[table_name]) + assert len(results) == 1 + assert results[0].object.__tablename__ == table_name - for table_name in [u'pokemon_species', u'moves', u'items', u'abilities', u'types']: - results = lookup.lookup(u'random', valid_types=[table_name]) - assert_equal(len(results), 1, u'Constrained random returns one result') - assert_equal(results[0].object.__tablename__, table_name, - u'Constrained random returns result from the right table') def test_crash_empty_prefix(): """Searching for ':foo' used to crash, augh!""" results = lookup.lookup(u':Eevee') - assert_equal(results[0].object.name, u'Eevee', u'Empty prefix dun crash') + assert results[0].object.name == u'Eevee' diff --git a/pokedex/tests/test_media.py b/pokedex/tests/test_media.py index f06ddcf..375c94d 100644 --- a/pokedex/tests/test_media.py +++ b/pokedex/tests/test_media.py @@ -1,4 +1,3 @@ - """Test the media accessors. If run directly from the command line, also tests the accessors and the names @@ -6,45 +5,33 @@ of all the media by getting just about everything in a naive brute-force way. This, of course, takes a lot of time to run. """ +import pytest + import os import re -from functools import wraps - -from nose.tools import * -from nose.plugins.skip import SkipTest -import nose -import pkg_resources from pokedex.db import tables, connect from pokedex.util import media +def pytest_funcarg__root(request): + root = request.config.option.media_root + if not root: + root = os.path.join(os.path.dirname(__file__), *'../data/media'.split('/')) + if not media.BaseMedia(root).available: + raise pytest.skip("Media unavailable") + return root + session = connect() -basedir = pkg_resources.resource_filename('pokedex', 'data/media') path_re = re.compile('^[-a-z0-9./]*$') -root = pkg_resources.resource_filename('pokedex', 'data/media') - -media_available = media.BaseMedia(root).available - -def if_available(func): - @wraps(func) - def if_available_wrapper(*args, **kwargs): - if not media_available: - raise SkipTest('Media not available at %s' % root) - else: - func(*args, **kwargs) - return if_available_wrapper - -@if_available -def test_totodile(): +def test_totodile(root): """Totodile's female sprite -- same as male""" totodile = session.query(tables.PokemonSpecies).filter_by(identifier=u'totodile').one() accessor = media.PokemonSpeciesMedia(root, totodile) assert accessor.sprite() == accessor.sprite(female=True) -@if_available -def test_chimecho(): +def test_chimecho(root): """Chimecho's Platinum female backsprite -- diffeent from male""" chimecho = session.query(tables.PokemonSpecies).filter_by(identifier=u'chimecho').one() accessor = media.PokemonSpeciesMedia(root, chimecho) @@ -52,15 +39,13 @@ def test_chimecho(): female = accessor.sprite('platinum', back=True, female=True, frame=2) assert male != female -@if_available -def test_venonat(): +def test_venonat(root): """Venonat's shiny Yellow sprite -- same as non-shiny""" venonat = session.query(tables.PokemonSpecies).filter_by(identifier=u'venonat').one() accessor = media.PokemonSpeciesMedia(root, venonat) assert accessor.sprite('yellow') == accessor.sprite('yellow', shiny=True) -@if_available -def test_arceus_icon(): +def test_arceus_icon(root): """Arceus fire-form icon -- same as base icon""" arceus = session.query(tables.PokemonSpecies).filter_by(identifier=u'arceus').one() accessor = media.PokemonSpeciesMedia(root, arceus) @@ -68,32 +53,28 @@ def test_arceus_icon(): fire_accessor = media.PokemonFormMedia(root, fire_arceus) assert accessor.icon() == fire_accessor.icon() -@if_available -@raises(ValueError) -def test_strict_castform(): +def test_strict_castform(root): """Castform rainy form overworld with strict -- unavailable""" - castform = session.query(tables.PokemonSpecies).filter_by(identifier=u'castform').first() - rainy_castform = [f for f in castform.forms if f.form_identifier == 'rainy'][0] - print rainy_castform - rainy_castform = media.PokemonFormMedia(root, rainy_castform) - rainy_castform.overworld('up', strict=True) + with pytest.raises(ValueError): + castform = session.query(tables.PokemonSpecies).filter_by(identifier=u'castform').first() + rainy_castform = [f for f in castform.forms if f.form_identifier == 'rainy'][0] + print rainy_castform + rainy_castform = media.PokemonFormMedia(root, rainy_castform) + rainy_castform.overworld('up', strict=True) -@if_available -@raises(ValueError) -def test_strict_exeggcute(): +def test_strict_exeggcute(root): """Exeggcutes's female backsprite, with strict -- unavailable""" - exeggcute = session.query(tables.PokemonSpecies).filter_by(identifier=u'exeggcute').one() - accessor = media.PokemonSpeciesMedia(root, exeggcute) - accessor.sprite(female=True, strict=True) + with pytest.raises(ValueError): + exeggcute = session.query(tables.PokemonSpecies).filter_by(identifier=u'exeggcute').one() + accessor = media.PokemonSpeciesMedia(root, exeggcute) + accessor.sprite(female=True, strict=True) -def get_all_filenames(): - print 'Reading all filenames...' - +def get_all_filenames(root): all_filenames = set() - for dirpath, dirnames, filenames in os.walk(basedir): + for dirpath, dirnames, filenames in os.walk(root): dirnames[:] = [dirname for dirname in dirnames if dirname != '.git'] for filename in filenames: path = os.path.join(dirpath, filename) @@ -123,8 +104,8 @@ def hit(filenames, method, *args, **kwargs): pass return True -@if_available -def check_get_everything(): +@pytest.mark.skipif("not config.getvalue('all')", reason='`--all` not specified') +def test_get_everything(root, pytestconfig): """ For every the accessor method, loop over the Cartesian products of all possible values for its arguments. @@ -133,13 +114,14 @@ def check_get_everything(): Well, there are exceptions of course. """ + assert pytestconfig.getvalue('all') versions = list(session.query(tables.Version).all()) versions.append('red-green') black = session.query(tables.Version).filter_by(identifier=u'black').one() - filenames = get_all_filenames() + filenames = get_all_filenames(root) # Some small stuff first @@ -252,26 +234,21 @@ def check_get_everything(): assert success # Remove exceptions - exceptions = [os.path.join(basedir, dirname) for dirname in + exceptions = [os.path.join(root, dirname) for dirname in 'chrome fonts ribbons'.split()] - exceptions.append(os.path.join(basedir, 'items', 'hm-')) + exceptions.append(os.path.join(root, 'items', 'hm-')) exceptions = tuple(exceptions) - for filename in tuple(filenames): + unaccessed_filenames = set(filenames) + for filename in filenames: if filename.startswith(exceptions): - filenames.remove(filename) + unaccessed_filenames.remove(filename) - if len(filenames): - print - print '-----------------' - print 'Unaccessed stuff:' - for filename in sorted(filenames): + if unaccessed_filenames: + print 'Unaccessed files:' + for filename in unaccessed_filenames: print filename - print len(filenames), 'unaccessed files :(' + + assert unaccessed_filenames == set() return (not filenames) - -if __name__ == '__main__': - result = nose.run(defaultTest=__file__) - result = result and check_get_everything() - exit(not result) diff --git a/pokedex/tests/test_roomaji.py b/pokedex/tests/test_roomaji.py index dc95afb..2721938 100644 --- a/pokedex/tests/test_roomaji.py +++ b/pokedex/tests/test_roomaji.py @@ -1,12 +1,9 @@ # encoding: utf8 -from nose.tools import * -import unittest import pokedex.roomaji +from pokedex.tests import positional_params - -def test_roomaji(): - tests = [ +@positional_params( (u'ヤミカラス', 'yamikarasu'), # Elongated vowel @@ -24,14 +21,13 @@ def test_roomaji(): (u'ラティアス', 'ratiasu'), (u'ウィー', 'wii'), (u'セレビィ', 'sereby'), - ] + ) +def test_roomaji(kana, roomaji): + result = pokedex.roomaji.romanize(kana) + assert result == roomaji - for kana, roomaji in tests: - result = pokedex.roomaji.romanize(kana) - assert_equal(result, roomaji, u"'%s' romanizes correctly" % roomaji) -def test_roomaji_cs(): - tests = [ +@positional_params( (u'ヤミカラス', u'jamikarasu'), # Elongated vowel @@ -49,8 +45,7 @@ def test_roomaji_cs(): (u'ラティアス', u'ratiasu'), (u'ウィー', u'wí'), (u'セレビィ', u'serebí'), - ] - - for kana, roomaji in tests: - result = pokedex.roomaji.romanize(kana, 'cs') - assert_equal(result, roomaji, u"'%s' romanizes correctly for Czech" % roomaji) + ) +def test_roomaji_cs(kana, roomaji): + result = pokedex.roomaji.romanize(kana, 'cs') + assert result == roomaji diff --git a/pokedex/tests/test_schema.py b/pokedex/tests/test_schema.py index c73182f..ce7b53a 100644 --- a/pokedex/tests/test_schema.py +++ b/pokedex/tests/test_schema.py @@ -1,6 +1,7 @@ # encoding: utf8 -from nose.tools import * -import unittest + +from pokedex.tests import single_params + from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.orm import class_mapper, joinedload, sessionmaker from sqlalchemy.orm.session import Session @@ -10,22 +11,23 @@ from pokedex.db import tables, markdown from pokedex.db.multilang import MultilangScopedSession, MultilangSession, \ create_translation_table -def test_variable_names(): +@single_params(*dir(tables)) +def test_variable_names(varname): """We want pokedex.db.tables to export tables using the class name""" - for varname in dir(tables): - if not varname[0].isupper(): - continue - table = getattr(tables, varname) - try: - if not issubclass(table, tables.TableBase) or table is tables.TableBase: - continue - except TypeError: - continue - classname = table.__name__ - if classname and varname[0].isupper(): - assert varname == classname, '%s refers to %s' % (varname, classname) - for table in tables.mapped_classes: - assert getattr(tables, table.__name__) is table + table = getattr(tables, varname) + try: + if not issubclass(table, tables.TableBase) or table is tables.TableBase: + return + except TypeError: + return + classname = table.__name__ + if classname and varname[0].isupper(): + assert varname == classname, '%s refers to %s' % (varname, classname) + +@single_params(*tables.mapped_classes) +def test_variable_names_2(table): + """We also want all of the tables exported""" + assert getattr(tables, table.__name__) is table def test_class_order(): """The declarative classes should be defined in alphabetical order. @@ -156,52 +158,52 @@ def test_i18n_table_creation(): assert foo.name_map[lang_en] == 'different english' assert foo.name_map[lang_ru] == 'new russian' -def test_texts(): +classes = [] +for cls in tables.mapped_classes: + classes.append(cls) + classes += cls.translation_classes +@single_params(*classes) +def test_texts(cls): """Check DB schema for integrity of text columns & translations. Mostly protects against copy/paste oversights and rebase hiccups. If there's a reason to relax the tests, do it """ - classes = [] - for cls in tables.mapped_classes: - classes.append(cls) - classes += cls.translation_classes - for cls in classes: - if hasattr(cls, 'local_language') or hasattr(cls, 'language'): - good_formats = 'markdown plaintext gametext'.split() - assert_text = '%s is language-specific' + if hasattr(cls, 'local_language') or hasattr(cls, 'language'): + good_formats = 'markdown plaintext gametext'.split() + assert_text = '%s is language-specific' + else: + good_formats = 'identifier latex'.split() + assert_text = '%s is not language-specific' + columns = sorted(cls.__table__.c, key=lambda c: c.name) + text_columns = [] + for column in columns: + format = column.info.get('format', None) + if format is not None: + if format not in good_formats: + raise AssertionError(assert_text % column) + if (format != 'identifier') and (column.name == 'identifier'): + raise AssertionError('%s: identifier column name/type mismatch' % column) + if column.info.get('official', None) and format not in 'gametext plaintext': + raise AssertionError('%s: official text with bad format' % column) + text_columns.append(column) else: - good_formats = 'identifier latex'.split() - assert_text = '%s is not language-specific' - columns = sorted(cls.__table__.c, key=lambda c: c.name) - text_columns = [] - for column in columns: - format = column.info.get('format', None) - if format is not None: - if format not in good_formats: - raise AssertionError(assert_text % column) - if (format != 'identifier') and (column.name == 'identifier'): - raise AssertionError('%s: identifier column name/type mismatch' % column) - if column.info.get('official', None) and format not in 'gametext plaintext': - raise AssertionError('%s: official text with bad format' % column) - text_columns.append(column) - else: - if isinstance(column.type, tables.Unicode): - raise AssertionError('%s: text column without format' % column) - if column.name == 'name' and format != 'plaintext': - raise AssertionError('%s: non-plaintext name' % column) - # No mention of English in the description - assert 'English' not in column.info['description'], column - # If there's more than one text column in a translation table, - # they have to be nullable, to support missing translations - if hasattr(cls, 'local_language') and len(text_columns) > 1: - for column in text_columns: - assert column.nullable + if isinstance(column.type, tables.Unicode): + raise AssertionError('%s: text column without format' % column) + if column.name == 'name' and format != 'plaintext': + raise AssertionError('%s: non-plaintext name' % column) + # No mention of English in the description + assert 'English' not in column.info['description'], column + # If there's more than one text column in a translation table, + # they have to be nullable, to support missing translations + if hasattr(cls, 'local_language') and len(text_columns) > 1: + for column in text_columns: + assert column.nullable -def test_identifiers_with_names(): +@single_params(*tables.mapped_classes) +def test_identifiers_with_names(table): """Test that named tables have identifiers """ - for table in sorted(tables.mapped_classes, key=lambda t: t.__name__): - for translation_class in table.translation_classes: - if hasattr(translation_class, 'name'): - assert hasattr(table, 'identifier'), table + for translation_class in table.translation_classes: + if hasattr(translation_class, 'name'): + assert hasattr(table, 'identifier'), table diff --git a/pokedex/tests/test_strings.py b/pokedex/tests/test_strings.py index 83dc94b..09fe6f9 100644 --- a/pokedex/tests/test_strings.py +++ b/pokedex/tests/test_strings.py @@ -1,150 +1,147 @@ # Encoding: UTF-8 -from nose.tools import * -from sqlalchemy.orm.exc import NoResultFound +import pytest + +from pokedex.tests import positional_params from pokedex.db import tables, connect, util, markdown -class TestStrings(object): - def setup(self): - self.connection = connect() +connection = connect() - def teardown(self): - self.connection.rollback() +def test_filter(): + q = connection.query(tables.PokemonSpecies).filter( + tables.PokemonSpecies.name == u"Marowak") + assert q.one().identifier == 'marowak' - def test_filter(self): - q = self.connection.query(tables.PokemonSpecies).filter( - tables.PokemonSpecies.name == u"Marowak") - assert q.one().identifier == 'marowak' +def test_languages(): + q = connection.query(tables.PokemonSpecies).filter( + tables.PokemonSpecies.name == u"Mightyena") + pkmn = q.one() + for lang, name in ( + ('en', u'Mightyena'), + ('ja', u'グラエナ'), + ('roomaji', u'Guraena'), + ('fr', u'Grahyèna'), + ): + language = connection.query(tables.Language).filter_by( + identifier=lang).one() + assert pkmn.name_map[language] == name - def test_languages(self): - q = self.connection.query(tables.PokemonSpecies).filter( - tables.PokemonSpecies.name == u"Mightyena") - pkmn = q.one() - for lang, name in ( - ('en', u'Mightyena'), - ('ja', u'グラエナ'), - ('roomaji', u'Guraena'), - ('fr', u'Grahyèna'), - ): - language = self.connection.query(tables.Language).filter_by( - identifier=lang).one() - assert pkmn.name_map[language] == name - - @raises(KeyError) - def test_bad_lang(self): - q = self.connection.query(tables.PokemonSpecies).filter( +def test_bad_lang(): + with pytest.raises(KeyError): + q = connection.query(tables.PokemonSpecies).filter( tables.PokemonSpecies.name == u"Mightyena") pkmn = q.one() pkmn.names["identifier of a language that doesn't exist"] - def test_mutating(self): - item = self.connection.query(tables.Item).filter_by( - identifier=u"jade-orb").one() - language = self.connection.query(tables.Language).filter_by( - identifier=u"de").one() - item.name_map[language] = u"foo" - assert item.name_map[language] == "foo" - item.name_map[language] = u"xyzzy" - assert item.name_map[language] == "xyzzy" +def test_mutating(): + item = connection.query(tables.Item).filter_by( + identifier=u"jade-orb").one() + language = connection.query(tables.Language).filter_by( + identifier=u"de").one() + item.name_map[language] = u"foo" + assert item.name_map[language] == "foo" + item.name_map[language] = u"xyzzy" + assert item.name_map[language] == "xyzzy" - def test_mutating_default(self): - item = self.connection.query(tables.Item).filter_by( - identifier=u"jade-orb").one() - item.name = u"foo" - assert item.name == "foo" +def test_mutating_default(): + item = connection.query(tables.Item).filter_by( + identifier=u"jade-orb").one() + item.name = u"foo" + assert item.name == "foo" - def test_string_mapping(self): - item = self.connection.query(tables.Item).filter_by( - identifier=u"jade-orb").one() - assert len(item.name_map) == len(item.names) - for lang in item.names: - assert item.name_map[lang] == item.names[lang].name - assert lang in item.name_map - assert "language that doesn't exist" not in item.name_map - assert tables.Language() not in item.name_map +def test_string_mapping(): + item = connection.query(tables.Item).filter_by( + identifier=u"jade-orb").one() + assert len(item.name_map) == len(item.names) + for lang in item.names: + assert item.name_map[lang] == item.names[lang].name + assert lang in item.name_map + assert "language that doesn't exist" not in item.name_map + assert tables.Language() not in item.name_map - def test_new_language(self): - item = self.connection.query(tables.Item).filter_by( - identifier=u"jade-orb").one() - language = tables.Language() - language.id = -1 - language.identifier = u'test' - language.iso639 = language.iso3166 = u'--' - language.official = False - self.connection.add(language) - item.name_map[language] = u"foo" - assert item.name_map[language] == "foo" - assert language in item.name_map - item.name_map[language] = u"xyzzy" - assert item.name_map[language] == "xyzzy" +def test_new_language(): + item = connection.query(tables.Item).filter_by( + identifier=u"jade-orb").one() + language = tables.Language() + language.id = -1 + language.identifier = u'test' + language.iso639 = language.iso3166 = u'--' + language.official = False + connection.add(language) + item.name_map[language] = u"foo" + assert item.name_map[language] == "foo" + assert language in item.name_map + item.name_map[language] = u"xyzzy" + assert item.name_map[language] == "xyzzy" - def test_markdown(self): - move = self.connection.query(tables.Move).filter_by( - identifier=u"thunderbolt").one() - language = self.connection.query(tables.Language).filter_by( - identifier=u"en").one() - assert '10%' in move.effect.as_text() - assert '10%' in move.effect_map[language].as_text() - assert '10%' in move.effect.as_html() - assert '10%' in move.effect_map[language].as_html() - assert '10%' in unicode(move.effect) - assert '10%' in unicode(move.effect_map[language]) - assert '10%' in move.effect.__html__() - assert '10%' in move.effect_map[language].__html__() +def test_markdown(): + move = connection.query(tables.Move).filter_by( + identifier=u"thunderbolt").one() + language = connection.query(tables.Language).filter_by( + identifier=u"en").one() + assert '10%' in move.effect.as_text() + assert '10%' in move.effect_map[language].as_text() + assert '10%' in move.effect.as_html() + assert '10%' in move.effect_map[language].as_html() + assert '10%' in unicode(move.effect) + assert '10%' in unicode(move.effect_map[language]) + assert '10%' in move.effect.__html__() + assert '10%' in move.effect_map[language].__html__() - def test_markdown_string(self): - en = util.get(self.connection, tables.Language, 'en') - md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis}', self.connection, en) - assert unicode(md) == 'Thunderbolt paralyzes' - assert md.as_html() == '
Thunderbolt paralyzes
' - assert md.as_html(object_url=lambda category, obj: "%s/%s" % (category, obj.identifier)) == ( - 'Thunderbolt paralyzes
') - print md.as_html(identifier_url=lambda category, ident: "%s/%s" % (category, ident)) - assert md.as_html(identifier_url=lambda category, ident: "%s/%s" % (category, ident)) == ( - '') +def test_markdown_string(): + en = util.get(connection, tables.Language, 'en') + md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis}', connection, en) + assert unicode(md) == 'Thunderbolt paralyzes' + assert md.as_html() == 'Thunderbolt paralyzes
' + assert md.as_html(object_url=lambda category, obj: "%s/%s" % (category, obj.identifier)) == ( + 'Thunderbolt paralyzes
') + print md.as_html(identifier_url=lambda category, ident: "%s/%s" % (category, ident)) + assert md.as_html(identifier_url=lambda category, ident: "%s/%s" % (category, ident)) == ( + '') - def test_markdown_values(self): - """Check all markdown values +def markdown_column_params(): + """Check all markdown values - Scans the database schema for Markdown columns, runs through every value - in each, and ensures that it's valid Markdown. - """ + Scans the database schema for Markdown columns, runs through every value + in each, and ensures that it's valid Markdown. + """ - # Move effects have their own special wrappers. Explicitly test them separately - yield self.check_markdown_column, tables.Move, None, 'effect' - yield self.check_markdown_column, tables.Move, None, 'short_effect' + # Move effects have their own special wrappers. Explicitly test them separately + yield tables.Move, None, 'effect' + yield tables.Move, None, 'short_effect' - for cls in tables.mapped_classes: - for translation_cls in cls.translation_classes: - for column in translation_cls.__table__.c: - if column.info.get('string_getter') == markdown.MarkdownString: - yield self.check_markdown_column, cls, translation_cls, column.name + for cls in tables.mapped_classes: + for translation_cls in cls.translation_classes: + for column in translation_cls.__table__.c: + if column.info.get('string_getter') == markdown.MarkdownString: + yield cls, translation_cls, column.name - def check_markdown_column(self, parent_class, translation_class, column_name): - """Implementation for the above""" - query = self.connection.query(parent_class) - if translation_class: - query = query.join(translation_class) - for item in query: - for language, markdown in getattr(item, column_name + '_map').items(): +@positional_params(*markdown_column_params()) +def test_markdown_values(parent_class, translation_class, column_name): + """Implementation for the above""" + query = connection.query(parent_class) + if translation_class: + query = query.join(translation_class) + for item in query: + for language, markdown in getattr(item, column_name + '_map').items(): - if markdown is None: - continue + if markdown is None: + continue - key = u"Markdown in {0} #{1}'s {2} (lang={3})".format( - parent_class.__name__, item.id, column_name, language.identifier) + key = u"Markdown in {0} #{1}'s {2} (lang={3})".format( + parent_class.__name__, item.id, column_name, language.identifier) - try: - text = markdown.as_text() - except NoResultFound: - assert False, u"{0} references something that doesn't exist:\n{1}".format( - key, markdown.source_text) - except AttributeError: - print markdown - raise + try: + text = markdown.as_text() + except NoResultFound: + assert False, u"{0} references something that doesn't exist:\n{1}".format( + key, markdown.source_text) + except AttributeError: + print markdown + raise - error_message = u"{0} leaves syntax cruft:\n{1}" - error_message = error_message.format(key, text) + error_message = u"{0} leaves syntax cruft:\n{1}" + error_message = error_message.format(key, text) - ok_(not any(char in text for char in '[]{}'), error_message) + assert not any(char in text for char in '[]{}'), error_message diff --git a/pokedex/tests/test_translations.py b/pokedex/tests/test_translations.py index af96331..1335573 100644 --- a/pokedex/tests/test_translations.py +++ b/pokedex/tests/test_translations.py @@ -2,7 +2,7 @@ import csv -from nose.tools import * +import pytest from pokedex.db import translations, tables diff --git a/pokedex/tests/test_util.py b/pokedex/tests/test_util.py index 18287d4..7c6a034 100644 --- a/pokedex/tests/test_util.py +++ b/pokedex/tests/test_util.py @@ -1,7 +1,8 @@ -# encoding: utf8 -from nose.tools import * -import unittest +# Encoding: utf8 +import pytest + +from pokedex.tests import single_params from pokedex.db import connect, tables, util session = connect() @@ -18,21 +19,21 @@ def test_get_english_by_identifier(): language = util.get(session, tables.Language, 'en') assert language.name == 'English' -def test_get_pokemon_identifier(): - for identifier in 'burmy shaymin unown cresselia'.split(): - poke = util.get(session, tables.PokemonSpecies, identifier=identifier) - assert poke.identifier == identifier +@single_params(*'burmy shaymin unown cresselia'.split()) +def test_get_pokemon_identifier(identifier): + poke = util.get(session, tables.PokemonSpecies, identifier=identifier) + assert poke.identifier == identifier -def test_get_pokemon_name(): - for name in 'Burmy Shaymin Unown Cresselia'.split(): - poke = util.get(session, tables.PokemonSpecies, name=name) - assert poke.name == name +@single_params(*'Burmy Shaymin Unown Cresselia'.split()) +def test_get_pokemon_name(name): + poke = util.get(session, tables.PokemonSpecies, name=name) + assert poke.name == name -def test_get_pokemon_name_explicit_language(): +@single_params(*'Cheniti Shaymin Zarbi Cresselia'.split()) +def test_get_pokemon_name_explicit_language(name): french = util.get(session, tables.Language, 'fr') - for name in 'Cheniti Shaymin Zarbi Cresselia'.split(): - poke = util.get(session, tables.PokemonSpecies, name=name, language=french) - assert poke.name_map[french] == name, poke.name_map[french] + poke = util.get(session, tables.PokemonSpecies, name=name, language=french) + assert poke.name_map[french] == name, poke.name_map[french] def test_types_french_order(): french = util.get(session, tables.Language, 'fr') @@ -40,3 +41,9 @@ def test_types_french_order(): types = list(util.order_by_name(types, tables.Type, language=french)) assert types[0].name_map[french] == 'Acier', types[0].name_map[french] assert types[-1].name_map[french] == 'Vol', types[-1].name_map[french] + +@single_params(*range(1, 10) * 2) +def test_get_pokemon_id(id): + result = util.get(session, tables.Pokemon, id=id) + assert result.id == id + assert result.__tablename__ == 'pokemon'