veekun_pokedex/pokedex/tests/test_database_sanity.py
Andrew Ekstedt 8161bd84e4 gift-pokemon: fix Cosplay Pikachu and Sinnoh starter gift locations
Cosplay Pikachu was listed as being encountered in contest-hall, but
that's a Sinnoh location. In OR/AS, the contest halls are not a
first-class location but rather just treated as part of the town or city
they are in. Cosplay Pikachu is given to the player after they
participate in their first contest, so its location can be any of the
four cities with a contest hall.

The Sinnoh starter that the player obtains in OR/AS is on Hoenn Route
101, not Sinnoh Route 201 (probably a copy/paste error).

Add a test to make sure that encounter regions always match the
region(s) that their game takes place in.
2019-07-12 18:48:07 -07:00

117 lines
4.8 KiB
Python

import pytest
parametrize = pytest.mark.parametrize
from sqlalchemy.orm import aliased, joinedload, lazyload
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql import func
from pokedex.db import tables, util
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)
sanity_q = session.query(tables.Encounter) \
.join((tables.EncounterSlot, tables.Encounter.slot)) \
.join((version_group_a, tables.EncounterSlot.version_group)) \
.join((tables.Version, tables.Encounter.version)) \
.join((version_group_b, tables.Version.version_group)) \
.filter(version_group_a.id != version_group_b.id)
# Encounter slots all match the encounters they belong to
assert sanity_q.count() == 0
def test_encounter_regions(session):
"""Check that encounter locations match the region of the game they're from.
"""
sanity_q = session.query(tables.Encounter) \
.join((tables.Version, tables.Encounter.version)) \
.join((tables.VersionGroup, tables.Version.version_group)) \
.join((tables.LocationArea, tables.Encounter.location_area)) \
.join((tables.Location, tables.LocationArea.location)) \
.join((tables.Region, tables.Location.region)) \
.filter(~tables.VersionGroup.version_group_regions.any(tables.VersionGroupRegion.region_id == tables.Region.id))
for e in sanity_q.limit(20):
acceptable_regions = " or ".join(r.identifier for r in e.version.version_group.regions)
if e.location_area.location.region is not None:
print("{e} ({e.pokemon.identifier}, {e.slot.method.identifier}, {e.version.identifier}) is in {e.location_area.location.region.identifier} ({e.location_area.location.identifier}) but should be in {acceptable_regions} ({e.version.identifier})".format(e=e, acceptable_regions=acceptable_regions))
else:
print("{e} ({e.pokemon.identifier}, {e.slot.method.identifier}, {e.version.identifier}) is in a pseudo-location ({e.location_area.location.identifier}) that is not part of any region, but should be in {acceptable_regions} ({e.version.identifier})".format(e=e, acceptable_regions=acceptable_regions))
# Encounter regions match the games they belong to
assert sanity_q.count() == 0
@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
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(session):
"""Check that tone PokemonForm.order value isn't used for more species"""
species_by_form_order = {}
query = session.query(tables.PokemonForm)
query = query.options(joinedload('pokemon.species'))
for form in query:
try:
previous_species = species_by_form_order[form.order]
except KeyError:
species_by_form_order[form.order] = form.species
else:
assert previous_species == form.species, (
"PokemonForm.order == %s is used for %s and %s" % (
form.order,
species_by_form_order[form.order].name,
form.species.name))
def test_default_forms(session):
"""Check that each pokemon has one default form and each species has one
default pokemon."""
q = session.query(tables.Pokemon)
q = q.join(tables.PokemonForm)
q = q.filter(tables.PokemonForm.is_default==True)
q = q.options(lazyload('*'))
q = q.group_by(tables.Pokemon)
q = q.add_columns(func.count(tables.PokemonForm.id))
for pokemon, num_default_forms in q:
if num_default_forms == 0:
pytest.fail("pokemon %s has no default forms" % pokemon.name)
elif num_default_forms > 1:
pytest.fail("pokemon %s has %d default forms" % (pokemon.name, num_default_forms))
q = session.query(tables.PokemonSpecies)
q = q.join(tables.Pokemon)
q = q.filter(tables.Pokemon.is_default==True)
q = q.options(lazyload('*'))
q = q.group_by(tables.PokemonSpecies)
q = q.add_columns(func.count(tables.Pokemon.id))
for species, num_default_pokemon in q:
if num_default_pokemon == 0:
pytest.fail("species %s has no default pokemon" % species.name)
elif num_default_pokemon > 1:
pytest.fail("species %s has %d default pokemon" % (species.name, num_default_pokemon))