Test media accessors, and the media organization itself
[zzz-pokedex.git] / pokedex / tests / test_media.py
1
2 """Test the media accessors.
3
4 If run directly from the command line, also tests the accessors and the names
5 of all the media by getting just about everything in a naive brute-force way.
6 This, of course, takes a lot of time to run.
7 """
8
9 import os
10 import re
11
12 from nose.tools import *
13 from nose.plugins.skip import SkipTest
14 import nose
15 import pkg_resources
16
17 from pokedex.db import tables, connect, media
18
19 session = connect()
20 basedir = pkg_resources.resource_filename('pokedex', 'data/media')
21
22 path_re = re.compile('^[-a-z0-9./]*$')
23
24 def test_totodile():
25 """Totodile's female sprite -- same as male"""
26 totodile = session.query(tables.Pokemon).filter_by(identifier=u'totodile').one()
27 accessor = media.PokemonMedia(totodile)
28 assert accessor.sprite() == accessor.sprite(female=True)
29
30 def test_chimecho():
31 """Chimecho's Platinum female backsprite -- diffeent from male"""
32 chimecho = session.query(tables.Pokemon).filter_by(identifier=u'chimecho').one()
33 accessor = media.PokemonMedia(chimecho)
34 male = accessor.sprite('platinum', back=True, frame=2)
35 female = accessor.sprite('platinum', back=True, female=True, frame=2)
36 assert male != female
37
38 def test_venonat():
39 """Venonat's shiny Yellow sprite -- same as non-shiny"""
40 venonat = session.query(tables.Pokemon).filter_by(identifier=u'venonat').one()
41 accessor = media.PokemonMedia(venonat)
42 assert accessor.sprite('yellow') == accessor.sprite('yellow', shiny=True)
43
44 def test_arceus_icon():
45 """Arceus fire-form icon -- same as base icon"""
46 arceus = session.query(tables.Pokemon).filter_by(identifier=u'arceus').one()
47 accessor = media.PokemonMedia(arceus)
48 fire_arceus = [f for f in arceus.forms if f.identifier == 'fire'][0]
49 fire_accessor = media.PokemonFormMedia(fire_arceus)
50 assert accessor.icon() == fire_accessor.icon()
51
52 @raises(ValueError)
53 def test_strict_castform():
54 """Castform rainy form overworld with strict -- unavailable"""
55 castform = session.query(tables.Pokemon).filter_by(identifier=u'castform').first()
56 rainy_castform = [f for f in castform.forms if f.identifier == 'rainy'][0]
57 rainy_castform = media.PokemonFormMedia(rainy_castform)
58 rainy_castform.overworld('up', strict=True)
59
60 @raises(ValueError)
61 def test_strict_exeggcute():
62 """Exeggcutes's female backsprite, with strict -- unavailable"""
63 exeggcute = session.query(tables.Pokemon).filter_by(identifier=u'exeggcute').one()
64 accessor = media.PokemonMedia(exeggcute)
65 accessor.sprite(female=True, strict=True)
66
67
68
69 def get_all_filenames():
70 print 'Reading all filenames...'
71
72 all_filenames = set()
73
74 for dirpath, dirnames, filenames in os.walk(basedir):
75 for filename in filenames:
76 path = os.path.join(dirpath, filename)
77 assert path_re.match(path), path
78 all_filenames.add(path)
79
80 return all_filenames
81
82 def hit(filenames, method, *args, **kwargs):
83 """
84 Run the given accessor method with args & kwargs; if found remove the
85 result path from filenames and return True, else return False.
86 """
87 try:
88 medium = method(*args, **kwargs)
89 #print 'Hit', medium.relative_path
90 assert medium.exists
91 except ValueError, e:
92 #print 'DNF', e
93 return False
94 except:
95 print 'Error while processing', method, args, kwargs
96 raise
97 try:
98 filenames.remove(medium.path)
99 except KeyError:
100 pass
101 return True
102
103 def check_get_everything():
104 """
105 For every the accessor method, loop over the Cartesian products of all
106 possible values for its arguments.
107 Make sure we get every file in the repo, and that we get a file whenever
108 we should.
109
110 Well, there are exceptions of course.
111 """
112
113 versions = list(session.query(tables.Version).all())
114 versions.append('red-green')
115
116 black = session.query(tables.Version).filter_by(identifier=u'black').one()
117
118 filenames = get_all_filenames()
119
120 # Some small stuff first
121
122 for damage_class in session.query(tables.MoveDamageClass).all():
123 assert hit(filenames, media.DamageClassMedia(damage_class).icon)
124
125 for habitat in session.query(tables.PokemonHabitat).all():
126 assert hit(filenames, media.HabitatMedia(habitat).icon)
127
128 for shape in session.query(tables.PokemonShape).all():
129 assert hit(filenames, media.ShapeMedia(shape).icon)
130
131 for item_pocket in session.query(tables.ItemPocket).all():
132 assert hit(filenames, media.ItemPocketMedia(item_pocket).icon)
133 assert hit(filenames, media.ItemPocketMedia(item_pocket).icon, selected=True)
134
135 for contest_type in session.query(tables.ContestType).all():
136 assert hit(filenames, media.ContestTypeMedia(contest_type).icon)
137
138 for elemental_type in session.query(tables.Type).all():
139 assert hit(filenames, media.TypeMedia(elemental_type).icon)
140
141 # Items
142 versions_for_items = [
143 None,
144 session.query(tables.Version).filter_by(identifier='emerald').one(),
145 ]
146
147 for item in session.query(tables.Item).all():
148 accessor = media.ItemMedia(item)
149 assert hit(filenames, accessor.berry_image) or not item.berry
150 for rotation in (0, 90, 180, 270):
151 assert hit(filenames, accessor.underground, rotation=rotation) or (
152 not item.appears_underground or rotation)
153 for version in versions_for_items:
154 success = hit(filenames, accessor.sprite, version=version)
155 if version is None:
156 assert success
157
158 for color in 'red green blue pale prism'.split():
159 for big in (True, False):
160 accessor = media.UndergroundSphereMedia(color=color, big=big)
161 assert hit(filenames, accessor.underground)
162
163 for rock_type in 'i ii o o-big s t z'.split():
164 accessor = media.UndergroundRockMedia(rock_type)
165 for rotation in (0, 90, 180, 270):
166 success = hit(filenames, accessor.underground, rotation=rotation)
167 assert success or rotation
168
169 # Pokemon!
170 accessors = []
171
172 accessors.append(media.UnknownPokemonMedia())
173 accessors.append(media.EggMedia())
174 manaphy = session.query(tables.Pokemon).filter_by(identifier=u'manaphy').one()
175 accessors.append(media.EggMedia(manaphy))
176 accessors.append(media.SubstituteMedia())
177
178 print 'Loading pokemon'
179
180 for form in session.query(tables.PokemonForm).filter(tables.PokemonForm.identifier != '').all():
181 accessors.append(media.PokemonFormMedia(form))
182
183 for pokemon in session.query(tables.Pokemon).all():
184 accessors.append(media.PokemonMedia(pokemon))
185
186 for accessor in accessors:
187 assert hit(filenames, accessor.footprint) or not accessor.form
188 assert hit(filenames, accessor.trozei) or not accessor.form or (
189 accessor.form.pokemon.generation.id > 3)
190 assert hit(filenames, accessor.cry) or not accessor.form
191 assert hit(filenames, accessor.cropped_sprite) or not accessor.form
192 for female in (True, False):
193 assert hit(filenames, accessor.icon, female=female) or not accessor.form
194 assert hit(filenames, accessor.sugimori, female=female) or (
195 not accessor.form or accessor.form.pokemon.id >= 647)
196 for shiny in (True, False):
197 for frame in (1, 2):
198 for direction in 'up down left right'.split():
199 assert hit(filenames, accessor.overworld,
200 direction=direction,
201 shiny=shiny,
202 female=female,
203 frame=frame,
204 ) or not accessor.form or (
205 accessor.form.pokemon.generation.id > 4)
206 for version in versions:
207 for animated in (True, False):
208 for back in (True, False):
209 for color in (None, 'gray', 'gbc'):
210 success = hit(filenames,
211 accessor.sprite,
212 version,
213 animated=animated,
214 back=back,
215 color=color,
216 shiny=shiny,
217 female=female,
218 frame=frame,
219 )
220 if (version == black and not animated
221 and not back and not color and not
222 shiny and not female and
223 frame == 1):
224 # All pokemon are in Black
225 assert success or not accessor.form
226 if (str(accessor.pokemon_id) == '1'
227 and not animated and not color and
228 frame == 1):
229 # Bulbasaur is in all versions
230 assert success
231
232 # Remove exceptions
233 exceptions = [os.path.join(basedir, dirname) for dirname in
234 'chrome fonts ribbons'.split()]
235 exceptions.append(os.path.join(basedir, 'items', 'hm-'))
236 exceptions = tuple(exceptions)
237
238 for filename in tuple(filenames):
239 if filename.startswith(exceptions):
240 filenames.remove(filename)
241
242 if len(filenames):
243 print
244 print '-----------------'
245 print 'Unaccessed stuff:'
246 for filename in sorted(filenames):
247 print filename
248 print len(filenames), 'unaccessed files :('
249
250 return (not filenames)
251
252 if __name__ == '__main__':
253 result = nose.run(defaultTest=__file__)
254 result = result and check_get_everything()
255 exit(not result)