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

Legend:
Removed from v.947  
changed lines
  Added in v.2458

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26