/[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 2642 - (hide annotations)
Fri Jul 1 20:49:04 2005 UTC (19 years, 8 months ago) by bh
Original Path: trunk/thuban/test/test_load.py
File MIME type: text/x-python
File size: 43311 byte(s)
First step towards unicode.  With this roughly we're at step 1
string_representation.txt

* Doc/technotes/string_representation.txt: New.  Document how
strings are represented in Thuban and how to get to a Unicode
Thuban.

* Thuban/__init__.py (set_internal_encoding)
(unicode_from_internal, internal_from_unicode): New. The first few
functions for the internal string representation

* Thuban/UI/about.py (unicodeToLocale): Removed.  Use
internal_from_unicode instead.

* Thuban/UI/__init__.py (install_wx_translation): Determine the
encoding to use for the internal string representation.  Also,
change the translation function to return strings in internal
representation even on unicode builds of wxPython

* Thuban/Model/load.py (SessionLoader.check_attrs): Decode
filenames too.
(SessionLoader.start_clrange): Use check_attrs to decode and check
the attributes.

* Thuban/Model/xmlreader.py (XMLReader.encode): Use
internal_from_unicode to convert unicode strings.

* Thuban/Model/xmlwriter.py (XMLWriter.encode): Use
unicode_from_internal when applicable

* test/runtests.py (main): New command line option:
internal-encoding to specify the internal string encoding to use
in the tests.

* test/support.py (initthuban): Set the internal encoding to
latin-1

* test/test_load.py (TestSingleLayer.test, TestClassification.test)
(TestLabelLayer.test): Use the internal string representation when
dealing with non-ascii characters

* test/test_load_1_0.py (TestSingleLayer.test)
(TestClassification.test, TestLabelLayer.test): Use the internal
string representation when dealing with non-ascii characters

* test/test_load_0_9.py (TestSingleLayer.test)
(TestClassification.test): Use the internal string representation
when dealing with non-ascii characters

* test/test_load_0_8.py (TestUnicodeStrings.test): Use the
internal string representation when dealing with non-ascii
characters

* test/test_save.py (XMLWriterTest.testEncode)
(SaveSessionTest.testClassifiedLayer): Use the internal string
representation when dealing with non-ascii characters where
applicable

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