/[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 2104 by bh, Fri Mar 12 12:19:15 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>  
 '''  
   
 contents_test_layer_projection = '''\  
 <?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>  
 '''  
73    
74  contents_test_visible = '''\      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" visible="false">  
         </layer>  
     </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()  
   
84          self.session = None          self.session = None
85    
86      def tearDown(self):      def tearDown(self):
# Line 224  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    
166                    if data[CLASSES][i][GROUP_TYPE] == "default":
167                        g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
168                    elif data[CLASSES][i][GROUP_TYPE] == "range":
169                        g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
170                                             data[CLASSES][i][GROUP_DATA][1]),
171                                            props, data[CLASSES][i][GROUP_LABEL])
172                    elif data[CLASSES][i][GROUP_TYPE] == "single":
173                        g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
174                                              props, data[CLASSES][i][GROUP_LABEL])
175    
176                    eq(group, g)
177    
178                    i += 1
179    
180    
181    
182    class TestSingleLayer(LoadSessionTest):
183    
184        # Note: The use of &amp; and non-ascii characters is deliberate. We
185        # want to test whether the loading code handles that correctly.
186        file_contents = '''\
187    <?xml version="1.0" encoding="UTF-8"?>
188    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
189    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
190            title="Stra\xc3\x9fen &amp; Landmarken">
191        <fileshapesource filetype="shapefile" id="D1"
192            filename="../../Data/iceland/political.shp"/>
193        <map title="\xc3\x9cbersicht">
194            <projection epsg="32627" name="WGS 84 / UTM zone 27N">
195                <parameter value="datum=WGS84"/>
196                <parameter value="ellps=WGS84"/>
197                <parameter value="proj=utm"/>
198                <parameter value="units=m"/>
199                <parameter value="zone=27"/>
200            </projection>
201            <layer shapestore="D1" visible="true"
202                    stroke="#000000" title="K\xc3\xbcste" stroke_width="1"
203                    fill="None"/>
204        </map>
205    </session>
206    '''
207    
208        def test(self):
209          """Load a session with a single map with a single layer"""          """Load a session with a single map with a single layer"""
210          eq = self.assertEquals          eq = self.assertEquals
211          session = load_session(self.temp_file_name("load_singlelayer.thuban"))          session = load_session(self.filename())
212          self.session = session          self.session = session
213    
214          # Check the title          # Check the title
215          eq(session.Title(), "single map&layer")          eq(session.Title(), "Stra\xdfen & Landmarken")
216    
217          # the session has one map.          # the session has one map.
218          maps = session.Maps()          maps = session.Maps()
# Line 239  class LoadSessionTest(unittest.TestCase, Line 220  class LoadSessionTest(unittest.TestCase,
220    
221          # Check the map's attributes          # Check the map's attributes
222          map = maps[0]          map = maps[0]
223          eq(map.Title(), "Test Map")          eq(map.Title(), "\xdcbersicht")
224            proj = map.GetProjection()
225            eq(proj.GetName(), "WGS 84 / UTM zone 27N")
226            eq(proj.EPSGCode(), "32627")
227            params = proj.GetAllParameters()
228            params.sort()
229            eq(params, ["datum=WGS84", "ellps=WGS84", "proj=utm", "units=m",
230                        "zone=27"])
231    
232          # the map has a single layer          # the map has a single layer
233          layers = map.Layers()          layers = map.Layers()
# Line 247  class LoadSessionTest(unittest.TestCase, Line 235  class LoadSessionTest(unittest.TestCase,
235    
236          # Check the layer attributes          # Check the layer attributes
237          layer = layers[0]          layer = layers[0]
238          eq(layer.Title(), "My Layer")          eq(layer.Title(), "K\xfcste")
239          self.failUnless(filenames_equal(layer.filename,          self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
240                                          os.path.join(self.temp_dir(),                                          os.path.join(self.temp_dir(),
241                                                       os.pardir, os.pardir,                                                       os.pardir, os.pardir,
242                                                       "Data", "iceland",                                                       "Data", "iceland",
243                                                       "political.shp")))                                                       "political.shp")))
244          eq(layer.GetClassification().GetDefaultFill(), Color.Transparent)          eq(layer.GetClassification().GetDefaultFill(), Transparent)
245          eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")          eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
246          eq(layer.Visible(), True)          eq(layer.Visible(), True)
247    
248            self.check_format()
249    
250          self.session.Destroy()          self.session.Destroy()
251          self.session = None          self.session = None
252    
253      def testLayerVisibility(self):      def test_leak(self):
254          """Test that the visible flag is correctly loaded for a layer."""          """Test load_session for resource leaks
255    
256            The load_session function had a resource leak in that it created
257            cyclic references. The objects would have been eventually
258            collected by the garbage collector but too late. One symptom is
259            that when layers are removed so that the last normal reference
260            owned indirectly by the session to a shape store goes away, the
261            shape store is not actually removed from the session even though
262            the session only keeps weak references because there are still
263            references owned by the cyclic garbage.
264            """
265            session = load_session(self.filename())
266            self.session = session
267    
268            # sanity check
269            self.assertEquals(len(session.ShapeStores()), 1)
270    
271            # remove the map. The shapestore should go away too
272            session.RemoveMap(session.Maps()[0])
273            self.assertEquals(len(session.ShapeStores()), 0)
274    
275    
276    class TestNonAsciiColumnName(LoadSessionTest):
277    
278        file_contents = '''\
279    <?xml version="1.0" encoding="UTF-8"?>
280    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
281    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
282            title="Non ASCII column name test">
283        <fileshapesource filetype="shapefile" id="D1"
284            filename="TestNonAsciiColumnName.shp"/>
285        <map title="map">
286            <projection name="Some Projection">
287                <parameter value="datum=WGS84"/>
288                <parameter value="ellps=WGS84"/>
289                <parameter value="proj=utm"/>
290                <parameter value="units=m"/>
291                <parameter value="zone=27"/>
292            </projection>
293            <layer shapestore="D1" visible="true"
294                    stroke="#000000" title="layer" stroke_width="1"
295                    fill="None">
296                <classification field="Fl\xc3\xa4che" field_type="double">
297                    <clnull label="">
298                        <cldata stroke="#000000" stroke_width="1" fill="None"/>
299                    </clnull>
300                </classification>
301            </layer>
302        </map>
303    </session>
304    '''
305    
306        def test(self):
307            """Load a session with a single map with a single layer"""
308    
309            # Create a shapefile and a dbffile with a non-ascii column name
310            dbffile = self.temp_file_name("TestNonAsciiColumnName.dbf")
311            shpfile = self.temp_file_name("TestNonAsciiColumnName.shp")
312            dbf = dbflib.create(dbffile)
313            dbf.add_field('Fl\xe4che', dbflib.FTDouble, 10, 5)
314            dbf.write_record(0, (0.0,))
315            dbf.close()
316            shp = shapelib.create(shpfile, shapelib.SHPT_POLYGON)
317            shp.write_object(-1, shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
318                                                    [[(0,0), (10, 10), (10, 0),
319                                                      (0, 0)]]))
320            shp.close()
321    
322            try:
323                session = load_session(self.filename())
324            except ValueError, v:
325                # Usually if the field name is not decoded properly the
326                # loading fails because the field type mentioned in the file
327                # is not None as returned from the layer for a non-existing
328                # column name so we check for that and report it as failure.
329                # Other exceptions are errors in the test case.
330                if str(v) == "xml field type differs from database!":
331                    self.fail("Cannot load file with non-ascii column names")
332                else:
333                    raise
334            self.session = session
335    
336            # In case Thuban could load the file anyway (i.e. no ValueError
337            # exception in load_session()), check explicitly whether the
338            # field name was decoded properly. The test will probably lead
339            # to a UnicodeError instead of a test failure so we check that
340            # too
341            layer = session.Maps()[0].Layers()[0]
342            try:
343                self.assertEquals(layer.GetClassificationColumn(), 'Fl\xe4che')
344            except UnicodeError:
345                # FIXME: Obviously this will have to change if Thuban ever
346                # supports unicode properly.
347                self.fail("Column name was not converted to a bytestring")
348    
349            # roundtrip check
350            self.check_format()
351    
352    
353    class TestLayerVisibility(LoadSessionTest):
354    
355        file_contents = '''\
356    <?xml version="1.0" encoding="UTF-8"?>
357    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
358    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
359            title="single map&amp;layer">
360        <fileshapesource filetype="shapefile" id="D1"
361            filename="../../Data/iceland/political.shp"/>
362        <map title="Test Map">
363            <projection name="Unknown">
364                <parameter value="zone=26"/>
365                <parameter value="proj=utm"/>
366                <parameter value="ellps=clrk66"/>
367            </projection>
368            <layer shapestore="D1" visible="false" stroke="#000000"
369                    title="My Layer" stroke_width="1" fill="None"/>
370        </map>
371    </session>
372    '''
373    
374        def test(self):
375            """Test that the visible flag is correctly loaded for a layer."""
376          eq = self.assertEquals          eq = self.assertEquals
377          session = load_session(self.temp_file_name("load_visible.thuban"))          session = load_session(self.filename())
378          self.session = session          self.session = session
379          maps = session.Maps()          maps = session.Maps()
380          eq(len(maps), 1)          eq(len(maps), 1)
# Line 275  class LoadSessionTest(unittest.TestCase, Line 385  class LoadSessionTest(unittest.TestCase,
385    
386          eq(layer.Visible(), False)          eq(layer.Visible(), False)
387    
388      def testClassification(self):          self.check_format()
389          """Load a session with a map and classified layers."""  
390    
391    class TestClassification(ClassificationTest):
392    
393        file_contents = '''\
394    <?xml version="1.0" encoding="UTF-8"?>
395    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
396    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
397            title="single map&amp;layer">
398        <fileshapesource filetype="shapefile" id="D138389860"
399            filename="../../Data/iceland/political.shp"/>
400        <fileshapesource filetype="shapefile" id="D138504492"
401            filename="../../Data/iceland/political.shp"/>
402        <map title="Test Map">
403            <projection name="">
404                <parameter value="zone=26"/>
405                <parameter value="proj=utm"/>
406                <parameter value="ellps=clrk66"/>
407            </projection>
408            <layer shapestore="D138389860" visible="true" stroke="#000000"
409                    title="My Layer" stroke_width="1" fill="None">
410                <classification field="POPYREG" field_type="string">
411                    <clnull label="">
412                        <cldata stroke="#000000" stroke_width="1" fill="None"/>
413                    </clnull>
414                    <clpoint label="" value="1">
415                        <cldata stroke="#000000" stroke_width="2" fill="None"/>
416                    </clpoint>
417                    <clpoint label="" value="1">
418                        <cldata stroke="#000000" stroke_width="10" fill="None"/>
419                    </clpoint>
420                    <clpoint label="\xc3\x9cml\xc3\xa4uts"
421                            value="\xc3\xa4\xc3\xb6\xc3\xbc">
422                        <cldata stroke="#000000" stroke_width="1" fill="None"/>
423                    </clpoint>
424                </classification>
425            </layer>
426            <layer shapestore="D138504492" visible="true" stroke="#000000"
427                    title="My Layer 2" stroke_width="2" fill="None">
428                <classification field="AREA" field_type="double">
429                    <clnull label="">
430                        <cldata stroke="#000000" stroke_width="2" fill="None"/>
431                    </clnull>
432                    <clrange label="" range="[0;1[">
433                        <cldata stroke="#111111" stroke_width="1" fill="None"/>
434                    </clrange>
435                    <clpoint label="" value="0.5">
436                        <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
437                    </clpoint>
438                    <clrange label="" range="[-1;0[">
439                        <cldata stroke="#000000" stroke_width="1" fill="None"/>
440                    </clrange>
441                    <clpoint label="" value="-0.5">
442                        <cldata stroke="#000000" stroke_width="1" fill="None"/>
443                    </clpoint>
444                </classification>
445            </layer>
446        </map>
447    </session>
448    '''
449    
450          session = load_session(self.temp_file_name("load_classified_v0_2.thuban"))      def test(self):
451            """Load a Thuban session with a map and classified layers."""
452            session = load_session(self.filename())
453          self.session = session          self.session = session
454    
455          map = self.session.Maps()[0] # only one map in the sample          map = self.session.Maps()[0] # only one map in the sample
456    
457          expected = [("My Layer", 2,          expected = [("My Layer", 3,
458                          [("default", (), "",                          [("default", (), "",
459                              ("#000000", 1, "None")),                              ("#000000", 1, "None")),
460                           ("single", "1", "",                           ("single", "1", "",
461                              ("#000000", 2, "None")),                              ("#000000", 2, "None")),
462                           ("single", "1", "",                           ("single", "1", "",
463                              ("#000000", 10, "None"))]),                              ("#000000", 10, "None")),
464                             ("single", "\xe4\xf6\xfc", "\xdcml\xe4uts",
465                                ("#000000", 1, "None"))]),
466                       ("My Layer 2", 4,                       ("My Layer 2", 4,
467                           [("default", (), "",                           [("default", (), "",
468                              ("#000000", 2, "None")),                              ("#000000", 2, "None")),
# Line 304  class LoadSessionTest(unittest.TestCase, Line 477  class LoadSessionTest(unittest.TestCase,
477    
478          self.TestLayers(map.Layers(), expected)          self.TestLayers(map.Layers(), expected)
479    
480      def TestLayers(self, layers, expected):          self.check_format()
   
         TITLE = 0  
         NUM_GROUPS = 1  
         CLASSES = 2  
         GROUP_TYPE = 0  
         GROUP_DATA = 1  
         GROUP_LABEL = 2  
         GROUP_PROPS = 3  
   
         eq = self.assertEquals  
481    
         eq(len(layers), len(expected))  
482    
483          for layer, data in zip(layers, expected):  class TestLabels(ClassificationTest):
             eq(layer.Title(), data[TITLE])  
484    
485              clazz = layer.GetClassification()      file_contents = '''\
486              eq(clazz.GetNumGroups(), data[NUM_GROUPS])  <?xml version="1.0" encoding="UTF-8"?>
487              eq(clazz.GetNumGroups() + 1, len(data[CLASSES]))  <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
488    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
489              i = 0          title="single map&amp;layer">
490              for group in clazz:      <fileshapesource filetype="shapefile" id="D1"
491                            filename="../../Data/iceland/political.shp"/>
492                  props = ClassGroupProperties()      <map title="Test Map">
493                  props.SetLineColor(          <projection name="Unknown">
494                      parse_color(data[CLASSES][i][GROUP_PROPS][0]))              <parameter value="zone=26"/>
495                  props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])              <parameter value="proj=utm"/>
496                  props.SetFill(              <parameter value="ellps=clrk66"/>
497                      parse_color(data[CLASSES][i][GROUP_PROPS][2]))          </projection>
498            <layer shapestore="D1" visible="true" stroke="#000000"
499                  if data[CLASSES][i][GROUP_TYPE] == "default":                  title="My Layer" stroke_width="1" fill="None">
500                      g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])              <classification field="POPYREG" field_type="string">
501                  elif data[CLASSES][i][GROUP_TYPE] == "range":                  <clnull label="hallo">
502                      g = ClassGroupRange(data[CLASSES][i][GROUP_DATA][0],                      <cldata stroke="#000000" stroke_width="1" fill="None"/>
503                                          data[CLASSES][i][GROUP_DATA][1],                  </clnull>
504                                          props, data[CLASSES][i][GROUP_LABEL])                  <clpoint label="welt" value="1">
505                  elif data[CLASSES][i][GROUP_TYPE] == "single":                      <cldata stroke="#000000" stroke_width="2" fill="None"/>
506                      g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],                  </clpoint>
507                                            props, data[CLASSES][i][GROUP_LABEL])              </classification>
508            </layer>
509                  eq(group, g)      </map>
510    </session>
511                  i += 1  '''
512    
513      def testLabels(self):      def test(self):
514          """Load a session and test for reading the group labels."""          """Load a session and test for reading the group labels."""
   
515          eq = self.assertEquals          eq = self.assertEquals
516          session = load_session(self.temp_file_name("load_labels.thuban"))          session = load_session(self.filename())
517          self.session = session          self.session = session
518    
519          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 525  class LoadSessionTest(unittest.TestCase,
525                              ("#000000", 2, "None"))])]                              ("#000000", 2, "None"))])]
526    
527          self.TestLayers(map.Layers(), expected)          self.TestLayers(map.Layers(), expected)
528            self.check_format()
529    
530    
531      def testLayerProjection(self):  class TestLayerProjection(LoadSessionTest):
532    
533        file_contents = '''\
534    <?xml version="1.0" encoding="UTF-8"?>
535    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
536    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
537            title="single map&amp;layer">
538        <fileshapesource filetype="shapefile" id="D2"
539            filename="../../Data/iceland/roads-line.shp"/>
540        <fileshapesource filetype="shapefile" id="D4"
541            filename="../../Data/iceland/political.shp"/>
542        <map title="Test Map">
543            <projection name="Unknown">
544                <parameter value="zone=26"/>
545                <parameter value="proj=utm"/>
546                <parameter value="ellps=clrk66"/>
547            </projection>
548            <layer shapestore="D4" visible="true" stroke="#000000"
549                    title="My Layer" stroke_width="1" fill="None">
550                <projection name="hello">
551                    <parameter value="zone=13"/>
552                    <parameter value="proj=tmerc"/>
553                    <parameter value="ellps=clrk66"/>
554                </projection>
555                <classification field="POPYREG" field_type="string">
556                    <clnull label="hallo">
557                        <cldata stroke="#000000" stroke_width="1" fill="None"/>
558                    </clnull>
559                    <clpoint label="welt" value="1">
560                        <cldata stroke="#000000" stroke_width="2" fill="None"/>
561                    </clpoint>
562                </classification>
563            </layer>
564            <layer shapestore="D2" visible="true" stroke="#000000"
565                    title="My Layer" stroke_width="1" fill="None">
566                <projection name="Unknown">
567                    <parameter value="proj=lcc"/>
568                    <parameter value="lat_1=10"/>
569                    <parameter value="lat_2=20"/>
570                    <parameter value="ellps=clrk66"/>
571                </projection>
572            </layer>
573        </map>
574    </session>
575    '''
576    
577        def test(self):
578            """Test loading layers with projections"""
579          eq = self.assertEquals          eq = self.assertEquals
580          neq = self.assertNotEqual          neq = self.assertNotEqual
581    
582          session = load_session(self.temp_file_name("load_layerproj.thuban"))          session = load_session(self.filename())
583          self.session = session          self.session = session
584    
585          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 599  class LoadSessionTest(unittest.TestCase,
599          neq(proj, None)          neq(proj, None)
600          eq(proj.GetName(), "Unknown")          eq(proj.GetName(), "Unknown")
601          eq(proj.GetParameter("proj"), "lcc")          eq(proj.GetParameter("proj"), "lcc")
602            eq(proj.GetParameter("lat_1"), "10")
603            eq(proj.GetParameter("lat_2"), "20")
604          eq(proj.GetParameter("ellps"), "clrk66")          eq(proj.GetParameter("ellps"), "clrk66")
605    
606  if __name__ == "__main__":          self.check_format()
607      unittest.main()  
608    
609    class TestRasterLayer(LoadSessionTest):
610    
611        file_contents = '''\
612    <?xml version="1.0" encoding="UTF-8"?>
613    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
614    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
615            title="single map&amp;layer">
616        <map title="Test Map">
617            <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
618                    title="My RasterLayer"/>
619        </map>
620    </session>
621    '''
622    
623        def test(self):
624            eq = self.assertEquals
625            neq = self.assertNotEqual
626    
627            session = load_session(self.filename())
628            self.session = session
629    
630            map = self.session.Maps()[0] # only one map in the sample
631    
632            layer = map.Layers()[0] # one layer in the sample
633    
634            eq(layer.Title(), "My RasterLayer")
635            self.failIf(layer.Visible())
636            self.failUnless(filenames_equal(layer.GetImageFilename(),
637                                            os.path.join(self.temp_dir(),
638                                                         os.pardir, os.pardir,
639                                                         "Data", "iceland",
640                                                         "island.tif")))
641            self.check_format()
642    
643    
644    class TestJoinedTable(LoadSessionTest):
645    
646        file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
647    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
648    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="A Joined Table session">
649        <fileshapesource filetype="shapefile" id="D137227612"
650            filename="../../Data/iceland/roads-line.shp"/>
651        <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
652            title="Some Title"/>
653        <jointable id="D136169900" title="Joined"
654            right="D136171140" left="D137227612"
655            leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
656            jointype="LEFT OUTER"/>
657        <derivedshapesource table="D136169900" shapesource="D137227612"
658            id="D136170932"/>
659        <map title="Test Map">
660            <layer shapestore="D136170932" visible="true" stroke="#000000"
661                    title="My Layer" stroke_width="1" fill="None"/>
662        </map>
663    </session>
664    '''
665    
666        def setUp(self):
667            """Extend inherited method to create the dbffile for the join"""
668            LoadSessionTest.setUp(self)
669            dbffile = self.temp_file_name("load_joinedtable.dbf")
670            dbf = dbflib.create(dbffile)
671            dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
672            dbf.add_field("TEXT", dbflib.FTString, 10, 0)
673            dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
674            dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
675            dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
676            dbf.close()
677    
678        def test(self):
679            """Test loading a session containing a joined table"""
680            session = load_session(self.filename())
681            self.session = session
682    
683            tables = session.Tables()
684            self.assertEquals(len(tables), 3)
685            # FIXME: The tests shouldn't assume a certain order of the tables
686            self.assertEquals(tables[0].Title(), "Some Title")
687            self.assertEquals(tables[1].Title(), "Joined")
688            self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
689            self.check_format()
690    
691    
692    class TestLabelLayer(LoadSessionTest):
693    
694        # Note that the labels deliberately contain non-ascii characters to
695        # test whether they're supported correctly.
696    
697        file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
698    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
699    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
700        <fileshapesource filetype="shapefile" id="D145265052"
701            filename="../../Data/iceland/political.shp"/>
702        <fileshapesource filetype="shapefile" id="D145412868"
703            filename="../../Data/iceland/cultural_landmark-point.shp"/>
704        <map title="Iceland map">
705            <projection name="Unknown">
706                <parameter value="zone=26"/>
707                <parameter value="proj=utm"/>
708                <parameter value="ellps=clrk66"/>
709            </projection>
710            <layer shapestore="D145265052" visible="true" stroke="#000000"
711                    title="political" stroke_width="1" fill="#c0c0c0">
712                <projection name="Geographic">
713                    <parameter value="proj=latlong"/>
714                    <parameter value="to_meter=0.017453"/>
715                    <parameter value="ellps=clrk66"/>
716                </projection>
717            </layer>
718            <layer shapestore="D145412868" visible="true" stroke="#000000"
719                    title="landmarks" stroke_width="1" fill="#ffff00">
720                <projection name="Geographic">
721                    <parameter value="proj=latlong"/>
722                    <parameter value="to_meter=0.017453"/>
723                    <parameter value="ellps=clrk66"/>
724                </projection>
725            </layer>
726            <labellayer>
727                <label x="-21.5" y="64.25" text="RUINS"
728                    halign="left" valign="center"/>
729                <label x="-15.125" y="64.75" text="H\xc3\xbctte"
730                    halign="right" valign="top"/>
731            </labellayer>
732        </map>
733    </session>
734    '''
735    
736        def test(self):
737            """Test loading a session with a label layer"""
738            session = load_session(self.filename())
739            self.session = session
740    
741            label_layer = self.session.Maps()[0].LabelLayer()
742            expected_labels = [(-21.5, 64.25, "RUINS", ALIGN_LEFT, ALIGN_CENTER),
743                               (-15.125, 64.75, "H\xfctte", ALIGN_RIGHT, ALIGN_TOP),
744                               ]
745            for label, values in zip(label_layer.Labels(), expected_labels):
746                self.assertEquals((label.x, label.y, label.text, label.halign,
747                                   label.valign),
748                                  values)
749            self.check_format()
750    
751    
752    class TestPostGISLayer(LoadSessionTest):
753    
754        file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
755    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
756    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
757            title="unnamed session">
758        <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
759            dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
760        <dbshapesource id="D143149420" dbconn="D142684948"
761            tablename="landmarks_point_id" id_column="point_id"
762            geometry_column="the_geom" />
763        <map title="unnamed map">
764            <layer shapestore="D143149420" visible="true" stroke="#000000"
765                    title="landmarks" stroke_width="1" fill="None"/>
766        </map>
767    </session>
768    '''
769    
770        def setUp(self):
771            """Extend the inherited method to start the postgis server
772    
773            Furthermore, patch the file contents with the real postgis db
774            information
775            """
776            postgissupport.skip_if_no_postgis()
777            self.server = postgissupport.get_test_server()
778            self.postgisdb = self.server.get_default_static_data_db()
779    
780            self.file_contents = self.__class__.file_contents % {
781                "dbname": self.postgisdb.dbname,
782                "user": self.server.user_name,
783                "port": self.server.port,
784                "host": self.server.host}
785            LoadSessionTest.setUp(self)
786    
787        def test(self):
788            """Test loading a session containing a postgis shapestore"""
789            session = load_session(self.filename())
790            self.session = session
791            connections = session.DBConnections()
792            self.assertEquals(len(connections), 1)
793            conn = connections[0]
794            for attr, value in [("host", self.server.host),
795                                ("port", str(self.server.port)),
796                                ("user", self.server.user_name),
797                                ("dbname", self.postgisdb.dbname)]:
798                self.assertEquals(getattr(conn, attr), value)
799            layer = session.Maps()[0].Layers()[0]
800            self.failUnless(layer.ShapeStore().DBConnection() is conn)
801    
802    
803    class TestPostGISLayerPassword(LoadSessionTest):
804    
805        file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
806    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
807    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
808            title="unnamed session">
809        <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
810            dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
811        <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
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            self.db_connection_callback_called = False
837            self.server.require_authentication(True)
838    
839        def tearDown(self):
840            """Extend the inherited method to switch off postgresql authentication
841            """
842            self.server.require_authentication(False)
843            LoadSessionTest.tearDown(self)
844    
845        def db_connection_callback(self, params, message):
846            """Implementation of Thuban.Model.hooks.query_db_connection_parameters
847            """
848            self.assertEquals(params,
849                              {"dbname": self.postgisdb.dbname,
850                               "user": self.server.user_name,
851                               "port": str(self.server.port),
852                               "host": self.server.host})
853            self.db_connection_callback_called = True
854            params = params.copy()
855            params["password"] = self.server.user_password
856            return params
857    
858        def test_with_callback(self):
859            """Test loading a session with postgis, authentication and a callback
860            """
861            session = load_session(self.filename(),
862                          db_connection_callback = self.db_connection_callback)
863            self.session = session
864            connections = session.DBConnections()
865            self.assertEquals(len(connections), 1)
866            conn = connections[0]
867            for attr, value in [("host", self.server.host),
868                                ("port", str(self.server.port)),
869                                ("user", self.server.user_name),
870                                ("dbname", self.postgisdb.dbname)]:
871                self.assertEquals(getattr(conn, attr), value)
872            layer = session.Maps()[0].Layers()[0]
873            self.failUnless(layer.ShapeStore().DBConnection() is conn)
874            self.failUnless(self.db_connection_callback_called)
875    
876        def test_without_callback(self):
877            """Test loading a session with postgis, authentication and no callback
878            """
879            # A password is required and there's no callback, so we should
880            # get a ConnectionError
881            self.assertRaises(ConnectionError, load_session, self.filename())
882    
883        def test_cancel(self):
884            """Test loading a session with postgis and cancelling authentication
885            """
886            def cancel(*args):
887                self.db_connection_callback_called = True
888                return None
889    
890            # If the user cancels, i.e. if the callbakc returns None, a
891            # LoadCancelled exception is raised.
892            self.assertRaises(LoadCancelled,
893                              load_session, self.filename(), cancel)
894            self.failUnless(self.db_connection_callback_called)
895    
896    
897    class TestLoadError(LoadSessionTest):
898    
899        file_contents = '''\
900    <?xml version="1.0" encoding="UTF-8"?>
901    <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
902    <session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
903            title="single map&amp;layer">
904        <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
905        <map title="Test Map">
906            <projection name="Unknown">
907                <parameter value="zone=26"/>
908                <parameter value="proj=utm"/>
909                <parameter value="ellps=clrk66"/>
910            </projection>
911            <layer shapestore="D1" visible="true"
912                    stroke="#000000" title="My Layer" stroke_width="1"
913                    fill="None"/>
914        </map>
915    </session>
916    '''
917    
918        def test(self):
919            """Test loading a session missing a required attribute"""
920            # Don't use assertRaises to make sure that if a session is
921            # actually returned it gets destroyed properly.
922            try:
923                self.session = load_session(self.filename())
924            except LoadError, value:
925                # Check the actual messge in value to make sure the
926                # LoadError really was about the missing attribute
927                self.assertEquals(str(value),
928                  "Element "
929                  "(u'http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd',"
930                  " u'fileshapesource') requires an attribute 'filetype'")
931            else:
932                self.fail("Missing filetype attribute doesn't raise LoadError")
933    
934    if __name__ == "__main__":
935        support.run_tests()

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26