"""Test the media accessors. If run directly from the command line, also tests the accessors and the names 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. """ from __future__ import print_function import pytest import os import re from pokedex.db import tables from pokedex.util import media path_re = re.compile('^[-a-z0-9./]*$') 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(media_root, totodile) assert accessor.sprite() == accessor.sprite(female=True) 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(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(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(media_root, venonat) assert accessor.sprite('yellow') == accessor.sprite('yellow', shiny=True) @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(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(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] rainy_castform = media.PokemonFormMedia(media_root, rainy_castform) rainy_castform.overworld('up', strict=True) 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(media_root, exeggcute) accessor.sprite(female=True, strict=True) def get_all_filenames(media_root): all_filenames = set() 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) assert path_re.match(path), path all_filenames.add(path) return all_filenames def hit(filenames, method, *args, **kwargs): """ Run the given accessor method with args & kwargs; if found remove the result path from filenames and return True, else return False. """ try: medium = method(*args, **kwargs) assert medium.exists except ValueError: return False except: print('Error while processing', method, args, kwargs) raise try: filenames.remove(medium.path) except KeyError: pass return True @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. Make sure we get every file in the repo, and that we get a file whenever we should. Well, there are exceptions of course. """ versions = list(session.query(tables.Version).all()) versions.append('red-green') # We don't have any graphics for Colosseum or XD versions.remove(session.query(tables.Version).filter_by(identifier=u'colosseum').one()) versions.remove(session.query(tables.Version).filter_by(identifier=u'xd').one()) black = session.query(tables.Version).filter_by(identifier=u'black').one() filenames = get_all_filenames(media_root) # Some small stuff first for damage_class in session.query(tables.MoveDamageClass).all(): assert hit(filenames, media.DamageClassMedia(media_root, damage_class).icon) for habitat in session.query(tables.PokemonHabitat).all(): assert hit(filenames, media.HabitatMedia(media_root, habitat).icon) for shape in session.query(tables.PokemonShape).all(): assert hit(filenames, media.ShapeMedia(media_root, shape).icon) for item_pocket in session.query(tables.ItemPocket).all(): 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(media_root, contest_type).icon) for elemental_type in session.query(tables.Type).all(): assert hit(filenames, media.TypeMedia(media_root, elemental_type).icon) # Items versions_for_items = [ None, session.query(tables.Version).filter_by(identifier='emerald').one(), ] for item in session.query(tables.Item).all(): 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 ( not item.appears_underground or rotation) for version in versions_for_items: success = hit(filenames, accessor.sprite, version=version) if version is None: assert success for color in 'red green blue pale prism'.split(): for big in (True, False): 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(media_root, rock_type) for rotation in (0, 90, 180, 270): success = hit(filenames, accessor.underground, rotation=rotation) assert success or rotation # Pokemon! accessors = [] 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(media_root, manaphy)) accessors.append(media.SubstituteMedia(media_root)) for form in session.query(tables.PokemonForm).all(): accessors.append(media.PokemonFormMedia(media_root, form)) for pokemon in session.query(tables.PokemonSpecies).all(): accessors.append(media.PokemonSpeciesMedia(media_root, pokemon)) for accessor in accessors: assert hit(filenames, accessor.footprint) or not accessor.is_proper assert hit(filenames, accessor.trozei) or not accessor.is_proper or ( accessor.introduced_in > 3) assert hit(filenames, accessor.cry) or not accessor.is_proper assert hit(filenames, accessor.cropped_sprite) or not accessor.is_proper for female in (True, False): assert hit(filenames, accessor.icon, female=female) or not accessor.is_proper assert hit(filenames, accessor.sugimori, female=female) or ( not accessor.is_proper or int(accessor.species_id) >= 647) for shiny in (True, False): for frame in (1, 2): for direction in 'up down left right'.split(): assert hit(filenames, accessor.overworld, direction=direction, shiny=shiny, female=female, frame=frame, ) or not accessor.is_proper or ( accessor.introduced_in > 4) for version in versions: for animated in (True, False): for back in (True, False): for color in (None, 'gray', 'gbc'): success = hit(filenames, accessor.sprite, version, animated=animated, back=back, color=color, shiny=shiny, female=female, frame=frame, ) if (version == black and not animated and not back and not color and not shiny and not female and frame == 1): # All pokemon are in Black assert success or not accessor.is_proper if (str(accessor.species_id) == '1' and not animated and not color and frame == 1): # Bulbasaur is in all versions assert success # Remove exceptions exceptions = [os.path.join(media_root, dirname) for dirname in 'chrome fonts ribbons'.split()] exceptions.append(os.path.join(media_root, 'items', 'hm-')) exceptions = tuple(exceptions) unaccessed_filenames = set(filenames) for filename in filenames: if filename.startswith(exceptions): unaccessed_filenames.remove(filename) if filename.endswith('-beta.png'): unaccessed_filenames.remove(filename) if unaccessed_filenames: print('Unaccessed files:') for filename in unaccessed_filenames: print(filename) assert unaccessed_filenames == set() return (not filenames)