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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.774  
changed lines
  Added in v.1976

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26