# -*- coding: utf-8 -*- from __future__ import unicode_literals import json import re from django.core import serializers from django.core.serializers.base import DeserializationError from django.test import TestCase, TransactionTestCase 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()) 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" } }]"""