/[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 2551 - (show annotations)
Thu Jan 27 14:19:41 2005 UTC (20 years, 1 month ago) by jonathan
Original Path: trunk/thuban/test/test_load.py
File MIME type: text/x-python
File size: 43002 byte(s)
Add a new dialog box for raster layers. The dialog box allows
the user to toggle a mask that is generated by ProjectRasterFile
and is used to only draw the real parts of the projected image.

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