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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2104 - (hide annotations)
Fri Mar 12 12:19:15 2004 UTC (20 years, 11 months ago) by bh
Original Path: trunk/thuban/test/test_load_1_0.py
File MIME type: text/x-python
File size: 33692 byte(s)
Final step for explicit id/geometry columns: Loading and saving

* Resources/XML/thuban-1.1.dtd: New.  Derived from thuban-1.0.dtd
with the following changes:
(dbshapesource): Two new attributes id_column and geometry_column

* Thuban/Model/save.py (SessionSaver.write): Use the new dtd
(SessionSaver.write_session): Use the new namespace
(SessionSaver.write_data_containers): Write the new dbshapesource
parameters

* Thuban/Model/load.py (SessionLoader.__init__): New namespace for
the new file format version
(SessionLoader.start_dbshapesource): Handle the new db parameters

* test/test_save.py: Update to the new dtd and namespace
(SaveSessionTest.test_save_postgis): Update the NonConnectionStore
mock object to provide a working IDColumn method.

* test/test_load_1_0.py: New.  Copy of the test_load.py before
today's changes but with the round-trip tests removed.

* test/test_load_0_9.py: Update doc-string.

* test/test_load.py: Update all .thuban files to the new dtd and
namespace.
(TestPostGISLayer.file_contents): Add the new dbshapesource
paramters

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