| 1 |
""" |
|---|
| 2 |
A limited test module is used for a limited spatial database. |
|---|
| 3 |
""" |
|---|
| 4 |
import os, unittest |
|---|
| 5 |
from models import Country, City, State, Feature |
|---|
| 6 |
from django.contrib.gis import gdal |
|---|
| 7 |
from django.contrib.gis.geos import * |
|---|
| 8 |
from django.core.exceptions import ImproperlyConfigured |
|---|
| 9 |
|
|---|
| 10 |
class GeoModelTest(unittest.TestCase): |
|---|
| 11 |
|
|---|
| 12 |
def test01_initial_sql(self): |
|---|
| 13 |
"Testing geographic initial SQL." |
|---|
| 14 |
# Ensuring that data was loaded from initial SQL. |
|---|
| 15 |
self.assertEqual(2, Country.objects.count()) |
|---|
| 16 |
self.assertEqual(8, City.objects.count()) |
|---|
| 17 |
self.assertEqual(2, State.objects.count()) |
|---|
| 18 |
|
|---|
| 19 |
def test02_proxy(self): |
|---|
| 20 |
"Testing Lazy-Geometry support (using the GeometryProxy)." |
|---|
| 21 |
#### Testing on a Point |
|---|
| 22 |
pnt = Point(0, 0) |
|---|
| 23 |
nullcity = City(name='NullCity', point=pnt) |
|---|
| 24 |
nullcity.save() |
|---|
| 25 |
|
|---|
| 26 |
# Making sure TypeError is thrown when trying to set with an |
|---|
| 27 |
# incompatible type. |
|---|
| 28 |
for bad in [5, 2.0, LineString((0, 0), (1, 1))]: |
|---|
| 29 |
try: |
|---|
| 30 |
nullcity.point = bad |
|---|
| 31 |
except TypeError: |
|---|
| 32 |
pass |
|---|
| 33 |
else: |
|---|
| 34 |
self.fail('Should throw a TypeError') |
|---|
| 35 |
|
|---|
| 36 |
# Now setting with a compatible GEOS Geometry, saving, and ensuring |
|---|
| 37 |
# the save took, notice no SRID is explicitly set. |
|---|
| 38 |
new = Point(5, 23) |
|---|
| 39 |
nullcity.point = new |
|---|
| 40 |
|
|---|
| 41 |
# Ensuring that the SRID is automatically set to that of the |
|---|
| 42 |
# field after assignment, but before saving. |
|---|
| 43 |
self.assertEqual(4326, nullcity.point.srid) |
|---|
| 44 |
nullcity.save() |
|---|
| 45 |
|
|---|
| 46 |
# Ensuring the point was saved correctly after saving |
|---|
| 47 |
self.assertEqual(new, City.objects.get(name='NullCity').point) |
|---|
| 48 |
|
|---|
| 49 |
# Setting the X and Y of the Point |
|---|
| 50 |
nullcity.point.x = 23 |
|---|
| 51 |
nullcity.point.y = 5 |
|---|
| 52 |
# Checking assignments pre & post-save. |
|---|
| 53 |
self.assertNotEqual(Point(23, 5), City.objects.get(name='NullCity').point) |
|---|
| 54 |
nullcity.save() |
|---|
| 55 |
self.assertEqual(Point(23, 5), City.objects.get(name='NullCity').point) |
|---|
| 56 |
nullcity.delete() |
|---|
| 57 |
|
|---|
| 58 |
#### Testing on a Polygon |
|---|
| 59 |
shell = LinearRing((0, 0), (0, 100), (100, 100), (100, 0), (0, 0)) |
|---|
| 60 |
inner = LinearRing((40, 40), (40, 60), (60, 60), (60, 40), (40, 40)) |
|---|
| 61 |
|
|---|
| 62 |
# Creating a State object using a built Polygon |
|---|
| 63 |
ply = Polygon(shell, inner) |
|---|
| 64 |
nullstate = State(name='NullState', poly=ply) |
|---|
| 65 |
self.assertEqual(4326, nullstate.poly.srid) # SRID auto-set from None |
|---|
| 66 |
nullstate.save() |
|---|
| 67 |
|
|---|
| 68 |
ns = State.objects.get(name='NullState') |
|---|
| 69 |
self.assertEqual(ply, ns.poly) |
|---|
| 70 |
|
|---|
| 71 |
# Testing the `ogr` and `srs` lazy-geometry properties. |
|---|
| 72 |
if gdal.HAS_GDAL: |
|---|
| 73 |
self.assertEqual(True, isinstance(ns.poly.ogr, gdal.OGRGeometry)) |
|---|
| 74 |
self.assertEqual(ns.poly.wkb, ns.poly.ogr.wkb) |
|---|
| 75 |
self.assertEqual(True, isinstance(ns.poly.srs, gdal.SpatialReference)) |
|---|
| 76 |
self.assertEqual('WGS 84', ns.poly.srs.name) |
|---|
| 77 |
|
|---|
| 78 |
# Changing the interior ring on the poly attribute. |
|---|
| 79 |
new_inner = LinearRing((30, 30), (30, 70), (70, 70), (70, 30), (30, 30)) |
|---|
| 80 |
ns.poly[1] = new_inner |
|---|
| 81 |
ply[1] = new_inner |
|---|
| 82 |
self.assertEqual(4326, ns.poly.srid) |
|---|
| 83 |
ns.save() |
|---|
| 84 |
self.assertEqual(ply, State.objects.get(name='NullState').poly) |
|---|
| 85 |
ns.delete() |
|---|
| 86 |
|
|---|
| 87 |
def test03_contains_contained(self): |
|---|
| 88 |
"Testing the 'contained', 'contains', and 'bbcontains' lookup types." |
|---|
| 89 |
# Getting Texas, yes we were a country -- once ;) |
|---|
| 90 |
texas = Country.objects.get(name='Texas') |
|---|
| 91 |
|
|---|
| 92 |
# Seeing what cities are in Texas, should get Houston and Dallas, |
|---|
| 93 |
# and Oklahoma City because MySQL 'within' only checks on the |
|---|
| 94 |
# _bounding box_ of the Geometries. |
|---|
| 95 |
qs = City.objects.filter(point__within=texas.mpoly) |
|---|
| 96 |
self.assertEqual(3, qs.count()) |
|---|
| 97 |
cities = ['Houston', 'Dallas', 'Oklahoma City'] |
|---|
| 98 |
for c in qs: self.assertEqual(True, c.name in cities) |
|---|
| 99 |
|
|---|
| 100 |
# Pulling out some cities. |
|---|
| 101 |
houston = City.objects.get(name='Houston') |
|---|
| 102 |
wellington = City.objects.get(name='Wellington') |
|---|
| 103 |
pueblo = City.objects.get(name='Pueblo') |
|---|
| 104 |
okcity = City.objects.get(name='Oklahoma City') |
|---|
| 105 |
lawrence = City.objects.get(name='Lawrence') |
|---|
| 106 |
|
|---|
| 107 |
# Now testing contains on the countries using the points for |
|---|
| 108 |
# Houston and Wellington. |
|---|
| 109 |
tx = Country.objects.get(mpoly__contains=houston.point) # Query w/GEOSGeometry |
|---|
| 110 |
nz = Country.objects.get(mpoly__contains=wellington.point.hex) # Query w/EWKBHEX |
|---|
| 111 |
ks = State.objects.get(poly__contains=lawrence.point) |
|---|
| 112 |
self.assertEqual('Texas', tx.name) |
|---|
| 113 |
self.assertEqual('New Zealand', nz.name) |
|---|
| 114 |
self.assertEqual('Kansas', ks.name) |
|---|
| 115 |
|
|---|
| 116 |
# Pueblo is not contained in Texas or New Zealand. |
|---|
| 117 |
self.assertEqual(0, len(Country.objects.filter(mpoly__contains=pueblo.point))) # Query w/GEOSGeometry object |
|---|
| 118 |
|
|---|
| 119 |
# OK City is contained w/in bounding box of Texas. |
|---|
| 120 |
qs = Country.objects.filter(mpoly__bbcontains=okcity.point) |
|---|
| 121 |
self.assertEqual(1, len(qs)) |
|---|
| 122 |
self.assertEqual('Texas', qs[0].name) |
|---|
| 123 |
|
|---|
| 124 |
def test04_disjoint(self): |
|---|
| 125 |
"Testing the `disjoint` lookup type." |
|---|
| 126 |
ptown = City.objects.get(name='Pueblo') |
|---|
| 127 |
qs1 = City.objects.filter(point__disjoint=ptown.point) |
|---|
| 128 |
self.assertEqual(7, qs1.count()) |
|---|
| 129 |
# TODO: This query should work in MySQL, but it appears the |
|---|
| 130 |
# `MBRDisjoint` function doesn't work properly (I went down |
|---|
| 131 |
# to the SQL level for debugging and still got bogus answers). |
|---|
| 132 |
#qs2 = State.objects.filter(poly__disjoint=ptown.point) |
|---|
| 133 |
#self.assertEqual(1, qs2.count()) |
|---|
| 134 |
#self.assertEqual('Kansas', qs2[0].name) |
|---|
| 135 |
|
|---|
| 136 |
def test05_equals(self): |
|---|
| 137 |
"Testing the 'same_as' and 'equals' lookup types." |
|---|
| 138 |
pnt = fromstr('POINT (-95.363151 29.763374)', srid=4326) |
|---|
| 139 |
c1 = City.objects.get(point=pnt) |
|---|
| 140 |
c2 = City.objects.get(point__same_as=pnt) |
|---|
| 141 |
c3 = City.objects.get(point__equals=pnt) |
|---|
| 142 |
for c in [c1, c2, c3]: self.assertEqual('Houston', c.name) |
|---|
| 143 |
|
|---|
| 144 |
def test06_geometryfield(self): |
|---|
| 145 |
"Testing GeometryField." |
|---|
| 146 |
f1 = Feature(name='Point', geom=Point(1, 1)) |
|---|
| 147 |
f2 = Feature(name='LineString', geom=LineString((0, 0), (1, 1), (5, 5))) |
|---|
| 148 |
f3 = Feature(name='Polygon', geom=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))) |
|---|
| 149 |
f4 = Feature(name='GeometryCollection', |
|---|
| 150 |
geom=GeometryCollection(Point(2, 2), LineString((0, 0), (2, 2)), |
|---|
| 151 |
Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))))) |
|---|
| 152 |
f1.save() |
|---|
| 153 |
f2.save() |
|---|
| 154 |
f3.save() |
|---|
| 155 |
f4.save() |
|---|
| 156 |
|
|---|
| 157 |
f_1 = Feature.objects.get(name='Point') |
|---|
| 158 |
self.assertEqual(True, isinstance(f_1.geom, Point)) |
|---|
| 159 |
self.assertEqual((1.0, 1.0), f_1.geom.tuple) |
|---|
| 160 |
f_2 = Feature.objects.get(name='LineString') |
|---|
| 161 |
self.assertEqual(True, isinstance(f_2.geom, LineString)) |
|---|
| 162 |
self.assertEqual(((0.0, 0.0), (1.0, 1.0), (5.0, 5.0)), f_2.geom.tuple) |
|---|
| 163 |
|
|---|
| 164 |
f_3 = Feature.objects.get(name='Polygon') |
|---|
| 165 |
self.assertEqual(True, isinstance(f_3.geom, Polygon)) |
|---|
| 166 |
f_4 = Feature.objects.get(name='GeometryCollection') |
|---|
| 167 |
self.assertEqual(True, isinstance(f_4.geom, GeometryCollection)) |
|---|
| 168 |
self.assertEqual(f_3.geom, f_4.geom[2]) |
|---|
| 169 |
|
|---|
| 170 |
def test07_mysql_limitations(self): |
|---|
| 171 |
"Testing that union(), kml(), gml() raise exceptions." |
|---|
| 172 |
self.assertRaises(ImproperlyConfigured, City.objects.union, Point(5, 23), field_name='point') |
|---|
| 173 |
self.assertRaises(ImproperlyConfigured, State.objects.all().kml, field_name='poly') |
|---|
| 174 |
self.assertRaises(ImproperlyConfigured, Country.objects.all().gml, field_name='mpoly') |
|---|
| 175 |
|
|---|
| 176 |
def suite(): |
|---|
| 177 |
s = unittest.TestSuite() |
|---|
| 178 |
s.addTest(unittest.makeSuite(GeoModelTest)) |
|---|
| 179 |
return s |
|---|