123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- # -*- coding: utf-8 -*-
- from __future__ import unicode_literals
- import decimal
- import json
- import re
- from django.core import serializers
- from django.core.serializers.base import DeserializationError
- from django.core.serializers.json import DjangoJSONEncoder
- from django.db import models
- from django.test import SimpleTestCase, TestCase, TransactionTestCase
- from django.test.utils import isolate_apps
- from django.utils.translation import override, ugettext_lazy
- from .models import Score
- from .tests import SerializersTestBase, SerializersTransactionTestBase
- class JsonSerializerTestCase(SerializersTestBase, TestCase):
- serializer_name = "json"
- pkless_str = """[
- {
- "pk": null,
- "model": "serializers.category",
- "fields": {"name": "Reference"}
- }, {
- "model": "serializers.category",
- "fields": {"name": "Non-fiction"}
- }]"""
- mapping_ordering_str = """[
- {
- "model": "serializers.article",
- "pk": %(article_pk)s,
- "fields": {
- "author": %(author_pk)s,
- "headline": "Poker has no place on ESPN",
- "pub_date": "2006-06-16T11:00:00",
- "categories": [
- %(first_category_pk)s,
- %(second_category_pk)s
- ],
- "meta_data": []
- }
- }
- ]
- """
- @staticmethod
- def _validate_output(serial_str):
- try:
- json.loads(serial_str)
- except Exception:
- return False
- else:
- return True
- @staticmethod
- def _get_pk_values(serial_str):
- ret_list = []
- serial_list = json.loads(serial_str)
- for obj_dict in serial_list:
- ret_list.append(obj_dict["pk"])
- return ret_list
- @staticmethod
- def _get_field_values(serial_str, field_name):
- ret_list = []
- serial_list = json.loads(serial_str)
- for obj_dict in serial_list:
- if field_name in obj_dict["fields"]:
- ret_list.append(obj_dict["fields"][field_name])
- return ret_list
- def test_indentation_whitespace(self):
- Score.objects.create(score=5.0)
- Score.objects.create(score=6.0)
- qset = Score.objects.all()
- s = serializers.json.Serializer()
- json_data = s.serialize(qset, indent=2)
- for line in json_data.splitlines():
- if re.search(r'.+,\s*$', line):
- self.assertEqual(line, line.rstrip())
- @isolate_apps('serializers')
- def test_custom_encoder(self):
- class ScoreDecimal(models.Model):
- score = models.DecimalField()
- class CustomJSONEncoder(json.JSONEncoder):
- def default(self, o):
- if isinstance(o, decimal.Decimal):
- return str(o)
- return super(CustomJSONEncoder, self).default(o)
- s = serializers.json.Serializer()
- json_data = s.serialize(
- [ScoreDecimal(score=decimal.Decimal(1.0))], cls=CustomJSONEncoder
- )
- self.assertIn('"fields": {"score": "1"}', json_data)
- def test_json_deserializer_exception(self):
- with self.assertRaises(DeserializationError):
- for obj in serializers.deserialize("json", """[{"pk":1}"""):
- pass
- def test_helpful_error_message_invalid_pk(self):
- """
- If there is an invalid primary key, the error message should contain
- the model associated with it.
- """
- test_string = """[{
- "pk": "badpk",
- "model": "serializers.player",
- "fields": {
- "name": "Bob",
- "rank": 1,
- "team": "Team"
- }
- }]"""
- with self.assertRaisesMessage(DeserializationError, "(serializers.player:pk=badpk)"):
- list(serializers.deserialize('json', test_string))
- def test_helpful_error_message_invalid_field(self):
- """
- If there is an invalid field value, the error message should contain
- the model associated with it.
- """
- test_string = """[{
- "pk": "1",
- "model": "serializers.player",
- "fields": {
- "name": "Bob",
- "rank": "invalidint",
- "team": "Team"
- }
- }]"""
- expected = "(serializers.player:pk=1) field_value was 'invalidint'"
- with self.assertRaisesMessage(DeserializationError, expected):
- list(serializers.deserialize('json', test_string))
- def test_helpful_error_message_for_foreign_keys(self):
- """
- Invalid foreign keys with a natural key should throw a helpful error
- message, such as what the failing key is.
- """
- test_string = """[{
- "pk": 1,
- "model": "serializers.category",
- "fields": {
- "name": "Unknown foreign key",
- "meta_data": [
- "doesnotexist",
- "metadata"
- ]
- }
- }]"""
- key = ["doesnotexist", "metadata"]
- expected = "(serializers.category:pk=1) field_value was '%r'" % key
- with self.assertRaisesMessage(DeserializationError, expected):
- list(serializers.deserialize('json', test_string))
- def test_helpful_error_message_for_many2many_non_natural(self):
- """
- Invalid many-to-many keys should throw a helpful error message.
- """
- test_string = """[{
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "author": 1,
- "headline": "Unknown many to many",
- "pub_date": "2014-09-15T10:35:00",
- "categories": [1, "doesnotexist"]
- }
- }, {
- "pk": 1,
- "model": "serializers.author",
- "fields": {
- "name": "Agnes"
- }
- }, {
- "pk": 1,
- "model": "serializers.category",
- "fields": {
- "name": "Reference"
- }
- }]"""
- expected = "(serializers.article:pk=1) field_value was 'doesnotexist'"
- with self.assertRaisesMessage(DeserializationError, expected):
- list(serializers.deserialize('json', test_string))
- def test_helpful_error_message_for_many2many_natural1(self):
- """
- Invalid many-to-many keys should throw a helpful error message.
- This tests the code path where one of a list of natural keys is invalid.
- """
- test_string = """[{
- "pk": 1,
- "model": "serializers.categorymetadata",
- "fields": {
- "kind": "author",
- "name": "meta1",
- "value": "Agnes"
- }
- }, {
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "author": 1,
- "headline": "Unknown many to many",
- "pub_date": "2014-09-15T10:35:00",
- "meta_data": [
- ["author", "meta1"],
- ["doesnotexist", "meta1"],
- ["author", "meta1"]
- ]
- }
- }, {
- "pk": 1,
- "model": "serializers.author",
- "fields": {
- "name": "Agnes"
- }
- }]"""
- key = ["doesnotexist", "meta1"]
- expected = "(serializers.article:pk=1) field_value was '%r'" % key
- with self.assertRaisesMessage(DeserializationError, expected):
- for obj in serializers.deserialize('json', test_string):
- obj.save()
- def test_helpful_error_message_for_many2many_natural2(self):
- """
- Invalid many-to-many keys should throw a helpful error message. This
- tests the code path where a natural many-to-many key has only a single
- value.
- """
- test_string = """[{
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "author": 1,
- "headline": "Unknown many to many",
- "pub_date": "2014-09-15T10:35:00",
- "meta_data": [1, "doesnotexist"]
- }
- }, {
- "pk": 1,
- "model": "serializers.categorymetadata",
- "fields": {
- "kind": "author",
- "name": "meta1",
- "value": "Agnes"
- }
- }, {
- "pk": 1,
- "model": "serializers.author",
- "fields": {
- "name": "Agnes"
- }
- }]"""
- expected = "(serializers.article:pk=1) field_value was 'doesnotexist'"
- with self.assertRaisesMessage(DeserializationError, expected):
- for obj in serializers.deserialize('json', test_string, ignore=False):
- obj.save()
- class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
- serializer_name = "json"
- fwd_ref_str = """[
- {
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "headline": "Forward references pose no problem",
- "pub_date": "2006-06-16T15:00:00",
- "categories": [1],
- "author": 1
- }
- },
- {
- "pk": 1,
- "model": "serializers.category",
- "fields": {
- "name": "Reference"
- }
- },
- {
- "pk": 1,
- "model": "serializers.author",
- "fields": {
- "name": "Agnes"
- }
- }]"""
- class DjangoJSONEncoderTests(SimpleTestCase):
- def test_lazy_string_encoding(self):
- self.assertEqual(
- json.dumps({'lang': ugettext_lazy("French")}, cls=DjangoJSONEncoder),
- '{"lang": "French"}'
- )
- with override('fr'):
- self.assertEqual(
- json.dumps({'lang': ugettext_lazy("French")}, cls=DjangoJSONEncoder),
- '{"lang": "Fran\\u00e7ais"}'
- )
|