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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2446 - (show annotations)
Mon Dec 13 11:52:34 2004 UTC (20 years, 2 months ago) by frank
Original Path: trunk/thuban/test/test_load.py
File MIME type: text/x-python
File size: 42603 byte(s)
Alternative Path feature:
	* test/test_load.py (TestAltPath): New, tests for alternative path feature
	in load_session()
	(Shapefile_CallBack): Helper, implements controllable callback.

	* Thuban/UI/application.py (ThubanApplication.OnInit):
	Added "alt_path" to self.path
	(ThubanApplication.OpenSession): Added shapefile_callback as second
	callback similar to db_connection_callback.
	(ThubanApplication.run_alt_path_dialog): New, implementaion of
	shapefile_callback. In addition to raising the dialog the control of
	self.path('alt_path') is implemented here.

	* Thuban/Model/load.py (SessionLoader.__init__): Added shapefile_callback.
	(SessionLoader.open_shapefile): Open shapefile, eventually with
	alternative path. This wrapps the "theSession.OpenShapefile(filename)"
	formerly used in start_fileshapesource()/start_layer().
	(SessionLoader.start_fileshapesource): Call open_shapefile().
	(SessionLoader.start_layer): Call open_shapefile().
	(load_session): Added shapefile_callback.

	* Thuban/UI/altpathdialog.py: New, implements dialogs for alternative path
	feature (search / check).

1 # Copyright (c) 2002, 2003, 2004 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 loading a thuban session from a file
10
11 The tests in this file (test_load.py) are always be the tests for the
12 current version of the thuban file format. Tests for older versions can
13 be found in the version specific test modules, e.g. test_load_0_2 for
14 files created by Thuban 0.2.
15
16 Maintenance of the test cases:
17
18 When during a development period the file format is changed with respect
19 to the last released version for the first time, the tests here should
20 be copied to the version specific test file. The round-trip tests which
21 save the session again and compare the XML files should not be copied
22 over as they only make sense here to make sure th that the files checked
23 here are actually ones that may have been written by the current thuban
24 version.
25 """
26
27 __version__ = "$Revision$"
28 # $Source$
29 # $Id$
30
31 import os
32 import unittest
33
34 import support
35 support.initthuban()
36
37 import postgissupport
38 from xmlsupport import sax_eventlist
39
40 import dbflib
41 import shapelib
42
43 from Thuban.Model.save import save_session
44 from Thuban.Model.load import load_session, parse_color, LoadError, \
45 LoadCancelled
46 from Thuban.Model.color import Transparent
47 from Thuban.Model.classification import ClassGroupProperties, ClassGroupRange,\
48 ClassGroupSingleton, ClassGroupDefault
49 from Thuban.Model.postgisdb import ConnectionError
50 from Thuban.Model.table import DBFTable, MemoryTable, \
51 FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING, \
52 table_to_dbf
53 from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
54 ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE
55
56
57 def filenames_equal(name1, name2):
58 """Return true if the filenames name1 and name2 are equal.
59
60 On systems where it is available, simply use os.path.samefile,
61 otherwise return whether the normalized versions of the filenames
62 according to os.path.normpath are equal.
63 """
64 if hasattr(os.path, "samefile"):
65 return os.path.samefile(name1, name2)
66 return os.path.normpath(name1) == os.path.normpath(name2)
67
68
69
70 class LoadSessionTest(support.FileLoadTestCase):
71
72 """Base class for .thuban file loading tests
73
74 Basically the same as the FileLoadTestCase, except that all tests
75 use the '.thuban' extension by default and that setUp and tearDown
76 handle sessions.
77 """
78
79 file_extension = ".thuban"
80
81 def setUp(self):
82 """Create the test files"""
83 support.FileLoadTestCase.setUp(self)
84 self.session = None
85
86 def tearDown(self):
87 if self.session is not None:
88 self.session.Destroy()
89 self.session = None
90
91
92 dtd = "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
93 thubanids = [((dtd, n), (None, "id")) for n in
94 ["fileshapesource", "filetable", "jointable",
95 "derivedshapesource"]]
96 thubanidrefs = [((dtd, n), (None, m)) for n, m in
97 [("layer", "shapestore"),
98 ("jointable", "left"),
99 ("jointable", "right"),
100 ("derivedshapesource", "table"),
101 ("derivedshapesource", "shapesource")]]
102
103 # The filenames in the tests should be understandable on all
104 # currently supported platforms so filenames is an empty list
105 filenames = []
106
107 del n, m, dtd
108
109 def check_format(self):
110 """Check whether the file we loaded from matches the one that
111 would be written. Call this from each test case after loading
112 the session
113 """
114 filename = self.temp_file_name(self.id() + ".roundtrip.thuban")
115 save_session(self.session, filename)
116 el1 = sax_eventlist(filename = filename, ids = self.thubanids,
117 idrefs = self.thubanidrefs,
118 filenames = self.filenames)
119 el2 = sax_eventlist(filename = self.filename(), ids = self.thubanids,
120 idrefs = self.thubanidrefs,
121 filenames = self.filenames)
122 if 0:
123 for a, b in zip(el1, el2):
124 print a != b and "***************" or ""
125 print a
126 print b
127 self.assertEquals(el1, el2,
128 "loaded file not equivalent to the saved file")
129
130
131 class ClassificationTest(LoadSessionTest):
132
133 """
134 Base class for tests that do some detailed checking of classifications
135 """
136
137 def TestLayers(self, layers, expected):
138 TITLE = 0
139 NUM_GROUPS = 1
140 CLASSES = 2
141 GROUP_TYPE = 0
142 GROUP_DATA = 1
143 GROUP_LABEL = 2
144 GROUP_PROPS = 3
145
146 eq = self.assertEquals
147
148 eq(len(layers), len(expected))
149
150 for layer, data in zip(layers, expected):
151 eq(layer.Title(), data[TITLE])
152
153 clazz = layer.GetClassification()
154 eq(clazz.GetNumGroups(), data[NUM_GROUPS])
155 eq(clazz.GetNumGroups() + 1, len(data[CLASSES]))
156
157 i = 0
158 for group in clazz:
159 props = ClassGroupProperties()
160 props.SetLineColor(
161 parse_color(data[CLASSES][i][GROUP_PROPS][0]))
162 props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])
163 props.SetFill(
164 parse_color(data[CLASSES][i][GROUP_PROPS][2]))
165 if len(data[CLASSES][i][GROUP_PROPS]) > 3:
166 props.SetSize(data[CLASSES][i][GROUP_PROPS][3])
167
168 if data[CLASSES][i][GROUP_TYPE] == "default":
169 g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
170 elif data[CLASSES][i][GROUP_TYPE] == "range":
171 g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
172 data[CLASSES][i][GROUP_DATA][1]),
173 props, data[CLASSES][i][GROUP_LABEL])
174 elif data[CLASSES][i][GROUP_TYPE] == "single":
175 g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
176 props, data[CLASSES][i][GROUP_LABEL])
177
178 eq(group, g)
179
180 i += 1
181
182
183
184 class TestSingleLayer(LoadSessionTest):
185
186 # Note: The use of &amp; and non-ascii characters is deliberate. We
187 # want to test whether the loading code handles that correctly.
188 file_contents = '''\
189 <?xml version="1.0" encoding="UTF-8"?>
190 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
191 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
192 title="Stra\xc3\x9fen &amp; Landmarken">
193 <fileshapesource filetype="shapefile" id="D1"
194 filename="../../Data/iceland/political.shp"/>
195 <map title="\xc3\x9cbersicht">
196 <projection epsg="32627" name="WGS 84 / UTM zone 27N">
197 <parameter value="datum=WGS84"/>
198 <parameter value="ellps=WGS84"/>
199 <parameter value="proj=utm"/>
200 <parameter value="units=m"/>
201 <parameter value="zone=27"/>
202 </projection>
203 <layer shapestore="D1" visible="true"
204 stroke="#000000" title="K\xc3\xbcste" stroke_width="1"
205 fill="None"/>
206 </map>
207 </session>
208 '''
209
210 def test(self):
211 """Load a session with a single map with a single layer"""
212 eq = self.assertEquals
213 session = load_session(self.filename())
214 self.session = session
215
216 # Check the title
217 eq(session.Title(), "Stra\xdfen & Landmarken")
218
219 # the session has one map.
220 maps = session.Maps()
221 eq(len(maps), 1)
222
223 # Check the map's attributes
224 map = maps[0]
225 eq(map.Title(), "\xdcbersicht")
226 proj = map.GetProjection()
227 eq(proj.GetName(), "WGS 84 / UTM zone 27N")
228 eq(proj.EPSGCode(), "32627")
229 params = proj.GetAllParameters()
230 params.sort()
231 eq(params, ["datum=WGS84", "ellps=WGS84", "proj=utm", "units=m",
232 "zone=27"])
233
234 # the map has a single layer
235 layers = map.Layers()
236 eq(len(layers), 1)
237
238 # Check the layer attributes
239 layer = layers[0]
240 eq(layer.Title(), "K\xfcste")
241 self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
242 os.path.join(self.temp_dir(),
243 os.pardir, os.pardir,
244 "Data", "iceland",
245 "political.shp")))
246 eq(layer.GetClassification().GetDefaultFill(), Transparent)
247 eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
248 eq(layer.Visible(), True)
249
250 self.check_format()
251
252 self.session.Destroy()
253 self.session = None
254
255 def test_leak(self):
256 """Test load_session for resource leaks
257
258 The load_session function had a resource leak in that it created
259 cyclic references. The objects would have been eventually
260 collected by the garbage collector but too late. One symptom is
261 that when layers are removed so that the last normal reference
262 owned indirectly by the session to a shape store goes away, the
263 shape store is not actually removed from the session even though
264 the session only keeps weak references because there are still
265 references owned by the cyclic garbage.
266 """
267 session = load_session(self.filename())
268 self.session = session
269
270 # sanity check
271 self.assertEquals(len(session.ShapeStores()), 1)
272
273 # remove the map. The shapestore should go away too
274 session.RemoveMap(session.Maps()[0])
275 self.assertEquals(len(session.ShapeStores()), 0)
276
277
278 class TestNonAsciiColumnName(LoadSessionTest):
279
280 file_contents = '''\
281 <?xml version="1.0" encoding="UTF-8"?>
282 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
283 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
284 title="Non ASCII column name test">
285 <fileshapesource filetype="shapefile" id="D1"
286 filename="TestNonAsciiColumnName.shp"/>
287 <map title="map">
288 <projection name="Some Projection">
289 <parameter value="datum=WGS84"/>
290 <parameter value="ellps=WGS84"/>
291 <parameter value="proj=utm"/>
292 <parameter value="units=m"/>
293 <parameter value="zone=27"/>
294 </projection>
295 <layer shapestore="D1" visible="true"
296 stroke="#000000" title="layer" stroke_width="1"
297 fill="None">
298 <classification field="Fl\xc3\xa4che" field_type="double">
299 <clnull label="">
300 <cldata stroke="#000000" stroke_width="1" fill="None"/>
301 </clnull>
302 </classification>
303 </layer>
304 </map>
305 </session>
306 '''
307
308 def test(self):
309 """Load a session with a single map with a single layer"""
310
311 # Create a shapefile and a dbffile with a non-ascii column name
312 dbffile = self.temp_file_name("TestNonAsciiColumnName.dbf")
313 shpfile = self.temp_file_name("TestNonAsciiColumnName.shp")
314 dbf = dbflib.create(dbffile)
315 dbf.add_field('Fl\xe4che', dbflib.FTDouble, 10, 5)
316 dbf.write_record(0, (0.0,))
317 dbf.close()
318 shp = shapelib.create(shpfile, shapelib.SHPT_POLYGON)
319 shp.write_object(-1, shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
320 [[(0,0), (10, 10), (10, 0),
321 (0, 0)]]))
322 shp.close()
323
324 try:
325 session = load_session(self.filename())
326 except ValueError, v:
327 # Usually if the field name is not decoded properly the
328 # loading fails because the field type mentioned in the file
329 # is not None as returned from the layer for a non-existing
330 # column name so we check for that and report it as failure.
331 # Other exceptions are errors in the test case.
332 if str(v) == "xml field type differs from database!":
333 self.fail("Cannot load file with non-ascii column names")
334 else:
335 raise
336 self.session = session
337
338 # In case Thuban could load the file anyway (i.e. no ValueError
339 # exception in load_session()), check explicitly whether the
340 # field name was decoded properly. The test will probably lead
341 # to a UnicodeError instead of a test failure so we check that
342 # too
343 layer = session.Maps()[0].Layers()[0]
344 try:
345 self.assertEquals(layer.GetClassificationColumn(), 'Fl\xe4che')
346 except UnicodeError:
347 # FIXME: Obviously this will have to change if Thuban ever
348 # supports unicode properly.
349 self.fail("Column name was not converted to a bytestring")
350
351 # roundtrip check
352 self.check_format()
353
354
355 class TestLayerVisibility(LoadSessionTest):
356
357 file_contents = '''\
358 <?xml version="1.0" encoding="UTF-8"?>
359 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
360 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
361 title="single map&amp;layer">
362 <fileshapesource filetype="shapefile" id="D1"
363 filename="../../Data/iceland/political.shp"/>
364 <map title="Test Map">
365 <projection name="Unknown">
366 <parameter value="zone=26"/>
367 <parameter value="proj=utm"/>
368 <parameter value="ellps=clrk66"/>
369 </projection>
370 <layer shapestore="D1" visible="false" stroke="#000000"
371 title="My Layer" stroke_width="1" fill="None"/>
372 </map>
373 </session>
374 '''
375
376 def test(self):
377 """Test that the visible flag is correctly loaded for a layer."""
378 eq = self.assertEquals
379 session = load_session(self.filename())
380 self.session = session
381 maps = session.Maps()
382 eq(len(maps), 1)
383 map = maps[0]
384 layers = map.Layers()
385 eq(len(layers), 1)
386 layer = layers[0]
387
388 eq(layer.Visible(), False)
389
390 self.check_format()
391
392
393 class TestSymbolSize(ClassificationTest):
394
395 file_contents = '''\
396 <?xml version="1.0" encoding="UTF-8"?>
397 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
398 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
399 <fileshapesource filetype="shapefile" id="D813968480" filename="../../Data/iceland/cultural_landmark-point.shp"/>
400 <map title="Iceland map">
401 <layer title="cultural_landmark-point" stroke_width="1" shapestore="D813968480" visible="true" stroke="#000000" fill="#000000">
402 <classification field="CLPTLABEL" field_type="string">
403 <clnull label="">
404 <cldata stroke="#000000" stroke_width="1" size="3" fill="#000000"/>
405 </clnull>
406 <clpoint label="" value="RUINS">
407 <cldata stroke="#000000" stroke_width="1" size="6" fill="#ffffff"/>
408 </clpoint>
409 <clpoint label="" value="FARM">
410 <cldata stroke="#000000" stroke_width="1" size="9" fill="#ffff00"/>
411 </clpoint>
412 </classification>
413 </layer>
414 </map>
415 </session>
416 '''
417
418 def test(self):
419 """Test that the size attribute for point symbols is correctly
420 loaded for a layer."""
421 eq = self.assertEquals
422 session = load_session(self.filename())
423 self.session = session
424
425 map = session.Maps()[0] # only one map in the sample
426
427 expected = [("cultural_landmark-point", 2,
428 [("default", (), "",
429 ("#000000", 1, "#000000", 3)),
430 ("single", "RUINS", "",
431 ("#000000", 1, "#ffffff", 6)),
432 ("single", "FARM", "",
433 ("#000000", 1, "#ffff00", 9))])]
434
435 self.TestLayers(map.Layers(), expected)
436
437 self.check_format()
438
439
440 class TestClassification(ClassificationTest):
441
442 file_contents = '''\
443 <?xml version="1.0" encoding="UTF-8"?>
444 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
445 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
446 title="single map&amp;layer">
447 <fileshapesource filetype="shapefile" id="D138389860"
448 filename="../../Data/iceland/political.shp"/>
449 <fileshapesource filetype="shapefile" id="D138504492"
450 filename="../../Data/iceland/political.shp"/>
451 <map title="Test Map">
452 <projection name="">
453 <parameter value="zone=26"/>
454 <parameter value="proj=utm"/>
455 <parameter value="ellps=clrk66"/>
456 </projection>
457 <layer shapestore="D138389860" visible="true" stroke="#000000"
458 title="My Layer" stroke_width="1" fill="None">
459 <classification field="POPYREG" field_type="string">
460 <clnull label="">
461 <cldata stroke="#000000" stroke_width="1" fill="None"/>
462 </clnull>
463 <clpoint label="" value="1">
464 <cldata stroke="#000000" stroke_width="2" fill="None"/>
465 </clpoint>
466 <clpoint label="" value="1">
467 <cldata stroke="#000000" stroke_width="10" fill="None"/>
468 </clpoint>
469 <clpoint label="\xc3\x9cml\xc3\xa4uts"
470 value="\xc3\xa4\xc3\xb6\xc3\xbc">
471 <cldata stroke="#000000" stroke_width="1" fill="None"/>
472 </clpoint>
473 </classification>
474 </layer>
475 <layer shapestore="D138504492" visible="true" stroke="#000000"
476 title="My Layer 2" stroke_width="2" fill="None">
477 <classification field="AREA" field_type="double">
478 <clnull label="">
479 <cldata stroke="#000000" stroke_width="2" fill="None"/>
480 </clnull>
481 <clrange label="" range="[0;1[">
482 <cldata stroke="#111111" stroke_width="1" fill="None"/>
483 </clrange>
484 <clpoint label="" value="0.5">
485 <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
486 </clpoint>
487 <clrange label="" range="[-1;0[">
488 <cldata stroke="#000000" stroke_width="1" fill="None"/>
489 </clrange>
490 <clpoint label="" value="-0.5">
491 <cldata stroke="#000000" stroke_width="1" fill="None"/>
492 </clpoint>
493 </classification>
494 </layer>
495 </map>
496 </session>
497 '''
498
499 def test(self):
500 """Load a Thuban session with a map and classified layers."""
501 session = load_session(self.filename())
502 self.session = session
503
504 map = self.session.Maps()[0] # only one map in the sample
505
506 expected = [("My Layer", 3,
507 [("default", (), "",
508 ("#000000", 1, "None")),
509 ("single", "1", "",
510 ("#000000", 2, "None")),
511 ("single", "1", "",
512 ("#000000", 10, "None")),
513 ("single", "\xe4\xf6\xfc", "\xdcml\xe4uts",
514 ("#000000", 1, "None"))]),
515 ("My Layer 2", 4,
516 [("default", (), "",
517 ("#000000", 2, "None")),
518 ("range", (0, 1), "",
519 ("#111111", 1, "None")),
520 ("single", .5, "",
521 ("#000000", 1, "#111111")),
522 ("range", (-1, 0), "",
523 ("#000000", 1, "None")),
524 ("single", -.5, "",
525 ("#000000", 1, "None"))])]
526
527 self.TestLayers(map.Layers(), expected)
528
529 self.check_format()
530
531
532 class TestLabels(ClassificationTest):
533
534 file_contents = '''\
535 <?xml version="1.0" encoding="UTF-8"?>
536 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
537 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
538 title="single map&amp;layer">
539 <fileshapesource filetype="shapefile" id="D1"
540 filename="../../Data/iceland/political.shp"/>
541 <map title="Test Map">
542 <projection name="Unknown">
543 <parameter value="zone=26"/>
544 <parameter value="proj=utm"/>
545 <parameter value="ellps=clrk66"/>
546 </projection>
547 <layer shapestore="D1" visible="true" stroke="#000000"
548 title="My Layer" stroke_width="1" fill="None">
549 <classification field="POPYREG" field_type="string">
550 <clnull label="hallo">
551 <cldata stroke="#000000" stroke_width="1" fill="None"/>
552 </clnull>
553 <clpoint label="welt" value="1">
554 <cldata stroke="#000000" stroke_width="2" fill="None"/>
555 </clpoint>
556 </classification>
557 </layer>
558 </map>
559 </session>
560 '''
561
562 def test(self):
563 """Load a session and test for reading the group labels."""
564 eq = self.assertEquals
565 session = load_session(self.filename())
566 self.session = session
567
568 map = self.session.Maps()[0] # only one map in the sample
569
570 expected = [("My Layer", 1,
571 [("default", (), "hallo",
572 ("#000000", 1, "None")),
573 ("single", "1", "welt",
574 ("#000000", 2, "None"))])]
575
576 self.TestLayers(map.Layers(), expected)
577 self.check_format()
578
579
580 class TestLayerProjection(LoadSessionTest):
581
582 file_contents = '''\
583 <?xml version="1.0" encoding="UTF-8"?>
584 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
585 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
586 title="single map&amp;layer">
587 <fileshapesource filetype="shapefile" id="D2"
588 filename="../../Data/iceland/roads-line.shp"/>
589 <fileshapesource filetype="shapefile" id="D4"
590 filename="../../Data/iceland/political.shp"/>
591 <map title="Test Map">
592 <projection name="Unknown">
593 <parameter value="zone=26"/>
594 <parameter value="proj=utm"/>
595 <parameter value="ellps=clrk66"/>
596 </projection>
597 <layer shapestore="D4" visible="true" stroke="#000000"
598 title="My Layer" stroke_width="1" fill="None">
599 <projection name="hello">
600 <parameter value="zone=13"/>
601 <parameter value="proj=tmerc"/>
602 <parameter value="ellps=clrk66"/>
603 </projection>
604 <classification field="POPYREG" field_type="string">
605 <clnull label="hallo">
606 <cldata stroke="#000000" stroke_width="1" fill="None"/>
607 </clnull>
608 <clpoint label="welt" value="1">
609 <cldata stroke="#000000" stroke_width="2" fill="None"/>
610 </clpoint>
611 </classification>
612 </layer>
613 <layer shapestore="D2" visible="true" stroke="#000000"
614 title="My Layer" stroke_width="1" fill="None">
615 <projection name="Unknown">
616 <parameter value="proj=lcc"/>
617 <parameter value="lat_1=10"/>
618 <parameter value="lat_2=20"/>
619 <parameter value="ellps=clrk66"/>
620 </projection>
621 </layer>
622 </map>
623 </session>
624 '''
625
626 def test(self):
627 """Test loading layers with projections"""
628 eq = self.assertEquals
629 neq = self.assertNotEqual
630
631 session = load_session(self.filename())
632 self.session = session
633
634 map = self.session.Maps()[0] # only one map in the sample
635
636 layers = map.Layers() # two layers in the sample
637
638 # test layer with a named projection
639 proj = layers[0].GetProjection()
640 neq(proj, None)
641 eq(proj.GetName(), "hello")
642 eq(proj.GetParameter("proj"), "tmerc")
643 eq(proj.GetParameter("zone"), "13")
644 eq(proj.GetParameter("ellps"), "clrk66")
645
646 # test layer with an unnamed projection
647 proj = layers[1].GetProjection()
648 neq(proj, None)
649 eq(proj.GetName(), "Unknown")
650 eq(proj.GetParameter("proj"), "lcc")
651 eq(proj.GetParameter("lat_1"), "10")
652 eq(proj.GetParameter("lat_2"), "20")
653 eq(proj.GetParameter("ellps"), "clrk66")
654
655 self.check_format()
656
657
658 class TestRasterLayer(LoadSessionTest):
659
660 file_contents = '''\
661 <?xml version="1.0" encoding="UTF-8"?>
662 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
663 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
664 title="single map&amp;layer">
665 <map title="Test Map">
666 <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
667 title="My RasterLayer"/>
668 </map>
669 </session>
670 '''
671
672 def test(self):
673 eq = self.assertEquals
674 neq = self.assertNotEqual
675
676 session = load_session(self.filename())
677 self.session = session
678
679 map = self.session.Maps()[0] # only one map in the sample
680
681 layer = map.Layers()[0] # one layer in the sample
682
683 eq(layer.Title(), "My RasterLayer")
684 self.failIf(layer.Visible())
685 self.failUnless(filenames_equal(layer.GetImageFilename(),
686 os.path.join(self.temp_dir(),
687 os.pardir, os.pardir,
688 "Data", "iceland",
689 "island.tif")))
690 self.check_format()
691
692
693 class TestJoinedTable(LoadSessionTest):
694
695 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
696 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
697 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="A Joined Table session">
698 <fileshapesource filetype="shapefile" id="D137227612"
699 filename="../../Data/iceland/roads-line.shp"/>
700 <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
701 title="Some Title"/>
702 <jointable id="D136169900" title="Joined"
703 right="D136171140" left="D137227612"
704 leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
705 jointype="LEFT OUTER"/>
706 <derivedshapesource table="D136169900" shapesource="D137227612"
707 id="D136170932"/>
708 <map title="Test Map">
709 <layer shapestore="D136170932" visible="true" stroke="#000000"
710 title="My Layer" stroke_width="1" fill="None"/>
711 </map>
712 </session>
713 '''
714
715 def setUp(self):
716 """Extend inherited method to create the dbffile for the join"""
717 LoadSessionTest.setUp(self)
718 dbffile = self.temp_file_name("load_joinedtable.dbf")
719 dbf = dbflib.create(dbffile)
720 dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
721 dbf.add_field("TEXT", dbflib.FTString, 10, 0)
722 dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
723 dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
724 dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
725 dbf.close()
726
727 def test(self):
728 """Test loading a session containing a joined table"""
729 session = load_session(self.filename())
730 self.session = session
731
732 tables = session.Tables()
733 self.assertEquals(len(tables), 3)
734 # FIXME: The tests shouldn't assume a certain order of the tables
735 self.assertEquals(tables[0].Title(), "Some Title")
736 self.assertEquals(tables[1].Title(), "Joined")
737 self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
738 self.check_format()
739
740
741 class TestLabelLayer(LoadSessionTest):
742
743 # Note that the labels deliberately contain non-ascii characters to
744 # test whether they're supported correctly.
745
746 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
747 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
748 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
749 <fileshapesource filetype="shapefile" id="D145265052"
750 filename="../../Data/iceland/political.shp"/>
751 <fileshapesource filetype="shapefile" id="D145412868"
752 filename="../../Data/iceland/cultural_landmark-point.shp"/>
753 <map title="Iceland map">
754 <projection name="Unknown">
755 <parameter value="zone=26"/>
756 <parameter value="proj=utm"/>
757 <parameter value="ellps=clrk66"/>
758 </projection>
759 <layer shapestore="D145265052" visible="true" stroke="#000000"
760 title="political" stroke_width="1" fill="#c0c0c0">
761 <projection name="Geographic">
762 <parameter value="proj=latlong"/>
763 <parameter value="to_meter=0.017453"/>
764 <parameter value="ellps=clrk66"/>
765 </projection>
766 </layer>
767 <layer shapestore="D145412868" visible="true" stroke="#000000"
768 title="landmarks" stroke_width="1" fill="#ffff00">
769 <projection name="Geographic">
770 <parameter value="proj=latlong"/>
771 <parameter value="to_meter=0.017453"/>
772 <parameter value="ellps=clrk66"/>
773 </projection>
774 </layer>
775 <labellayer>
776 <label x="-21.5" y="64.25" text="RUINS"
777 halign="left" valign="center"/>
778 <label x="-15.125" y="64.75" text="H\xc3\xbctte"
779 halign="right" valign="top"/>
780 </labellayer>
781 </map>
782 </session>
783 '''
784
785 def test(self):
786 """Test loading a session with a label layer"""
787 session = load_session(self.filename())
788 self.session = session
789
790 label_layer = self.session.Maps()[0].LabelLayer()
791 expected_labels = [(-21.5, 64.25, "RUINS", ALIGN_LEFT, ALIGN_CENTER),
792 (-15.125, 64.75, "H\xfctte", ALIGN_RIGHT, ALIGN_TOP),
793 ]
794 for label, values in zip(label_layer.Labels(), expected_labels):
795 self.assertEquals((label.x, label.y, label.text, label.halign,
796 label.valign),
797 values)
798 self.check_format()
799
800
801 class TestPostGISLayer(LoadSessionTest):
802
803 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
804 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
805 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
806 title="unnamed session">
807 <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
808 dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
809 <dbshapesource id="D143149420" dbconn="D142684948"
810 tablename="landmarks_point_id" id_column="point_id"
811 geometry_column="the_geom" />
812 <map title="unnamed map">
813 <layer shapestore="D143149420" visible="true" stroke="#000000"
814 title="landmarks" stroke_width="1" fill="None"/>
815 </map>
816 </session>
817 '''
818
819 def setUp(self):
820 """Extend the inherited method to start the postgis server
821
822 Furthermore, patch the file contents with the real postgis db
823 information
824 """
825 postgissupport.skip_if_no_postgis()
826 self.server = postgissupport.get_test_server()
827 self.postgisdb = self.server.get_default_static_data_db()
828
829 self.file_contents = self.__class__.file_contents % {
830 "dbname": self.postgisdb.dbname,
831 "user": self.server.user_name,
832 "port": self.server.port,
833 "host": self.server.host}
834 LoadSessionTest.setUp(self)
835
836 def test(self):
837 """Test loading a session containing a postgis shapestore"""
838 session = load_session(self.filename())
839 self.session = session
840 connections = session.DBConnections()
841 self.assertEquals(len(connections), 1)
842 conn = connections[0]
843 for attr, value in [("host", self.server.host),
844 ("port", str(self.server.port)),
845 ("user", self.server.user_name),
846 ("dbname", self.postgisdb.dbname)]:
847 self.assertEquals(getattr(conn, attr), value)
848 layer = session.Maps()[0].Layers()[0]
849 self.failUnless(layer.ShapeStore().DBConnection() is conn)
850
851
852 class TestPostGISLayerPassword(LoadSessionTest):
853
854 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
855 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
856 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
857 title="unnamed session">
858 <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
859 dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
860 <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
861 <map title="unnamed map">
862 <layer shapestore="D143149420" visible="true" stroke="#000000"
863 title="landmarks" stroke_width="1" fill="None"/>
864 </map>
865 </session>
866 '''
867
868 def setUp(self):
869 """Extend the inherited method to start the postgis server
870
871 Furthermore, patch the file contents with the real postgis db
872 information
873 """
874 postgissupport.skip_if_no_postgis()
875 self.server = postgissupport.get_test_server()
876 self.postgisdb = self.server.get_default_static_data_db()
877
878 self.file_contents = self.__class__.file_contents % {
879 "dbname": self.postgisdb.dbname,
880 "user": self.server.user_name,
881 "port": self.server.port,
882 "host": self.server.host}
883 LoadSessionTest.setUp(self)
884
885 self.db_connection_callback_called = False
886 self.server.require_authentication(True)
887
888 def tearDown(self):
889 """Extend the inherited method to switch off postgresql authentication
890 """
891 self.server.require_authentication(False)
892 LoadSessionTest.tearDown(self)
893
894 def db_connection_callback(self, params, message):
895 """Implementation of Thuban.Model.hooks.query_db_connection_parameters
896 """
897 self.assertEquals(params,
898 {"dbname": self.postgisdb.dbname,
899 "user": self.server.user_name,
900 "port": str(self.server.port),
901 "host": self.server.host})
902 self.db_connection_callback_called = True
903 params = params.copy()
904 params["password"] = self.server.user_password
905 return params
906
907 def test_with_callback(self):
908 """Test loading a session with postgis, authentication and a callback
909 """
910 session = load_session(self.filename(),
911 db_connection_callback = self.db_connection_callback)
912 self.session = session
913 connections = session.DBConnections()
914 self.assertEquals(len(connections), 1)
915 conn = connections[0]
916 for attr, value in [("host", self.server.host),
917 ("port", str(self.server.port)),
918 ("user", self.server.user_name),
919 ("dbname", self.postgisdb.dbname)]:
920 self.assertEquals(getattr(conn, attr), value)
921 layer = session.Maps()[0].Layers()[0]
922 self.failUnless(layer.ShapeStore().DBConnection() is conn)
923 self.failUnless(self.db_connection_callback_called)
924
925 def test_without_callback(self):
926 """Test loading a session with postgis, authentication and no callback
927 """
928 # A password is required and there's no callback, so we should
929 # get a ConnectionError
930 self.assertRaises(ConnectionError, load_session, self.filename())
931
932 def test_cancel(self):
933 """Test loading a session with postgis and cancelling authentication
934 """
935 def cancel(*args):
936 self.db_connection_callback_called = True
937 return None
938
939 # If the user cancels, i.e. if the callbakc returns None, a
940 # LoadCancelled exception is raised.
941 self.assertRaises(LoadCancelled,
942 load_session, self.filename(), cancel)
943 self.failUnless(self.db_connection_callback_called)
944
945
946 class TestLoadError(LoadSessionTest):
947
948 file_contents = '''\
949 <?xml version="1.0" encoding="UTF-8"?>
950 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
951 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
952 title="single map&amp;layer">
953 <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
954 <map title="Test Map">
955 <projection name="Unknown">
956 <parameter value="zone=26"/>
957 <parameter value="proj=utm"/>
958 <parameter value="ellps=clrk66"/>
959 </projection>
960 <layer shapestore="D1" visible="true"
961 stroke="#000000" title="My Layer" stroke_width="1"
962 fill="None"/>
963 </map>
964 </session>
965 '''
966
967 def test(self):
968 """Test loading a session missing a required attribute"""
969 # Don't use assertRaises to make sure that if a session is
970 # actually returned it gets destroyed properly.
971 try:
972 self.session = load_session(self.filename())
973 except LoadError, value:
974 # Check the actual messge in value to make sure the
975 # LoadError really was about the missing attribute
976 self.assertEquals(str(value),
977 "Element "
978 "(u'http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd',"
979 " u'fileshapesource') requires an attribute 'filetype'")
980 else:
981 self.fail("Missing filetype attribute doesn't raise LoadError")
982
983 class Shapefile_CallBack:
984
985 def __init__(self, params):
986 """Initialize the callback return values.
987
988 params must be a dictionary of the potential CB modes (keys),
989 with lists of tuples of return values as values.
990 Depending on the test the callback can be called multiple,
991 each time a return value is poped from the list
992 """
993
994 self.params = params
995
996
997 def s_cb(self, filename, mode = None, second_try= 0):
998 if self.params.has_key(mode):
999 return self.params[mode].pop(0)
1000 else:
1001 raise LoadError
1002
1003 class TestAltPath(LoadSessionTest):
1004
1005 """Test the various cases in the alternative path feature.
1006
1007 The test checks the reasonable cases:
1008 - First recognition of a path error, fixed with user interaction.
1009 - First recognition of a path error, load cancelled.
1010 - Path error fixed from list, confirmed by user.
1011 - Path error fixed from list, changed by user.
1012 - Path error fixed from list, cancelled by user.
1013 - Path error wrongly fixed from list, manual fix forced.
1014 """
1015
1016 file_contents = '''\
1017 <?xml version="1.0" encoding="UTF-8"?>
1018 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
1019 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
1020 <fileshapesource filetype="shapefile" id="D1108450956" filename="../../Data/iceland/political.shp"/>
1021 <fileshapesource filetype="shapefile" id="D1108900076" filename="../Data/iceland/roads-line.shp"/>
1022 <fileshapesource filetype="shapefile" id="D1108947244" filename="../../Data/iceland/cultural_landmark-point.shp"/>
1023 <map title="not the iceland map">
1024 <layer title="political" stroke_width="1" shapestore="D1108450956" visible="true" stroke="#000000" fill="#c0c0c0"/>
1025 <layer title="roads-line" stroke_width="1" shapestore="D1108900076" visible="true" stroke="#000000" fill="None"/>
1026 <layer title="something else" stroke_width="1" shapestore="D1108947244" visible="true" stroke="#000000" fill="None"/>
1027 </map>
1028 </session>
1029 '''
1030
1031 def test_01_single_path_error_fix(self):
1032 """Test single file path error fix."""
1033 # The usual initial case
1034 s_cb = Shapefile_CallBack({
1035 "search": [("../Data/iceland/roads-line.shp",0)],
1036 "check": [(None, None)]})
1037 self.session = load_session(self.filename(),
1038 shapefile_callback =s_cb.s_cb)
1039 self.session.Destroy()
1040 self.session = None
1041
1042 def test_02_path_error_fix_from_list(self):
1043 """Test single file path error fix."""
1044 # This represents the usual case for "from_list"
1045 s_cb = Shapefile_CallBack({
1046 "search": [("../Data/iceland/roads-line.shp",1)],
1047 "check": [(os.path.abspath("../Data/iceland/roads-line.shp"),1)]
1048 })
1049 self.session = load_session(self.filename(),
1050 shapefile_callback =s_cb.s_cb)
1051 self.session.Destroy()
1052 self.session = None
1053
1054 def test_03_single_path_error_cancelled(self):
1055 """Test alternative path cancelled."""
1056 s_cb = Shapefile_CallBack({
1057 "search": [(None,0)],
1058 "check": [(None, None)]})
1059 self.assertRaises(LoadCancelled,
1060 load_session, self.filename(), None, s_cb.s_cb)
1061
1062 def test_04_path_error_fix_from_list_cancelled(self):
1063 """Test alternative path from list cancelled."""
1064 s_cb = Shapefile_CallBack({
1065 "search": [("../Data/iceland/roads-line.shp",1)],
1066 "check": [(None,1)]
1067 })
1068 self.assertRaises(LoadCancelled,
1069 load_session, self.filename(), None, s_cb.s_cb)
1070
1071 def test_05_path_error_fix_from_list_changed(self):
1072 """Test alternative path from list changed."""
1073 s_cb = Shapefile_CallBack({
1074 "search": [("../Data/iceland/roads-line.shp",1)],
1075 "check": [("../Data/iceland/roads-line.shp",0)]
1076 })
1077 self.session = load_session(self.filename(),
1078 shapefile_callback =s_cb.s_cb)
1079 self.session.Destroy()
1080 self.session = None
1081
1082 def test_06_path_error_fix_from_list_fails(self):
1083 """Test alternative path recovery from list."""
1084 s_cb = Shapefile_CallBack({
1085 "search": [("../wrong/iceland/roads-line.shp",1),
1086 ("../Data/iceland/roads-line.shp",0)],
1087 "check": [(None,None)]
1088 })
1089 self.session = load_session(self.filename(),
1090 shapefile_callback =s_cb.s_cb)
1091 self.assertRaises(IndexError,
1092 s_cb.s_cb, None, "search")
1093
1094 self.session.Destroy()
1095 self.session = None
1096
1097
1098 if __name__ == "__main__":
1099 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