/[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 2654 - (hide annotations)
Wed Jul 27 21:44:16 2005 UTC (19 years, 7 months ago) by jan
Original Path: trunk/thuban/test/test_load.py
File MIME type: text/x-python
File size: 43775 byte(s)
(TestSingleLayer, TestNonAsciiColumnName, TestLayerVisibility,
TestSymbolSize, TestClassification, TestLabels, TestLayerProjection,
TestJoinedTable, TestLabelLayer): Removed attributes from layer
element to classification clnull element.

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