import django
import environ
import os
import sys
from django.apps import apps
from django.test import TestCase
from model_bakery import baker
sys.path.append(str(environ.Path(__file__) - 3))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
django.setup()


{% for model, options in model_dict.items() -%}
class {{model.__name__}}Tests(TestCase):
    """ test CRUD operations on {{ model.__name__ }} """
    def setUp(self):
        self.model = apps.get_model('{{ model._meta.app_label }}', '{{ model._meta.model_name }}')
        self.to_bake = '{{model._meta.label}}'
        {%- if options['auditlog'] %}
        self.logentry = apps.get_model('auditlog', 'LogEntry'){% endif %}

    def bake(self):
        """ add row """
        return baker.make(self.to_bake, {% if options['fill_optional'] %}_fill_optional={{ options['fill_optional'] }}{% endif %})

    def test_create(self):
        """ verify object can be created """
        before_count = self.model.objects.count()
        row = self.bake()
        after_count = self.model.objects.count()
        self.assertTrue(isinstance(row, self.model))
        self.assertGreater(after_count, before_count)
        {% if options['auditlog'] %}
    def test_create_auditlog(self):
        """ verify an auditlog entry is created when new row is created """
        row = self.bake()
        log = self.logentry.objects.filter(content_type__model=row._meta.model_name,
                                           object_id=row.id).latest('id')
        self.assertIsNotNone(log)
        self.assertEqual(log.content_type.model, row._meta.model_name)
        self.assertEqual(log.object_id, row.id)
        self.assertEqual(log.action, 0)
        {% endif %}
    def test_read(self):
        """ verify object can be read """
        row = self.bake()
        entry = self.model.objects.get(id=row.id)
        self.assertTrue(isinstance(entry, self.model))
        self.assertEqual(row.id, entry.id)

    def test_delete(self):
        """ verify object can be deleted """
        row = self.bake()
        before_count = self.model.objects.count()
        row_id = row.id
        row.delete()
        after_count = self.model.objects.count()
        with self.assertRaises(self.model.DoesNotExist):
            self.model.objects.get(id=row_id)
        self.assertLess(after_count, before_count)
        {% if options['auditlog'] %}
    def test_delete_auditlog(self):
        """ verify an auditlog entry is created when a row is deleted """
        row = self.bake()
        object_repr = row.__str__()
        object_id = row.id
        row.delete()
        log = self.logentry.objects.filter(content_type__model=row._meta.model_name,
                                           object_repr__icontains=object_repr).latest('id')
        self.assertIsNotNone(log)
        self.assertEqual(log.content_type.model, row._meta.model_name)
        self.assertEqual(log.object_id, object_id)
        self.assertEqual(log.action, 2)
        {% endif %}{% for field in options['update_field_list'] %}
    def test_update_{{ field.name }}(self):
        """ verify {{ field.name }} ({{ field.get_internal_type() }}) can be updated """
        row = self.bake()
        original_value = row.{{ field.name }}
        {% if field.get_internal_type() == 'ForeignKey' -%}
        updated_value = baker.make('{{ field.related_model._meta.app_label }}.{{ field.related_model._meta.model_name }}')
        {% elif field.get_internal_type() == 'CharField' -%}
        updated_value = baker.prepare(self.to_bake, _fill_optional=['{{ field.name }}']).{{ field.name }}
        {% elif field.get_internal_type() == 'TextField' -%}
        updated_value = baker.prepare(self.to_bake, _fill_optional=['{{ field.name }}']).{{ field.name }}
        {% endif -%}
        setattr(row, '{{ field.name }}', updated_value)
        row.save()
        self.assertEqual(getattr(row, '{{ field.name }}'), updated_value)
        self.assertNotEqual(getattr(row, '{{ field.name }}'), original_value)
        {%- if options['auditlog'] %}
        # verify auditlog entry
        log = self.logentry.objects.filter(content_type__model=row._meta.model_name,
                                           object_id=row.id).latest('id')
        self.assertIsNotNone(log)
        self.assertEqual(log.content_type.model, row._meta.model_name)
        self.assertEqual(log.object_id, row.id)
        self.assertEqual(log.action, 1){% endif %}
    {% endfor %}

{% endfor %}