#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