from django.forms import ModelForm
from django.test import TestCase

from .models import JSONNotRequiredModel


class JSONModelFormTest(TestCase):
    def setUp(self):
        class JSONNotRequiredForm(ModelForm):
            class Meta:
                model = JSONNotRequiredModel
                fields = '__all__'

        self.form_class = JSONNotRequiredForm

    def test_blank_form(self):
        form = self.form_class(data={'json': ''})
        self.assertFalse(form.has_changed())

    def test_form_with_data(self):
        form = self.form_class(data={'json': '{}'})
        self.assertTrue(form.has_changed())

    def test_form_save(self):
        form = self.form_class(data={'json': ''})
        form.save()

    def test_save_values(self):
        values = [
            # (type, form input, db value)
            ('object', '{"a": "b"}', {'a': 'b'}),
            ('array', '[1, 2]', [1, 2]),
            ('string', '"test"', 'test'),
            ('float', '1.2', 1.2),
            ('int', '1234', 1234),
            ('bool', 'true', True),
            ('null', 'null', None),
        ]

        for vtype, form_input, db_value in values:
            with self.subTest(type=vtype, input=form_input, db=db_value):
                form = self.form_class(data={'json': form_input})
                self.assertTrue(form.is_valid(), msg=form.errors)

                instance = form.save()
                self.assertEqual(instance.json, db_value)

    def test_render_initial_values(self):
        values = [
            # (type, db value, form output)
            ('object', {'a': 'b'}, '{\n    "a": "b"\n}'),
            ('array', [1, 2], "[\n    1,\n    2\n]"),
            ('string', 'test', '"test"'),
            ('float', 1.2, '1.2'),
            ('int', 1234, '1234'),
            ('bool', True, 'true'),
            ('null', None, 'null'),
        ]

        for vtype, db_value, form_output in values:
            with self.subTest(type=vtype, db=db_value, output=form_output):
                instance = JSONNotRequiredModel.objects.create(json=db_value)

                form = self.form_class(instance=instance)
                self.assertEqual(form['json'].value(), form_output)

    def test_render_bound_values(self):
        values = [
            # (type, db value, form input, form output)
            ('object', '{"a": "b"}', '{\n    "a": "b"\n}'),
            ('array', '[1, 2]', "[\n    1,\n    2\n]"),
            ('string', '"test"', '"test"'),
            ('float', '1.2', '1.2'),
            ('int', '1234', '1234'),
            ('bool', 'true', 'true'),
            ('null', 'null', 'null'),
        ]

        for vtype, form_input, form_output in values:
            with self.subTest(type=vtype, input=form_input, output=form_output):
                form = self.form_class(data={'json': form_input})
                self.assertEqual(form['json'].value(), form_output)

    def test_invalid_value(self):
        form = self.form_class(data={'json': 'foo'})

        self.assertFalse(form.is_valid())
        self.assertEqual(form.errors, {
            'json': ['"foo" value must be valid JSON.'],
        })
        self.assertEqual(form['json'].value(), 'foo')

    def test_disabled_field(self):
        instance = JSONNotRequiredModel.objects.create(json=100)

        form = self.form_class(data={'json': '{"foo": "bar"}'}, instance=instance)
        form.fields['json'].disabled = True

        self.assertTrue(form.is_valid())
        self.assertEqual(form.cleaned_data, {'json': 100})

        # rendered value
        self.assertEqual(form['json'].value(), '100')

    def test_initial_data_has_changed(self):
        instance = JSONNotRequiredModel.objects.create(json=[1, 2])

        form = self.form_class(data={'json': '[1, 2]'}, instance=instance)
        self.assertFalse(form.has_changed())

        form = self.form_class(data={'json': '[3, 4]'}, instance=instance)
        self.assertTrue(form.has_changed())

@@ -8,22 +8,16 @@
 ango
-.forms
  import 
 Mode
@@ -12,25 +12,21 @@
  import 
-ModelF
+f
 orm
+s
 %0Afrom dj
@@ -185,16 +185,22 @@
 redForm(
+forms.
 ModelFor
@@ -3940,28 +3940,1150 @@
 ertTrue(form.has_changed())%0A
+%0A%0Aclass NonJSONFieldModelFormTest(TestCase):%0A    %22%22%22Test model form behavior when field class has been overridden.%22%22%22%0A%0A    def setUp(self):%0A        class JSONNotRequiredForm(forms.ModelForm):%0A            class Meta:%0A                model = JSONNotRequiredModel%0A                fields = %5B'json'%5D%0A                field_classes = %7B%0A                    'json': forms.CharField,%0A                %7D%0A%0A        self.form_class = JSONNotRequiredForm%0A%0A    def test_field_type(self):%0A        form = self.form_class()%0A        field = form.fields%5B'json'%5D%0A%0A        self.assertIsInstance(field, forms.CharField)%0A%0A    def test_field_kwargs(self):%0A        form = self.form_class()%0A        field = form.fields%5B'json'%5D%0A%0A        self.assertFalse(hasattr(field, 'dump_kwargs'))%0A        self.assertFalse(hasattr(field, 'load_kwargs'))%0A%0A    def test_no_indent(self):%0A        # Because we're using a regular CharField, the value is not parsed and%0A        # rerendered with indentation. Compare with %60test_render_bound_values%60.%0A        form = self.form_class(data=%7B'json': '%7B%22a%22: %22b%22%7D'%7D)%0A        self.assertEqual(form%5B'json'%5D.value(), '%7B%22a%22: %22b%22%7D')%0A

Test non-JSONField form field