mirror of
https://github.com/django/django.git
synced 2024-12-23 17:46:27 +00:00
6789ded0a6
Thanks to Adam Johnson, Carlton Gibson, Mariusz Felisiak, and Raphael Michel for mentoring this Google Summer of Code 2019 project and everyone else who helped with the patch. Special thanks to Mads Jensen, Nick Pope, and Simon Charette for extensive reviews. Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
import json
|
|
import uuid
|
|
|
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
from django.forms import (
|
|
CharField, Form, JSONField, Textarea, TextInput, ValidationError,
|
|
)
|
|
from django.test import SimpleTestCase
|
|
|
|
|
|
class JSONFieldTest(SimpleTestCase):
|
|
def test_valid(self):
|
|
field = JSONField()
|
|
value = field.clean('{"a": "b"}')
|
|
self.assertEqual(value, {'a': 'b'})
|
|
|
|
def test_valid_empty(self):
|
|
field = JSONField(required=False)
|
|
value = field.clean('')
|
|
self.assertIsNone(value)
|
|
|
|
def test_invalid(self):
|
|
field = JSONField()
|
|
with self.assertRaisesMessage(ValidationError, 'Enter a valid JSON.'):
|
|
field.clean('{some badly formed: json}')
|
|
|
|
def test_prepare_value(self):
|
|
field = JSONField()
|
|
self.assertEqual(field.prepare_value({'a': 'b'}), '{"a": "b"}')
|
|
self.assertEqual(field.prepare_value(None), 'null')
|
|
self.assertEqual(field.prepare_value('foo'), '"foo"')
|
|
|
|
def test_widget(self):
|
|
field = JSONField()
|
|
self.assertIsInstance(field.widget, Textarea)
|
|
|
|
def test_custom_widget_kwarg(self):
|
|
field = JSONField(widget=TextInput)
|
|
self.assertIsInstance(field.widget, TextInput)
|
|
|
|
def test_custom_widget_attribute(self):
|
|
"""The widget can be overridden with an attribute."""
|
|
class CustomJSONField(JSONField):
|
|
widget = TextInput
|
|
|
|
field = CustomJSONField()
|
|
self.assertIsInstance(field.widget, TextInput)
|
|
|
|
def test_converted_value(self):
|
|
field = JSONField(required=False)
|
|
tests = [
|
|
'["a", "b", "c"]',
|
|
'{"a": 1, "b": 2}',
|
|
'1',
|
|
'1.5',
|
|
'"foo"',
|
|
'true',
|
|
'false',
|
|
'null',
|
|
]
|
|
for json_string in tests:
|
|
with self.subTest(json_string=json_string):
|
|
val = field.clean(json_string)
|
|
self.assertEqual(field.clean(val), val)
|
|
|
|
def test_has_changed(self):
|
|
field = JSONField()
|
|
self.assertIs(field.has_changed({'a': True}, '{"a": 1}'), True)
|
|
self.assertIs(field.has_changed({'a': 1, 'b': 2}, '{"b": 2, "a": 1}'), False)
|
|
|
|
def test_custom_encoder_decoder(self):
|
|
class CustomDecoder(json.JSONDecoder):
|
|
def __init__(self, object_hook=None, *args, **kwargs):
|
|
return super().__init__(object_hook=self.as_uuid, *args, **kwargs)
|
|
|
|
def as_uuid(self, dct):
|
|
if 'uuid' in dct:
|
|
dct['uuid'] = uuid.UUID(dct['uuid'])
|
|
return dct
|
|
|
|
value = {'uuid': uuid.UUID('{c141e152-6550-4172-a784-05448d98204b}')}
|
|
encoded_value = '{"uuid": "c141e152-6550-4172-a784-05448d98204b"}'
|
|
field = JSONField(encoder=DjangoJSONEncoder, decoder=CustomDecoder)
|
|
self.assertEqual(field.prepare_value(value), encoded_value)
|
|
self.assertEqual(field.clean(encoded_value), value)
|
|
|
|
def test_formfield_disabled(self):
|
|
class JSONForm(Form):
|
|
json_field = JSONField(disabled=True)
|
|
|
|
form = JSONForm({'json_field': '["bar"]'}, initial={'json_field': ['foo']})
|
|
self.assertIn('["foo"]</textarea>', form.as_p())
|
|
|
|
def test_redisplay_wrong_input(self):
|
|
"""
|
|
Displaying a bound form (typically due to invalid input). The form
|
|
should not overquote JSONField inputs.
|
|
"""
|
|
class JSONForm(Form):
|
|
name = CharField(max_length=2)
|
|
json_field = JSONField()
|
|
|
|
# JSONField input is valid, name is too long.
|
|
form = JSONForm({'name': 'xyz', 'json_field': '["foo"]'})
|
|
self.assertNotIn('json_field', form.errors)
|
|
self.assertIn('["foo"]</textarea>', form.as_p())
|
|
# Invalid JSONField.
|
|
form = JSONForm({'name': 'xy', 'json_field': '{"foo"}'})
|
|
self.assertEqual(form.errors['json_field'], ['Enter a valid JSON.'])
|
|
self.assertIn('{"foo"}</textarea>', form.as_p())
|