/[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 1976 - (show annotations)
Tue Nov 25 14:26:08 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: 32961 byte(s)
(TestClassification.test): Add the missing
round trip test.
(TestClassification.file_contents): Update to the newest file
format

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-1.0.dtd">
393 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd"
394 title="single map&amp;layer">
395 <fileshapesource filetype="shapefile" id="D138389860"
396 filename="../../Data/iceland/political.shp"/>
397 <fileshapesource filetype="shapefile" id="D138504492"
398 filename="../../Data/iceland/political.shp"/>
399 <map title="Test Map">
400 <projection name="">
401 <parameter value="zone=26"/>
402 <parameter value="proj=utm"/>
403 <parameter value="ellps=clrk66"/>
404 </projection>
405 <layer shapestore="D138389860" visible="true" stroke="#000000"
406 title="My Layer" stroke_width="1" fill="None">
407 <classification field="POPYREG" field_type="string">
408 <clnull label="">
409 <cldata stroke="#000000" stroke_width="1" fill="None"/>
410 </clnull>
411 <clpoint label="" value="1">
412 <cldata stroke="#000000" stroke_width="2" fill="None"/>
413 </clpoint>
414 <clpoint label="" value="1">
415 <cldata stroke="#000000" stroke_width="10" fill="None"/>
416 </clpoint>
417 <clpoint label="\xc3\x9cml\xc3\xa4uts"
418 value="\xc3\xa4\xc3\xb6\xc3\xbc">
419 <cldata stroke="#000000" stroke_width="1" fill="None"/>
420 </clpoint>
421 </classification>
422 </layer>
423 <layer shapestore="D138504492" visible="true" stroke="#000000"
424 title="My Layer 2" stroke_width="2" fill="None">
425 <classification field="AREA" field_type="double">
426 <clnull label="">
427 <cldata stroke="#000000" stroke_width="2" fill="None"/>
428 </clnull>
429 <clrange label="" range="[0;1[">
430 <cldata stroke="#111111" stroke_width="1" fill="None"/>
431 </clrange>
432 <clpoint label="" value="0.5">
433 <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
434 </clpoint>
435 <clrange label="" range="[-1;0[">
436 <cldata stroke="#000000" stroke_width="1" fill="None"/>
437 </clrange>
438 <clpoint label="" value="-0.5">
439 <cldata stroke="#000000" stroke_width="1" fill="None"/>
440 </clpoint>
441 </classification>
442 </layer>
443 </map>
444 </session>
445 '''
446
447 def test(self):
448 """Load a Thuban session with a map and classified layers."""
449 session = load_session(self.filename())
450 self.session = session
451
452 map = self.session.Maps()[0] # only one map in the sample
453
454 expected = [("My Layer", 3,
455 [("default", (), "",
456 ("#000000", 1, "None")),
457 ("single", "1", "",
458 ("#000000", 2, "None")),
459 ("single", "1", "",
460 ("#000000", 10, "None")),
461 ("single", "\xe4\xf6\xfc", "\xdcml\xe4uts",
462 ("#000000", 1, "None"))]),
463 ("My Layer 2", 4,
464 [("default", (), "",
465 ("#000000", 2, "None")),
466 ("range", (0, 1), "",
467 ("#111111", 1, "None")),
468 ("single", .5, "",
469 ("#000000", 1, "#111111")),
470 ("range", (-1, 0), "",
471 ("#000000", 1, "None")),
472 ("single", -.5, "",
473 ("#000000", 1, "None"))])]
474
475 self.TestLayers(map.Layers(), expected)
476
477 self.check_format()
478
479
480 class TestLabels(ClassificationTest):
481
482 file_contents = '''\
483 <?xml version="1.0" encoding="UTF-8"?>
484 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
485 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd"
486 title="single map&amp;layer">
487 <fileshapesource filetype="shapefile" id="D1"
488 filename="../../Data/iceland/political.shp"/>
489 <map title="Test Map">
490 <projection name="Unknown">
491 <parameter value="zone=26"/>
492 <parameter value="proj=utm"/>
493 <parameter value="ellps=clrk66"/>
494 </projection>
495 <layer shapestore="D1" visible="true" stroke="#000000"
496 title="My Layer" stroke_width="1" fill="None">
497 <classification field="POPYREG" field_type="string">
498 <clnull label="hallo">
499 <cldata stroke="#000000" stroke_width="1" fill="None"/>
500 </clnull>
501 <clpoint label="welt" value="1">
502 <cldata stroke="#000000" stroke_width="2" fill="None"/>
503 </clpoint>
504 </classification>
505 </layer>
506 </map>
507 </session>
508 '''
509
510 def test(self):
511 """Load a session and test for reading the group labels."""
512 eq = self.assertEquals
513 session = load_session(self.filename())
514 self.session = session
515
516 map = self.session.Maps()[0] # only one map in the sample
517
518 expected = [("My Layer", 1,
519 [("default", (), "hallo",
520 ("#000000", 1, "None")),
521 ("single", "1", "welt",
522 ("#000000", 2, "None"))])]
523
524 self.TestLayers(map.Layers(), expected)
525 self.check_format()
526
527
528 class TestLayerProjection(LoadSessionTest):
529
530 file_contents = '''\
531 <?xml version="1.0" encoding="UTF-8"?>
532 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
533 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd"
534 title="single map&amp;layer">
535 <fileshapesource filetype="shapefile" id="D2"
536 filename="../../Data/iceland/roads-line.shp"/>
537 <fileshapesource filetype="shapefile" id="D4"
538 filename="../../Data/iceland/political.shp"/>
539 <map title="Test Map">
540 <projection name="Unknown">
541 <parameter value="zone=26"/>
542 <parameter value="proj=utm"/>
543 <parameter value="ellps=clrk66"/>
544 </projection>
545 <layer shapestore="D4" visible="true" stroke="#000000"
546 title="My Layer" stroke_width="1" fill="None">
547 <projection name="hello">
548 <parameter value="zone=13"/>
549 <parameter value="proj=tmerc"/>
550 <parameter value="ellps=clrk66"/>
551 </projection>
552 <classification field="POPYREG" field_type="string">
553 <clnull label="hallo">
554 <cldata stroke="#000000" stroke_width="1" fill="None"/>
555 </clnull>
556 <clpoint label="welt" value="1">
557 <cldata stroke="#000000" stroke_width="2" fill="None"/>
558 </clpoint>
559 </classification>
560 </layer>
561 <layer shapestore="D2" visible="true" stroke="#000000"
562 title="My Layer" stroke_width="1" fill="None">
563 <projection name="Unknown">
564 <parameter value="proj=lcc"/>
565 <parameter value="lat_1=10"/>
566 <parameter value="lat_2=20"/>
567 <parameter value="ellps=clrk66"/>
568 </projection>
569 </layer>
570 </map>
571 </session>
572 '''
573
574 def test(self):
575 """Test loading layers with projections"""
576 eq = self.assertEquals
577 neq = self.assertNotEqual
578
579 session = load_session(self.filename())
580 self.session = session
581
582 map = self.session.Maps()[0] # only one map in the sample
583
584 layers = map.Layers() # two layers in the sample
585
586 # test layer with a named projection
587 proj = layers[0].GetProjection()
588 neq(proj, None)
589 eq(proj.GetName(), "hello")
590 eq(proj.GetParameter("proj"), "tmerc")
591 eq(proj.GetParameter("zone"), "13")
592 eq(proj.GetParameter("ellps"), "clrk66")
593
594 # test layer with an unnamed projection
595 proj = layers[1].GetProjection()
596 neq(proj, None)
597 eq(proj.GetName(), "Unknown")
598 eq(proj.GetParameter("proj"), "lcc")
599 eq(proj.GetParameter("lat_1"), "10")
600 eq(proj.GetParameter("lat_2"), "20")
601 eq(proj.GetParameter("ellps"), "clrk66")
602
603 self.check_format()
604
605
606 class TestRasterLayer(LoadSessionTest):
607
608 file_contents = '''\
609 <?xml version="1.0" encoding="UTF-8"?>
610 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
611 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd"
612 title="single map&amp;layer">
613 <map title="Test Map">
614 <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
615 title="My RasterLayer"/>
616 </map>
617 </session>
618 '''
619
620 def test(self):
621 eq = self.assertEquals
622 neq = self.assertNotEqual
623
624 session = load_session(self.filename())
625 self.session = session
626
627 map = self.session.Maps()[0] # only one map in the sample
628
629 layer = map.Layers()[0] # one layer in the sample
630
631 eq(layer.Title(), "My RasterLayer")
632 self.failIf(layer.Visible())
633 self.failUnless(filenames_equal(layer.GetImageFilename(),
634 os.path.join(self.temp_dir(),
635 os.pardir, os.pardir,
636 "Data", "iceland",
637 "island.tif")))
638 self.check_format()
639
640
641 class TestJoinedTable(LoadSessionTest):
642
643 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
644 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
645 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd" title="A Joined Table session">
646 <fileshapesource filetype="shapefile" id="D137227612"
647 filename="../../Data/iceland/roads-line.shp"/>
648 <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
649 title="Some Title"/>
650 <jointable id="D136169900" title="Joined"
651 right="D136171140" left="D137227612"
652 leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
653 jointype="LEFT OUTER"/>
654 <derivedshapesource table="D136169900" shapesource="D137227612"
655 id="D136170932"/>
656 <map title="Test Map">
657 <layer shapestore="D136170932" visible="true" stroke="#000000"
658 title="My Layer" stroke_width="1" fill="None"/>
659 </map>
660 </session>
661 '''
662
663 def setUp(self):
664 """Extend inherited method to create the dbffile for the join"""
665 LoadSessionTest.setUp(self)
666 dbffile = self.temp_file_name("load_joinedtable.dbf")
667 dbf = dbflib.create(dbffile)
668 dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
669 dbf.add_field("TEXT", dbflib.FTString, 10, 0)
670 dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
671 dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
672 dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
673 dbf.close()
674
675 def test(self):
676 """Test loading a session containing a joined table"""
677 session = load_session(self.filename())
678 self.session = session
679
680 tables = session.Tables()
681 self.assertEquals(len(tables), 3)
682 # FIXME: The tests shouldn't assume a certain order of the tables
683 self.assertEquals(tables[0].Title(), "Some Title")
684 self.assertEquals(tables[1].Title(), "Joined")
685 self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
686 self.check_format()
687
688
689
690 class TestPostGISLayer(LoadSessionTest):
691
692 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
693 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
694 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd"
695 title="unnamed session">
696 <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
697 dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
698 <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
699 <map title="unnamed map">
700 <layer shapestore="D143149420" visible="true" stroke="#000000"
701 title="landmarks" stroke_width="1" fill="None"/>
702 </map>
703 </session>
704 '''
705
706 def setUp(self):
707 """Extend the inherited method to start the postgis server
708
709 Furthermore, patch the file contents with the real postgis db
710 information
711 """
712 postgissupport.skip_if_no_postgis()
713 self.server = postgissupport.get_test_server()
714 self.postgisdb = self.server.get_default_static_data_db()
715
716 self.file_contents = self.__class__.file_contents % {
717 "dbname": self.postgisdb.dbname,
718 "user": self.server.user_name,
719 "port": self.server.port,
720 "host": self.server.host}
721 LoadSessionTest.setUp(self)
722
723 def test(self):
724 """Test loading a session containing a postgis shapestore"""
725 session = load_session(self.filename())
726 self.session = session
727 connections = session.DBConnections()
728 self.assertEquals(len(connections), 1)
729 conn = connections[0]
730 for attr, value in [("host", self.server.host),
731 ("port", str(self.server.port)),
732 ("user", self.server.user_name),
733 ("dbname", self.postgisdb.dbname)]:
734 self.assertEquals(getattr(conn, attr), value)
735 layer = session.Maps()[0].Layers()[0]
736 self.failUnless(layer.ShapeStore().DBConnection() is conn)
737
738
739 class TestPostGISLayerPassword(LoadSessionTest):
740
741 file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
742 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
743 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd"
744 title="unnamed session">
745 <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
746 dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
747 <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
748 <map title="unnamed map">
749 <layer shapestore="D143149420" visible="true" stroke="#000000"
750 title="landmarks" stroke_width="1" fill="None"/>
751 </map>
752 </session>
753 '''
754
755 def setUp(self):
756 """Extend the inherited method to start the postgis server
757
758 Furthermore, patch the file contents with the real postgis db
759 information
760 """
761 postgissupport.skip_if_no_postgis()
762 self.server = postgissupport.get_test_server()
763 self.postgisdb = self.server.get_default_static_data_db()
764
765 self.file_contents = self.__class__.file_contents % {
766 "dbname": self.postgisdb.dbname,
767 "user": self.server.user_name,
768 "port": self.server.port,
769 "host": self.server.host}
770 LoadSessionTest.setUp(self)
771
772 self.db_connection_callback_called = False
773 self.server.require_authentication(True)
774
775 def tearDown(self):
776 """Extend the inherited method to switch off postgresql authentication
777 """
778 self.server.require_authentication(False)
779 LoadSessionTest.tearDown(self)
780
781 def db_connection_callback(self, params, message):
782 """Implementation of Thuban.Model.hooks.query_db_connection_parameters
783 """
784 self.assertEquals(params,
785 {"dbname": self.postgisdb.dbname,
786 "user": self.server.user_name,
787 "port": str(self.server.port),
788 "host": self.server.host})
789 self.db_connection_callback_called = True
790 params = params.copy()
791 params["password"] = self.server.user_password
792 return params
793
794 def test_with_callback(self):
795 """Test loading a session with postgis, authentication and a callback
796 """
797 session = load_session(self.filename(),
798 db_connection_callback = self.db_connection_callback)
799 self.session = session
800 connections = session.DBConnections()
801 self.assertEquals(len(connections), 1)
802 conn = connections[0]
803 for attr, value in [("host", self.server.host),
804 ("port", str(self.server.port)),
805 ("user", self.server.user_name),
806 ("dbname", self.postgisdb.dbname)]:
807 self.assertEquals(getattr(conn, attr), value)
808 layer = session.Maps()[0].Layers()[0]
809 self.failUnless(layer.ShapeStore().DBConnection() is conn)
810 self.failUnless(self.db_connection_callback_called)
811
812 def test_without_callback(self):
813 """Test loading a session with postgis, authentication and no callback
814 """
815 # A password is required and there's no callback, so we should
816 # get a ConnectionError
817 self.assertRaises(ConnectionError, load_session, self.filename())
818
819 def test_cancel(self):
820 """Test loading a session with postgis and cancelling authentication
821 """
822 def cancel(*args):
823 self.db_connection_callback_called = True
824 return None
825
826 # If the user cancels, i.e. if the callbakc returns None, a
827 # LoadCancelled exception is raised.
828 self.assertRaises(LoadCancelled,
829 load_session, self.filename(), cancel)
830 self.failUnless(self.db_connection_callback_called)
831
832
833 class TestLoadError(LoadSessionTest):
834
835 file_contents = '''\
836 <?xml version="1.0" encoding="UTF-8"?>
837 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
838 <session xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd"
839 title="single map&amp;layer">
840 <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
841 <map title="Test Map">
842 <projection name="Unknown">
843 <parameter value="zone=26"/>
844 <parameter value="proj=utm"/>
845 <parameter value="ellps=clrk66"/>
846 </projection>
847 <layer shapestore="D1" visible="true"
848 stroke="#000000" title="My Layer" stroke_width="1"
849 fill="None"/>
850 </map>
851 </session>
852 '''
853
854 def test(self):
855 """Test loading a session missing a required attribute"""
856 # Don't use assertRaises to make sure that if a session is
857 # actually returned it gets destroyed properly.
858 try:
859 self.session = load_session(self.filename())
860 except LoadError, value:
861 # Check the actual messge in value to make sure the
862 # LoadError really was about the missing attribute
863 self.assertEquals(str(value),
864 "Element "
865 "(u'http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd',"
866 " u'fileshapesource') requires an attribute 'filetype'")
867 else:
868 self.fail("Missing filetype attribute doesn't raise LoadError")
869
870 if __name__ == "__main__":
871 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