/[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 1989 - (show annotations)
Fri Nov 28 12:00:54 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: 32918 byte(s)
Unify the filenames stored in .thuban files so that the .thuban
files are more platform independend

* Thuban/Model/save.py (unify_filename): New. Unify filenames so
that they can be used on both windows and unix
(SessionSaver.prepare_filename): New. Handle all filename
transformations for filenames stored in the thuban file
(SessionSaver.write_data_containers, SessionSaver.write_layer):
Use prepare_filename

* test/test_save.py (SaveSessionTest.testSingleLayer)
(SaveSessionTest.testLayerProjection)
(SaveSessionTest.testRasterLayer)
(SaveSessionTest.testClassifiedLayer)
(SaveSessionTest.test_dbf_table)
(SaveSessionTest.test_joined_table): Filenames are always stored
with slashes on all currently supported platforms so adapt all
tests to this

* test/test_load.py (LoadSessionTest.filenames): With the new
filename scheme the filenames in the tests should be
understandable on all currently supported platforms so we turn
this into an empty list because we don't have to normalize them
anymore

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