diff options
Diffstat (limited to 'djangorestframework/tests')
| -rw-r--r-- | djangorestframework/tests/accept.py | 14 | ||||
| -rw-r--r-- | djangorestframework/tests/authentication.py | 5 | ||||
| -rw-r--r-- | djangorestframework/tests/content.py | 233 | ||||
| -rw-r--r-- | djangorestframework/tests/files.py | 9 | ||||
| -rw-r--r-- | djangorestframework/tests/methods.py | 32 | ||||
| -rw-r--r-- | djangorestframework/tests/mixins.py | 53 | ||||
| -rw-r--r-- | djangorestframework/tests/renderers.py | 193 | ||||
| -rw-r--r-- | djangorestframework/tests/request.py | 248 | ||||
| -rw-r--r-- | djangorestframework/tests/response.py | 301 | ||||
| -rw-r--r-- | djangorestframework/tests/reverse.py | 3 | ||||
| -rw-r--r-- | djangorestframework/tests/throttling.py | 3 | ||||
| -rw-r--r-- | djangorestframework/tests/validators.py | 32 |
12 files changed, 610 insertions, 516 deletions
diff --git a/djangorestframework/tests/accept.py b/djangorestframework/tests/accept.py index d66f6fb0..e7dfc303 100644 --- a/djangorestframework/tests/accept.py +++ b/djangorestframework/tests/accept.py @@ -1,6 +1,8 @@ from django.test import TestCase + from djangorestframework.compat import RequestFactory from djangorestframework.views import View +from djangorestframework.response import Response # See: http://www.useragentstring.com/ @@ -21,9 +23,10 @@ class UserAgentMungingTest(TestCase): class MockView(View): permissions = () + response_class = Response def get(self, request): - return {'a':1, 'b':2, 'c':3} + return self.response_class({'a':1, 'b':2, 'c':3}) self.req = RequestFactory() self.MockView = MockView @@ -37,18 +40,22 @@ class UserAgentMungingTest(TestCase): MSIE_7_USER_AGENT): req = self.req.get('/', HTTP_ACCEPT='*/*', HTTP_USER_AGENT=user_agent) resp = self.view(req) + resp.render() self.assertEqual(resp['Content-Type'], 'text/html') - + def test_dont_rewrite_msie_accept_header(self): """Turn off _IGNORE_IE_ACCEPT_HEADER, send MSIE user agent strings and ensure that we get a JSON response if we set a */* accept header.""" - view = self.MockView.as_view(_IGNORE_IE_ACCEPT_HEADER=False) + class IgnoreIEAcceptResponse(Response): + _IGNORE_IE_ACCEPT_HEADER=False + view = self.MockView.as_view(response_class=IgnoreIEAcceptResponse) for user_agent in (MSIE_9_USER_AGENT, MSIE_8_USER_AGENT, MSIE_7_USER_AGENT): req = self.req.get('/', HTTP_ACCEPT='*/*', HTTP_USER_AGENT=user_agent) resp = view(req) + resp.render() self.assertEqual(resp['Content-Type'], 'application/json') def test_dont_munge_nice_browsers_accept_header(self): @@ -61,5 +68,6 @@ class UserAgentMungingTest(TestCase): OPERA_11_0_OPERA_USER_AGENT): req = self.req.get('/', HTTP_ACCEPT='*/*', HTTP_USER_AGENT=user_agent) resp = self.view(req) + resp.render() self.assertEqual(resp['Content-Type'], 'application/json') diff --git a/djangorestframework/tests/authentication.py b/djangorestframework/tests/authentication.py index 303bf96b..25410b04 100644 --- a/djangorestframework/tests/authentication.py +++ b/djangorestframework/tests/authentication.py @@ -3,6 +3,7 @@ from django.contrib.auth.models import User from django.test import Client, TestCase from django.utils import simplejson as json +from django.http import HttpResponse from djangorestframework.views import View from djangorestframework import permissions @@ -14,10 +15,10 @@ class MockView(View): permissions = (permissions.IsAuthenticated,) def post(self, request): - return {'a': 1, 'b': 2, 'c': 3} + return HttpResponse({'a': 1, 'b': 2, 'c': 3}) def put(self, request): - return {'a': 1, 'b': 2, 'c': 3} + return HttpResponse({'a': 1, 'b': 2, 'c': 3}) urlpatterns = patterns('', (r'^$', MockView.as_view()), diff --git a/djangorestframework/tests/content.py b/djangorestframework/tests/content.py deleted file mode 100644 index 6bae8feb..00000000 --- a/djangorestframework/tests/content.py +++ /dev/null @@ -1,233 +0,0 @@ -""" -Tests for content parsing, and form-overloaded content parsing. -""" -from django.conf.urls.defaults import patterns -from django.contrib.auth.models import User -from django.test import TestCase, Client -from djangorestframework import status -from djangorestframework.authentication import UserLoggedInAuthentication -from djangorestframework.compat import RequestFactory, unittest -from djangorestframework.mixins import RequestMixin -from djangorestframework.parsers import FormParser, MultiPartParser, \ - PlainTextParser, JSONParser -from djangorestframework.response import Response -from djangorestframework.views import View - -class MockView(View): - authentication = (UserLoggedInAuthentication,) - def post(self, request): - if request.POST.get('example') is not None: - return Response(status.HTTP_200_OK) - - return Response(status.INTERNAL_SERVER_ERROR) - -urlpatterns = patterns('', - (r'^$', MockView.as_view()), -) - -class TestContentParsing(TestCase): - def setUp(self): - self.req = RequestFactory() - - def ensure_determines_no_content_GET(self, view): - """Ensure view.DATA returns None for GET request with no content.""" - view.request = self.req.get('/') - self.assertEqual(view.DATA, None) - - def ensure_determines_no_content_HEAD(self, view): - """Ensure view.DATA returns None for HEAD request.""" - view.request = self.req.head('/') - self.assertEqual(view.DATA, None) - - def ensure_determines_form_content_POST(self, view): - """Ensure view.DATA returns content for POST request with form content.""" - form_data = {'qwerty': 'uiop'} - view.parsers = (FormParser, MultiPartParser) - view.request = self.req.post('/', data=form_data) - self.assertEqual(view.DATA.items(), form_data.items()) - - def ensure_determines_non_form_content_POST(self, view): - """Ensure view.RAW_CONTENT returns content for POST request with non-form content.""" - content = 'qwerty' - content_type = 'text/plain' - view.parsers = (PlainTextParser,) - view.request = self.req.post('/', content, content_type=content_type) - self.assertEqual(view.DATA, content) - - def ensure_determines_form_content_PUT(self, view): - """Ensure view.RAW_CONTENT returns content for PUT request with form content.""" - form_data = {'qwerty': 'uiop'} - view.parsers = (FormParser, MultiPartParser) - view.request = self.req.put('/', data=form_data) - self.assertEqual(view.DATA.items(), form_data.items()) - - def ensure_determines_non_form_content_PUT(self, view): - """Ensure view.RAW_CONTENT returns content for PUT request with non-form content.""" - content = 'qwerty' - content_type = 'text/plain' - view.parsers = (PlainTextParser,) - view.request = self.req.post('/', content, content_type=content_type) - self.assertEqual(view.DATA, content) - - def test_standard_behaviour_determines_no_content_GET(self): - """Ensure view.DATA returns None for GET request with no content.""" - self.ensure_determines_no_content_GET(RequestMixin()) - - def test_standard_behaviour_determines_no_content_HEAD(self): - """Ensure view.DATA returns None for HEAD request.""" - self.ensure_determines_no_content_HEAD(RequestMixin()) - - def test_standard_behaviour_determines_form_content_POST(self): - """Ensure view.DATA returns content for POST request with form content.""" - self.ensure_determines_form_content_POST(RequestMixin()) - - def test_standard_behaviour_determines_non_form_content_POST(self): - """Ensure view.DATA returns content for POST request with non-form content.""" - self.ensure_determines_non_form_content_POST(RequestMixin()) - - def test_standard_behaviour_determines_form_content_PUT(self): - """Ensure view.DATA returns content for PUT request with form content.""" - self.ensure_determines_form_content_PUT(RequestMixin()) - - def test_standard_behaviour_determines_non_form_content_PUT(self): - """Ensure view.DATA returns content for PUT request with non-form content.""" - self.ensure_determines_non_form_content_PUT(RequestMixin()) - - def test_overloaded_behaviour_allows_content_tunnelling(self): - """Ensure request.DATA returns content for overloaded POST request""" - content = 'qwerty' - content_type = 'text/plain' - view = RequestMixin() - form_data = {view._CONTENT_PARAM: content, - view._CONTENTTYPE_PARAM: content_type} - view.request = self.req.post('/', form_data) - view.parsers = (PlainTextParser,) - self.assertEqual(view.DATA, content) - - def test_accessing_post_after_data_form(self): - """Ensures request.POST can be accessed after request.DATA in form request""" - form_data = {'qwerty': 'uiop'} - view = RequestMixin() - view.parsers = (FormParser, MultiPartParser) - view.request = self.req.post('/', data=form_data) - - self.assertEqual(view.DATA.items(), form_data.items()) - self.assertEqual(view.request.POST.items(), form_data.items()) - - @unittest.skip('This test was disabled some time ago for some reason') - def test_accessing_post_after_data_for_json(self): - """Ensures request.POST can be accessed after request.DATA in json request""" - from django.utils import simplejson as json - - data = {'qwerty': 'uiop'} - content = json.dumps(data) - content_type = 'application/json' - - view = RequestMixin() - view.parsers = (JSONParser,) - - view.request = self.req.post('/', content, content_type=content_type) - - self.assertEqual(view.DATA.items(), data.items()) - self.assertEqual(view.request.POST.items(), []) - - def test_accessing_post_after_data_for_overloaded_json(self): - """Ensures request.POST can be accessed after request.DATA in overloaded json request""" - from django.utils import simplejson as json - - data = {'qwerty': 'uiop'} - content = json.dumps(data) - content_type = 'application/json' - - view = RequestMixin() - view.parsers = (JSONParser,) - - form_data = {view._CONTENT_PARAM: content, - view._CONTENTTYPE_PARAM: content_type} - - view.request = self.req.post('/', data=form_data) - - self.assertEqual(view.DATA.items(), data.items()) - self.assertEqual(view.request.POST.items(), form_data.items()) - - def test_accessing_data_after_post_form(self): - """Ensures request.DATA can be accessed after request.POST in form request""" - form_data = {'qwerty': 'uiop'} - view = RequestMixin() - view.parsers = (FormParser, MultiPartParser) - view.request = self.req.post('/', data=form_data) - - self.assertEqual(view.request.POST.items(), form_data.items()) - self.assertEqual(view.DATA.items(), form_data.items()) - - def test_accessing_data_after_post_for_json(self): - """Ensures request.DATA can be accessed after request.POST in json request""" - from django.utils import simplejson as json - - data = {'qwerty': 'uiop'} - content = json.dumps(data) - content_type = 'application/json' - - view = RequestMixin() - view.parsers = (JSONParser,) - - view.request = self.req.post('/', content, content_type=content_type) - - post_items = view.request.POST.items() - - self.assertEqual(len(post_items), 1) - self.assertEqual(len(post_items[0]), 2) - self.assertEqual(post_items[0][0], content) - self.assertEqual(view.DATA.items(), data.items()) - - def test_accessing_data_after_post_for_overloaded_json(self): - """Ensures request.DATA can be accessed after request.POST in overloaded json request""" - from django.utils import simplejson as json - - data = {'qwerty': 'uiop'} - content = json.dumps(data) - content_type = 'application/json' - - view = RequestMixin() - view.parsers = (JSONParser,) - - form_data = {view._CONTENT_PARAM: content, - view._CONTENTTYPE_PARAM: content_type} - - view.request = self.req.post('/', data=form_data) - - self.assertEqual(view.request.POST.items(), form_data.items()) - self.assertEqual(view.DATA.items(), data.items()) - -class TestContentParsingWithAuthentication(TestCase): - urls = 'djangorestframework.tests.content' - - def setUp(self): - self.csrf_client = Client(enforce_csrf_checks=True) - self.username = 'john' - self.email = 'lennon@thebeatles.com' - self.password = 'password' - self.user = User.objects.create_user(self.username, self.email, self.password) - self.req = RequestFactory() - - def test_user_logged_in_authentication_has_post_when_not_logged_in(self): - """Ensures request.POST exists after UserLoggedInAuthentication when user doesn't log in""" - content = {'example': 'example'} - - response = self.client.post('/', content) - self.assertEqual(status.HTTP_200_OK, response.status_code, "POST data is malformed") - - response = self.csrf_client.post('/', content) - self.assertEqual(status.HTTP_200_OK, response.status_code, "POST data is malformed") - - # def test_user_logged_in_authentication_has_post_when_logged_in(self): - # """Ensures request.POST exists after UserLoggedInAuthentication when user does log in""" - # self.client.login(username='john', password='password') - # self.csrf_client.login(username='john', password='password') - # content = {'example': 'example'} - - # response = self.client.post('/', content) - # self.assertEqual(status.OK, response.status_code, "POST data is malformed") - - # response = self.csrf_client.post('/', content) - # self.assertEqual(status.OK, response.status_code, "POST data is malformed") diff --git a/djangorestframework/tests/files.py b/djangorestframework/tests/files.py index d3b1cc56..bbdff70b 100644 --- a/djangorestframework/tests/files.py +++ b/djangorestframework/tests/files.py @@ -1,8 +1,11 @@ from django.test import TestCase from django import forms + from djangorestframework.compat import RequestFactory from djangorestframework.views import View from djangorestframework.resources import FormResource +from djangorestframework.response import Response + import StringIO class UploadFilesTests(TestCase): @@ -20,13 +23,13 @@ class UploadFilesTests(TestCase): form = FileForm def post(self, request, *args, **kwargs): - return {'FILE_NAME': self.CONTENT['file'].name, - 'FILE_CONTENT': self.CONTENT['file'].read()} + return Response({'FILE_NAME': self.CONTENT['file'].name, + 'FILE_CONTENT': self.CONTENT['file'].read()}) file = StringIO.StringIO('stuff') file.name = 'stuff.txt' request = self.factory.post('/', {'file': file}) view = MockView.as_view() response = view(request) - self.assertEquals(response.content, '{"FILE_CONTENT": "stuff", "FILE_NAME": "stuff.txt"}') + self.assertEquals(response.raw_content, {"FILE_CONTENT": "stuff", "FILE_NAME": "stuff.txt"}) diff --git a/djangorestframework/tests/methods.py b/djangorestframework/tests/methods.py index 4b90a21f..e69de29b 100644 --- a/djangorestframework/tests/methods.py +++ b/djangorestframework/tests/methods.py @@ -1,32 +0,0 @@ -from django.test import TestCase -from djangorestframework.compat import RequestFactory -from djangorestframework.mixins import RequestMixin - - -class TestMethodOverloading(TestCase): - def setUp(self): - self.req = RequestFactory() - - def test_standard_behaviour_determines_GET(self): - """GET requests identified""" - view = RequestMixin() - view.request = self.req.get('/') - self.assertEqual(view.method, 'GET') - - def test_standard_behaviour_determines_POST(self): - """POST requests identified""" - view = RequestMixin() - view.request = self.req.post('/') - self.assertEqual(view.method, 'POST') - - def test_overloaded_POST_behaviour_determines_overloaded_method(self): - """POST requests can be overloaded to another method by setting a reserved form field""" - view = RequestMixin() - view.request = self.req.post('/', {view._METHOD_PARAM: 'DELETE'}) - self.assertEqual(view.method, 'DELETE') - - def test_HEAD_is_a_valid_method(self): - """HEAD requests identified""" - view = RequestMixin() - view.request = self.req.head('/') - self.assertEqual(view.method, 'HEAD') diff --git a/djangorestframework/tests/mixins.py b/djangorestframework/tests/mixins.py index 8268fdca..85c95d61 100644 --- a/djangorestframework/tests/mixins.py +++ b/djangorestframework/tests/mixins.py @@ -6,7 +6,7 @@ from djangorestframework.compat import RequestFactory from django.contrib.auth.models import Group, User from djangorestframework.mixins import CreateModelMixin, PaginatorMixin, ReadModelMixin from djangorestframework.resources import ModelResource -from djangorestframework.response import Response, ErrorResponse +from djangorestframework.response import Response, ImmediateResponse from djangorestframework.tests.models import CustomUser from djangorestframework.tests.testcases import TestModelsTestCase from djangorestframework.views import View @@ -31,7 +31,7 @@ class TestModelRead(TestModelsTestCase): mixin.resource = GroupResource response = mixin.get(request, id=group.id) - self.assertEquals(group.name, response.name) + self.assertEquals(group.name, response.raw_content.name) def test_read_404(self): class GroupResource(ModelResource): @@ -41,7 +41,7 @@ class TestModelRead(TestModelsTestCase): mixin = ReadModelMixin() mixin.resource = GroupResource - self.assertRaises(ErrorResponse, mixin.get, request, id=12345) + self.assertRaises(ImmediateResponse, mixin.get, request, id=12345) class TestModelCreation(TestModelsTestCase): @@ -65,7 +65,7 @@ class TestModelCreation(TestModelsTestCase): response = mixin.post(request) self.assertEquals(1, Group.objects.count()) - self.assertEquals('foo', response.cleaned_content.name) + self.assertEquals('foo', response.raw_content.name) def test_creation_with_m2m_relation(self): class UserResource(ModelResource): @@ -91,8 +91,8 @@ class TestModelCreation(TestModelsTestCase): response = mixin.post(request) self.assertEquals(1, User.objects.count()) - self.assertEquals(1, response.cleaned_content.groups.count()) - self.assertEquals('foo', response.cleaned_content.groups.all()[0].name) + self.assertEquals(1, response.raw_content.groups.count()) + self.assertEquals('foo', response.raw_content.groups.all()[0].name) def test_creation_with_m2m_relation_through(self): """ @@ -114,7 +114,7 @@ class TestModelCreation(TestModelsTestCase): response = mixin.post(request) self.assertEquals(1, CustomUser.objects.count()) - self.assertEquals(0, response.cleaned_content.groups.count()) + self.assertEquals(0, response.raw_content.groups.count()) group = Group(name='foo1') group.save() @@ -129,8 +129,8 @@ class TestModelCreation(TestModelsTestCase): response = mixin.post(request) self.assertEquals(2, CustomUser.objects.count()) - self.assertEquals(1, response.cleaned_content.groups.count()) - self.assertEquals('foo1', response.cleaned_content.groups.all()[0].name) + self.assertEquals(1, response.raw_content.groups.count()) + self.assertEquals('foo1', response.raw_content.groups.all()[0].name) group2 = Group(name='foo2') group2.save() @@ -145,19 +145,19 @@ class TestModelCreation(TestModelsTestCase): response = mixin.post(request) self.assertEquals(3, CustomUser.objects.count()) - self.assertEquals(2, response.cleaned_content.groups.count()) - self.assertEquals('foo1', response.cleaned_content.groups.all()[0].name) - self.assertEquals('foo2', response.cleaned_content.groups.all()[1].name) + self.assertEquals(2, response.raw_content.groups.count()) + self.assertEquals('foo1', response.raw_content.groups.all()[0].name) + self.assertEquals('foo2', response.raw_content.groups.all()[1].name) class MockPaginatorView(PaginatorMixin, View): total = 60 def get(self, request): - return range(0, self.total) + return Response(range(0, self.total)) def post(self, request): - return Response(status.HTTP_201_CREATED, {'status': 'OK'}) + return Response({'status': 'OK'}, status=status.HTTP_201_CREATED) class TestPagination(TestCase): @@ -168,8 +168,7 @@ class TestPagination(TestCase): """ Tests if pagination works without overwriting the limit """ request = self.req.get('/paginator') response = MockPaginatorView.as_view()(request) - - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(MockPaginatorView.total, content['total']) @@ -183,8 +182,7 @@ class TestPagination(TestCase): request = self.req.get('/paginator') response = MockPaginatorView.as_view(limit=limit)(request) - - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(content['per_page'], limit) @@ -200,8 +198,7 @@ class TestPagination(TestCase): request = self.req.get('/paginator/?limit=%d' % limit) response = MockPaginatorView.as_view()(request) - - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(MockPaginatorView.total, content['total']) @@ -217,8 +214,7 @@ class TestPagination(TestCase): request = self.req.get('/paginator/?limit=%d' % limit) response = MockPaginatorView.as_view()(request) - - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(MockPaginatorView.total, content['total']) @@ -230,8 +226,7 @@ class TestPagination(TestCase): """ Pagination should only work for GET requests """ request = self.req.post('/paginator', data={'content': 'spam'}) response = MockPaginatorView.as_view()(request) - - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(None, content.get('per_page')) @@ -248,12 +243,12 @@ class TestPagination(TestCase): """ Tests that the page range is handle correctly """ request = self.req.get('/paginator/?page=0') response = MockPaginatorView.as_view()(request) - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) request = self.req.get('/paginator/') response = MockPaginatorView.as_view()(request) - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(range(0, MockPaginatorView.limit), content['results']) @@ -261,13 +256,13 @@ class TestPagination(TestCase): request = self.req.get('/paginator/?page=%d' % num_pages) response = MockPaginatorView.as_view()(request) - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(range(MockPaginatorView.limit*(num_pages-1), MockPaginatorView.total), content['results']) request = self.req.get('/paginator/?page=%d' % (num_pages + 1,)) response = MockPaginatorView.as_view()(request) - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_existing_query_parameters_are_preserved(self): @@ -275,7 +270,7 @@ class TestPagination(TestCase): generating next/previous page links """ request = self.req.get('/paginator/?foo=bar&another=something') response = MockPaginatorView.as_view()(request) - content = json.loads(response.content) + content = response.raw_content self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue('foo=bar' in content['next']) self.assertTrue('another=something' in content['next']) diff --git a/djangorestframework/tests/renderers.py b/djangorestframework/tests/renderers.py index 9a02d0a9..cc211dce 100644 --- a/djangorestframework/tests/renderers.py +++ b/djangorestframework/tests/renderers.py @@ -1,177 +1,20 @@ import re +from django.test import TestCase + from django.conf.urls.defaults import patterns, url from django.test import TestCase -from djangorestframework import status +from djangorestframework.response import Response from djangorestframework.views import View -from djangorestframework.compat import View as DjangoView from djangorestframework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \ XMLRenderer, JSONPRenderer, DocumentingHTMLRenderer from djangorestframework.parsers import JSONParser, YAMLParser, XMLParser -from djangorestframework.mixins import ResponseMixin -from djangorestframework.response import Response from StringIO import StringIO import datetime from decimal import Decimal -DUMMYSTATUS = status.HTTP_200_OK -DUMMYCONTENT = 'dummycontent' - -RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x -RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x - - -class RendererA(BaseRenderer): - media_type = 'mock/renderera' - format = "formata" - - def render(self, obj=None, media_type=None): - return RENDERER_A_SERIALIZER(obj) - - -class RendererB(BaseRenderer): - media_type = 'mock/rendererb' - format = "formatb" - - def render(self, obj=None, media_type=None): - return RENDERER_B_SERIALIZER(obj) - - -class MockView(ResponseMixin, DjangoView): - renderers = (RendererA, RendererB) - - def get(self, request, **kwargs): - response = Response(DUMMYSTATUS, DUMMYCONTENT) - return self.render(response) - - -class MockGETView(View): - - def get(self, request, **kwargs): - return {'foo': ['bar', 'baz']} - - -class HTMLView(View): - renderers = (DocumentingHTMLRenderer, ) - - def get(self, request, **kwargs): - return 'text' - - -class HTMLView1(View): - renderers = (DocumentingHTMLRenderer, JSONRenderer) - - def get(self, request, **kwargs): - return 'text' - -urlpatterns = patterns('', - url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderers=[RendererA, RendererB])), - url(r'^$', MockView.as_view(renderers=[RendererA, RendererB])), - url(r'^jsonp/jsonrenderer$', MockGETView.as_view(renderers=[JSONRenderer, JSONPRenderer])), - url(r'^jsonp/nojsonrenderer$', MockGETView.as_view(renderers=[JSONPRenderer])), - url(r'^html$', HTMLView.as_view()), - url(r'^html1$', HTMLView1.as_view()), -) - - -class RendererIntegrationTests(TestCase): - """ - End-to-end testing of renderers using an RendererMixin on a generic view. - """ - - urls = 'djangorestframework.tests.renderers' - - def test_default_renderer_serializes_content(self): - """If the Accept header is not set the default renderer should serialize the response.""" - resp = self.client.get('/') - self.assertEquals(resp['Content-Type'], RendererA.media_type) - self.assertEquals(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_head_method_serializes_no_content(self): - """No response must be included in HEAD requests.""" - resp = self.client.head('/') - self.assertEquals(resp.status_code, DUMMYSTATUS) - self.assertEquals(resp['Content-Type'], RendererA.media_type) - self.assertEquals(resp.content, '') - - def test_default_renderer_serializes_content_on_accept_any(self): - """If the Accept header is set to */* the default renderer should serialize the response.""" - resp = self.client.get('/', HTTP_ACCEPT='*/*') - self.assertEquals(resp['Content-Type'], RendererA.media_type) - self.assertEquals(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_specified_renderer_serializes_content_default_case(self): - """If the Accept header is set the specified renderer should serialize the response. - (In this case we check that works for the default renderer)""" - resp = self.client.get('/', HTTP_ACCEPT=RendererA.media_type) - self.assertEquals(resp['Content-Type'], RendererA.media_type) - self.assertEquals(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_specified_renderer_serializes_content_non_default_case(self): - """If the Accept header is set the specified renderer should serialize the response. - (In this case we check that works for a non-default renderer)""" - resp = self.client.get('/', HTTP_ACCEPT=RendererB.media_type) - self.assertEquals(resp['Content-Type'], RendererB.media_type) - self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_specified_renderer_serializes_content_on_accept_query(self): - """The '_accept' query string should behave in the same way as the Accept header.""" - resp = self.client.get('/?_accept=%s' % RendererB.media_type) - self.assertEquals(resp['Content-Type'], RendererB.media_type) - self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_unsatisfiable_accept_header_on_request_returns_406_status(self): - """If the Accept header is unsatisfiable we should return a 406 Not Acceptable response.""" - resp = self.client.get('/', HTTP_ACCEPT='foo/bar') - self.assertEquals(resp.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_specified_renderer_serializes_content_on_format_query(self): - """If a 'format' query is specified, the renderer with the matching - format attribute should serialize the response.""" - resp = self.client.get('/?format=%s' % RendererB.format) - self.assertEquals(resp['Content-Type'], RendererB.media_type) - self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_specified_renderer_serializes_content_on_format_kwargs(self): - """If a 'format' keyword arg is specified, the renderer with the matching - format attribute should serialize the response.""" - resp = self.client.get('/something.formatb') - self.assertEquals(resp['Content-Type'], RendererB.media_type) - self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_specified_renderer_is_used_on_format_query_with_matching_accept(self): - """If both a 'format' query and a matching Accept header specified, - the renderer with the matching format attribute should serialize the response.""" - resp = self.client.get('/?format=%s' % RendererB.format, - HTTP_ACCEPT=RendererB.media_type) - self.assertEquals(resp['Content-Type'], RendererB.media_type) - self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_conflicting_format_query_and_accept_ignores_accept(self): - """If a 'format' query is specified that does not match the Accept - header, we should only honor the 'format' query string.""" - resp = self.client.get('/?format=%s' % RendererB.format, - HTTP_ACCEPT='dummy') - self.assertEquals(resp['Content-Type'], RendererB.media_type) - self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) - - def test_bla(self): - resp = self.client.get('/?format=formatb', - HTTP_ACCEPT='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8') - self.assertEquals(resp['Content-Type'], RendererB.media_type) - self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) - self.assertEquals(resp.status_code, DUMMYSTATUS) _flat_repr = '{"foo": ["bar", "baz"]}' _indented_repr = '{\n "foo": [\n "bar",\n "baz"\n ]\n}' @@ -223,6 +66,18 @@ class JSONRendererTests(TestCase): self.assertEquals(obj, data) +class MockGETView(View): + + def get(self, request, **kwargs): + return Response({'foo': ['bar', 'baz']}) + + +urlpatterns = patterns('', + url(r'^jsonp/jsonrenderer$', MockGETView.as_view(renderer_classes=[JSONRenderer, JSONPRenderer])), + url(r'^jsonp/nojsonrenderer$', MockGETView.as_view(renderer_classes=[JSONPRenderer])), +) + + class JSONPRendererTests(TestCase): """ Tests specific to the JSONP Renderer @@ -391,21 +246,3 @@ class XMLRendererTestCase(TestCase): self.assertTrue(xml.endswith('</root>')) self.assertTrue(string in xml, '%r not in %r' % (string, xml)) - -class Issue122Tests(TestCase): - """ - Tests that covers #122. - """ - urls = 'djangorestframework.tests.renderers' - - def test_only_html_renderer(self): - """ - Test if no infinite recursion occurs. - """ - resp = self.client.get('/html') - - def test_html_renderer_is_first(self): - """ - Test if no infinite recursion occurs. - """ - resp = self.client.get('/html1') diff --git a/djangorestframework/tests/request.py b/djangorestframework/tests/request.py new file mode 100644 index 00000000..c92d3f5f --- /dev/null +++ b/djangorestframework/tests/request.py @@ -0,0 +1,248 @@ +""" +Tests for content parsing, and form-overloaded content parsing. +""" +from django.conf.urls.defaults import patterns +from django.contrib.auth.models import User +from django.test import TestCase, Client +from djangorestframework import status +from djangorestframework.authentication import UserLoggedInAuthentication +from djangorestframework.compat import RequestFactory +from djangorestframework.mixins import RequestMixin +from djangorestframework.parsers import FormParser, MultiPartParser, \ + PlainTextParser, JSONParser +from djangorestframework.request import Request +from djangorestframework.response import Response +from djangorestframework.request import Request +from djangorestframework.views import View + + +class RequestTestCase(TestCase): + + def build_request(self, method, *args, **kwargs): + factory = RequestFactory() + method = getattr(factory, method) + original_request = method(*args, **kwargs) + return Request(original_request) + + +class TestMethodOverloading(RequestTestCase): + + def test_standard_behaviour_determines_GET(self): + """GET requests identified""" + request = self.build_request('get', '/') + self.assertEqual(request.method, 'GET') + + def test_standard_behaviour_determines_POST(self): + """POST requests identified""" + request = self.build_request('post', '/') + self.assertEqual(request.method, 'POST') + + def test_overloaded_POST_behaviour_determines_overloaded_method(self): + """POST requests can be overloaded to another method by setting a reserved form field""" + request = self.build_request('post', '/', {Request._METHOD_PARAM: 'DELETE'}) + self.assertEqual(request.method, 'DELETE') + + def test_HEAD_is_a_valid_method(self): + """HEAD requests identified""" + request = request = self.build_request('head', '/') + self.assertEqual(request.method, 'HEAD') + + +class TestContentParsing(RequestTestCase): + + def build_request(self, method, *args, **kwargs): + factory = RequestFactory() + parsers = kwargs.pop('parsers', None) + method = getattr(factory, method) + original_request = method(*args, **kwargs) + rkwargs = {} + if parsers is not None: + rkwargs['parsers'] = parsers + request = Request(original_request, **rkwargs) + # TODO: Just a hack because the parsers need a view. This will be fixed in the future + class Obj(object): pass + obj = Obj() + obj.request = request + for p in request.parsers: + p.view = obj + return request + + def test_standard_behaviour_determines_no_content_GET(self): + """Ensure request.DATA returns None for GET request with no content.""" + request = self.build_request('get', '/') + self.assertEqual(request.DATA, None) + + def test_standard_behaviour_determines_no_content_HEAD(self): + """Ensure request.DATA returns None for HEAD request.""" + request = self.build_request('head', '/') + self.assertEqual(request.DATA, None) + + def test_standard_behaviour_determines_form_content_POST(self): + """Ensure request.DATA returns content for POST request with form content.""" + form_data = {'qwerty': 'uiop'} + parsers = (FormParser(), MultiPartParser()) + + request = self.build_request('post', '/', data=form_data, parsers=parsers) + self.assertEqual(request.DATA.items(), form_data.items()) + + def test_standard_behaviour_determines_non_form_content_POST(self): + """Ensure request.DATA returns content for POST request with non-form content.""" + content = 'qwerty' + content_type = 'text/plain' + parsers = (PlainTextParser(),) + + request = self.build_request('post', '/', content, content_type=content_type, parsers=parsers) + self.assertEqual(request.DATA, content) + + def test_standard_behaviour_determines_form_content_PUT(self): + """Ensure request.DATA returns content for PUT request with form content.""" + form_data = {'qwerty': 'uiop'} + parsers = (FormParser(), MultiPartParser()) + + request = self.build_request('put', '/', data=form_data, parsers=parsers) + self.assertEqual(request.DATA.items(), form_data.items()) + + def test_standard_behaviour_determines_non_form_content_PUT(self): + """Ensure request.DATA returns content for PUT request with non-form content.""" + content = 'qwerty' + content_type = 'text/plain' + parsers = (PlainTextParser(),) + + request = self.build_request('put', '/', content, content_type=content_type, parsers=parsers) + self.assertEqual(request.DATA, content) + + def test_overloaded_behaviour_allows_content_tunnelling(self): + """Ensure request.DATA returns content for overloaded POST request""" + content = 'qwerty' + content_type = 'text/plain' + form_data = {Request._CONTENT_PARAM: content, + Request._CONTENTTYPE_PARAM: content_type} + parsers = (PlainTextParser(),) + + request = self.build_request('post', '/', form_data, parsers=parsers) + self.assertEqual(request.DATA, content) + + def test_accessing_post_after_data_form(self): + """Ensures request.POST can be accessed after request.DATA in form request""" + form_data = {'qwerty': 'uiop'} + parsers = (FormParser(), MultiPartParser()) + + request = self.build_request('post', '/', data=form_data) + self.assertEqual(request.DATA.items(), form_data.items()) + self.assertEqual(request.POST.items(), form_data.items()) + + def test_accessing_post_after_data_for_json(self): + """Ensures request.POST can be accessed after request.DATA in json request""" + from django.utils import simplejson as json + + data = {'qwerty': 'uiop'} + content = json.dumps(data) + content_type = 'application/json' + parsers = (JSONParser(),) + + request = self.build_request('post', '/', content, content_type=content_type, parsers=parsers) + self.assertEqual(request.DATA.items(), data.items()) + self.assertEqual(request.POST.items(), []) + + def test_accessing_post_after_data_for_overloaded_json(self): + """Ensures request.POST can be accessed after request.DATA in overloaded json request""" + from django.utils import simplejson as json + + data = {'qwerty': 'uiop'} + content = json.dumps(data) + content_type = 'application/json' + parsers = (JSONParser(),) + form_data = {Request._CONTENT_PARAM: content, + Request._CONTENTTYPE_PARAM: content_type} + + request = self.build_request('post', '/', data=form_data, parsers=parsers) + self.assertEqual(request.DATA.items(), data.items()) + self.assertEqual(request.POST.items(), form_data.items()) + + def test_accessing_data_after_post_form(self): + """Ensures request.DATA can be accessed after request.POST in form request""" + form_data = {'qwerty': 'uiop'} + parsers = (FormParser, MultiPartParser) + request = self.build_request('post', '/', data=form_data, parsers=parsers) + + self.assertEqual(request.POST.items(), form_data.items()) + self.assertEqual(request.DATA.items(), form_data.items()) + + def test_accessing_data_after_post_for_json(self): + """Ensures request.DATA can be accessed after request.POST in json request""" + from django.utils import simplejson as json + + data = {'qwerty': 'uiop'} + content = json.dumps(data) + content_type = 'application/json' + parsers = (JSONParser(),) + + request = self.build_request('post', '/', content, content_type=content_type, parsers=parsers) + post_items = request.POST.items() + + self.assertEqual(len(post_items), 1) + self.assertEqual(len(post_items[0]), 2) + self.assertEqual(post_items[0][0], content) + self.assertEqual(request.DATA.items(), data.items()) + + def test_accessing_data_after_post_for_overloaded_json(self): + """Ensures request.DATA can be accessed after request.POST in overloaded json request""" + from django.utils import simplejson as json + + data = {'qwerty': 'uiop'} + content = json.dumps(data) + content_type = 'application/json' + parsers = (JSONParser(),) + form_data = {Request._CONTENT_PARAM: content, + Request._CONTENTTYPE_PARAM: content_type} + + request = self.build_request('post', '/', data=form_data, parsers=parsers) + self.assertEqual(request.POST.items(), form_data.items()) + self.assertEqual(request.DATA.items(), data.items()) + + +class MockView(View): + authentication = (UserLoggedInAuthentication,) + def post(self, request): + if request.POST.get('example') is not None: + return Response(status=status.HTTP_200_OK) + + return Response(status=status.INTERNAL_SERVER_ERROR) + +urlpatterns = patterns('', + (r'^$', MockView.as_view()), +) + + +class TestContentParsingWithAuthentication(TestCase): + urls = 'djangorestframework.tests.request' + + def setUp(self): + self.csrf_client = Client(enforce_csrf_checks=True) + self.username = 'john' + self.email = 'lennon@thebeatles.com' + self.password = 'password' + self.user = User.objects.create_user(self.username, self.email, self.password) + self.req = RequestFactory() + + def test_user_logged_in_authentication_has_post_when_not_logged_in(self): + """Ensures request.POST exists after UserLoggedInAuthentication when user doesn't log in""" + content = {'example': 'example'} + + response = self.client.post('/', content) + self.assertEqual(status.HTTP_200_OK, response.status_code, "POST data is malformed") + + response = self.csrf_client.post('/', content) + self.assertEqual(status.HTTP_200_OK, response.status_code, "POST data is malformed") + + # def test_user_logged_in_authentication_has_post_when_logged_in(self): + # """Ensures request.POST exists after UserLoggedInAuthentication when user does log in""" + # self.client.login(username='john', password='password') + # self.csrf_client.login(username='john', password='password') + # content = {'example': 'example'} + + # response = self.client.post('/', content) + # self.assertEqual(status.OK, response.status_code, "POST data is malformed") + + # response = self.csrf_client.post('/', content) + # self.assertEqual(status.OK, response.status_code, "POST data is malformed") diff --git a/djangorestframework/tests/response.py b/djangorestframework/tests/response.py index d973deb4..95603680 100644 --- a/djangorestframework/tests/response.py +++ b/djangorestframework/tests/response.py @@ -1,19 +1,284 @@ -# Right now we expect this test to fail - I'm just going to leave it commented out. -# Looking forward to actually being able to raise ExpectedFailure sometime! -# -#from django.test import TestCase -#from djangorestframework.response import Response -# -# -#class TestResponse(TestCase): -# -# # Interface tests -# -# # This is mainly to remind myself that the Response interface needs to change slightly -# def test_response_interface(self): -# """Ensure the Response interface is as expected.""" -# response = Response() -# getattr(response, 'status') -# getattr(response, 'content') -# getattr(response, 'headers') +import json +import unittest +from django.conf.urls.defaults import patterns, url +from django.test import TestCase + +from djangorestframework.response import Response, ImmediateResponse +from djangorestframework.mixins import ResponseMixin +from djangorestframework.views import View +from djangorestframework.compat import View as DjangoView +from djangorestframework.renderers import BaseRenderer, DEFAULT_RENDERERS +from djangorestframework.compat import RequestFactory +from djangorestframework import status +from djangorestframework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \ + XMLRenderer, JSONPRenderer, DocumentingHTMLRenderer + + +class TestResponseDetermineRenderer(TestCase): + + def get_response(self, url='', accept_list=[], renderers=[]): + kwargs = {} + if accept_list is not None: + kwargs['HTTP_ACCEPT'] = HTTP_ACCEPT=','.join(accept_list) + request = RequestFactory().get(url, **kwargs) + return Response(request=request, renderers=renderers) + + def get_renderer_mock(self, media_type): + return type('RendererMock', (BaseRenderer,), { + 'media_type': media_type, + })() + + def test_determine_accept_list_accept_header(self): + """ + Test that determine_accept_list takes the Accept header. + """ + accept_list = ['application/pickle', 'application/json'] + response = self.get_response(accept_list=accept_list) + self.assertEqual(response._determine_accept_list(), accept_list) + + def test_determine_accept_list_default(self): + """ + Test that determine_accept_list takes the default renderer if Accept is not specified. + """ + response = self.get_response(accept_list=None) + self.assertEqual(response._determine_accept_list(), ['*/*']) + + def test_determine_accept_list_overriden_header(self): + """ + Test Accept header overriding. + """ + accept_list = ['application/pickle', 'application/json'] + response = self.get_response(url='?_accept=application/x-www-form-urlencoded', + accept_list=accept_list) + self.assertEqual(response._determine_accept_list(), ['application/x-www-form-urlencoded']) + + def test_determine_renderer(self): + """ + Test that right renderer is chosen, in the order of Accept list. + """ + accept_list = ['application/pickle', 'application/json'] + prenderer = self.get_renderer_mock('application/pickle') + jrenderer = self.get_renderer_mock('application/json') + + response = self.get_response(accept_list=accept_list, renderers=(prenderer, jrenderer)) + renderer, media_type = response._determine_renderer() + self.assertEqual(media_type, 'application/pickle') + self.assertTrue(renderer, prenderer) + + response = self.get_response(accept_list=accept_list, renderers=(jrenderer,)) + renderer, media_type = response._determine_renderer() + self.assertEqual(media_type, 'application/json') + self.assertTrue(renderer, jrenderer) + + def test_determine_renderer_default(self): + """ + Test determine renderer when Accept was not specified. + """ + prenderer = self.get_renderer_mock('application/pickle') + + response = self.get_response(accept_list=None, renderers=(prenderer,)) + renderer, media_type = response._determine_renderer() + self.assertEqual(media_type, '*/*') + self.assertTrue(renderer, prenderer) + + def test_determine_renderer_no_renderer(self): + """ + Test determine renderer when no renderer can satisfy the Accept list. + """ + accept_list = ['application/json'] + prenderer = self.get_renderer_mock('application/pickle') + + response = self.get_response(accept_list=accept_list, renderers=(prenderer,)) + self.assertRaises(ImmediateResponse, response._determine_renderer) + + +class TestResponseRenderContent(TestCase): + + def get_response(self, url='', accept_list=[], content=None): + request = RequestFactory().get(url, HTTP_ACCEPT=','.join(accept_list)) + return Response(request=request, content=content, renderers=[r() for r in DEFAULT_RENDERERS]) + + def test_render(self): + """ + Test rendering simple data to json. + """ + content = {'a': 1, 'b': [1, 2, 3]} + content_type = 'application/json' + response = self.get_response(accept_list=[content_type], content=content) + response.render() + self.assertEqual(json.loads(response.content), content) + self.assertEqual(response['Content-Type'], content_type) + + +DUMMYSTATUS = status.HTTP_200_OK +DUMMYCONTENT = 'dummycontent' + +RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x +RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x + + +class RendererA(BaseRenderer): + media_type = 'mock/renderera' + format = "formata" + + def render(self, obj=None, media_type=None): + return RENDERER_A_SERIALIZER(obj) + + +class RendererB(BaseRenderer): + media_type = 'mock/rendererb' + format = "formatb" + + def render(self, obj=None, media_type=None): + return RENDERER_B_SERIALIZER(obj) + + +class MockView(ResponseMixin, DjangoView): + renderer_classes = (RendererA, RendererB) + + def get(self, request, **kwargs): + response = Response(DUMMYCONTENT, status=DUMMYSTATUS) + self.response = self.prepare_response(response) + return self.response + + +class HTMLView(View): + renderer_classes = (DocumentingHTMLRenderer, ) + + def get(self, request, **kwargs): + return Response('text') + + +class HTMLView1(View): + renderer_classes = (DocumentingHTMLRenderer, JSONRenderer) + + def get(self, request, **kwargs): + return Response('text') + + +urlpatterns = patterns('', + url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderer_classes=[RendererA, RendererB])), + url(r'^$', MockView.as_view(renderer_classes=[RendererA, RendererB])), + url(r'^html$', HTMLView.as_view()), + url(r'^html1$', HTMLView1.as_view()), +) + + +# TODO: Clean tests bellow - remove duplicates with above, better unit testing, ... +class RendererIntegrationTests(TestCase): + """ + End-to-end testing of renderers using an ResponseMixin on a generic view. + """ + + urls = 'djangorestframework.tests.response' + + def test_default_renderer_serializes_content(self): + """If the Accept header is not set the default renderer should serialize the response.""" + resp = self.client.get('/') + self.assertEquals(resp['Content-Type'], RendererA.media_type) + self.assertEquals(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_head_method_serializes_no_content(self): + """No response must be included in HEAD requests.""" + resp = self.client.head('/') + self.assertEquals(resp.status_code, DUMMYSTATUS) + self.assertEquals(resp['Content-Type'], RendererA.media_type) + self.assertEquals(resp.content, '') + + def test_default_renderer_serializes_content_on_accept_any(self): + """If the Accept header is set to */* the default renderer should serialize the response.""" + resp = self.client.get('/', HTTP_ACCEPT='*/*') + self.assertEquals(resp['Content-Type'], RendererA.media_type) + self.assertEquals(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_specified_renderer_serializes_content_default_case(self): + """If the Accept header is set the specified renderer should serialize the response. + (In this case we check that works for the default renderer)""" + resp = self.client.get('/', HTTP_ACCEPT=RendererA.media_type) + self.assertEquals(resp['Content-Type'], RendererA.media_type) + self.assertEquals(resp.content, RENDERER_A_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_specified_renderer_serializes_content_non_default_case(self): + """If the Accept header is set the specified renderer should serialize the response. + (In this case we check that works for a non-default renderer)""" + resp = self.client.get('/', HTTP_ACCEPT=RendererB.media_type) + self.assertEquals(resp['Content-Type'], RendererB.media_type) + self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_specified_renderer_serializes_content_on_accept_query(self): + """The '_accept' query string should behave in the same way as the Accept header.""" + resp = self.client.get('/?_accept=%s' % RendererB.media_type) + self.assertEquals(resp['Content-Type'], RendererB.media_type) + self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + @unittest.skip('can\'t pass because view is a simple Django view and response is an ImmediateResponse') + def test_unsatisfiable_accept_header_on_request_returns_406_status(self): + """If the Accept header is unsatisfiable we should return a 406 Not Acceptable response.""" + resp = self.client.get('/', HTTP_ACCEPT='foo/bar') + self.assertEquals(resp.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_specified_renderer_serializes_content_on_format_query(self): + """If a 'format' query is specified, the renderer with the matching + format attribute should serialize the response.""" + resp = self.client.get('/?format=%s' % RendererB.format) + self.assertEquals(resp['Content-Type'], RendererB.media_type) + self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_specified_renderer_serializes_content_on_format_kwargs(self): + """If a 'format' keyword arg is specified, the renderer with the matching + format attribute should serialize the response.""" + resp = self.client.get('/something.formatb') + self.assertEquals(resp['Content-Type'], RendererB.media_type) + self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_specified_renderer_is_used_on_format_query_with_matching_accept(self): + """If both a 'format' query and a matching Accept header specified, + the renderer with the matching format attribute should serialize the response.""" + resp = self.client.get('/?format=%s' % RendererB.format, + HTTP_ACCEPT=RendererB.media_type) + self.assertEquals(resp['Content-Type'], RendererB.media_type) + self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_conflicting_format_query_and_accept_ignores_accept(self): + """If a 'format' query is specified that does not match the Accept + header, we should only honor the 'format' query string.""" + resp = self.client.get('/?format=%s' % RendererB.format, + HTTP_ACCEPT='dummy') + self.assertEquals(resp['Content-Type'], RendererB.media_type) + self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + def test_bla(self): + resp = self.client.get('/?format=formatb', + HTTP_ACCEPT='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8') + self.assertEquals(resp['Content-Type'], RendererB.media_type) + self.assertEquals(resp.content, RENDERER_B_SERIALIZER(DUMMYCONTENT)) + self.assertEquals(resp.status_code, DUMMYSTATUS) + + +class Issue122Tests(TestCase): + """ + Tests that covers #122. + """ + urls = 'djangorestframework.tests.response' + + def test_only_html_renderer(self): + """ + Test if no infinite recursion occurs. + """ + resp = self.client.get('/html') + + def test_html_renderer_is_first(self): + """ + Test if no infinite recursion occurs. + """ + resp = self.client.get('/html1') diff --git a/djangorestframework/tests/reverse.py b/djangorestframework/tests/reverse.py index 2d1ca79e..c49caca0 100644 --- a/djangorestframework/tests/reverse.py +++ b/djangorestframework/tests/reverse.py @@ -4,6 +4,7 @@ from django.test import TestCase from django.utils import simplejson as json from djangorestframework.views import View +from djangorestframework.response import Response class MockView(View): @@ -11,7 +12,7 @@ class MockView(View): permissions = () def get(self, request): - return reverse('another') + return Response(reverse('another')) urlpatterns = patterns('', url(r'^$', MockView.as_view()), diff --git a/djangorestframework/tests/throttling.py b/djangorestframework/tests/throttling.py index 7fdc6491..393c3ec8 100644 --- a/djangorestframework/tests/throttling.py +++ b/djangorestframework/tests/throttling.py @@ -10,13 +10,14 @@ from djangorestframework.compat import RequestFactory from djangorestframework.views import View from djangorestframework.permissions import PerUserThrottling, PerViewThrottling, PerResourceThrottling from djangorestframework.resources import FormResource +from djangorestframework.response import Response class MockView(View): permissions = ( PerUserThrottling, ) throttle = '3/sec' def get(self, request): - return 'foo' + return Response('foo') class MockView_PerViewThrottling(MockView): permissions = ( PerViewThrottling, ) diff --git a/djangorestframework/tests/validators.py b/djangorestframework/tests/validators.py index 15d92231..771b3125 100644 --- a/djangorestframework/tests/validators.py +++ b/djangorestframework/tests/validators.py @@ -2,7 +2,7 @@ from django import forms from django.db import models from django.test import TestCase from djangorestframework.resources import FormResource, ModelResource -from djangorestframework.response import ErrorResponse +from djangorestframework.response import ImmediateResponse from djangorestframework.views import View @@ -81,10 +81,10 @@ class TestNonFieldErrors(TestCase): content = {'field1': 'example1', 'field2': 'example2'} try: MockResource(view).validate_request(content, None) - except ErrorResponse, exc: - self.assertEqual(exc.response.raw_content, {'errors': [MockForm.ERROR_TEXT]}) + except ImmediateResponse, response: + self.assertEqual(response.raw_content, {'errors': [MockForm.ERROR_TEXT]}) else: - self.fail('ErrorResponse was not raised') + self.fail('ImmediateResponse was not raised') class TestFormValidation(TestCase): @@ -120,14 +120,14 @@ class TestFormValidation(TestCase): def validation_failure_raises_response_exception(self, validator): """If form validation fails a ResourceException 400 (Bad Request) should be raised.""" content = {} - self.assertRaises(ErrorResponse, validator.validate_request, content, None) + self.assertRaises(ImmediateResponse, validator.validate_request, content, None) def validation_does_not_allow_extra_fields_by_default(self, validator): """If some (otherwise valid) content includes fields that are not in the form then validation should fail. It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up broken clients more easily (eg submitting content with a misnamed field)""" content = {'qwerty': 'uiop', 'extra': 'extra'} - self.assertRaises(ErrorResponse, validator.validate_request, content, None) + self.assertRaises(ImmediateResponse, validator.validate_request, content, None) def validation_allows_extra_fields_if_explicitly_set(self, validator): """If we include an allowed_extra_fields paramater on _validate, then allow fields with those names.""" @@ -154,8 +154,8 @@ class TestFormValidation(TestCase): content = {} try: validator.validate_request(content, None) - except ErrorResponse, exc: - self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}}) + except ImmediateResponse, response: + self.assertEqual(response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}}) else: self.fail('ResourceException was not raised') @@ -164,8 +164,8 @@ class TestFormValidation(TestCase): content = {'qwerty': ''} try: validator.validate_request(content, None) - except ErrorResponse, exc: - self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}}) + except ImmediateResponse, response: + self.assertEqual(response.raw_content, {'field_errors': {'qwerty': ['This field is required.']}}) else: self.fail('ResourceException was not raised') @@ -174,8 +174,8 @@ class TestFormValidation(TestCase): content = {'qwerty': 'uiop', 'extra': 'extra'} try: validator.validate_request(content, None) - except ErrorResponse, exc: - self.assertEqual(exc.response.raw_content, {'field_errors': {'extra': ['This field does not exist.']}}) + except ImmediateResponse, response: + self.assertEqual(response.raw_content, {'field_errors': {'extra': ['This field does not exist.']}}) else: self.fail('ResourceException was not raised') @@ -184,8 +184,8 @@ class TestFormValidation(TestCase): content = {'qwerty': '', 'extra': 'extra'} try: validator.validate_request(content, None) - except ErrorResponse, exc: - self.assertEqual(exc.response.raw_content, {'field_errors': {'qwerty': ['This field is required.'], + except ImmediateResponse, response: + self.assertEqual(response.raw_content, {'field_errors': {'qwerty': ['This field is required.'], 'extra': ['This field does not exist.']}}) else: self.fail('ResourceException was not raised') @@ -307,14 +307,14 @@ class TestModelFormValidator(TestCase): It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up broken clients more easily (eg submitting content with a misnamed field)""" content = {'qwerty': 'example', 'uiop': 'example', 'readonly': 'read only', 'extra': 'extra'} - self.assertRaises(ErrorResponse, self.validator.validate_request, content, None) + self.assertRaises(ImmediateResponse, self.validator.validate_request, content, None) def test_validate_requires_fields_on_model_forms(self): """If some (otherwise valid) content includes fields that are not in the form then validation should fail. It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up broken clients more easily (eg submitting content with a misnamed field)""" content = {'readonly': 'read only'} - self.assertRaises(ErrorResponse, self.validator.validate_request, content, None) + self.assertRaises(ImmediateResponse, self.validator.validate_request, content, None) def test_validate_does_not_require_blankable_fields_on_model_forms(self): """Test standard ModelForm validation behaviour - fields with blank=True are not required.""" |
