mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 16:07:38 +03:00 
			
		
		
		
	Added tests
This commit is contained in:
		
							parent
							
								
									650111dc8c
								
							
						
					
					
						commit
						8a12f89aaa
					
				
							
								
								
									
										13
									
								
								README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								README.txt
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| # To install django-rest-framework... | ||||
| # | ||||
| # Requirements: | ||||
| #   python2.6 | ||||
| #   virtualenv | ||||
| 
 | ||||
| hg clone https://tomchristie@bitbucket.org/tomchristie/django-rest-framework | ||||
| cd django-rest-framework/ | ||||
| virtualenv --no-site-packages --distribute --python=python2.6 env | ||||
| source ./env/bin/activate | ||||
| pip install -r ./requirements.txt | ||||
| python ./src/manage.py test | ||||
| 
 | ||||
|  | @ -4,6 +4,14 @@ from rest import emitters, parsers | |||
| 
 | ||||
| class Resource(object): | ||||
| 
 | ||||
|     class HTTPException(Exception): | ||||
|         def __init__(self, status, content, headers): | ||||
|             self.status = status | ||||
|             self.content = content | ||||
|             self.headers = headers | ||||
| 
 | ||||
|     allowed_methods = ('GET',) | ||||
| 
 | ||||
|     callmap = { 'GET': 'read', 'POST': 'create',  | ||||
|                 'PUT': 'update', 'DELETE': 'delete' } | ||||
| 
 | ||||
|  | @ -17,6 +25,7 @@ class Resource(object): | |||
|                 'application/xml': parsers.XMLParser, | ||||
|                 'application/x-www-form-urlencoded': parsers.FormParser } | ||||
| 
 | ||||
| 
 | ||||
|     def __new__(cls, request, *args, **kwargs): | ||||
|         self = object.__new__(cls) | ||||
|         self.__init__() | ||||
|  | @ -28,7 +37,6 @@ class Resource(object): | |||
|     def _determine_parser(self, request): | ||||
|         """Return the appropriate parser for the input, given the client's 'Content-Type' header, | ||||
|         and the content types that this Resource knows how to parse.""" | ||||
|         print request.META | ||||
|         return self.parsers.values()[0] | ||||
|      | ||||
|         # TODO: Raise 415 Unsupported media type | ||||
|  | @ -79,25 +87,40 @@ class Resource(object): | |||
|                         (accept_mimetype == mimetype)): | ||||
|                             return (mimetype, emitter)       | ||||
| 
 | ||||
|         # TODO: Raise 406, Not Acceptable | ||||
|         raise self.HTTPException(406, {'status': 'Not Acceptable', | ||||
|                                        'accepts': ','.join(item[0] for item in self.emitters)}, {}) | ||||
| 
 | ||||
| 
 | ||||
|     def _handle_request(self, request, *args, **kwargs): | ||||
|         meth = request.method | ||||
|         method = request.method | ||||
| 
 | ||||
|         try: | ||||
|             if not method in self.allowed_methods: | ||||
|                 raise self.HTTPException(405, {'status': 'Method Not Allowed'}, {}) | ||||
|      | ||||
|             # Parse the HTTP Request content | ||||
|             func = getattr(self, self.callmap.get(method, '')) | ||||
|      | ||||
|             if method in ('PUT', 'POST'): | ||||
|                 parser = self._determine_parser(request) | ||||
|                 data = parser(self, request).parse(request.raw_post_data) | ||||
|                 (status, ret, headers) = func(data, request.META, *args, **kwargs) | ||||
|      | ||||
|             else: | ||||
|                 (status, ret, headers) = func(request.META, *args, **kwargs) | ||||
|         except self.HTTPException, exc: | ||||
|             (status, ret, headers) = (exc.status, exc.content, exc.headers) | ||||
| 
 | ||||
|         headers['Allow'] = ', '.join(self.allowed_methods) | ||||
|          | ||||
|         # Parse the HTTP Request content | ||||
|         if meth in ('PUT', 'POST'): | ||||
|             parser = self._determine_parser(request) | ||||
|             data = parser(self, request).parse(request.raw_post_data) | ||||
| 
 | ||||
|         if meth == "POST": | ||||
|             (status, ret, headers) = self.handle_post(data, request.META, *args, **kwargs) | ||||
|         else: | ||||
|             (status, ret, headers) = self.handle_get(request.META, *args, **kwargs) | ||||
| 
 | ||||
|         # Serialize the HTTP Response content | ||||
|         mimetype, emitter = self._determine_emitter(request) | ||||
|         try:         | ||||
|             mimetype, emitter = self._determine_emitter(request) | ||||
|         except self.HTTPException, exc: | ||||
|             (status, ret, headers) = (exc.status, exc.content, exc.headers) | ||||
|             mimetype, emitter = self.emitters[0] | ||||
|              | ||||
|         content = emitter(self, status, headers).emit(ret) | ||||
|         print mimetype, emitter, content | ||||
| 
 | ||||
|         # Build the HTTP Response | ||||
|         resp = HttpResponse(content, mimetype=mimetype, status=status) | ||||
|  | @ -106,8 +129,19 @@ class Resource(object): | |||
| 
 | ||||
|         return resp | ||||
| 
 | ||||
|     def handle_get(self): | ||||
|         raise NotImplementedError(self.handle_get) | ||||
|     def _not_implemented(self, operation): | ||||
|         resource_name = self.__class__.__name__ | ||||
|         return (500, {'status': 'Internal Server Error', | ||||
|                           'detail': '%s %s operation is permitted but has not been implemented' % (resource_name, operation)}, {}) | ||||
| 
 | ||||
|     def handle_post(self): | ||||
|         raise NotImplementedError(self.handle_post) | ||||
|     def read(self, headers={}, *args, **kwargs): | ||||
|         return self._not_implemented('read') | ||||
| 
 | ||||
|     def create(self, data=None, headers={}, *args, **kwargs): | ||||
|         return self._not_implemented('create') | ||||
|      | ||||
|     def update(self, data=None, headers={}, *args, **kwargs): | ||||
|         return self._not_implemented('update') | ||||
| 
 | ||||
|     def delete(self, headers={}, *args, **kwargs): | ||||
|         return self._not_implemented('delete') | ||||
|  |  | |||
|  | @ -75,7 +75,7 @@ MIDDLEWARE_CLASSES = ( | |||
|     'django.contrib.messages.middleware.MessageMiddleware', | ||||
| ) | ||||
| 
 | ||||
| ROOT_URLCONF = 'src.urls' | ||||
| ROOT_URLCONF = 'urls' | ||||
| 
 | ||||
| TEMPLATE_DIRS = ( | ||||
|     # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". | ||||
|  | @ -93,5 +93,6 @@ INSTALLED_APPS = ( | |||
|     'django.contrib.admin', | ||||
|     # Uncomment the next line to enable admin documentation: | ||||
|     # 'django.contrib.admindocs', | ||||
|     'testarchive', | ||||
|     'testapp', | ||||
|     'rest', | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										54
									
								
								src/testapp/tests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/testapp/tests.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| """ | ||||
| This file demonstrates two different styles of tests (one doctest and one | ||||
| unittest). These will both pass when you run "manage.py test". | ||||
| 
 | ||||
| Replace these with more appropriate tests for your application. | ||||
| """ | ||||
| 
 | ||||
| from django.test import TestCase | ||||
| from django.core.urlresolvers import reverse | ||||
| from testapp.views import ReadOnlyResource, MirroringWriteResource | ||||
| 
 | ||||
| class AcceptHeaderTests(TestCase): | ||||
|     def assert_accept_mimetype(self, mimetype, expect=None, expect_match=True): | ||||
|         """ | ||||
|         Assert that a request with given mimetype in the accept header, | ||||
|         gives a response with the appropriate content-type. | ||||
|         """ | ||||
|         if expect is None: | ||||
|             expect = mimetype | ||||
| 
 | ||||
|         resp = self.client.get(reverse(ReadOnlyResource), HTTP_ACCEPT=mimetype) | ||||
| 
 | ||||
|         if expect_match: | ||||
|             self.assertEquals(resp['content-type'], expect) | ||||
|         else: | ||||
|             self.assertNotEquals(resp['content-type'], expect) | ||||
| 
 | ||||
|     def test_accept_xml(self): | ||||
|         self.assert_accept_mimetype('application/xml') | ||||
| 
 | ||||
|     def test_accept_json(self): | ||||
|         self.assert_accept_mimetype('application/json') | ||||
| 
 | ||||
|     def test_accept_xml_prefered_to_json(self): | ||||
|         self.assert_accept_mimetype('application/xml,q=0.9;application/json,q=0.1', expect='application/xml') | ||||
| 
 | ||||
|     def test_accept_json_prefered_to_xml(self): | ||||
|         self.assert_accept_mimetype('application/json,q=0.9;application/xml,q=0.1', expect='application/json') | ||||
| 
 | ||||
|     def test_dont_accept_invalid(self): | ||||
|         self.assert_accept_mimetype('application/invalid', expect_match=False) | ||||
| 
 | ||||
|     def test_invalid_accept_header_returns_406(self): | ||||
|         resp = self.client.get(reverse(ReadOnlyResource), HTTP_ACCEPT='invalid/invalid') | ||||
|         self.assertEquals(resp.status_code, 406) | ||||
| 
 | ||||
| class AllowedMethodsTests(TestCase): | ||||
|     def test_write_on_read_only_resource_returns_405(self): | ||||
|         resp = self.client.put(reverse(ReadOnlyResource), {}) | ||||
|         self.assertEquals(resp.status_code, 405) | ||||
| 
 | ||||
|     def test_read_on_write_only_resource_returns_405(self): | ||||
|         resp = self.client.get(reverse(MirroringWriteResource)) | ||||
|         self.assertEquals(resp.status_code, 405) | ||||
							
								
								
									
										8
									
								
								src/testapp/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/testapp/urls.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| from django.conf.urls.defaults import patterns | ||||
| from testapp.views import ReadOnlyResource, MirroringWriteResource | ||||
| 
 | ||||
| 
 | ||||
| urlpatterns = patterns('', | ||||
|     (r'^read-only$', ReadOnlyResource), | ||||
|     (r'^mirroring-write$', MirroringWriteResource), | ||||
| ) | ||||
							
								
								
									
										21
									
								
								src/testapp/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/testapp/views.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| from decimal import Decimal | ||||
| from rest.resource import Resource | ||||
| 
 | ||||
| class ReadOnlyResource(Resource): | ||||
|     """This is my docstring | ||||
|     """ | ||||
|     allowed_methods = ('GET',) | ||||
| 
 | ||||
|     def read(self, headers={}, *args, **kwargs): | ||||
|         return (200, {'ExampleString': 'Example', | ||||
|                       'ExampleInt': 1, | ||||
|                       'ExampleDecimal': 1.0}, {}) | ||||
| 
 | ||||
| 
 | ||||
| class MirroringWriteResource(Resource): | ||||
|     """This is my docstring | ||||
|     """ | ||||
|     allowed_methods = ('PUT',) | ||||
| 
 | ||||
|     def create(self, data, headers={}, *args, **kwargs): | ||||
|         return (200, data, {}) | ||||
|  | @ -1,23 +0,0 @@ | |||
| """ | ||||
| This file demonstrates two different styles of tests (one doctest and one | ||||
| unittest). These will both pass when you run "manage.py test". | ||||
| 
 | ||||
| Replace these with more appropriate tests for your application. | ||||
| """ | ||||
| 
 | ||||
| from django.test import TestCase | ||||
| 
 | ||||
| class SimpleTest(TestCase): | ||||
|     def test_basic_addition(self): | ||||
|         """ | ||||
|         Tests that 1 + 1 always equals 2. | ||||
|         """ | ||||
|         self.failUnlessEqual(1 + 1, 3) | ||||
| 
 | ||||
| __test__ = {"doctest": """ | ||||
| Another way to test that 1 + 1 is equal to 2. | ||||
| 
 | ||||
| >>> 1 + 1 == 2 | ||||
| True | ||||
| """} | ||||
| 
 | ||||
|  | @ -1,7 +0,0 @@ | |||
| from django.conf.urls.defaults import patterns | ||||
| from testarchive.views import RootResource | ||||
| 
 | ||||
| 
 | ||||
| urlpatterns = patterns('', | ||||
|     (r'^$', RootResource), | ||||
| ) | ||||
|  | @ -1,8 +0,0 @@ | |||
| from rest.resource import Resource | ||||
| 
 | ||||
| class RootResource(Resource): | ||||
|     """This is my docstring | ||||
|     """ | ||||
| 
 | ||||
|     def handle_get(self, headers={}, *args, **kwargs): | ||||
|         return (200, {'Name': 'Test', 'Value': 1}, {'Location': 'BLAH'}) | ||||
|  | @ -5,7 +5,7 @@ admin.autodiscover() | |||
| 
 | ||||
| urlpatterns = patterns('', | ||||
|     # Example: | ||||
|     (r'^testarchive/', include('testarchive.urls')), | ||||
|     (r'^testapp/', include('testapp.urls')), | ||||
| 
 | ||||
|     # Uncomment the admin/doc line below to enable admin documentation: | ||||
|     (r'^admin/doc/', include('django.contrib.admindocs.urls')), | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user