diff --git a/conftest.py b/conftest.py index 1d64705..a1d0c76 100644 --- a/conftest.py +++ b/conftest.py @@ -1,4 +1,3 @@ - # Configuration for the tests. # Use `py.test` to run the tests. @@ -8,14 +7,37 @@ import pytest import os def pytest_addoption(parser): - parser.addoption("--media-root", action="store", - default=None, + group = parser.getgroup("pokedex") + group.addoption("--engine", action="store", default=None, + help="Pokedex database URI") + group.addoption("--index", action="store", default=None, + help="Path to index directory") + group.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, + group.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))) +def pytest_runtest_setup(item): + if 'slow' in item.keywords and not item.config.getvalue('all'): + pytest.skip("skipping slow tests") + +@pytest.fixture(scope="module") +def session(request): + import pokedex.db + engine_uri = request.config.getvalue("engine") + return pokedex.db.connect(engine_uri) + +@pytest.fixture(scope="module") +def lookup(request, session): + import pokedex.lookup + index_dir = request.config.getvalue("index") + return pokedex.lookup.PokedexLookup(index_dir, session) + +@pytest.fixture(scope="session") +def media_root(request): + media_root = request.config.getvalue("media_root") + if not media_root: + media_root = os.path.join(os.path.dirname(__file__), '..', 'data', 'media') + if not os.path.isdir(media_root): + raise pytest.skip("Media unavailable") + return media_root diff --git a/pokedex/tests/__init__.py b/pokedex/tests/__init__.py index 3bc8d3c..e69de29 100644 --- a/pokedex/tests/__init__.py +++ b/pokedex/tests/__init__.py @@ -1,45 +0,0 @@ - -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 6ce6ddf..8614bc2 100644 --- a/pokedex/tests/test_database_sanity.py +++ b/pokedex/tests/test_database_sanity.py @@ -1,5 +1,5 @@ - import pytest +parametrize = pytest.mark.parametrize from sqlalchemy.orm import aliased, joinedload, lazyload from sqlalchemy.orm.exc import NoResultFound @@ -7,11 +7,11 @@ from sqlalchemy.sql import func from pokedex.db import connect, tables, util -def test_encounter_slots(): - # Encounters have a version, which has a version group; encounters also - # have an encounter_slot, which has a version group. The two version - # groups should match, universally. - session = connect() +def test_encounter_slots(session): + """Encounters have a version, which has a version group; encounters also + have an encounter_slot, which has a version group. The two version + groups should match, universally. + """ version_group_a = aliased(tables.VersionGroup) version_group_b = aliased(tables.VersionGroup) @@ -26,27 +26,26 @@ def test_encounter_slots(): # Encounter slots all match the encounters they belong to assert sanity_q.count() == 0 -def test_nonzero_autoincrement_ids(): +@parametrize('cls', tables.mapped_classes) +def test_nonzero_autoincrement_ids(session, cls): """Check that autoincrementing ids don't contain zeroes MySQL doesn't like these, see e.g. bug #580 """ + if 'id' not in cls.__table__.c: + return + if not cls.__table__.c.id.autoincrement: + return - session = connect() - for cls in tables.mapped_classes: - if 'id' in cls.__table__.c: - if cls.__table__.c.id.autoincrement: - def nonzero_id(cls): - with pytest.raises(NoResultFound): - util.get(session, cls, id=0) - nonzero_id.description = "No zero id in %s" % cls.__name__ - yield nonzero_id, cls + try: + util.get(session, cls, id=0) + except NoResultFound: + pass + else: + pytest.fail("No zero id in %s" % cls.__name__) -def test_unique_form_order(): - """Check that tone PokemonForm.order value isn't used for more species - """ - - session = connect() +def test_unique_form_order(session): + """Check that tone PokemonForm.order value isn't used for more species""" species_by_form_order = {} @@ -66,12 +65,10 @@ def test_unique_form_order(): species_by_form_order[form.order].name, form.species.name)) -def test_default_forms(): +def test_default_forms(session): """Check that each pokemon has one default form and each species has one default pokemon.""" - session = connect() - q = session.query(tables.Pokemon) q = q.join(tables.PokemonForm) q = q.filter(tables.PokemonForm.is_default==True) @@ -81,9 +78,9 @@ def test_default_forms(): for pokemon, num_default_forms in q: if num_default_forms == 0: - raise AssertionError("pokemon %s has no default forms" % pokemon.name) + pytest.fail("pokemon %s has no default forms" % pokemon.name) elif num_default_forms > 1: - raise AssertionError("pokemon %s has %d default forms" % (pokemon.name, num_default_forms)) + pytest.fail("pokemon %s has %d default forms" % (pokemon.name, num_default_forms)) q = session.query(tables.PokemonSpecies) q = q.join(tables.Pokemon) @@ -94,6 +91,6 @@ def test_default_forms(): for species, num_default_pokemon in q: if num_default_pokemon == 0: - raise AssertionError("species %s has no default pokemon" % species.name) + pytest.fail("species %s has no default pokemon" % species.name) elif num_default_pokemon > 1: - raise AssertionError("species %s has %d default pokemon" % (species.name, num_default_pokemon)) + pytest.fail("species %s has %d default pokemon" % (species.name, num_default_pokemon)) diff --git a/pokedex/tests/test_lookup.py b/pokedex/tests/test_lookup.py index 9683aaf..392dfaa 100644 --- a/pokedex/tests/test_lookup.py +++ b/pokedex/tests/test_lookup.py @@ -1,12 +1,11 @@ # Encoding: UTF-8 -from pokedex.tests import * +import pytest +parametrize = pytest.mark.parametrize -from pokedex.lookup import PokedexLookup - -lookup = PokedexLookup() - -@positional_params( +@parametrize( + ('input', 'table', 'id'), + [ # Simple lookups (u'Eevee', 'pokemon_species',133), (u'Scratch', 'moves', 10), @@ -31,8 +30,9 @@ lookup = PokedexLookup() (u'이브이', 'pokemon_species', 133), (u'伊布', 'pokemon_species', 133), (u'Evoli', 'pokemon_species', 133), - ) -def test_exact_lookup(input, table, id): + ] +) +def test_exact_lookup(lookup, input, table, id): results = lookup.lookup(input) assert len(results) == 1 assert results[0].exact == True @@ -42,19 +42,19 @@ def test_exact_lookup(input, table, id): assert row.id == id -def test_id_lookup(): +def test_id_lookup(lookup): results = lookup.lookup(u'1') assert len(results) >= 5 assert all(result.object.id == 1 for result in results) -def test_multi_lookup(): +def test_multi_lookup(lookup): results = lookup.lookup(u'Metronome') assert len(results) == 2 assert results[0].exact -def test_type_lookup(): +def test_type_lookup(lookup): results = lookup.lookup(u'pokemon:1') assert results[0].object.__tablename__ == 'pokemon_species' assert len(results) == 1 @@ -64,7 +64,7 @@ def test_type_lookup(): assert results[0].object.name == u'Bulbasaur' -def test_language_lookup(): +def test_language_lookup(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') @@ -85,7 +85,9 @@ def test_language_lookup(): assert results[0].object.name, u'Tackle' -@positional_params( +@parametrize( + ('misspelling', 'name'), + [ # Regular English names (u'chamander', u'Charmander'), (u'pokeball', u'Poké Ball'), @@ -97,51 +99,58 @@ def test_language_lookup(): # Sufficiently long foreign names (u'カクレオ', u'Kecleon'), (u'Yamikrasu', u'Murkrow'), - ) -def test_fuzzy_lookup(misspelling, name): + ] +) +def test_fuzzy_lookup(lookup, misspelling, name): results = lookup.lookup(misspelling) first_result = results[0] assert first_result.object.name == name -def test_nidoran(): +def test_nidoran(lookup): results = lookup.lookup(u'Nidoran') top_names = [result.object.name for result in results[0:2]] assert u'Nidoran♂' in top_names assert u'Nidoran♀' in top_names -@positional_params( +@parametrize( + ('wildcard', 'name'), + [ (u'pokemon:*meleon', u'Charmeleon'), (u'item:master*', u'Master Ball'), (u'ee?ee', u'Eevee'), - ) -def test_wildcard_lookup(wildcard, name): + ] +) +def test_wildcard_lookup(lookup, wildcard, name): results = lookup.lookup(wildcard) first_result = results[0] assert first_result.object.name == name -def test_bare_random(): +def test_bare_random(lookup): for i in range(5): results = lookup.lookup(u'random') assert len(results) == 1 -@positional_params( - [u'pokemon_species'], - [u'moves'], - [u'items'], - [u'abilities'], - [u'types'], - ) -def test_qualified_random(table_name): +@parametrize( + 'table_name', + [ + u'pokemon_species', + u'moves', + u'items', + u'abilities', + u'types' + ] +) +def test_qualified_random(lookup, table_name): results = lookup.lookup(u'random', valid_types=[table_name]) assert len(results) == 1 assert results[0].object.__tablename__ == table_name -def test_crash_empty_prefix(): +def test_crash_empty_prefix(lookup): """Searching for ':foo' used to crash, augh!""" results = lookup.lookup(u':Eevee') assert results[0].object.name == u'Eevee' diff --git a/pokedex/tests/test_media.py b/pokedex/tests/test_media.py index 48f213e..3015585 100644 --- a/pokedex/tests/test_media.py +++ b/pokedex/tests/test_media.py @@ -10,76 +10,62 @@ import pytest import os import re -from pokedex.db import tables, connect +from pokedex.db import tables from pokedex.util import media -def pytest_addoption(parser): - group = parser.getgroup("pokedex") - group.addoption("--media-root", dest="media_root", action="store", default=None, - help="path to pokedex-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() - path_re = re.compile('^[-a-z0-9./]*$') -def test_totodile(root): +def test_totodile(session, media_root): """Totodile's female sprite -- same as male""" totodile = session.query(tables.PokemonSpecies).filter_by(identifier=u'totodile').one() - accessor = media.PokemonSpeciesMedia(root, totodile) + accessor = media.PokemonSpeciesMedia(media_root, totodile) assert accessor.sprite() == accessor.sprite(female=True) -def test_chimecho(root): +def test_chimecho(session, media_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) + accessor = media.PokemonSpeciesMedia(media_root, chimecho) male = accessor.sprite('platinum', back=True, frame=2) female = accessor.sprite('platinum', back=True, female=True, frame=2) assert male != female -def test_venonat(root): +def test_venonat(session, media_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) + accessor = media.PokemonSpeciesMedia(media_root, venonat) assert accessor.sprite('yellow') == accessor.sprite('yellow', shiny=True) -def test_arceus_icon(root): - """Arceus fire-form icon -- same as base icon""" +@pytest.mark.xfail +def test_arceus_icon(session, media_root): + """Arceus normal-form icon -- same as base icon""" arceus = session.query(tables.PokemonSpecies).filter_by(identifier=u'arceus').one() - accessor = media.PokemonSpeciesMedia(root, arceus) - fire_arceus = [f for f in arceus.forms if f.form_identifier == 'fire'][0] - fire_accessor = media.PokemonFormMedia(root, fire_arceus) - assert accessor.icon() == fire_accessor.icon() + accessor = media.PokemonSpeciesMedia(media_root, arceus) + normal_arceus = [f for f in arceus.forms if f.form_identifier == 'normal'][0] + normal_accessor = media.PokemonFormMedia(media_root, normal_arceus) + assert accessor.icon() == normal_accessor.icon() -def test_strict_castform(root): +def test_strict_castform(session, media_root): """Castform rainy form overworld with strict -- unavailable""" 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 = media.PokemonFormMedia(media_root, rainy_castform) rainy_castform.overworld('up', strict=True) -def test_strict_exeggcute(root): +def test_strict_exeggcute(session, media_root): """Exeggcutes's female backsprite, with strict -- unavailable""" with pytest.raises(ValueError): exeggcute = session.query(tables.PokemonSpecies).filter_by(identifier=u'exeggcute').one() - accessor = media.PokemonSpeciesMedia(root, exeggcute) + accessor = media.PokemonSpeciesMedia(media_root, exeggcute) accessor.sprite(female=True, strict=True) -def get_all_filenames(root): +def get_all_filenames(media_root): all_filenames = set() - for dirpath, dirnames, filenames in os.walk(root): + for dirpath, dirnames, filenames in os.walk(media_root): dirnames[:] = [dirname for dirname in dirnames if dirname != '.git'] for filename in filenames: path = os.path.join(dirpath, filename) @@ -109,8 +95,9 @@ def hit(filenames, method, *args, **kwargs): pass return True -@pytest.mark.skipif("not config.getvalue('all')", reason='`--all` not specified') -def test_get_everything(root, pytestconfig): +@pytest.mark.slow +@pytest.mark.xfail +def test_get_everything(session, media_root): """ For every the accessor method, loop over the Cartesian products of all possible values for its arguments. @@ -119,7 +106,6 @@ def test_get_everything(root, pytestconfig): Well, there are exceptions of course. """ - assert pytestconfig.getvalue('all') versions = list(session.query(tables.Version).all()) versions.append('red-green') @@ -130,37 +116,37 @@ def test_get_everything(root, pytestconfig): black = session.query(tables.Version).filter_by(identifier=u'black').one() - filenames = get_all_filenames(root) + filenames = get_all_filenames(media_root) # Some small stuff first for damage_class in session.query(tables.MoveDamageClass).all(): - assert hit(filenames, media.DamageClassMedia(root, damage_class).icon) + assert hit(filenames, media.DamageClassMedia(media_root, damage_class).icon) for habitat in session.query(tables.PokemonHabitat).all(): - assert hit(filenames, media.HabitatMedia(root, habitat).icon) + assert hit(filenames, media.HabitatMedia(media_root, habitat).icon) for shape in session.query(tables.PokemonShape).all(): - assert hit(filenames, media.ShapeMedia(root, shape).icon) + assert hit(filenames, media.ShapeMedia(media_root, shape).icon) for item_pocket in session.query(tables.ItemPocket).all(): - assert hit(filenames, media.ItemPocketMedia(root, item_pocket).icon) - assert hit(filenames, media.ItemPocketMedia(root, item_pocket).icon, selected=True) + assert hit(filenames, media.ItemPocketMedia(media_root, item_pocket).icon) + assert hit(filenames, media.ItemPocketMedia(media_root, item_pocket).icon, selected=True) for contest_type in session.query(tables.ContestType).all(): - assert hit(filenames, media.ContestTypeMedia(root, contest_type).icon) + assert hit(filenames, media.ContestTypeMedia(media_root, contest_type).icon) for elemental_type in session.query(tables.Type).all(): - assert hit(filenames, media.TypeMedia(root, elemental_type).icon) + assert hit(filenames, media.TypeMedia(media_root, elemental_type).icon) # Items versions_for_items = [ - None, - session.query(tables.Version).filter_by(identifier='emerald').one(), - ] + None, + session.query(tables.Version).filter_by(identifier='emerald').one(), + ] for item in session.query(tables.Item).all(): - accessor = media.ItemMedia(root, item) + accessor = media.ItemMedia(media_root, item) assert hit(filenames, accessor.berry_image) or not item.berry for rotation in (0, 90, 180, 270): assert hit(filenames, accessor.underground, rotation=rotation) or ( @@ -172,11 +158,11 @@ def test_get_everything(root, pytestconfig): for color in 'red green blue pale prism'.split(): for big in (True, False): - accessor = media.UndergroundSphereMedia(root, color=color, big=big) + accessor = media.UndergroundSphereMedia(media_root, color=color, big=big) assert hit(filenames, accessor.underground) for rock_type in 'i ii o o-big s t z'.split(): - accessor = media.UndergroundRockMedia(root, rock_type) + accessor = media.UndergroundRockMedia(media_root, rock_type) for rotation in (0, 90, 180, 270): success = hit(filenames, accessor.underground, rotation=rotation) assert success or rotation @@ -184,17 +170,17 @@ def test_get_everything(root, pytestconfig): # Pokemon! accessors = [] - accessors.append(media.UnknownPokemonMedia(root)) - accessors.append(media.EggMedia(root)) + accessors.append(media.UnknownPokemonMedia(media_root)) + accessors.append(media.EggMedia(media_root)) manaphy = session.query(tables.PokemonSpecies).filter_by(identifier=u'manaphy').one() - accessors.append(media.EggMedia(root, manaphy)) - accessors.append(media.SubstituteMedia(root)) + accessors.append(media.EggMedia(media_root, manaphy)) + accessors.append(media.SubstituteMedia(media_root)) for form in session.query(tables.PokemonForm).all(): - accessors.append(media.PokemonFormMedia(root, form)) + accessors.append(media.PokemonFormMedia(media_root, form)) for pokemon in session.query(tables.PokemonSpecies).all(): - accessors.append(media.PokemonSpeciesMedia(root, pokemon)) + accessors.append(media.PokemonSpeciesMedia(media_root, pokemon)) for accessor in accessors: assert hit(filenames, accessor.footprint) or not accessor.is_proper @@ -243,9 +229,9 @@ def test_get_everything(root, pytestconfig): assert success # Remove exceptions - exceptions = [os.path.join(root, dirname) for dirname in + exceptions = [os.path.join(media_root, dirname) for dirname in 'chrome fonts ribbons'.split()] - exceptions.append(os.path.join(root, 'items', 'hm-')) + exceptions.append(os.path.join(media_root, 'items', 'hm-')) exceptions = tuple(exceptions) unaccessed_filenames = set(filenames) diff --git a/pokedex/tests/test_roomaji.py b/pokedex/tests/test_roomaji.py index 2721938..2ac08c1 100644 --- a/pokedex/tests/test_roomaji.py +++ b/pokedex/tests/test_roomaji.py @@ -1,9 +1,13 @@ # encoding: utf8 -import pokedex.roomaji -from pokedex.tests import positional_params +import pytest +parametrize = pytest.mark.parametrize -@positional_params( +import pokedex.roomaji + +@parametrize( + ('kana', 'roomaji'), + [ (u'ヤミカラス', 'yamikarasu'), # Elongated vowel @@ -21,13 +25,16 @@ from pokedex.tests import positional_params (u'ラティアス', 'ratiasu'), (u'ウィー', 'wii'), (u'セレビィ', 'sereby'), - ) + ] +) def test_roomaji(kana, roomaji): result = pokedex.roomaji.romanize(kana) assert result == roomaji -@positional_params( +@parametrize( + ('kana', 'roomaji'), + [ (u'ヤミカラス', u'jamikarasu'), # Elongated vowel @@ -45,7 +52,8 @@ def test_roomaji(kana, roomaji): (u'ラティアス', u'ratiasu'), (u'ウィー', u'wí'), (u'セレビィ', u'serebí'), - ) + ] +) 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 69fc41c..ebfd3e0 100644 --- a/pokedex/tests/test_schema.py +++ b/pokedex/tests/test_schema.py @@ -1,6 +1,6 @@ # encoding: utf8 -from pokedex.tests import single_params +import pytest from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.orm import class_mapper, joinedload, sessionmaker @@ -11,7 +11,9 @@ from pokedex.db import tables, markdown from pokedex.db.multilang import MultilangScopedSession, MultilangSession, \ create_translation_table -@single_params(*dir(tables)) +parametrize = pytest.mark.parametrize + +@parametrize('varname', [attr for attr in dir(tables) if not attr.startswith('_')]) def test_variable_names(varname): """We want pokedex.db.tables to export tables using the class name""" table = getattr(tables, varname) @@ -24,7 +26,7 @@ def test_variable_names(varname): if classname and varname[0].isupper(): assert varname == classname, '%s refers to %s' % (varname, classname) -@single_params(*tables.mapped_classes) +@parametrize('table', tables.mapped_classes) def test_variable_names_2(table): """We also want all of the tables exported""" assert getattr(tables, table.__name__) is table @@ -162,7 +164,7 @@ classes = [] for cls in tables.mapped_classes: classes.append(cls) classes += cls.translation_classes -@single_params(*classes) +@parametrize('cls', classes) def test_texts(cls): """Check DB schema for integrity of text columns & translations. @@ -181,26 +183,27 @@ def test_texts(cls): format = column.info.get('format', None) if format is not None: if format not in good_formats: - raise AssertionError(assert_text % column) + pytest.fail(assert_text % column) if (format != 'identifier') and (column.name == 'identifier'): - raise AssertionError('%s: identifier column name/type mismatch' % column) + pytest.fail('%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) + pytest.fail('%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) + pytest.fail('%s: text column without format' % column) if column.name == 'name' and format != 'plaintext': - raise AssertionError('%s: non-plaintext name' % column) + pytest.fail('%s: non-plaintext name' % column) # No mention of English in the description - assert u'English' not in column.__doc__, column + if column.doc and u'English' in column.doc: + pytest.fail("%s: description mentions English" % 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 -@single_params(*tables.mapped_classes) +@parametrize('table', tables.mapped_classes) def test_identifiers_with_names(table): """Test that named tables have identifiers """ diff --git a/pokedex/tests/test_strings.py b/pokedex/tests/test_strings.py index ef9bd41..4d14818 100644 --- a/pokedex/tests/test_strings.py +++ b/pokedex/tests/test_strings.py @@ -1,21 +1,24 @@ # Encoding: UTF-8 import pytest -from sqlalchemy.orm.exc import NoResultFound +parametrize = pytest.mark.parametrize -from pokedex.tests import positional_params +from sqlalchemy.orm.exc import NoResultFound from pokedex.db import tables, connect, util, markdown -connection = connect() +@pytest.fixture(scope="module") +def session(request): + uri = request.config.getvalue("engine") + return connect(uri) -def test_filter(): - q = connection.query(tables.PokemonSpecies).filter( +def test_filter(session): + q = session.query(tables.PokemonSpecies).filter( tables.PokemonSpecies.name == u"Marowak") assert q.one().identifier == 'marowak' -def test_languages(): - q = connection.query(tables.PokemonSpecies).filter( +def test_languages(session): + q = session.query(tables.PokemonSpecies).filter( tables.PokemonSpecies.name == u"Mightyena") pkmn = q.one() for lang, name in ( @@ -24,35 +27,35 @@ def test_languages(): ('roomaji', u'Guraena'), ('fr', u'Grahyèna'), ): - language = connection.query(tables.Language).filter_by( + language = session.query(tables.Language).filter_by( identifier=lang).one() assert pkmn.name_map[language] == name -def test_bad_lang(): +def test_bad_lang(session): with pytest.raises(KeyError): - q = connection.query(tables.PokemonSpecies).filter( + q = session.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(): - item = connection.query(tables.Item).filter_by( +def test_mutating(session): + item = session.query(tables.Item).filter_by( identifier=u"jade-orb").one() - language = connection.query(tables.Language).filter_by( + language = session.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(): - item = connection.query(tables.Item).filter_by( +def test_mutating_default(session): + item = session.query(tables.Item).filter_by( identifier=u"jade-orb").one() item.name = u"foo" assert item.name == "foo" -def test_string_mapping(): - item = connection.query(tables.Item).filter_by( +def test_string_mapping(session): + item = session.query(tables.Item).filter_by( identifier=u"jade-orb").one() assert len(item.name_map) == len(item.names) for lang in item.names: @@ -61,25 +64,25 @@ def test_string_mapping(): assert "language that doesn't exist" not in item.name_map assert tables.Language() not in item.name_map -def test_new_language(): - item = connection.query(tables.Item).filter_by( +def test_new_language(session): + item = session.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) + session.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(): - move = connection.query(tables.Move).filter_by( +def test_markdown(session): + move = session.query(tables.Move).filter_by( identifier=u"thunderbolt").one() - language = connection.query(tables.Language).filter_by( + language = session.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() @@ -90,9 +93,9 @@ def test_markdown(): assert '10%' in move.effect.__html__() assert '10%' in move.effect_map[language].__html__() -def test_markdown_string(): - en = util.get(connection, tables.Language, 'en') - md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis} []{form:sky shaymin}. []{pokemon:mewthree} does not exist.', connection, en) +def test_markdown_string(session): + en = util.get(session, tables.Language, 'en') + md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis} []{form:sky shaymin}. []{pokemon:mewthree} does not exist.', session, en) assert unicode(md) == 'Thunderbolt paralyzes Sky Shaymin. mewthree does not exist.' assert md.as_html() == '

Thunderbolt paralyzes Sky Shaymin. mewthree does not exist.

' @@ -108,9 +111,9 @@ def test_markdown_string(): def identifier_url(self, category, ident): return "%s/%s" % (category, ident) - assert md.as_html(extension=ObjectTestExtension(connection)) == ( + assert md.as_html(extension=ObjectTestExtension(session)) == ( '

Thunderbolt paralyzes Sky Shaymin. mewthree does not exist.

') - assert md.as_html(extension=IdentifierTestExtension(connection)) == ( + assert md.as_html(extension=IdentifierTestExtension(session)) == ( '

Thunderbolt paralyzes Sky Shaymin. mewthree does not exist.

') def markdown_column_params(): @@ -130,10 +133,14 @@ def markdown_column_params(): if column.info.get('string_getter') == markdown.MarkdownString: yield cls, translation_cls, column.name -@positional_params(*markdown_column_params()) -def test_markdown_values(parent_class, translation_class, column_name): +@pytest.mark.slow +@parametrize( + ('parent_class', 'translation_class', 'column_name'), + list(markdown_column_params()) +) +def test_markdown_values(session, parent_class, translation_class, column_name): """Implementation for the above""" - query = connection.query(parent_class) + query = session.query(parent_class) if translation_class: query = query.join(translation_class) @@ -150,7 +157,7 @@ def test_markdown_values(parent_class, translation_class, column_name): '%s: unknown link target: {%s:%s}' % (key, category, ident)) - test_extension = TestExtension(connection) + test_extension = TestExtension(session) for item in query: for language, md_text in getattr(item, column_name + '_map').items(): diff --git a/pokedex/tests/test_translations.py b/pokedex/tests/test_translations.py index 1335573..78c9ec2 100644 --- a/pokedex/tests/test_translations.py +++ b/pokedex/tests/test_translations.py @@ -2,39 +2,40 @@ import csv -import pytest - from pokedex.db import translations, tables fake_version_names = ( - 'version_id,local_language_id,name', - '1,0,name1', '2,0,name2', '3,0,name3', '3,1,othername3', - ) + 'version_id,local_language_id,name', + '1,0,name1', + '2,0,name2', + '3,0,name3', + '3,1,othername3', +) fake_translation_csv = ( - 'language_id,table,id,column,source_crc,string', - '0,Version,1,name,,name1', - '0,Version,2,name,,name2', - '0,Version,3,name,,name3', - '1,Version,3,name,,othername3', - ) + 'language_id,table,id,column,source_crc,string', + '0,Version,1,name,,name1', + '0,Version,2,name,,name2', + '0,Version,3,name,,name3', + '1,Version,3,name,,othername3', +) def test_yield_source_csv_messages(): check_version_message_stream(translations.yield_source_csv_messages( - tables.Version.names_table, - tables.Version, - csv.reader(iter(fake_version_names)), - )) + tables.Version.names_table, + tables.Version, + csv.reader(iter(fake_version_names)), + )) def test_yield_guessed_csv_messages(): check_version_message_stream(translations.yield_guessed_csv_messages( - iter(fake_translation_csv), - )) + iter(fake_translation_csv), + )) def test_yield_translation_csv_messages(): check_version_message_stream(translations.yield_translation_csv_messages( - iter(fake_translation_csv), - )) + iter(fake_translation_csv), + )) def check_version_message_stream(messages): messages = list(messages) @@ -53,59 +54,59 @@ def get_messages(*rows): def test_merge_translations(): source = get_messages( - '0,Table,1,col,,none', - '0,Table,2,col,,new', - '0,Table,3,col,,existing', - '0,Table,4,col,,both', - '0,Table,5,col,,(gap)', - '0,Table,6,col,,new-bad', - '0,Table,7,col,,existing-bad', - '0,Table,8,col,,both-bad', - '0,Table,9,col,,new-bad-ex-good', - '0,Table,10,col,,new-good-ex-bad', - '0,Table,11,col,,(gap)', - '0,Table,12,col,,"Numbers: 1, 2, and 003"', - '0,Table,13,col,,"Numbers: 3, 2, and 001"', - ) + '0,Table,1,col,,none', + '0,Table,2,col,,new', + '0,Table,3,col,,existing', + '0,Table,4,col,,both', + '0,Table,5,col,,(gap)', + '0,Table,6,col,,new-bad', + '0,Table,7,col,,existing-bad', + '0,Table,8,col,,both-bad', + '0,Table,9,col,,new-bad-ex-good', + '0,Table,10,col,,new-good-ex-bad', + '0,Table,11,col,,(gap)', + '0,Table,12,col,,"Numbers: 1, 2, and 003"', + '0,Table,13,col,,"Numbers: 3, 2, and 001"', + ) new = get_messages( - '0,Table,2,col,%s,new' % translations.crc('new'), - '0,Table,4,col,%s,new' % translations.crc('both'), - '0,Table,6,col,%s,new' % translations.crc('----'), - '0,Table,8,col,%s,new' % translations.crc('----'), - '0,Table,9,col,%s,new' % translations.crc('----'), - '0,Table,10,col,%s,new' % translations.crc('new-good-ex-bad'), - '0,Table,12,col,%s,{num} {num} {num}' % translations.crc('Numbers: {num}, {num}, and {num}'), - '0,Table,13,col,%s,{num} {num} {num}' % translations.crc('----'), - '0,Table,100,col,%s,unused' % translations.crc('----'), - ) + '0,Table,2,col,%s,new' % translations.crc('new'), + '0,Table,4,col,%s,new' % translations.crc('both'), + '0,Table,6,col,%s,new' % translations.crc('----'), + '0,Table,8,col,%s,new' % translations.crc('----'), + '0,Table,9,col,%s,new' % translations.crc('----'), + '0,Table,10,col,%s,new' % translations.crc('new-good-ex-bad'), + '0,Table,12,col,%s,{num} {num} {num}' % translations.crc('Numbers: {num}, {num}, and {num}'), + '0,Table,13,col,%s,{num} {num} {num}' % translations.crc('----'), + '0,Table,100,col,%s,unused' % translations.crc('----'), + ) new[-3].number_replacement = True new[-3].source = 'Numbers: 1, 2, and 003' new[-2].number_replacement = True new[-2].source = '----' existing = get_messages( - '0,Table,3,col,%s,existing' % translations.crc('existing'), - '0,Table,4,col,%s,existing' % translations.crc('both'), - '0,Table,7,col,%s,existing' % translations.crc('----'), - '0,Table,8,col,%s,existing' % translations.crc('----'), - '0,Table,9,col,%s,existing' % translations.crc('new-bad-ex-good'), - '0,Table,10,col,%s,existing' % translations.crc('----'), - '0,Table,100,col,%s,unused' % translations.crc('----'), - ) + '0,Table,3,col,%s,existing' % translations.crc('existing'), + '0,Table,4,col,%s,existing' % translations.crc('both'), + '0,Table,7,col,%s,existing' % translations.crc('----'), + '0,Table,8,col,%s,existing' % translations.crc('----'), + '0,Table,9,col,%s,existing' % translations.crc('new-bad-ex-good'), + '0,Table,10,col,%s,existing' % translations.crc('----'), + '0,Table,100,col,%s,unused' % translations.crc('----'), + ) expected_list = ( - ('none', None, None), - ('new', True, 'new'), - ('existing', True, 'existing'), - ('both', True, 'new'), - ('(gap)', None, None), - ('new-bad', False, 'new'), - ('existing-bad', False, 'existing'), - ('both-bad', False, 'new'), - ('new-bad-ex-good', True, 'existing'), - ('new-good-ex-bad', True, 'new'), - ('(gap)', None, None), - ('Numbers: 1, 2, and 003', True, '1 2 003'), - ('Numbers: 3, 2, and 001', False, '3 2 001'), - ) + ('none', None, None), + ('new', True, 'new'), + ('existing', True, 'existing'), + ('both', True, 'new'), + ('(gap)', None, None), + ('new-bad', False, 'new'), + ('existing-bad', False, 'existing'), + ('both-bad', False, 'new'), + ('new-bad-ex-good', True, 'existing'), + ('new-good-ex-bad', True, 'new'), + ('(gap)', None, None), + ('Numbers: 1, 2, and 003', True, '1 2 003'), + ('Numbers: 3, 2, and 001', False, '3 2 001'), + ) unused = [] result_stream = list(translations.merge_translations(source, new, [], existing, unused=unused.append)) for result, expected in zip(result_stream, expected_list): diff --git a/pokedex/tests/test_util.py b/pokedex/tests/test_util.py index 7c6a034..3e7842b 100644 --- a/pokedex/tests/test_util.py +++ b/pokedex/tests/test_util.py @@ -1,49 +1,47 @@ # Encoding: utf8 import pytest +parametrize = pytest.mark.parametrize -from pokedex.tests import single_params from pokedex.db import connect, tables, util -session = connect() - -def test_get_item_identifier(): +def test_get_item_identifier(session): item = util.get(session, tables.Item, identifier='master-ball') assert item.name == 'Master Ball' -def test_get_item_name(): +def test_get_item_name(session): item = util.get(session, tables.Item, name='Awakening') assert item.name == 'Awakening' -def test_get_english_by_identifier(): +def test_get_english_by_identifier(session): language = util.get(session, tables.Language, 'en') assert language.name == 'English' -@single_params(*'burmy shaymin unown cresselia'.split()) -def test_get_pokemon_identifier(identifier): +@parametrize('identifier', ['burmy', 'shaymin', 'unown', 'cresselia']) +def test_get_pokemon_identifier(session, identifier): poke = util.get(session, tables.PokemonSpecies, identifier=identifier) assert poke.identifier == identifier -@single_params(*'Burmy Shaymin Unown Cresselia'.split()) -def test_get_pokemon_name(name): +@parametrize('name', ['Burmy', 'Shaymin', 'Unown', 'Cresselia']) +def test_get_pokemon_name(session, name): poke = util.get(session, tables.PokemonSpecies, name=name) assert poke.name == name -@single_params(*'Cheniti Shaymin Zarbi Cresselia'.split()) -def test_get_pokemon_name_explicit_language(name): +@parametrize('name', ['Cheniti', 'Shaymin', 'Zarbi', 'Cresselia']) +def test_get_pokemon_name_explicit_language(session, name): french = util.get(session, tables.Language, 'fr') 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(): +def test_types_french_order(session): french = util.get(session, tables.Language, 'fr') types = session.query(tables.Type).filter(tables.Type.id < 10000) 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): +@parametrize('id', range(1, 10)) +def test_get_pokemon_id(session, id): result = util.get(session, tables.Pokemon, id=id) assert result.id == id assert result.__tablename__ == 'pokemon'