/[thuban]/branches/WIP-pyshapelib-bramz/test/test_load.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/test/test_load.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2451 - (hide annotations)
Mon Dec 13 17:51:11 2004 UTC (20 years, 2 months ago) by bh
Original Path: trunk/thuban/test/test_load.py
File MIME type: text/x-python
File size: 42367 byte(s)
* test/test_load.py (TestAltPath.test_01_single_path_error_fix)
(TestAltPath.test_02_path_error_fix_from_list)
(TestAltPath.test_05_path_error_fix_from_list_changed)
(TestAltPath.test_06_path_error_fix_from_list_fails): self.session
is destroyed in tearDown, so there's no need to do it in a test
case.

* Thuban/Model/load.py (SessionLoader.open_shapefile): Remove a
debug print

1 bh 2104 # Copyright (c) 2002, 2003, 2004 by Intevation GmbH
2 bh 292 # 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 bh 1247
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 bh 2104 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 bh 1257 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 bh 292 """
26    
27     __version__ = "$Revision$"
28     # $Source$
29     # $Id$
30    
31     import os
32     import unittest
33    
34     import support
35     support.initthuban()
36    
37 bh 1646 import postgissupport
38 bh 1257 from xmlsupport import sax_eventlist
39 bh 1268
40     import dbflib
41 bh 1970 import shapelib
42 bh 1268
43 bh 1257 from Thuban.Model.save import save_session
44 bh 1646 from Thuban.Model.load import load_session, parse_color, LoadError, \
45     LoadCancelled
46 jonathan 1350 from Thuban.Model.color import Transparent
47 jonathan 684 from Thuban.Model.classification import ClassGroupProperties, ClassGroupRange,\
48     ClassGroupSingleton, ClassGroupDefault
49 bh 1646 from Thuban.Model.postgisdb import ConnectionError
50 bh 1970 from Thuban.Model.table import DBFTable, MemoryTable, \
51     FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING, \
52     table_to_dbf
53 bh 2034 from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
54     ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE
55 jonathan 684
56 bh 1970
57 bh 292 def filenames_equal(name1, name2):
58     """Return true if the filenames name1 and name2 are equal.
59    
60     On systems where it is available, simply use os.path.samefile,
61     otherwise return whether the normalized versions of the filenames
62     according to os.path.normpath are equal.
63     """
64     if hasattr(os.path, "samefile"):
65     return os.path.samefile(name1, name2)
66     return os.path.normpath(name1) == os.path.normpath(name2)
67    
68    
69 bh 957
70     class LoadSessionTest(support.FileLoadTestCase):
71    
72     """Base class for .thuban file loading tests
73    
74     Basically the same as the FileLoadTestCase, except that all tests
75     use the '.thuban' extension by default and that setUp and tearDown
76     handle sessions.
77     """
78    
79     file_extension = ".thuban"
80    
81     def setUp(self):
82     """Create the test files"""
83     support.FileLoadTestCase.setUp(self)
84     self.session = None
85    
86     def tearDown(self):
87     if self.session is not None:
88     self.session.Destroy()
89     self.session = None
90    
91 bh 1268
92 bh 2104 dtd = "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
93 bh 1268 thubanids = [((dtd, n), (None, "id")) for n in
94     ["fileshapesource", "filetable", "jointable",
95     "derivedshapesource"]]
96     thubanidrefs = [((dtd, n), (None, m)) for n, m in
97     [("layer", "shapestore"),
98     ("jointable", "left"),
99     ("jointable", "right"),
100     ("derivedshapesource", "table"),
101     ("derivedshapesource", "shapesource")]]
102 bh 1989
103     # The filenames in the tests should be understandable on all
104     # currently supported platforms so filenames is an empty list
105     filenames = []
106    
107 bh 1268 del n, m, dtd
108    
109 bh 1257 def check_format(self):
110     """Check whether the file we loaded from matches the one that
111     would be written. Call this from each test case after loading
112     the session
113     """
114     filename = self.temp_file_name(self.id() + ".roundtrip.thuban")
115     save_session(self.session, filename)
116 bh 1268 el1 = sax_eventlist(filename = filename, ids = self.thubanids,
117 bh 1683 idrefs = self.thubanidrefs,
118     filenames = self.filenames)
119 bh 1268 el2 = sax_eventlist(filename = self.filename(), ids = self.thubanids,
120 bh 1683 idrefs = self.thubanidrefs,
121     filenames = self.filenames)
122 bh 1268 if 0:
123     for a, b in zip(el1, el2):
124     print a != b and "***************" or ""
125     print a
126     print b
127     self.assertEquals(el1, el2,
128     "loaded file not equivalent to the saved file")
129 bh 957
130 bh 1257
131 bh 957 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 jan 2373 if len(data[CLASSES][i][GROUP_PROPS]) > 3:
166     props.SetSize(data[CLASSES][i][GROUP_PROPS][3])
167 bh 957
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 jonathan 1357 g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
172     data[CLASSES][i][GROUP_DATA][1]),
173 bh 957 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 bh 1846 # Note: The use of &amp; and non-ascii characters is deliberate. We
187     # want to test whether the loading code handles that correctly.
188 bh 957 file_contents = '''\
189 bh 292 <?xml version="1.0" encoding="UTF-8"?>
190 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
191     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
192 bh 1848 title="Stra\xc3\x9fen &amp; Landmarken">
193 bh 1268 <fileshapesource filetype="shapefile" id="D1"
194     filename="../../Data/iceland/political.shp"/>
195 bh 1848 <map title="\xc3\x9cbersicht">
196 bh 1846 <projection epsg="32627" name="WGS 84 / UTM zone 27N">
197     <parameter value="datum=WGS84"/>
198     <parameter value="ellps=WGS84"/>
199 bh 1268 <parameter value="proj=utm"/>
200 bh 1846 <parameter value="units=m"/>
201     <parameter value="zone=27"/>
202 bh 1268 </projection>
203     <layer shapestore="D1" visible="true"
204 bh 1848 stroke="#000000" title="K\xc3\xbcste" stroke_width="1"
205 bh 1268 fill="None"/>
206     </map>
207 bh 292 </session>
208     '''
209    
210 bh 957 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 bh 1848 eq(session.Title(), "Stra\xdfen & Landmarken")
218 bh 957
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 bh 1848 eq(map.Title(), "\xdcbersicht")
226 bh 1846 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 bh 957
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 bh 1848 eq(layer.Title(), "K\xfcste")
241 bh 1219 self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
242 bh 957 os.path.join(self.temp_dir(),
243     os.pardir, os.pardir,
244     "Data", "iceland",
245     "political.shp")))
246 jonathan 1347 eq(layer.GetClassification().GetDefaultFill(), Transparent)
247 bh 957 eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
248     eq(layer.Visible(), True)
249    
250 bh 1257 self.check_format()
251    
252 bh 957 self.session.Destroy()
253     self.session = None
254    
255 bh 1931 def test_leak(self):
256     """Test load_session for resource leaks
257 bh 957
258 bh 1931 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 bh 1970 class TestNonAsciiColumnName(LoadSessionTest):
279    
280     file_contents = '''\
281     <?xml version="1.0" encoding="UTF-8"?>
282 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
283     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
284 bh 1970 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 bh 957 class TestLayerVisibility(LoadSessionTest):
356    
357     file_contents = '''\
358 jonathan 690 <?xml version="1.0" encoding="UTF-8"?>
359 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
360     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
361 bh 1268 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 bh 957 </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 bh 1257 self.check_format()
391 bh 957
392    
393 jan 2373 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 bh 957 class TestClassification(ClassificationTest):
441    
442     file_contents = '''\
443     <?xml version="1.0" encoding="UTF-8"?>
444 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
445     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
446 bh 1976 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 jonathan 690 <classification field="POPYREG" field_type="string">
460 bh 1976 <clnull label="">
461 jonathan 690 <cldata stroke="#000000" stroke_width="1" fill="None"/>
462     </clnull>
463 bh 1976 <clpoint label="" value="1">
464 jonathan 690 <cldata stroke="#000000" stroke_width="2" fill="None"/>
465     </clpoint>
466 bh 1976 <clpoint label="" value="1">
467 jonathan 690 <cldata stroke="#000000" stroke_width="10" fill="None"/>
468     </clpoint>
469 bh 1976 <clpoint label="\xc3\x9cml\xc3\xa4uts"
470     value="\xc3\xa4\xc3\xb6\xc3\xbc">
471     <cldata stroke="#000000" stroke_width="1" fill="None"/>
472 bh 1417 </clpoint>
473 jonathan 690 </classification>
474     </layer>
475 bh 1976 <layer shapestore="D138504492" visible="true" stroke="#000000"
476     title="My Layer 2" stroke_width="2" fill="None">
477 jonathan 690 <classification field="AREA" field_type="double">
478 bh 1976 <clnull label="">
479 jonathan 690 <cldata stroke="#000000" stroke_width="2" fill="None"/>
480     </clnull>
481 bh 1976 <clrange label="" range="[0;1[">
482 jonathan 692 <cldata stroke="#111111" stroke_width="1" fill="None"/>
483 jonathan 690 </clrange>
484 bh 1976 <clpoint label="" value="0.5">
485 jonathan 692 <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
486 jonathan 690 </clpoint>
487 bh 1976 <clrange label="" range="[-1;0[">
488 jonathan 690 <cldata stroke="#000000" stroke_width="1" fill="None"/>
489     </clrange>
490 bh 1976 <clpoint label="" value="-0.5">
491 jonathan 690 <cldata stroke="#000000" stroke_width="1" fill="None"/>
492     </clpoint>
493     </classification>
494     </layer>
495 bh 1976 </map>
496 jonathan 690 </session>
497     '''
498 bh 292
499 bh 957 def test(self):
500 bh 1247 """Load a Thuban session with a map and classified layers."""
501 bh 957 session = load_session(self.filename())
502     self.session = session
503    
504     map = self.session.Maps()[0] # only one map in the sample
505    
506 bh 1417 expected = [("My Layer", 3,
507 bh 957 [("default", (), "",
508     ("#000000", 1, "None")),
509     ("single", "1", "",
510     ("#000000", 2, "None")),
511     ("single", "1", "",
512 bh 1417 ("#000000", 10, "None")),
513     ("single", "\xe4\xf6\xfc", "\xdcml\xe4uts",
514     ("#000000", 1, "None"))]),
515 bh 957 ("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 bh 1976 self.check_format()
530 bh 957
531 bh 1976
532 bh 957 class TestLabels(ClassificationTest):
533    
534     file_contents = '''\
535 jonathan 690 <?xml version="1.0" encoding="UTF-8"?>
536 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
537     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
538 bh 1268 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 jonathan 690 <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 bh 957 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 bh 1257 self.check_format()
578 bh 957
579    
580     class TestLayerProjection(LoadSessionTest):
581    
582     file_contents = '''\
583 jonathan 746 <?xml version="1.0" encoding="UTF-8"?>
584 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
585     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
586 bh 1268 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 jonathan 746 <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 bh 1268 <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 bh 1687 <parameter value="lat_1=10"/>
618     <parameter value="lat_2=20"/>
619 bh 1268 <parameter value="ellps=clrk66"/>
620     </projection>
621 jonathan 746 </layer>
622     </map>
623     </session>
624     '''
625    
626 bh 957 def test(self):
627     """Test loading layers with projections"""
628 bh 292 eq = self.assertEquals
629 jonathan 746 neq = self.assertNotEqual
630    
631 bh 957 session = load_session(self.filename())
632 jonathan 746 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 bh 1687 eq(proj.GetParameter("lat_1"), "10")
652     eq(proj.GetParameter("lat_2"), "20")
653 jonathan 746 eq(proj.GetParameter("ellps"), "clrk66")
654    
655 bh 1257 self.check_format()
656 bh 957
657 bh 1257
658 bh 957 class TestRasterLayer(LoadSessionTest):
659    
660     file_contents = '''\
661     <?xml version="1.0" encoding="UTF-8"?>
662 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
663     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
664 bh 1268 title="single map&amp;layer">
665     <map title="Test Map">
666     <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
667     title="My RasterLayer"/>
668 bh 957 </map>
669     </session>
670     '''
671    
672     def test(self):
673 jonathan 947 eq = self.assertEquals
674     neq = self.assertNotEqual
675    
676 bh 957 session = load_session(self.filename())
677 jonathan 947 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     eq(layer.Title(), "My RasterLayer")
684     self.failIf(layer.Visible())
685     self.failUnless(filenames_equal(layer.GetImageFilename(),
686     os.path.join(self.temp_dir(),
687     os.pardir, os.pardir,
688     "Data", "iceland",
689     "island.tif")))
690 bh 1257 self.check_format()
691 jonathan 947
692 bh 1268
693     class TestJoinedTable(LoadSessionTest):
694    
695     file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
696 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
697     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="A Joined Table session">
698 bh 1282 <fileshapesource filetype="shapefile" id="D137227612"
699     filename="../../Data/iceland/roads-line.shp"/>
700     <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
701     title="Some Title"/>
702 bh 1375 <jointable id="D136169900" title="Joined"
703     right="D136171140" left="D137227612"
704     leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
705     jointype="LEFT OUTER"/>
706 bh 1282 <derivedshapesource table="D136169900" shapesource="D137227612"
707     id="D136170932"/>
708 bh 1268 <map title="Test Map">
709 bh 1282 <layer shapestore="D136170932" visible="true" stroke="#000000"
710     title="My Layer" stroke_width="1" fill="None"/>
711 bh 1268 </map>
712 bh 1282 </session>
713     '''
714 bh 1268
715     def setUp(self):
716     """Extend inherited method to create the dbffile for the join"""
717     LoadSessionTest.setUp(self)
718     dbffile = self.temp_file_name("load_joinedtable.dbf")
719     dbf = dbflib.create(dbffile)
720     dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
721     dbf.add_field("TEXT", dbflib.FTString, 10, 0)
722     dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
723     dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
724     dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
725     dbf.close()
726    
727     def test(self):
728     """Test loading a session containing a joined table"""
729     session = load_session(self.filename())
730     self.session = session
731    
732     tables = session.Tables()
733     self.assertEquals(len(tables), 3)
734     # FIXME: The tests shouldn't assume a certain order of the tables
735     self.assertEquals(tables[0].Title(), "Some Title")
736     self.assertEquals(tables[1].Title(), "Joined")
737 bh 1375 self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
738 bh 1282 self.check_format()
739 bh 1268
740    
741 bh 2034 class TestLabelLayer(LoadSessionTest):
742 bh 1646
743 bh 2034 # Note that the labels deliberately contain non-ascii characters to
744     # test whether they're supported correctly.
745    
746     file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
747 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
748     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
749 bh 2034 <fileshapesource filetype="shapefile" id="D145265052"
750     filename="../../Data/iceland/political.shp"/>
751     <fileshapesource filetype="shapefile" id="D145412868"
752     filename="../../Data/iceland/cultural_landmark-point.shp"/>
753     <map title="Iceland map">
754     <projection name="Unknown">
755     <parameter value="zone=26"/>
756     <parameter value="proj=utm"/>
757     <parameter value="ellps=clrk66"/>
758     </projection>
759     <layer shapestore="D145265052" visible="true" stroke="#000000"
760     title="political" stroke_width="1" fill="#c0c0c0">
761     <projection name="Geographic">
762     <parameter value="proj=latlong"/>
763     <parameter value="to_meter=0.017453"/>
764     <parameter value="ellps=clrk66"/>
765     </projection>
766     </layer>
767     <layer shapestore="D145412868" visible="true" stroke="#000000"
768     title="landmarks" stroke_width="1" fill="#ffff00">
769     <projection name="Geographic">
770     <parameter value="proj=latlong"/>
771     <parameter value="to_meter=0.017453"/>
772     <parameter value="ellps=clrk66"/>
773     </projection>
774     </layer>
775     <labellayer>
776     <label x="-21.5" y="64.25" text="RUINS"
777     halign="left" valign="center"/>
778     <label x="-15.125" y="64.75" text="H\xc3\xbctte"
779     halign="right" valign="top"/>
780     </labellayer>
781     </map>
782     </session>
783     '''
784    
785     def test(self):
786     """Test loading a session with a label layer"""
787     session = load_session(self.filename())
788     self.session = session
789    
790     label_layer = self.session.Maps()[0].LabelLayer()
791     expected_labels = [(-21.5, 64.25, "RUINS", ALIGN_LEFT, ALIGN_CENTER),
792     (-15.125, 64.75, "H\xfctte", ALIGN_RIGHT, ALIGN_TOP),
793     ]
794     for label, values in zip(label_layer.Labels(), expected_labels):
795     self.assertEquals((label.x, label.y, label.text, label.halign,
796     label.valign),
797     values)
798     self.check_format()
799    
800    
801 bh 1646 class TestPostGISLayer(LoadSessionTest):
802    
803     file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
804 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
805     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
806 bh 1646 title="unnamed session">
807     <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
808     dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
809 bh 2104 <dbshapesource id="D143149420" dbconn="D142684948"
810     tablename="landmarks_point_id" id_column="point_id"
811     geometry_column="the_geom" />
812 bh 1646 <map title="unnamed map">
813     <layer shapestore="D143149420" visible="true" stroke="#000000"
814     title="landmarks" stroke_width="1" fill="None"/>
815     </map>
816     </session>
817     '''
818    
819     def setUp(self):
820     """Extend the inherited method to start the postgis server
821    
822     Furthermore, patch the file contents with the real postgis db
823     information
824     """
825     postgissupport.skip_if_no_postgis()
826     self.server = postgissupport.get_test_server()
827     self.postgisdb = self.server.get_default_static_data_db()
828    
829     self.file_contents = self.__class__.file_contents % {
830     "dbname": self.postgisdb.dbname,
831     "user": self.server.user_name,
832     "port": self.server.port,
833     "host": self.server.host}
834     LoadSessionTest.setUp(self)
835    
836     def test(self):
837     """Test loading a session containing a postgis shapestore"""
838     session = load_session(self.filename())
839     self.session = session
840     connections = session.DBConnections()
841     self.assertEquals(len(connections), 1)
842     conn = connections[0]
843     for attr, value in [("host", self.server.host),
844     ("port", str(self.server.port)),
845     ("user", self.server.user_name),
846     ("dbname", self.postgisdb.dbname)]:
847     self.assertEquals(getattr(conn, attr), value)
848     layer = session.Maps()[0].Layers()[0]
849     self.failUnless(layer.ShapeStore().DBConnection() is conn)
850    
851    
852     class TestPostGISLayerPassword(LoadSessionTest):
853    
854     file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
855 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
856     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
857 bh 1646 title="unnamed session">
858     <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
859     dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
860     <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
861     <map title="unnamed map">
862     <layer shapestore="D143149420" visible="true" stroke="#000000"
863     title="landmarks" stroke_width="1" fill="None"/>
864     </map>
865     </session>
866     '''
867    
868     def setUp(self):
869     """Extend the inherited method to start the postgis server
870    
871     Furthermore, patch the file contents with the real postgis db
872     information
873     """
874     postgissupport.skip_if_no_postgis()
875     self.server = postgissupport.get_test_server()
876     self.postgisdb = self.server.get_default_static_data_db()
877    
878     self.file_contents = self.__class__.file_contents % {
879     "dbname": self.postgisdb.dbname,
880     "user": self.server.user_name,
881     "port": self.server.port,
882     "host": self.server.host}
883     LoadSessionTest.setUp(self)
884    
885     self.db_connection_callback_called = False
886     self.server.require_authentication(True)
887    
888     def tearDown(self):
889     """Extend the inherited method to switch off postgresql authentication
890     """
891     self.server.require_authentication(False)
892     LoadSessionTest.tearDown(self)
893    
894     def db_connection_callback(self, params, message):
895     """Implementation of Thuban.Model.hooks.query_db_connection_parameters
896     """
897     self.assertEquals(params,
898     {"dbname": self.postgisdb.dbname,
899     "user": self.server.user_name,
900     "port": str(self.server.port),
901     "host": self.server.host})
902     self.db_connection_callback_called = True
903     params = params.copy()
904     params["password"] = self.server.user_password
905     return params
906    
907     def test_with_callback(self):
908     """Test loading a session with postgis, authentication and a callback
909     """
910     session = load_session(self.filename(),
911     db_connection_callback = self.db_connection_callback)
912     self.session = session
913     connections = session.DBConnections()
914     self.assertEquals(len(connections), 1)
915     conn = connections[0]
916     for attr, value in [("host", self.server.host),
917     ("port", str(self.server.port)),
918     ("user", self.server.user_name),
919     ("dbname", self.postgisdb.dbname)]:
920     self.assertEquals(getattr(conn, attr), value)
921     layer = session.Maps()[0].Layers()[0]
922     self.failUnless(layer.ShapeStore().DBConnection() is conn)
923     self.failUnless(self.db_connection_callback_called)
924    
925     def test_without_callback(self):
926     """Test loading a session with postgis, authentication and no callback
927     """
928     # A password is required and there's no callback, so we should
929     # get a ConnectionError
930     self.assertRaises(ConnectionError, load_session, self.filename())
931    
932     def test_cancel(self):
933     """Test loading a session with postgis and cancelling authentication
934     """
935     def cancel(*args):
936     self.db_connection_callback_called = True
937     return None
938    
939     # If the user cancels, i.e. if the callbakc returns None, a
940     # LoadCancelled exception is raised.
941     self.assertRaises(LoadCancelled,
942     load_session, self.filename(), cancel)
943     self.failUnless(self.db_connection_callback_called)
944    
945    
946 bh 1268 class TestLoadError(LoadSessionTest):
947    
948     file_contents = '''\
949     <?xml version="1.0" encoding="UTF-8"?>
950 bh 2104 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
951     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
952 bh 1268 title="single map&amp;layer">
953     <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
954     <map title="Test Map">
955     <projection name="Unknown">
956     <parameter value="zone=26"/>
957     <parameter value="proj=utm"/>
958     <parameter value="ellps=clrk66"/>
959     </projection>
960     <layer shapestore="D1" visible="true"
961     stroke="#000000" title="My Layer" stroke_width="1"
962     fill="None"/>
963     </map>
964     </session>
965     '''
966    
967     def test(self):
968     """Test loading a session missing a required attribute"""
969     # Don't use assertRaises to make sure that if a session is
970     # actually returned it gets destroyed properly.
971     try:
972     self.session = load_session(self.filename())
973     except LoadError, value:
974 bh 1642 # Check the actual messge in value to make sure the
975     # LoadError really was about the missing attribute
976     self.assertEquals(str(value),
977     "Element "
978 bh 2104 "(u'http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd',"
979 bh 1642 " u'fileshapesource') requires an attribute 'filetype'")
980 bh 1268 else:
981     self.fail("Missing filetype attribute doesn't raise LoadError")
982    
983 frank 2446 class Shapefile_CallBack:
984    
985     def __init__(self, params):
986     """Initialize the callback return values.
987    
988     params must be a dictionary of the potential CB modes (keys),
989     with lists of tuples of return values as values.
990     Depending on the test the callback can be called multiple,
991     each time a return value is poped from the list
992     """
993    
994     self.params = params
995    
996    
997     def s_cb(self, filename, mode = None, second_try= 0):
998     if self.params.has_key(mode):
999     return self.params[mode].pop(0)
1000     else:
1001     raise LoadError
1002    
1003     class TestAltPath(LoadSessionTest):
1004    
1005     """Test the various cases in the alternative path feature.
1006    
1007     The test checks the reasonable cases:
1008     - First recognition of a path error, fixed with user interaction.
1009     - First recognition of a path error, load cancelled.
1010     - Path error fixed from list, confirmed by user.
1011     - Path error fixed from list, changed by user.
1012     - Path error fixed from list, cancelled by user.
1013     - Path error wrongly fixed from list, manual fix forced.
1014     """
1015    
1016     file_contents = '''\
1017     <?xml version="1.0" encoding="UTF-8"?>
1018     <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
1019     <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
1020     <fileshapesource filetype="shapefile" id="D1108450956" filename="../../Data/iceland/political.shp"/>
1021     <fileshapesource filetype="shapefile" id="D1108900076" filename="../Data/iceland/roads-line.shp"/>
1022     <fileshapesource filetype="shapefile" id="D1108947244" filename="../../Data/iceland/cultural_landmark-point.shp"/>
1023     <map title="not the iceland map">
1024     <layer title="political" stroke_width="1" shapestore="D1108450956" visible="true" stroke="#000000" fill="#c0c0c0"/>
1025     <layer title="roads-line" stroke_width="1" shapestore="D1108900076" visible="true" stroke="#000000" fill="None"/>
1026     <layer title="something else" stroke_width="1" shapestore="D1108947244" visible="true" stroke="#000000" fill="None"/>
1027     </map>
1028     </session>
1029     '''
1030    
1031     def test_01_single_path_error_fix(self):
1032     """Test single file path error fix."""
1033     # The usual initial case
1034     s_cb = Shapefile_CallBack({
1035     "search": [("../Data/iceland/roads-line.shp",0)],
1036     "check": [(None, None)]})
1037     self.session = load_session(self.filename(),
1038     shapefile_callback =s_cb.s_cb)
1039    
1040     def test_02_path_error_fix_from_list(self):
1041     """Test single file path error fix."""
1042     # This represents the usual case for "from_list"
1043     s_cb = Shapefile_CallBack({
1044     "search": [("../Data/iceland/roads-line.shp",1)],
1045     "check": [(os.path.abspath("../Data/iceland/roads-line.shp"),1)]
1046     })
1047     self.session = load_session(self.filename(),
1048     shapefile_callback =s_cb.s_cb)
1049    
1050     def test_03_single_path_error_cancelled(self):
1051     """Test alternative path cancelled."""
1052     s_cb = Shapefile_CallBack({
1053     "search": [(None,0)],
1054     "check": [(None, None)]})
1055     self.assertRaises(LoadCancelled,
1056     load_session, self.filename(), None, s_cb.s_cb)
1057    
1058     def test_04_path_error_fix_from_list_cancelled(self):
1059     """Test alternative path from list cancelled."""
1060     s_cb = Shapefile_CallBack({
1061     "search": [("../Data/iceland/roads-line.shp",1)],
1062     "check": [(None,1)]
1063     })
1064     self.assertRaises(LoadCancelled,
1065     load_session, self.filename(), None, s_cb.s_cb)
1066    
1067     def test_05_path_error_fix_from_list_changed(self):
1068     """Test alternative path from list changed."""
1069     s_cb = Shapefile_CallBack({
1070     "search": [("../Data/iceland/roads-line.shp",1)],
1071     "check": [("../Data/iceland/roads-line.shp",0)]
1072     })
1073     self.session = load_session(self.filename(),
1074     shapefile_callback =s_cb.s_cb)
1075    
1076     def test_06_path_error_fix_from_list_fails(self):
1077     """Test alternative path recovery from list."""
1078     s_cb = Shapefile_CallBack({
1079     "search": [("../wrong/iceland/roads-line.shp",1),
1080     ("../Data/iceland/roads-line.shp",0)],
1081     "check": [(None,None)]
1082     })
1083     self.session = load_session(self.filename(),
1084     shapefile_callback =s_cb.s_cb)
1085     self.assertRaises(IndexError,
1086     s_cb.s_cb, None, "search")
1087    
1088    
1089    
1090 bh 292 if __name__ == "__main__":
1091 bh 1683 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