/[thuban]/branches/WIP-pyshapelib-bramz/test/test_layer.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/test/test_layer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1599 - (show annotations)
Mon Aug 18 12:45:28 2003 UTC (21 years, 6 months ago) by bh
Original Path: trunk/thuban/test/test_layer.py
File MIME type: text/x-python
File size: 18730 byte(s)
Fix some bugs in Thuban and the test suite that were uncovered by
changes introduced in Python 2.3:

* Thuban/Model/table.py (DBFTable.__init__): Make sure the
filename is an absolute name

* Thuban/Model/layer.py (RasterLayer.__init__): Make sure the
filename is an absolute name

* test/test_save.py (SaveSessionTest.testRasterLayer): Use a
unique filename to save to and use the correct relative filename
in the expected output.
(SaveSessionTest.test_dbf_table): Use the correct relative
filename in the expected output.

* test/test_layer.py (TestLayer.test_raster_layer): Update the
test to check whether the filename is absolute.

1 # Copyright (c) 2002, 2003 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with Thuban for details.
7
8 """
9 Test the Layer class
10 """
11
12 __version__ = "$Revision$"
13 # $Source$
14 # $Id$
15
16 import os
17 import unittest
18
19 import mockgeo
20 import support
21 support.initthuban()
22
23 import shapelib
24 import dbflib
25
26 from Thuban.Model.session import Session
27 from Thuban.Model.layer import BaseLayer, Layer, RasterLayer
28 from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
29 from Thuban.Model.messages import LAYER_LEGEND_CHANGED, \
30 LAYER_VISIBILITY_CHANGED, LAYER_SHAPESTORE_REPLACED, LAYER_CHANGED
31 from Thuban.Model.table import FIELDTYPE_DOUBLE, FIELDTYPE_STRING, MemoryTable
32 from Thuban.Model.proj import Projection
33 from Thuban.Model.data import DerivedShapeStore
34 from Thuban.Model.classification import Classification, ClassGroupSingleton, \
35 ClassGroupRange
36
37 import Thuban.Model.resource
38
39 class TestLayer(unittest.TestCase, support.FileTestMixin,
40 support.FloatComparisonMixin):
41
42 """Test cases for different layer (shape) types"""
43
44 def setUp(self):
45 """Create a session self.session and initialize self.layer to None"""
46 self.session = Session("Test session for %s" % self.__class__)
47 self.layer = None
48
49 def tearDown(self):
50 """Call the layer's Destroy method and set session and layer to None"""
51 self.session = None
52 if self.layer is not None:
53 self.layer.Destroy()
54 self.layer = None
55
56 def build_path(self, filename):
57 return os.path.join("..", "Data", "iceland", filename)
58
59 def open_shapefile(self, filename):
60 """Open and return a shapestore for filename in the iceland data set"""
61 return self.session.OpenShapefile(self.build_path(filename))
62
63 def test_base_layer(self):
64 layer = self.layer = BaseLayer("Test BaseLayer")
65 self.assertEquals(layer.Title(), "Test BaseLayer")
66 self.failUnless(layer.Visible())
67
68 # toggle visibility
69 layer.SetVisible(False)
70 self.failIf(layer.Visible())
71
72 layer.SetVisible(True)
73 self.failUnless(layer.Visible())
74
75 self.failIf(layer.HasClassification())
76 self.failIf(layer.HasShapes())
77
78 self.assertEquals(layer.GetProjection(), None)
79
80 # set/get projection
81 proj = Projection(["proj=utm", "zone=26"])
82
83 layer.SetProjection(proj)
84 self.failUnless(layer.GetProjection() is proj)
85
86 # __init__ with other arguments
87 layer = BaseLayer("Test BaseLayer", False, proj)
88 self.failIf(layer.Visible())
89 self.failUnless(layer.GetProjection() is proj)
90
91 def test_arc_layer(self):
92 """Test Layer with arc shapes"""
93 layer = self.layer = Layer("Test Layer",
94 self.open_shapefile("roads-line.shp"))
95 self.failUnless(layer.HasClassification())
96 self.failUnless(layer.HasShapes())
97 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
98 self.assertEquals(layer.NumShapes(), 839)
99 shape = layer.Shape(32)
100 self.assertPointListEquals(shape.Points(),
101 [[(-15.082174301147461, 66.27738189697265),
102 (-15.026350021362305, 66.27339172363281)]])
103 self.assertFloatSeqEqual(layer.BoundingBox(),
104 [-24.450359344482422, 63.426830291748047,
105 -13.55668830871582, 66.520111083984375])
106 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
107 self.assertEquals([s.ShapeID() for s in shapes],
108 [613, 726, 838])
109
110 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
111 [-15.082174301147461, 66.27339172363281,
112 -15.026350021362305, 66.27738189697265])
113
114 shape = layer.Shape(33)
115 self.assertPointListEquals(shape.Points(),
116 [[(-22.24850654602050, 66.30645751953125),
117 (-22.23273086547851, 66.29407501220703),
118 (-22.23158073425293, 66.2876892089843),
119 (-22.24631881713867, 66.27006530761718)]])
120
121 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32, 33]),
122 [-22.248506546020508, 66.270065307617188,
123 -15.026350021362305, 66.30645751953125])
124
125 self.assertEquals(layer.ShapesBoundingBox([]), None)
126 self.assertEquals(layer.ShapesBoundingBox(None), None)
127
128 def test_polygon_layer(self):
129 """Test Layer with polygon shapes"""
130 layer = self.layer = Layer("Test Layer",
131 self.open_shapefile("political.shp"))
132 self.failUnless(layer.HasClassification())
133 self.failUnless(layer.HasShapes())
134 self.assertEquals(layer.ShapeType(), SHAPETYPE_POLYGON)
135 self.assertEquals(layer.NumShapes(), 156)
136 shape = layer.Shape(4)
137 self.assertPointListEquals(shape.Points(),
138 [[(-22.40639114379882, 64.714111328125),
139 (-22.41621208190918, 64.7160034179687),
140 (-22.40605163574218, 64.719200134277),
141 (-22.40639114379882, 64.714111328125)]])
142 self.assertFloatSeqEqual(layer.BoundingBox(),
143 [-24.546524047851562, 63.286754608154297,
144 -13.495815277099609, 66.563774108886719])
145 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.9, 64.1))
146 self.assertEquals([s.ShapeID() for s in shapes],
147 [91, 92, 144, 146, 148, 150, 152, 153])
148
149 def test_point_layer(self):
150 """Test Layer with point shapes"""
151 layer = self.layer = Layer("Test Layer",
152 self.open_shapefile("cultural_landmark-point.shp"))
153 self.failUnless(layer.HasClassification())
154 self.failUnless(layer.HasShapes())
155 self.assertEquals(layer.ShapeType(), SHAPETYPE_POINT)
156 self.assertEquals(layer.NumShapes(), 34)
157 shape = layer.Shape(0)
158 self.assertPointListEquals(shape.Points(),
159 [[(-22.711074829101562, 66.36572265625)]])
160 self.assertFloatSeqEqual(layer.BoundingBox(),
161 [-23.806047439575195, 63.405960083007812,
162 -15.12291431427002, 66.36572265625])
163 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.80, 64.1))
164 self.assertEquals([s.ShapeID() for s in shapes],
165 [0, 1, 2, 3, 4, 5, 27, 28, 29, 30, 31])
166
167 def test_point_layer_with_projection(self):
168 """Test Layer with point shapes and a projection"""
169 # We use mock data here so that we have precise control over the
170 # values
171 table = MemoryTable([("FOO", FIELDTYPE_STRING)], [("bla",)])
172 store = mockgeo.SimpleShapeStore(SHAPETYPE_POINT, [[[(10,10)]]], table)
173 layer = self.layer = Layer("Test Layer", store)
174
175 # Rotation by 45 degrees counter clockwise. This detects a bug
176 # in the ShapesInRegion method which transforms the bounding box
177 # by only transforming two opposite corners because they have
178 # the same x or y coordinates after application of the
179 # projection or its inverse.
180 proj = mockgeo.AffineProjection((1, 1, -1, 1, 0, 0))
181 layer.SetProjection(proj)
182
183 self.assertEquals(layer.BoundingBox(), (10, 10, 10, 10))
184 self.assertEquals(layer.LatLongBoundingBox(), (10.0, 0.0, 10.0, 0.0))
185 shapes = layer.ShapesInRegion((0, 0, 20, 20))
186 self.assertEquals([s.ShapeID() for s in shapes], [0])
187
188 def test_empty_layer(self):
189 """Test Layer with empty shape file"""
190 # create an empty shape file
191 shapefilename = self.temp_file_name("layer_empty.shp")
192 shp = shapelib.create(shapefilename, shapelib.SHPT_POLYGON)
193 shp.close()
194 # create an empty DBF file too because Thuban can't cope yet
195 # with missing DBF file.
196 dbffilename = self.temp_file_name("layer_empty.dbf")
197 dbf = dbflib.create(dbffilename)
198 dbf.add_field("NAME", dbflib.FTString, 20, 0)
199
200 # Now try to open it.
201 layer = self.layer = Layer("Empty Layer",
202 self.session.OpenShapefile(shapefilename))
203 self.assertEquals(layer.BoundingBox(), None)
204 self.assertEquals(layer.LatLongBoundingBox(), None)
205 self.assertEquals(layer.NumShapes(), 0)
206
207 def test_get_field_type(self):
208 """Test Layer.GetFieldType()"""
209 layer = self.layer = Layer("Test Layer",
210 self.open_shapefile("roads-line.shp"))
211 self.assertEquals(layer.GetFieldType("LENGTH"), FIELDTYPE_DOUBLE)
212 self.assertEquals(layer.GetFieldType("non existing"), None)
213
214 def test_raster_layer(self):
215 if not Thuban.Model.resource.has_gdal_support():
216 raise support.SkipTest("No gdal support")
217
218 filename = self.build_path("island.tif")
219 layer = RasterLayer("Test RasterLayer", filename)
220 self.failIf(layer.HasClassification())
221 self.failIf(layer.HasShapes())
222 self.assertEquals(layer.GetImageFilename(), os.path.abspath(filename))
223 self.assertFloatSeqEqual(layer.BoundingBox(),
224 [-24.5500000, 63.2833330,
225 -13.4916670, 66.5666670])
226 self.assertFloatSeqEqual(layer.LatLongBoundingBox(),
227 [-24.5500000, 63.2833330,
228 -13.4916670, 66.5666670])
229
230 def test_derived_store(self):
231 """Test layer with derived store"""
232 layer = self.layer = Layer("Test Layer",
233 self.open_shapefile("roads-line.shp"))
234 try:
235 store = layer.ShapeStore()
236 derived = DerivedShapeStore(store, store.Table())
237 layer.SetShapeStore(derived)
238 self.assert_(layer.ShapeStore() is derived)
239
240 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
241 self.assertEquals(layer.NumShapes(), 839)
242 shape = layer.Shape(32)
243 self.assertPointListEquals(shape.Points(),
244 [[(-15.082174301147, 66.277381896972),
245 (-15.026350021362, 66.273391723632)]])
246 self.assertFloatSeqEqual(layer.BoundingBox(),
247 [-24.450359344482422, 63.426830291748047,
248 -13.55668830871582, 66.520111083984375])
249 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
250 self.assertEquals([s.ShapeID() for s in shapes],
251 [613, 726, 838])
252
253 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
254 [-15.082174301147461, 66.27339172363281,
255 -15.026350021362305, 66.27738189697265])
256
257 finally:
258 store = derived = None
259
260
261 class SetShapeStoreTests(unittest.TestCase, support.SubscriberMixin):
262
263 def setUp(self):
264 """Create a layer with a classification as self.layer"""
265 self.clear_messages()
266 self.session = Session("Test session for %s" % self.__class__)
267 self.shapefilename = os.path.join("..", "Data", "iceland",
268 "cultural_landmark-point.dbf")
269 self.store = self.session.OpenShapefile(self.shapefilename)
270 self.layer = Layer("test layer", self.store)
271 self.classification = Classification()
272 self.classification.AppendGroup(ClassGroupSingleton("FARM"))
273 self.layer.SetClassificationColumn("CLPTLABEL")
274 self.layer.SetClassification(self.classification)
275 self.layer.UnsetModified()
276 self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
277 self.subscribe_with_params,
278 LAYER_SHAPESTORE_REPLACED)
279 self.layer.Subscribe(LAYER_CHANGED,
280 self.subscribe_with_params, LAYER_CHANGED)
281
282 def tearDown(self):
283 self.clear_messages()
284 self.layer.Destroy()
285 self.session.Destroy()
286 self.session = self.layer = self.store = self.classification = None
287
288 def test_sanity(self):
289 """SetShapeStoreTests sanity check
290
291 Test the initial state of the test case instances after setUp.
292 """
293 cls = self.layer.GetClassification()
294 self.assert_(cls is self.classification)
295 field = self.layer.GetClassificationColumn()
296 self.assertEquals(field, "CLPTLABEL")
297 self.assertEquals(self.layer.GetFieldType(field), FIELDTYPE_STRING)
298 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 1)
299 self.failIf(self.layer.WasModified())
300
301 def test_set_shape_store_modified_flag(self):
302 """Test whether Layer.SetShapeStore() sets the modified flag"""
303 memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
304 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
305 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
306
307 self.assert_(self.layer.WasModified())
308
309 def test_set_shape_store_different_field_name(self):
310 """Test Layer.SetShapeStore() with different column name"""
311 memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
312 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
313 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
314 # The classification should contain only the default group now.
315 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
316 self.check_messages([(self.layer, LAYER_CHANGED),
317 (self.layer, LAYER_SHAPESTORE_REPLACED)])
318
319 def test_set_shape_store_same_field(self):
320 """Test Layer.SetShapeStore() with same column name and type"""
321 memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_STRING)],
322 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
323 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
324 # The classification should be the same as before
325 self.assert_(self.layer.GetClassification() is self.classification)
326 self.check_messages([(self.layer, LAYER_SHAPESTORE_REPLACED)])
327
328 def test_set_shape_store_same_field_different_type(self):
329 """Test Layer.SetShapeStore() with same column name but different type
330 """
331 memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_DOUBLE)],
332 [(0.0,)] * self.layer.ShapeStore().Table().NumRows())
333 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
334 # The classification should contain only the default group now.
335 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
336 self.check_messages([(self.layer, LAYER_CHANGED),
337 (self.layer, LAYER_SHAPESTORE_REPLACED)])
338
339
340 class TestLayerModification(unittest.TestCase, support.SubscriberMixin):
341
342 """Test cases for Layer method that modify the layer.
343 """
344
345 def setUp(self):
346 """Clear the list of received messages and create a layer and a session
347
348 The layer is bound to self.layer and the session to self.session.
349 """
350 self.clear_messages()
351 self.session = Session("Test session for %s" % self.__class__)
352 filename = os.path.join("..", "Data", "iceland", "political.shp")
353 self.layer = Layer("Test Layer",
354 self.session.OpenShapefile(filename))
355 self.layer.Subscribe(LAYER_LEGEND_CHANGED, self.subscribe_with_params,
356 LAYER_LEGEND_CHANGED)
357 self.layer.Subscribe(LAYER_VISIBILITY_CHANGED,
358 self.subscribe_with_params,
359 LAYER_VISIBILITY_CHANGED)
360 self.layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
361 LAYER_CHANGED)
362
363 def tearDown(self):
364 """Clear the list of received messages and explictly destroy self.layer
365 """
366 self.layer.Destroy()
367 self.layer = None
368 self.session.Destroy()
369 self.session = None
370 self.clear_messages()
371
372 def test_sanity(self):
373 """TestLayerModification Sanity Checks"""
374 # test default settings
375 self.failIf(self.layer.WasModified())
376 self.assertEquals(self.layer.Visible(), 1)
377 # no messages should have been produced
378 self.check_messages([])
379
380 def test_visibility(self):
381 """Test Layer visibility"""
382 self.layer.SetVisible(0)
383 self.assertEquals(self.layer.Visible(), 0)
384 self.check_messages([(self.layer, LAYER_VISIBILITY_CHANGED)])
385
386 # currently, modifying the visibility doesn't count as changing
387 # the layer.
388 self.failIf(self.layer.WasModified())
389
390 def test_set_classification(self):
391 """Test Layer.SetClassification"""
392 classification = Classification()
393 classification.AppendGroup(ClassGroupRange((0.0, 0.1)))
394
395 self.layer.SetClassification(classification)
396 self.layer.SetClassificationColumn("AREA")
397
398 self.check_messages([(self.layer, LAYER_CHANGED),
399 (self.layer, LAYER_CHANGED)])
400 self.failUnless(self.layer.WasModified())
401
402 self.clear_messages()
403 self.layer.UnsetModified()
404
405 # change only the classification column. This should issue a
406 # LAYER_CHANGED message as well.
407 self.layer.SetClassificationColumn("PERIMETER")
408
409 self.check_messages([(self.layer, LAYER_CHANGED)])
410 self.failUnless(self.layer.WasModified())
411
412
413 #
414 # the tree info now contains Color objects which are difficult to test
415 #
416 # def test_tree_info(self):
417 # """Test Layer.TreeInfo"""
418 # self.assertEquals(self.layer.TreeInfo(),
419 # ("Layer 'Test Layer'",
420 # ['Shown',
421 # 'Shapes: 156',
422 # ('Extent (lat-lon):'
423 # ' (-24.5465, 63.2868, -13.4958, 66.5638)'),
424 # 'Shapetype: Polygon',
425 # 'Fill: None',
426 # 'Outline: (0.000, 0.000, 0.000)']))
427
428
429 if __name__ == "__main__":
430 support.run_tests()

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26