import warnings
from django.test import TestCase
from django.db import models


class FieldDeconstructionTests(TestCase):
    """
    Tests the deconstruct() method on all core fields.
    """

    def test_name(self):
        """
        Tests the outputting of the correct name if assigned one.
        """
        # First try using a "normal" field
        field = models.CharField(max_length=65)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(name, None)
        field.set_attributes_from_name("is_awesome_test")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(name, "is_awesome_test")
        # Now try with a ForeignKey
        field = models.ForeignKey("some_fake.ModelName")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(name, None)
        field.set_attributes_from_name("author")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(name, "author")

    def test_auto_field(self):
        field = models.AutoField(primary_key=True)
        field.set_attributes_from_name("id")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.AutoField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"primary_key": True})

    def test_big_integer_field(self):
        field = models.BigIntegerField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.BigIntegerField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_boolean_field(self):
        field = models.BooleanField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.BooleanField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})
        field = models.BooleanField(default=True)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.BooleanField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"default": True})

    def test_char_field(self):
        field = models.CharField(max_length=65)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.CharField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"max_length": 65})
        field = models.CharField(max_length=65, null=True, blank=True)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.CharField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"max_length": 65, "null": True, "blank": True})

    def test_csi_field(self):
        field = models.CommaSeparatedIntegerField(max_length=100)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.CommaSeparatedIntegerField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"max_length": 100})

    def test_date_field(self):
        field = models.DateField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.DateField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})
        field = models.DateField(auto_now=True)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.DateField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"auto_now": True})

    def test_datetime_field(self):
        field = models.DateTimeField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.DateTimeField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})
        field = models.DateTimeField(auto_now_add=True)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.DateTimeField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"auto_now_add": True})

    def test_decimal_field(self):
        field = models.DecimalField(max_digits=5, decimal_places=2)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.DecimalField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"max_digits": 5, "decimal_places": 2})

    def test_email_field(self):
        field = models.EmailField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.EmailField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"max_length": 75})
        field = models.EmailField(max_length=255)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.EmailField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"max_length": 255})

    def test_file_field(self):
        field = models.FileField(upload_to="foo/bar")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.FileField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"upload_to": "foo/bar"})

    def test_file_path_field(self):
        field = models.FilePathField(match=".*\.txt$")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.FilePathField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"match": ".*\.txt$"})
        field = models.FilePathField(recursive=True, allow_folders=True)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.FilePathField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"recursive": True, "allow_folders": True})

    def test_float_field(self):
        field = models.FloatField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.FloatField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_foreign_key(self):
        field = models.ForeignKey("auth.User")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.ForeignKey")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"to": "auth.User"})
        field = models.ForeignKey("something.Else")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.ForeignKey")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"to": "something.Else"})
        field = models.ForeignKey("auth.User", on_delete=models.SET_NULL)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.ForeignKey")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"to": "auth.User", "on_delete": models.SET_NULL})

    def test_image_field(self):
        field = models.ImageField(upload_to="foo/barness", width_field="width", height_field="height")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.ImageField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"upload_to": "foo/barness", "width_field": "width", "height_field": "height"})

    def test_integer_field(self):
        field = models.IntegerField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.IntegerField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_ip_address_field(self):
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            field = models.IPAddressField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.IPAddressField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_generic_ip_address_field(self):
        field = models.GenericIPAddressField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.GenericIPAddressField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})
        field = models.GenericIPAddressField(protocol="IPv6")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.GenericIPAddressField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"protocol": "IPv6"})

    def test_many_to_many_field(self):
        field = models.ManyToManyField("auth.User")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.ManyToManyField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"to": "auth.User"})

    def test_null_boolean_field(self):
        field = models.NullBooleanField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.NullBooleanField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_positive_integer_field(self):
        field = models.PositiveIntegerField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.PositiveIntegerField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_positive_small_integer_field(self):
        field = models.PositiveSmallIntegerField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.PositiveSmallIntegerField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_slug_field(self):
        field = models.SlugField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.SlugField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})
        field = models.SlugField(db_index=False)
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.SlugField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"db_index": False})

    def test_small_integer_field(self):
        field = models.SmallIntegerField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.SmallIntegerField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_text_field(self):
        field = models.TextField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.TextField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})

    def test_url_field(self):
        field = models.URLField()
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.URLField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {})