/[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 2036 - (show annotations)
Mon Dec 22 17:49:43 2003 UTC (21 years, 2 months ago) by bh
Original Path: trunk/thuban/test/test_load.py
File MIME type: text/x-python
File size: 35527 byte(s)
* setup.py (setup call): 1.0.0, yeah!

* Thuban/version.py (longversion): 1.0.0, yeah!

* Thuban/Model/load.py (SessionLoader.__init__): Accept the
1.0.0 namespace too

* Thuban/Model/save.py (SessionSaver.write_session): Save with
1.0.0 namespace

* test/test_load.py (LoadSessionTest.dtd)
(TestSingleLayer.file_contents)
(TestNonAsciiColumnName.file_contents)
(TestLayerVisibility.file_contents)
(TestClassification.file_contents, TestLabels.file_contents)
(TestLayerProjection.file_contents)
(TestRasterLayer.file_contents, TestJoinedTable.file_contents)
(TestLabelLayer.file_contents, TestPostGISLayer.file_contents)
(TestPostGISLayerPassword.file_contents)
(TestLoadError.file_contents, TestLoadError.test): Update for
1.0.0 namespace

* test/test_save.py (SaveSessionTest.dtd)
(SaveSessionTest.testEmptySession)
(SaveSessionTest.testSingleLayer)
(SaveSessionTest.testLayerProjection)
(SaveSessionTest.testRasterLayer)
(SaveSessionTest.testClassifiedLayer)
(SaveSessionTest.test_dbf_table)
(SaveSessionTest.test_joined_table)
(SaveSessionTest.test_save_postgis): Update for 1.0.0 namespace

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 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, the tests here should be
20 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.0.0.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
166 if data[CLASSES][i][GROUP_TYPE] == "default":
167 g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
168 elif data[CLASSES][i][GROUP_TYPE] == "range":
169 g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
170 data[CLASSES][i][GROUP_DATA][1]),
171 props, data[CLASSES][i][GROUP_LABEL])
172 elif data[CLASSES][i][GROUP_TYPE] == "single":
173 g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
174 props, data[CLASSES][i][GROUP_LABEL])
175
176 eq(group, g)
177
178 i += 1
179
180
181
182 class TestSingleLayer(LoadSessionTest):
183
184 # Note: The use of &amp; and non-ascii characters is deliberate. We
185 # want to test whether the loading code handles that correctly.
186 file_contents = '''\
187 <?xml version="1.0" encoding="UTF-8"?>
188 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
189 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
190 title="Stra\xc3\x9fen &amp; Landmarken">
191 <fileshapesource filetype="shapefile" id="D1"
192 filename="../../Data/iceland/political.shp"/>
193 <map title="\xc3\x9cbersicht">
194 <projection epsg="32627" name="WGS 84 / UTM zone 27N">
195 <parameter value="datum=WGS84"/>
196 <parameter value="ellps=WGS84"/>
197 <parameter value="proj=utm"/>
198 <parameter value="units=m"/>
199 <parameter value="zone=27"/>
200 </projection>
201 <layer shapestore="D1" visible="true"
202 stroke="#000000" title="K\xc3\xbcste" stroke_width="1"
203 fill="None"/>
204 </map>
205 </session>
206 '''
207
208 def test(self):
209 """Load a session with a single map with a single layer"""
210 eq = self.assertEquals
211 session = load_session(self.filename())
212 self.session = session
213
214 # Check the title
215 eq(session.Title(), "Stra\xdfen & Landmarken")
216
217 # the session has one map.
218 maps = session.Maps()
219 eq(len(maps), 1)
220
221 # Check the map's attributes
222 map = maps[0]
223 eq(map.Title(), "\xdcbersicht")
224 proj = map.GetProjection()
225 eq(proj.GetName(), "WGS 84 / UTM zone 27N")
226 eq(proj.EPSGCode(), "32627")
227 params = proj.GetAllParameters()
228 params.sort()
229 eq(params, ["datum=WGS84", "ellps=WGS84", "proj=utm", "units=m",
230 "zone=27"])
231
232 # the map has a single layer
233 layers = map.Layers()
234 eq(len(layers), 1)
235
236 # Check the layer attributes
237 layer = layers[0]
238 eq(layer.Title(), "K\xfcste")
239 self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
240 os.path.join(self.temp_dir(),
241 os.pardir, os.pardir,
242 "Data", "iceland",
243 "political.shp")))
244 eq(layer.GetClassification().GetDefaultFill(), Transparent)
245 eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
246 eq(layer.Visible(), True)
247
248 self.check_format()
249
250 self.session.Destroy()
251 self.session = None
252
253 def test_leak(self):
254 """Test load_session for resource leaks
255
256 The load_session function had a resource leak in that it created
257 cyclic references. The objects would have been eventually
258 collected by the garbage collector but too late. One symptom is
259 that when layers are removed so that the last normal reference
260 owned indirectly by the session to a shape store goes away, the
261 shape store is not actually removed from the session even though
262 the session only keeps weak references because there are still
263 references owned by the cyclic garbage.
264 """
265 session = load_session(self.filename())
266 self.session = session
267
268 # sanity check
269 self.assertEquals(len(session.ShapeStores()), 1)
270
271 # remove the map. The shapestore should go away too
272 session.RemoveMap(session.Maps()[0])
273 self.assertEquals(len(session.ShapeStores()), 0)
274
275
276 class TestNonAsciiColumnName(LoadSessionTest):
277
278 file_contents = '''\
279 <?xml version="1.0" encoding="UTF-8"?>
280 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
281 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
282 title="Non ASCII column name test">
283 <fileshapesource filetype="shapefile" id="D1"
284 filename="TestNonAsciiColumnName.shp"/>
285 <map title="map">
286 <projection name="Some Projection">
287 <parameter value="datum=WGS84"/>
288 <parameter value="ellps=WGS84"/>
289 <parameter value="proj=utm"/>
290 <parameter value="units=m"/>
291 <parameter value="zone=27"/>
292 </projection>
293 <layer shapestore="D1" visible="true"
294 stroke="#000000" title="layer" stroke_width="1"
295 fill="None">
296 <classification field="Fl\xc3\xa4che" field_type="double">
297 <clnull label="">
298 <cldata stroke="#000000" stroke_width="1" fill="None"/>
299 </clnull>
300 </classification>
301 </layer>
302 </map>
303 </session>
304 '''
305
306 def test(self):
307 """Load a session with a single map with a single layer"""
308
309 # Create a shapefile and a dbffile with a non-ascii column name
310 dbffile = self.temp_file_name("TestNonAsciiColumnName.dbf")
311 shpfile = self.temp_file_name("TestNonAsciiColumnName.shp")
312 dbf = dbflib.create(dbffile)
313 dbf.add_field('Fl\xe4che', dbflib.FTDouble, 10, 5)
314 dbf.write_record(0, (0.0,))
315 dbf.close()
316 shp = shapelib.create(shpfile, shapelib.SHPT_POLYGON)
317 shp.write_object(-1, shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
318 [[(0,0), (10, 10), (10, 0),
319 (0, 0)]]))
320 shp.close()
321
322 try:
323 session = load_session(self.filename())
324 except ValueError, v:
325 # Usually if the field name is not decoded properly the
326 # loading fails because the field type mentioned in the file
327 # is not None as returned from the layer for a non-existing
328 # column name so we check for that and report it as failure.
329 # Other exceptions are errors in the test case.
330 if str(v) == "xml field type differs from database!":
331 self.fail("Cannot load file with non-ascii column names")
332 else:
333 raise
334 self.session = session
335
336 # In case Thuban could load the file anyway (i.e. no ValueError
337 # exception in load_session()), check explicitly whether the
338 # field name was decoded properly. The test will probably lead
339 # to a UnicodeError instead of a test failure so we check that
340 # too
341 layer = session.Maps()[0].Layers()[0]
342 try:
343 self.assertEquals(layer.GetClassificationColumn(), 'Fl\xe4che')
344 except UnicodeError:
345 # FIXME: Obviously this will have to change if Thuban ever
346 # supports unicode properly.
347 self.fail("Column name was not converted to a bytestring")
348
349 # roundtrip check
350 self.check_format()
351
352
353 class TestLayerVisibility(LoadSessionTest):
354
355 file_contents = '''\
356 <?xml version="1.0" encoding="UTF-8"?>
357 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
358 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
359 title="single map&amp;layer">
360 <fileshapesource filetype="shapefile" id="D1"
361 filename="../../Data/iceland/political.shp"/>
362 <map title="Test Map">
363 <projection name="Unknown">
364 <parameter value="zone=26"/>
365 <parameter value="proj=utm"/>
366 <parameter value="ellps=clrk66"/>
367 </projection>
368 <layer shapestore="D1" visible="false" stroke="#000000"
369 title="My Layer" stroke_width="1" fill="None"/>
370 </map>
371 </session>
372 '''
373
374 def test(self):
375 """Test that the visible flag is correctly loaded for a layer."""
376 eq = self.assertEquals
377 session = load_session(self.filename())
378 self.session = session
379 maps = session.Maps()
380 eq(len(maps), 1)
381 map = maps[0]
382 layers = map.Layers()
383 eq(len(layers), 1)
384 layer = layers[0]
385
386 eq(layer.Visible(), False)
387
388 self.check_format()
389
390
391 class TestClassification(ClassificationTest):
392
393 file_contents = '''\
394 <?xml version="1.0" encoding="UTF-8"?>
395 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
396 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
397 title="single map&amp;layer">
398 <fileshapesource filetype="shapefile" id="D138389860"
399 filename="../../Data/iceland/political.shp"/>
400 <fileshapesource filetype="shapefile" id="D138504492"
401 filename="../../Data/iceland/political.shp"/>
402 <map title="Test Map">
403 <projection name="">
404 <parameter value="zone=26"/>
405 <parameter value="proj=utm"/>
406 <parameter value="ellps=clrk66"/>
407 </projection>
408 <layer shapestore="D138389860" visible="true" stroke="#000000"
409 title="My Layer" stroke_width="1" fill="None">
410 <classification field="POPYREG" field_type="string">
411 <clnull label="">
412 <cldata stroke="#000000" stroke_width="1" fill="None"/>
413 </clnull>
414 <clpoint label="" value="1">
415 <cldata stroke="#000000" stroke_width="2" fill="None"/>
416 </clpoint>
417 <clpoint label="" value="1">
418 <cldata stroke="#000000" stroke_width="10" fill="None"/>
419 </clpoint>
420 <clpoint label="\xc3\x9cml\xc3\xa4uts"
421 value="\xc3\xa4\xc3\xb6\xc3\xbc">
422 <cldata stroke="#000000" stroke_width="1" fill="None"/>
423 </clpoint>
424 </classification>
425 </layer>
426 <layer shapestore="D138504492" visible="true" stroke="#000000"
427 title="My Layer 2" stroke_width="2" fill="None">
428 <classification field="AREA" field_type="double">
429 <clnull label="">
430 <cldata stroke="#000000" stroke_width="2" fill="None"/>
431 </clnull>
432 <clrange label="" range="[0;1[">
433 <cldata stroke="#111111" stroke_width="1" fill="None"/>
434 </clrange>
435 <clpoint label="" value="0.5">
436 <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
437 </clpoint>
438 <clrange label="" range="[-1;0[">
439 <cldata stroke="#000000" stroke_width="1" fill="None"/>
440 </clrange>
441 <clpoint label="" value="-0.5">
442 <cldata stroke="#000000" stroke_width="1" fill="None"/>
443 </clpoint>
444 </classification>
445 </layer>
446 </map>
447 </session>
448 '''
449
450 def test(self):
451 """Load a Thuban session with a map and classified layers."""
452 session = load_session(self.filename())
453 self.session = session
454
455 map = self.session.Maps()[0] # only one map in the sample
456
457 expected = [("My Layer", 3,
458 [("default", (), "",
459 ("#000000", 1, "None")),
460 ("single", "1", "",
461 ("#000000", 2, "None")),
462 ("single", "1", "",
463 ("#000000", 10, "None")),
464 ("single", "\xe4\xf6\xfc", "\xdcml\xe4uts",
465 ("#000000", 1, "None"))]),
466 ("My Layer 2", 4,
467 [("default", (), "",
468 ("#000000", 2, "None")),
469 ("range", (0, 1), "",
470 ("#111111", 1, "None")),
471 ("single", .5, "",
472 ("#000000", 1, "#111111")),
473 ("range", (-1, 0), "",
474 ("#000000", 1, "None")),
475 ("single", -.5, "",
476 ("#000000", 1, "None"))])]
477
478 self.TestLayers(map.Layers(), expected)
479
480 self.check_format()
481
482
483 class TestLabels(ClassificationTest):
484
485 file_contents = '''\
486 <?xml version="1.0" encoding="UTF-8"?>
487 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
488 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
489 title="single map&amp;layer">
490 <fileshapesource filetype="shapefile" id="D1"
491 filename="../../Data/iceland/political.shp"/>
492 <map title="Test Map">
493 <projection name="Unknown">
494 <parameter value="zone=26"/>
495 <parameter value="proj=utm"/>
496 <parameter value="ellps=clrk66"/>
497 </projection>
498 <layer shapestore="D1" visible="true" stroke="#000000"
499 title="My Layer" stroke_width="1" fill="None">
500 <classification field="POPYREG" field_type="string">
501 <clnull label="hallo">
502 <cldata stroke="#000000" stroke_width="1" fill="None"/>
503 </clnull>
504 <clpoint label="welt" value="1">
505 <cldata stroke="#000000" stroke_width="2" fill="None"/>
506 </clpoint>
507 </classification>
508 </layer>
509 </map>
510 </session>
511 '''
512
513 def test(self):
514 """Load a session and test for reading the group labels."""
515 eq = self.assertEquals
516 session = load_session(self.filename())
517 self.session = session
518
519 map = self.session.Maps()[0] # only one map in the sample
520
521 expected = [("My Layer", 1,
522 [("default", (), "hallo",
523 ("#000000", 1, "None")),
524 ("single", "1", "welt",
525 ("#000000", 2, "None"))])]
526
527 self.TestLayers(map.Layers(), expected)
528 self.check_format()
529
530
531 class TestLayerProjection(LoadSessionTest):
532
533 file_contents = '''\
534 <?xml version="1.0" encoding="UTF-8"?>
535 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
536 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
537 title="single map&amp;layer">
538 <fileshapesource filetype="shapefile" id="D2"
539 filename="../../Data/iceland/roads-line.shp"/>
540 <fileshapesource filetype="shapefile" id="D4"
541 filename="../../Data/iceland/political.shp"/>
542 <map title="Test Map">
543 <projection name="Unknown">
544 <parameter value="zone=26"/>
545 <parameter value="proj=utm"/>
546 <parameter value="ellps=clrk66"/>
547 </projection>
548 <layer shapestore="D4" visible="true" stroke="#000000"
549 title="My Layer" stroke_width="1" fill="None">
550 <projection name="hello">
551 <parameter value="zone=13"/>
552 <parameter value="proj=tmerc"/>
553 <parameter value="ellps=clrk66"/>
554 </projection>
555 <classification field="POPYREG" field_type="string">
556 <clnull label="hallo">
557 <cldata stroke="#000000" stroke_width="1" fill="None"/>
558 </clnull>
559 <clpoint label="welt" value="1">
560 <cldata stroke="#000000" stroke_width="2" fill="None"/>
561 </clpoint>
562 </classification>
563 </layer>
564 <layer shapestore="D2" visible="true" stroke="#000000"
565 title="My Layer" stroke_width="1" fill="None">
566 <projection name="Unknown">
567 <parameter value="proj=lcc"/>
568 <parameter value="lat_1=10"/>
569 <parameter value="lat_2=20"/>
570 <parameter value="ellps=clrk66"/>
571 </projection>
572 </layer>
573 </map>
574 </session>
575 '''
576
577 def test(self):
578 """Test loading layers with projections"""
579 eq = self.assertEquals
580 neq = self.assertNotEqual
581
582 session = load_session(self.filename())
583 self.session = session
584
585 map = self.session.Maps()[0] # only one map in the sample
586
587 layers = map.Layers() # two layers in the sample
588
589 # test layer with a named projection
590 proj = layers[0].GetProjection()
591 neq(proj, None)
592 eq(proj.GetName(), "hello")
593 eq(proj.GetParameter("proj"), "tmerc")
594 eq(proj.GetParameter("zone"), "13")
595 eq(proj.GetParameter("ellps"), "clrk66")
596
597 # test layer with an unnamed projection
598 proj = layers[1].GetProjection()
599 neq(proj, None)
600 eq(proj.GetName(), "Unknown")
601 eq(proj.GetParameter("proj"), "lcc")
602 eq(proj.GetParameter("lat_1"), "10")
603 eq(proj.GetParameter("lat_2"), "20")
604 eq(proj.GetParameter("ellps"), "clrk66")
605
606 self.check_format()
607
608
609 class TestRasterLayer(LoadSessionTest):
610
611 file_contents = '''\
612 <?xml version="1.0" encoding="UTF-8"?>
613 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
614 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
615 title="single map&amp;layer">
616 <map title="Test Map">
617 <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
618 title="My RasterLayer"/>
619 </map>
620 </session>
621 '''
622
623 def test(self):
624 eq = self.assertEquals
625 neq = self.assertNotEqual
626
627 session = load_session(self.filename())
628 self.session = session
629
630 map = self.session.Maps()[0] # only one map in the sample
631
632 layer = map.Layers()[0] # one layer in the sample
633
634 eq(layer.Title(), "My RasterLayer")
635 self.failIf(layer.Visible())
636 self.failUnless(filenames_equal(layer.GetImageFilename(),
637 os.path.join(self.temp_dir(),
638 os.pardir, os.pardir,
639 "Data", "iceland",
640 "island.tif")))
641 self.check_format()
642
643
644 class TestJoinedTable(LoadSessionTest):
645
646 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
647 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
648 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd" title="A Joined Table session">
649 <fileshapesource filetype="shapefile" id="D137227612"
650 filename="../../Data/iceland/roads-line.shp"/>
651 <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
652 title="Some Title"/>
653 <jointable id="D136169900" title="Joined"
654 right="D136171140" left="D137227612"
655 leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
656 jointype="LEFT OUTER"/>
657 <derivedshapesource table="D136169900" shapesource="D137227612"
658 id="D136170932"/>
659 <map title="Test Map">
660 <layer shapestore="D136170932" visible="true" stroke="#000000"
661 title="My Layer" stroke_width="1" fill="None"/>
662 </map>
663 </session>
664 '''
665
666 def setUp(self):
667 """Extend inherited method to create the dbffile for the join"""
668 LoadSessionTest.setUp(self)
669 dbffile = self.temp_file_name("load_joinedtable.dbf")
670 dbf = dbflib.create(dbffile)
671 dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
672 dbf.add_field("TEXT", dbflib.FTString, 10, 0)
673 dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
674 dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
675 dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
676 dbf.close()
677
678 def test(self):
679 """Test loading a session containing a joined table"""
680 session = load_session(self.filename())
681 self.session = session
682
683 tables = session.Tables()
684 self.assertEquals(len(tables), 3)
685 # FIXME: The tests shouldn't assume a certain order of the tables
686 self.assertEquals(tables[0].Title(), "Some Title")
687 self.assertEquals(tables[1].Title(), "Joined")
688 self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
689 self.check_format()
690
691
692 class TestLabelLayer(LoadSessionTest):
693
694 # Note that the labels deliberately contain non-ascii characters to
695 # test whether they're supported correctly.
696
697 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
698 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
699 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd" title="Thuban sample session">
700 <fileshapesource filetype="shapefile" id="D145265052"
701 filename="../../Data/iceland/political.shp"/>
702 <fileshapesource filetype="shapefile" id="D145412868"
703 filename="../../Data/iceland/cultural_landmark-point.shp"/>
704 <map title="Iceland map">
705 <projection name="Unknown">
706 <parameter value="zone=26"/>
707 <parameter value="proj=utm"/>
708 <parameter value="ellps=clrk66"/>
709 </projection>
710 <layer shapestore="D145265052" visible="true" stroke="#000000"
711 title="political" stroke_width="1" fill="#c0c0c0">
712 <projection name="Geographic">
713 <parameter value="proj=latlong"/>
714 <parameter value="to_meter=0.017453"/>
715 <parameter value="ellps=clrk66"/>
716 </projection>
717 </layer>
718 <layer shapestore="D145412868" visible="true" stroke="#000000"
719 title="landmarks" stroke_width="1" fill="#ffff00">
720 <projection name="Geographic">
721 <parameter value="proj=latlong"/>
722 <parameter value="to_meter=0.017453"/>
723 <parameter value="ellps=clrk66"/>
724 </projection>
725 </layer>
726 <labellayer>
727 <label x="-21.5" y="64.25" text="RUINS"
728 halign="left" valign="center"/>
729 <label x="-15.125" y="64.75" text="H\xc3\xbctte"
730 halign="right" valign="top"/>
731 </labellayer>
732 </map>
733 </session>
734 '''
735
736 def test(self):
737 """Test loading a session with a label layer"""
738 session = load_session(self.filename())
739 self.session = session
740
741 label_layer = self.session.Maps()[0].LabelLayer()
742 expected_labels = [(-21.5, 64.25, "RUINS", ALIGN_LEFT, ALIGN_CENTER),
743 (-15.125, 64.75, "H\xfctte", ALIGN_RIGHT, ALIGN_TOP),
744 ]
745 for label, values in zip(label_layer.Labels(), expected_labels):
746 self.assertEquals((label.x, label.y, label.text, label.halign,
747 label.valign),
748 values)
749 self.check_format()
750
751
752 class TestPostGISLayer(LoadSessionTest):
753
754 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
755 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
756 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
757 title="unnamed session">
758 <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
759 dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
760 <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
761 <map title="unnamed map">
762 <layer shapestore="D143149420" visible="true" stroke="#000000"
763 title="landmarks" stroke_width="1" fill="None"/>
764 </map>
765 </session>
766 '''
767
768 def setUp(self):
769 """Extend the inherited method to start the postgis server
770
771 Furthermore, patch the file contents with the real postgis db
772 information
773 """
774 postgissupport.skip_if_no_postgis()
775 self.server = postgissupport.get_test_server()
776 self.postgisdb = self.server.get_default_static_data_db()
777
778 self.file_contents = self.__class__.file_contents % {
779 "dbname": self.postgisdb.dbname,
780 "user": self.server.user_name,
781 "port": self.server.port,
782 "host": self.server.host}
783 LoadSessionTest.setUp(self)
784
785 def test(self):
786 """Test loading a session containing a postgis shapestore"""
787 session = load_session(self.filename())
788 self.session = session
789 connections = session.DBConnections()
790 self.assertEquals(len(connections), 1)
791 conn = connections[0]
792 for attr, value in [("host", self.server.host),
793 ("port", str(self.server.port)),
794 ("user", self.server.user_name),
795 ("dbname", self.postgisdb.dbname)]:
796 self.assertEquals(getattr(conn, attr), value)
797 layer = session.Maps()[0].Layers()[0]
798 self.failUnless(layer.ShapeStore().DBConnection() is conn)
799
800
801 class TestPostGISLayerPassword(LoadSessionTest):
802
803 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
804 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
805 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.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 tablename="landmarks" id="D143149420" dbconn="D142684948"/>
810 <map title="unnamed map">
811 <layer shapestore="D143149420" visible="true" stroke="#000000"
812 title="landmarks" stroke_width="1" fill="None"/>
813 </map>
814 </session>
815 '''
816
817 def setUp(self):
818 """Extend the inherited method to start the postgis server
819
820 Furthermore, patch the file contents with the real postgis db
821 information
822 """
823 postgissupport.skip_if_no_postgis()
824 self.server = postgissupport.get_test_server()
825 self.postgisdb = self.server.get_default_static_data_db()
826
827 self.file_contents = self.__class__.file_contents % {
828 "dbname": self.postgisdb.dbname,
829 "user": self.server.user_name,
830 "port": self.server.port,
831 "host": self.server.host}
832 LoadSessionTest.setUp(self)
833
834 self.db_connection_callback_called = False
835 self.server.require_authentication(True)
836
837 def tearDown(self):
838 """Extend the inherited method to switch off postgresql authentication
839 """
840 self.server.require_authentication(False)
841 LoadSessionTest.tearDown(self)
842
843 def db_connection_callback(self, params, message):
844 """Implementation of Thuban.Model.hooks.query_db_connection_parameters
845 """
846 self.assertEquals(params,
847 {"dbname": self.postgisdb.dbname,
848 "user": self.server.user_name,
849 "port": str(self.server.port),
850 "host": self.server.host})
851 self.db_connection_callback_called = True
852 params = params.copy()
853 params["password"] = self.server.user_password
854 return params
855
856 def test_with_callback(self):
857 """Test loading a session with postgis, authentication and a callback
858 """
859 session = load_session(self.filename(),
860 db_connection_callback = self.db_connection_callback)
861 self.session = session
862 connections = session.DBConnections()
863 self.assertEquals(len(connections), 1)
864 conn = connections[0]
865 for attr, value in [("host", self.server.host),
866 ("port", str(self.server.port)),
867 ("user", self.server.user_name),
868 ("dbname", self.postgisdb.dbname)]:
869 self.assertEquals(getattr(conn, attr), value)
870 layer = session.Maps()[0].Layers()[0]
871 self.failUnless(layer.ShapeStore().DBConnection() is conn)
872 self.failUnless(self.db_connection_callback_called)
873
874 def test_without_callback(self):
875 """Test loading a session with postgis, authentication and no callback
876 """
877 # A password is required and there's no callback, so we should
878 # get a ConnectionError
879 self.assertRaises(ConnectionError, load_session, self.filename())
880
881 def test_cancel(self):
882 """Test loading a session with postgis and cancelling authentication
883 """
884 def cancel(*args):
885 self.db_connection_callback_called = True
886 return None
887
888 # If the user cancels, i.e. if the callbakc returns None, a
889 # LoadCancelled exception is raised.
890 self.assertRaises(LoadCancelled,
891 load_session, self.filename(), cancel)
892 self.failUnless(self.db_connection_callback_called)
893
894
895 class TestLoadError(LoadSessionTest):
896
897 file_contents = '''\
898 <?xml version="1.0" encoding="UTF-8"?>
899 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
900 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
901 title="single map&amp;layer">
902 <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
903 <map title="Test Map">
904 <projection name="Unknown">
905 <parameter value="zone=26"/>
906 <parameter value="proj=utm"/>
907 <parameter value="ellps=clrk66"/>
908 </projection>
909 <layer shapestore="D1" visible="true"
910 stroke="#000000" title="My Layer" stroke_width="1"
911 fill="None"/>
912 </map>
913 </session>
914 '''
915
916 def test(self):
917 """Test loading a session missing a required attribute"""
918 # Don't use assertRaises to make sure that if a session is
919 # actually returned it gets destroyed properly.
920 try:
921 self.session = load_session(self.filename())
922 except LoadError, value:
923 # Check the actual messge in value to make sure the
924 # LoadError really was about the missing attribute
925 self.assertEquals(str(value),
926 "Element "
927 "(u'http://thuban.intevation.org/dtds/thuban-1.0.0.dtd',"
928 " u'fileshapesource') requires an attribute 'filetype'")
929 else:
930 self.fail("Missing filetype attribute doesn't raise LoadError")
931
932 if __name__ == "__main__":
933 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