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