/[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 1970 - (show annotations)
Mon Nov 24 18:36:00 2003 UTC (21 years, 3 months ago) by bh
Original Path: trunk/thuban/test/test_load.py
File MIME type: text/x-python
File size: 32559 byte(s)
* Thuban/Model/load.py (SessionLoader.check_attrs): If no
converter is specified for an attribute assume it's a string
containing only Latin1 characters. Update doc-string accordingly.
This change should fix many places where unicode objects might
accidentally enter Thuban.

* test/test_load.py (TestNonAsciiColumnName): New test to check
what happens with column names in DBF files that contain non-ascii
characters

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