transport-accessibility/transport_accessibility/pt_map/tests_gtfs_compliance.py

110 lines
5.1 KiB
Python

#TODO: Test LocationsGeojson
#TODO: Test MTM
from django.test import TestCase, TransactionTestCase
from pt_map.test_data import *
from pt_map.models import *
import unittest
from django.db import models, transaction
import random
import time
import inspect
import pt_map.models
import datetime
def _get_test_data(f):
"""Get test data for a field type."""
def wrapper(self, field, model, d, *args, **kwargs):
if field["name"] == "service_id":
self.add += 1
return f"{d['pk']}{self.add}"
match field["type"]:
case "fk":
if isinstance(field["references"], list):
field["references"] = random.choice(field["references"])
if not field["references"] == model and field["references"] not in [LocationsGeojson]:
fk = field["references"].objects.create(**{**{f["name"]: self.get_test_data(f, field["references"], d) for f in self.gtfs_fields[field["references"]._meta.object_name] if not f["type"] == "mtm"}, "feed_info_id": self.feed_info})
return fk
return None
case "unique":
return (d[field["pk"]], "unique")
case "enum":
return random.choice(field["allowed_values"])
case "date":
return datetime.datetime.fromisoformat(d["date"])
case "pk":
self.add += 1
return f"{d['pk']}{self.add}"
case _:
return d[field["type"]]
return wrapper
def _test_constructor(index):
def decorate(f):
def wrapper(self, *args, **kwargs):
for name, model in [tpl for tpl in inspect.getmembers(pt_map.models, inspect.isclass) if tpl[1] not in [FeedInfo, LocationsGeojson]]:
with self.subTest(name=name):
d = data[index]
values = {**{f["name"]: self.get_test_data(f, model, d) for f in self.gtfs_fields[name] if not f["type"] == "mtm"}, "feed_info_id": self.feed_info}
obj = model.objects.create(**values)
self.assertIsNotNone(obj)
self.assertIsInstance(obj, models.Model)
return wrapper
return decorate
class AllFieldsPresentTestCase(TestCase):
"""Test for the presence of all the fields of all the models, the GTFS reference describes."""
def setUp(self):
self.model_fields = {name: [*[f.name for f in model._meta.fields], *[f.name for f in model._meta.many_to_many]] for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if not model == LocationsGeojson}
self.gtfs_fields = {name: get_all_fields(name) for name,model in inspect.getmembers(pt_map.models, inspect.isclass) if not model == LocationsGeojson}
def test_all_fields_present(self):
"""Make sure the model has properties for all fields - regardless if required - provided by the GTFS standard."""
for name in self.model_fields.keys():
with self.subTest(name=name):
for f in self.gtfs_fields[name]:
with self.subTest(f=f):
self.assertIn(f["name"], self.model_fields[name])
class ConstructorAllFieldsTestCase(TransactionTestCase):
"""Test all the models can be initialized using appropriate data as specified by the GTFS."""
def setUp(self):
self.model_fields = {name: [f.name for f in model._meta.fields] for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if not model == FeedInfo}
self.model_mtm = {name: [f.name for f in model._meta.many_to_many] for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if not model == FeedInfo}
self.gtfs_fields = {name: get_all_fields(name) for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if not model == FeedInfo}
self.feed_info = FeedInfo.objects.create(**{f["name"]: data[0][f["type"]] for f in get_all_fields("FeedInfo")})
self.add = 0
@_get_test_data
def get_test_data(self, field, model, d):
pass
@_test_constructor(0)
def test_constructor_all_fields_fixed(self):
"""Make sure all of the model's fields are initializable with appropriate values. Fixed test data."""
pass
@_test_constructor(random.randint(0, len(data)-1))
def test_constructor_all_fields_other(self):
"""Make sure all of the model's fields are initializable with appropriate values. A second set of test data."""
pass
class ConstructorRequiredFieldsOnlyTestCase(TransactionTestCase):
def setUp(self):
self.gtfs_fields = {name: get_required_fields(name) for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if model not in [FeedInfo, LocationsGeojson]}
self.feed_info = FeedInfo.objects.create(**{f["name"]: data[0][f["type"]] for f in get_required_fields("FeedInfo")})
self.add = 0
@_get_test_data
def get_test_data(self):
pass
@_test_constructor(0)
def test_constructor_required_fields_only_fixed(self):
pass
@_test_constructor(random.randint(0, len(data)-1))
def test_constructor_required_fields_only_other(self):
pass