from django.db import models

class TestModel:
    '''
    Base class for Lostplaces models
    '''
    model_name = None

    def _test_field(self, field_name, field_class):
        '''
        Tests if a field exists under the given name and
        if the field is of the right type
        '''
        field = self.object._meta.get_field(field_name)
        self.assertTrue(
            field,
            msg="%s has no field named '%s'" % (
                self.model_name,
                field_name
            )
        )
        self.assertEqual(
            type(field), field_class, 
            msg='%s.%s name field is no CharField' % (
                self.model_name,
                field_name
            )
        )
        return field


    def _test_char_field(self, field_name, min_length, max_length):
        '''
        Tests if the given field is a char field and if its max_length
        is in min_length and max_legth
        '''
        field = self._test_field(field_name, models.CharField)
        self.assertEqual(
            type(field), models.CharField, 
            msg='%s.%s name field is no CharField' % (
                self.model_name,
                field_name
            )
        )
        self.assertTrue(
            field.max_length in range(min_length, max_length),
            msg='%s.%s field max_length not in range of %d and %d' % (
                self.model_name,
                field_name,
                min_length,
                max_length
                )
        )
    
    def _test_float_field(self, field_name, min_value=None, max_value=None):
        '''
        Tests if the field is a floatfield. If min_value and/or max_value are passed,
        the validators of the field are also checked. The validator list of the field should
        look like 
        [MinValueValidator, MayValueValidator], if both values are passed,
        [MinValueValidator] if only min_value is passed,
        [MaxValueValidator] if only max_value is passed
        '''
        field = self._test_field(field_name, models.FloatField)
        if min_value:
            self.assertTrue(
                len(field.validators) >= 1,
                msg='%s.%s first validator should check minimum' % (
                    self.model_name,
                    field_name
                    )
                )
            self.assertEqual(
                field.validators[0].limit_value,
                min_value,
                msg='%s.%s min value missmatch' % (
                    self.model_name,
                    field_name
                )
            )
        if max_value:
            index = 0
            if min_value:
                index += 1
            self.assertTrue(
                len(field.validators) >= index+1,
                msg='%s.%s second validator should check maximum' % (
                    self.model_name,
                    field_name
                    )
            )
            self.assertEqual(
                field.validators[1].limit_value,
                max_value,
                msg='%s.%s max value missmatch' % (
                    self.model_name,
                    field_name
                )
            )

class TestSubmittable(TestModel):
    model_name='<Class>'
    related_name = None
    nullable = False

    def test_submitted_when(self):
        submitted_when = self._test_field('submitted_when', models.DateTimeField)
        self.assertTrue(submitted_when.auto_now_add, 
            msg='%s.submitted_when should be auto_now_add' % (
                self.model_name
            )
        )

    def test_submitted_by(self):
        submitted_by = self._test_field('submitted_by',models.ForeignKey)
        if self.related_name:
            self.assertEqual(submitted_by.remote_field.related_name, self.related_name)
        if self.nullable:
            self.assertTrue(submitted_by.null,)
            self.assertTrue(submitted_by.blank)
            self.assertEqual(submitted_by.remote_field.on_delete, models.SET_NULL)