Skip to content

Commit 3fa2354

Browse files
committed
100% code coverage
* removed untested/broken/old code * added tests for corner cases * added .coveragerc to omit __init__ files * cleaned up flake8 warnings
1 parent d5ca30a commit 3fa2354

File tree

10 files changed

+124
-31
lines changed

10 files changed

+124
-31
lines changed

.coveragerc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[run]
2+
omit =
3+
/*/__init__.py

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ tests/static/
1010
._*
1111
*.DS_Store
1212
*.komodoproject
13+
/htmlcov

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ before_script:
4141

4242
# command to run tests, e.g. python setup.py test
4343
script:
44-
- coverage run --source=rest_framework_gis,django_restframework_gis_tests runtests.py
44+
- coverage run --source=rest_framework_gis runtests.py
4545

4646
after_success:
4747
coveralls

rest_framework_gis/filters.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313

1414
try:
1515
import django_filters
16-
except ImportError:
16+
except ImportError: # pragma: no cover
1717
raise ImproperlyConfigured(
1818
'restframework-gis filters depend on package "django-filter" '
1919
'which is missing. Install with "pip install django-filter".'
2020
)
2121

22-
try:
22+
try: # pragma: no cover
2323
# django >= 1.8
2424
from django.contrib.gis.db.models.lookups import gis_lookups
25-
except ImportError:
25+
except ImportError: # pragma: no cover
2626
# django <= 1.7
2727
gis_lookups = models.sql.query.ALL_TERMS
2828

@@ -48,8 +48,7 @@ def get_filter_bbox(self, request):
4848
try:
4949
p1x, p1y, p2x, p2y = (float(n) for n in bbox_string.split(','))
5050
except ValueError:
51-
raise ParseError("Not valid bbox string in parameter %s."
52-
% self.bbox_param)
51+
raise ParseError('Invalid bbox string supplied for parameter {0}'.format(self.bbox_param))
5352

5453
x = Polygon.from_bbox((p1x, p1y, p2x, p2y))
5554
return x
@@ -101,8 +100,7 @@ def get_filter_bbox(self, request):
101100
try:
102101
z, x, y = (int(n) for n in tile_string.split('/'))
103102
except ValueError:
104-
raise ParseError("Not valid tile string in parameter %s."
105-
% self.tile_param)
103+
raise ParseError('Invalid tile string supplied for parameter {0}'.format(self.tile_param))
106104

107105
bbox = Polygon.from_bbox(tile_edges(x, y, z))
108106
return bbox
@@ -120,8 +118,7 @@ def get_filter_point(self, request):
120118
try:
121119
(x, y) = (float(n) for n in point_string.split(','))
122120
except ValueError:
123-
raise ParseError("Not valid geometry string in parameter %s."
124-
% self.point_param)
121+
raise ParseError('Invalid geometry string supplied for parameter {0}'.format(self.point_param))
125122

126123
p = Point(x, y)
127124
return p
@@ -148,8 +145,8 @@ def dist_to_deg(self, distance, latitude):
148145
"""
149146
# d * (180 / pi) / earthRadius ==> degrees longitude
150147
# (degrees longitude) / cos(latitude) ==> degrees latitude
151-
lat = latitude if latitude >= 0 else -1*latitude
152-
rad2deg = 180/pi
148+
lat = latitude if latitude >= 0 else -1 * latitude
149+
rad2deg = 180 / pi
153150
earthRadius = 6378160.0
154151
latitudeCorrection = 0.5 * (1 + cos(lat * pi / 180))
155152
return (distance / (earthRadius * latitudeCorrection) * rad2deg)
@@ -171,8 +168,7 @@ def filter_queryset(self, request, queryset, view):
171168
try:
172169
dist = float(dist_string)
173170
except ValueError:
174-
raise ParseError("Not valid distance string in parameter %s."
175-
% self.dist_param)
171+
raise ParseError('Invalid distance string supplied for parameter {0}'.format(self.dist_param))
176172

177173
if (convert_distance_input):
178174
# Warning: assumes that the point is (lon,lat)

rest_framework_gis/serializers.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
try:
99
from collections import OrderedDict
1010
# python 2.6
11-
except ImportError:
11+
except ImportError: # pragma: no cover
1212
from ordereddict import OrderedDict
1313

1414
from .fields import GeometryField, GeometrySerializerMethodField # noqa
@@ -68,14 +68,13 @@ def many_init(cls, *args, **kwargs):
6868
def __init__(self, *args, **kwargs):
6969
super(GeoFeatureModelSerializer, self).__init__(*args, **kwargs)
7070
self.Meta.id_field = getattr(self.Meta, 'id_field', self.Meta.model._meta.pk.name)
71-
if self.Meta.geo_field is None:
71+
if not hasattr(self.Meta, 'geo_field') or not self.Meta.geo_field:
7272
raise ImproperlyConfigured("You must define a 'geo_field'.")
7373

7474
def check_excludes(field_name, field_role):
7575
"""make sure the field is not excluded"""
76-
if hasattr(self.Meta, 'exclude'):
77-
if field_name in self.Meta.exclude:
78-
raise ImproperlyConfigured("You cannot exclude your '{0}'.".format(field_role))
76+
if hasattr(self.Meta, 'exclude') and field_name in self.Meta.exclude:
77+
raise ImproperlyConfigured("You cannot exclude your '{0}'.".format(field_role))
7978

8079
def add_to_fields(field_name):
8180
"""Make sure the field is included in the fields"""
@@ -119,9 +118,6 @@ def to_representation(self, instance):
119118

120119
for field in fields:
121120
field_name = field.field_name
122-
if field.read_only and instance is None:
123-
continue
124-
125121
value = field.get_attribute(instance)
126122
value_repr = None
127123

@@ -160,12 +156,7 @@ def make_unformated_data(feature):
160156
_dict.update({self.Meta.bbox_geo_field: Polygon.from_bbox(feature['bbox'])})
161157
return _dict
162158

163-
if 'features' in data:
164-
_unformatted_data = []
165-
features = data['features']
166-
for feature in features:
167-
_unformatted_data.append(make_unformated_data(feature))
168-
elif 'properties' in data:
159+
if 'properties' in data:
169160
_unformatted_data = make_unformated_data(data)
170161
else:
171162
_unformatted_data = data

tests/django_restframework_gis_tests/serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class Meta:
5757
model = Location
5858
geo_field = 'geometry'
5959
id_field = 'slug'
60-
fields = ['name', 'slug']
60+
fields = ('name', 'slug')
6161

6262

6363
class LocationGeoFeatureFalseIDSerializer(LocationGeoFeatureSerializer):

tests/django_restframework_gis_tests/test_bbox.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
from django.test import TestCase
44
from django.core.urlresolvers import reverse
5+
from django.core.exceptions import ImproperlyConfigured
6+
7+
from rest_framework_gis import serializers as gis_serializers
58

69
from .models import BoxedLocation, Location
10+
from .serializers import LocationGeoSerializer
711

812

913
class TestRestFrameworkGisBBox(TestCase):
@@ -64,3 +68,14 @@ def test_get_autogenerated_location_bbox_geojson(self):
6468
self.assertEqual(response.status_code, 200)
6569
self.assertEqual(len(response.data['features']), 1)
6670
self.assertEqual(response.data['features'][0]['bbox'], self.l1.geometry.extent)
71+
72+
def test_bbox_improperly_configured(self):
73+
self._create_locations()
74+
class LocationGeoFeatureSerializer(gis_serializers.GeoFeatureModelSerializer):
75+
class Meta:
76+
model = Location
77+
geo_field = 'geometry'
78+
bbox_geo_field = 'geometry'
79+
auto_bbox = True
80+
with self.assertRaises(ImproperlyConfigured):
81+
LocationGeoFeatureSerializer(instance=self.l1)

tests/django_restframework_gis_tests/test_filters.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def test_DistanceToPointFilter_filtering(self):
128128
self.assertEqual(Location.objects.count(), 0)
129129

130130
# Filter parameters
131-
distance = 5000 #meters
131+
distance = 5000 # meters
132132
point_inside_ggpark = [-122.49034881591797, 37.76949349270407]
133133
point_on_golden_gate_bridge = [-122.47894, 37.8199]
134134
point_on_alcatraz = [-122.4222, 37.82667]
@@ -379,3 +379,56 @@ def test_GeometryField_filtering(self):
379379
# try without any param, should return both
380380
response = self.client.get(self.geojson_contained_in_geometry)
381381
self.assertEqual(len(response.data), 2)
382+
383+
def test_inBBOXFilter_filtering_none(self):
384+
url_params = '?in_bbox=&format=json'
385+
response = self.client.get(self.location_contained_in_bbox_list_url + url_params)
386+
self.assertDictEqual(response.data, {'type':'FeatureCollection','features':[]})
387+
388+
def test_inBBOXFilter_ValueError(self):
389+
url_params = '?in_bbox=0&format=json'
390+
response = self.client.get(self.location_contained_in_bbox_list_url + url_params)
391+
self.assertEqual(response.data['detail'], 'Invalid bbox string supplied for parameter in_bbox')
392+
393+
def test_inBBOXFilter_filter_field_none(self):
394+
from .views import GeojsonLocationContainedInBBoxList as view
395+
original_value = view.bbox_filter_field
396+
view.bbox_filter_field = None
397+
url_params = '?in_bbox=0,0,0,0&format=json'
398+
response = self.client.get(self.location_contained_in_bbox_list_url + url_params)
399+
self.assertDictEqual(response.data, {'type':'FeatureCollection','features':[]})
400+
view.bbox_filter_field = original_value
401+
402+
def test_TileFilter_filtering_none(self):
403+
url_params = '?tile=&format=json'
404+
response = self.client.get(self.location_contained_in_tile_list_url + url_params)
405+
self.assertEqual(response.data, {'type':'FeatureCollection','features':[]})
406+
407+
def test_TileFilter_ValueError(self):
408+
url_params = '?tile=1/0&format=json'
409+
response = self.client.get(self.location_contained_in_tile_list_url + url_params)
410+
self.assertEqual(response.data['detail'], 'Invalid tile string supplied for parameter tile')
411+
412+
def test_DistanceToPointFilter_filtering_none(self):
413+
url_params = '?dist=%0.4f&point=&format=json' % 5000
414+
response = self.client.get('%s%s' % (self.location_within_distance_of_point_list_url, url_params))
415+
self.assertDictEqual(response.data, {'type':'FeatureCollection','features':[]})
416+
417+
def test_DistanceToPointFilter_filter_field_none(self):
418+
from .views import GeojsonLocationWithinDistanceOfPointList as view
419+
original_value = view.distance_filter_field
420+
view.distance_filter_field = None
421+
url_params = '?dist=%0.4f&point=&format=json' % 5000
422+
response = self.client.get('%s%s' % (self.location_within_distance_of_point_list_url, url_params))
423+
self.assertDictEqual(response.data, {'type':'FeatureCollection','features':[]})
424+
view.distance_filter_field = original_value
425+
426+
def test_DistanceToPointFilter_ValueError_point(self):
427+
url_params = '?dist=500.0&point=hello&format=json'
428+
response = self.client.get('%s%s' % (self.location_within_distance_of_point_list_url, url_params))
429+
self.assertEqual(response.data['detail'], 'Invalid geometry string supplied for parameter point')
430+
431+
def test_DistanceToPointFilter_ValueError_distance(self):
432+
url_params = '?dist=wrong&point=12.0,42.0&format=json'
433+
response = self.client.get('%s%s' % (self.location_within_distance_of_point_list_url, url_params))
434+
self.assertEqual(response.data['detail'], 'Invalid distance string supplied for parameter dist')

tests/django_restframework_gis_tests/tests.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@
55
import urllib
66
import sys
77
import json
8+
89
from django.test import TestCase
910
from django.contrib.gis.geos import GEOSGeometry, Polygon, Point
1011
from django.core.urlresolvers import reverse
12+
from django.core.exceptions import ImproperlyConfigured
13+
14+
from rest_framework_gis import serializers as gis_serializers
1115

1216
from .models import Location, LocatedFile
17+
from .serializers import LocationGeoSerializer
1318

1419

1520
class TestRestFrameworkGis(TestCase):
@@ -489,3 +494,33 @@ def test_geometry_serializer_method_field(self):
489494
self.assertEqual(response.data['properties']['name'], 'hidden geometry')
490495
self.assertEqual(response.data['geometry']['type'], 'Point')
491496
self.assertEqual(response.data['geometry']['coordinates'], [0.0, 0.0])
497+
498+
def test_filterset(self):
499+
from rest_framework_gis.filterset import GeoFilterSet
500+
501+
def test_geometry_field_to_representation_none(self):
502+
self._create_locations()
503+
f = LocationGeoSerializer(instance=self.l1).fields['geometry']
504+
self.assertIsNone(f.to_representation(None))
505+
506+
def test_geometry_field_to_internal_value_none(self):
507+
self._create_locations()
508+
f = LocationGeoSerializer(instance=self.l1).fields['geometry']
509+
self.assertIsNone(f.to_internal_value(None))
510+
511+
def test_no_geo_field_improperly_configured(self):
512+
class LocationGeoFeatureSerializer(gis_serializers.GeoFeatureModelSerializer):
513+
class Meta:
514+
model = Location
515+
with self.assertRaises(ImproperlyConfigured):
516+
LocationGeoFeatureSerializer()
517+
518+
def test_exclude_geo_field_improperly_configured(self):
519+
self._create_locations()
520+
class LocationGeoFeatureSerializer(gis_serializers.GeoFeatureModelSerializer):
521+
class Meta:
522+
model = Location
523+
geo_field = 'geometry'
524+
exclude = ('geometry', )
525+
with self.assertRaises(ImproperlyConfigured):
526+
LocationGeoFeatureSerializer(instance=self.l1)

tests/django_restframework_gis_tests/views.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ class GeojsonBoxedLocationList(generics.ListCreateAPIView):
151151
model = BoxedLocation
152152
serializer_class = BoxedLocationGeoFeatureSerializer
153153
queryset = BoxedLocation.objects.all()
154-
#pagination_class = PaginatedLocationGeoFeatureSerializer
155154

156155
geojson_boxedlocation_list = GeojsonBoxedLocationList.as_view()
157156

0 commit comments

Comments
 (0)