/[thuban]/trunk/thuban/test/test_save.py
ViewVC logotype

Diff of /trunk/thuban/test/test_save.py

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

revision 494 by jonathan, Mon Mar 10 10:45:33 2003 UTC revision 2688 by frank, Fri Jun 30 12:27:20 2006 UTC
# Line 1  Line 1 
1  # Copyright (c) 2002 by Intevation GmbH  # Copyright (c) 2002, 2003, 2004, 2005 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# Line 17  import os Line 17  import os
17  import unittest  import unittest
18  from StringIO import StringIO  from StringIO import StringIO
19    
20  import xml.sax  import xmlsupport
21  import xml.sax.handler  import postgissupport
 from xml.sax import make_parser, ErrorHandler  
22    
23  import support  import support
24  support.initthuban()  support.initthuban()
25    
26  from Thuban.Model.save import save_session  import dbflib
27    
28    from Thuban import internal_from_unicode
29    from Thuban.Lib.fileutil import relative_filename
30    from Thuban.Model.save import XMLWriter, save_session, sort_data_stores
31  from Thuban.Model.session import Session  from Thuban.Model.session import Session
32  from Thuban.Model.map import Map  from Thuban.Model.map import Map
33  from Thuban.Model.layer import Layer  from Thuban.Model.layer import Layer, RasterLayer
34  from Thuban.Model.proj import Projection  from Thuban.Model.proj import Projection
35    from Thuban.Model.table import DBFTable
36    from Thuban.Model.transientdb import TransientJoinedTable
37  class SaxEventLister(xml.sax.handler.ContentHandler):  from Thuban.Model.data import DerivedShapeStore, SHAPETYPE_ARC
38    
39      def __init__(self):  from Thuban.Model.classification import ClassGroupSingleton, ClassGroupRange, \
40          self.eventlist = []      ClassGroupPattern, ClassGroupProperties
41    
42      def startElementNS(self, name, qname, attrs):  from Thuban.Model.range import Range
43          items = attrs.items()  
44          items.sort()  from Thuban.Model.postgisdb import PostGISConnection, PostGISShapeStore
45          self.eventlist.append(("start", name, qname, items))  
46    
47      def endElementNS(self, name, qname):  class XMLWriterTest(unittest.TestCase):
48          self.eventlist.append(("end", name, qname))  
49        def testEncode(self):
50            """Test XMLWriter.encode"""
51  def sax_eventlist(data):          writer = XMLWriter()
52      """Return a list of SAX event generated for the XML data.          eq = self.assertEquals
53      """  
54      handler = SaxEventLister()          eq(writer.encode("hello world"), "hello world")
55      parser = make_parser()          eq(writer.encode(unicode("hello world")), unicode("hello world"))
56      parser.setContentHandler(handler)  
57      parser.setErrorHandler(ErrorHandler())          eq(writer.encode(internal_from_unicode(u"\x80\x90\xc2\x100")),
58      parser.setFeature(xml.sax.handler.feature_namespaces, 1)                           "\xc2\x80\xc2\x90\xc3\x82\x100")
59            eq(writer.encode(u"\x80\x90\xc2\x100"),
60      inpsrc = xml.sax.InputSource()                           "\xc2\x80\xc2\x90\xc3\x82\x100")
61      inpsrc.setByteStream(StringIO(data))          eq(writer.encode(u"\xFF5E"), "\xc3\xbf5E")
62      parser.parse(inpsrc)  
63            eq(writer.encode('&"\'<>'), "&amp;&quot;&apos;&lt;&gt;")
64      return handler.eventlist          eq(writer.encode(unicode('&"\'<>')), "&amp;&quot;&apos;&lt;&gt;")
65    
66  class SaveSessionTest(unittest.TestCase, support.FileTestMixin):  class SaveSessionTest(unittest.TestCase, support.FileTestMixin,
67                          xmlsupport.ValidationTest):
68    
69        dtd = "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
70        thubanids = [((dtd, n), (None, "id")) for n in
71                     ["fileshapesource", "filetable", "jointable",
72                      "derivedshapesource", "dbshapesource", "dbconnection"]]
73        thubanidrefs = [((dtd, n), (None, m)) for n, m in
74                        [("layer", "shapestore"),
75                         ("jointable", "left"),
76                         ("jointable", "right"),
77                         ("derivedshapesource", "table"),
78                         ("derivedshapesource", "shapesource"),
79                         ("dbshapesource", "dbconn")]]
80        del n, m, dtd
81    
82        def tearDown(self):
83            """Call self.session.Destroy
84    
85            Test cases that create session should bind it to self.session so
86            that it gets destroyed properly
87            """
88            if hasattr(self, "session"):
89                self.session.Destroy()
90                self.session = None
91    
92      def compare_xml(self, xml1, xml2):      def compare_xml(self, xml1, xml2):
93          self.assertEquals(sax_eventlist(xml1), sax_eventlist(xml2))          list1 = xmlsupport.sax_eventlist(xml1, ids = self.thubanids,
94                                             idrefs = self.thubanidrefs)
95            list2 = xmlsupport.sax_eventlist(xml2, ids = self.thubanids,
96                                             idrefs = self.thubanidrefs)
97            if list1 != list2:
98                for a, b in zip(list1, list2):
99                    if a != b:
100                        self.fail("%r != %r" % (a, b))
101    
102    
103      def testEmptySession(self):      def testEmptySession(self):
104          """Save an empty session"""          """Save an empty session"""
# Line 77  class SaveSessionTest(unittest.TestCase, Line 112  class SaveSessionTest(unittest.TestCase,
112          file.close()          file.close()
113          self.compare_xml(written_contents,          self.compare_xml(written_contents,
114                           '<?xml version="1.0" encoding="UTF-8"?>\n'                           '<?xml version="1.0" encoding="UTF-8"?>\n'
115                           '<!DOCTYPE session SYSTEM "thuban.dtd">\n'                           '<!DOCTYPE session SYSTEM "thuban-1.1.dtd">\n'
116                           '<session title="empty session">\n</session>\n')                           '<session title="empty session" '
117             'xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">'
118                             '\n</session>\n')
119    
120            self.validate_data(written_contents)
121    
122      def testSingleLayer(self):      def testSingleLayer(self):
123          """Save a session with a single map with a single layer"""          """Save a session with a single map with a single layer"""
124          # deliberately put an apersand in the title :)          # deliberately put an apersand in the title :)
125          session = Session("single map&layer")          session = Session("single map&layer")
126          proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])          proj = Projection(["proj=utm", "zone=27", "ellps=WGS84",
127                               "datum=WGS84", "units=m"],
128                              name = "WGS 84 / UTM zone 27N",
129                              epsg = "32627")
130          map = Map("Test Map", projection = proj)          map = Map("Test Map", projection = proj)
131          session.AddMap(map)          session.AddMap(map)
132          # use shapefile from the example data          # use shapefile from the example data
133          shpfile = os.path.join(os.path.dirname(__file__),          shpfile = os.path.join(os.path.dirname(__file__),
134                                 os.pardir, "Data", "iceland", "political.shp")                                 os.pardir, "Data", "iceland", "political.shp")
135          layer = Layer("My Layer", shpfile)          layer = Layer("My Layer", session.OpenShapefile(shpfile))
136          map.AddLayer(layer)          map.AddLayer(layer)
137    
138          filename = self.temp_file_name("save_singlemap.thuban")          filename = self.temp_file_name("save_singlemap.thuban")
139          save_session(session, filename)          save_session(session, filename)
140    
141            file = open(filename)
142            written_contents = file.read()
143            file.close()
144            expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
145            <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
146            <session title="single map&amp;layer"
147               xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
148                <fileshapesource id="D1"
149                    filename="../../Data/iceland/political.shp"
150                    filetype="shapefile"/>
151                <map title="Test Map">
152                    <projection epsg="32627" name="WGS 84 / UTM zone 27N">
153                        <parameter value="proj=utm"/>
154                        <parameter value="zone=27"/>
155                        <parameter value="ellps=WGS84"/>
156                        <parameter value="datum=WGS84"/>
157                        <parameter value="units=m"/>
158                    </projection>
159                    <layer title="My Layer" shapestore="D1" visible="%s">
160                        <classification>
161                            <clnull label="">
162                                <cldata fill="None" stroke="#000000"
163                                    stroke_width="1"/>
164                            </clnull>
165                        </classification>
166                    </layer>
167                </map>
168            </session>'''
169    
170            expected_contents = expected_template % "true"
171    
172            self.compare_xml(written_contents, expected_contents)
173    
174            self.validate_data(written_contents)
175    
176            # Repeat with an invisible layer
177            layer.SetVisible(False)
178            save_session(session, filename)
179    
180            file = open(filename)
181            written_contents = file.read()
182            file.close()
183            expected_contents = expected_template % "false"
184            self.compare_xml(written_contents, expected_contents)
185            self.validate_data(written_contents)
186    
187          session.Destroy()          session.Destroy()
188    
189        def testLayerProjection(self):
190            """Test saving layers with projections"""
191            # deliberately put an apersand in the title :)
192            session = self.session = Session("single map&layer")
193            proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
194            map = Map("Test Map", projection = proj)
195            session.AddMap(map)
196            # use shapefile from the example data
197            shpfile = os.path.join(os.path.dirname(__file__),
198                                   os.pardir, "Data", "iceland", "political.shp")
199            layer = Layer("My Layer", session.OpenShapefile(shpfile))
200            proj = Projection(["proj=lcc", "ellps=clrk66",
201                               "lat_1=0", "lat_2=20"],
202                              "Layer Projection")
203            layer.SetProjection(proj)
204            map.AddLayer(layer)
205    
206            filename = self.temp_file_name("save_layerproj.thuban")
207            save_session(session, filename)
208    
209            file = open(filename)
210            written_contents = file.read()
211            file.close()
212            expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
213            <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
214            <session title="single map&amp;layer"
215               xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
216                <fileshapesource id="D1"
217                    filename="../../Data/iceland/political.shp"
218                    filetype="shapefile"/>
219                <map title="Test Map">
220                    <projection name="Unknown">
221                        <parameter value="zone=26"/>
222                        <parameter value="proj=utm"/>
223                        <parameter value="ellps=clrk66"/>
224                    </projection>
225                    <layer title="My Layer" shapestore="D1" visible="true">
226                        <projection name="Layer Projection">
227                            <parameter value="proj=lcc"/>
228                            <parameter value="ellps=clrk66"/>
229                            <parameter value="lat_1=0"/>
230                            <parameter value="lat_2=20"/>
231                        </projection>
232                        <classification>
233                            <clnull label="">
234                                <cldata fill="None" stroke="#000000"
235                                    stroke_width="1"/>
236                            </clnull>
237                        </classification>
238                    </layer>
239                </map>
240            </session>'''
241            #print written_contents
242            #print "********************************************"
243            #print expected_contents
244            self.compare_xml(written_contents, expected_contents)
245    
246            self.validate_data(written_contents)
247    
248        def testRasterLayer(self):
249    
250            MASK_NONE = RasterLayer.MASK_NONE
251            MASK_BIT = RasterLayer.MASK_BIT
252            MASK_ALPHA = RasterLayer.MASK_ALPHA
253    
254            for opacity, masktype, opname, maskname in \
255                [(1,  MASK_BIT,   '', ''),
256                 (.2, MASK_BIT,   'opacity="0.2"', ''),
257                 (1,  MASK_ALPHA, '',              'masktype="alpha"'),
258                 (.5, MASK_ALPHA, 'opacity="0.5"', 'masktype="alpha"'),
259                 (1,  MASK_NONE,  '',              'masktype="none"'),
260                 (0,  MASK_NONE,  'opacity="0"',   'masktype="none"') ]:
261    
262    
263                # deliberately put an apersand in the title :)
264                session = Session("single map&layer")
265                map = Map("Test Map")
266                session.AddMap(map)
267                # use shapefile from the example data
268                imgfile = os.path.join(os.path.dirname(__file__),
269                                       os.pardir, "Data", "iceland", "island.tif")
270                layer = RasterLayer("My RasterLayer", imgfile)
271    
272                layer.SetOpacity(opacity)
273                layer.SetMaskType(masktype)
274    
275                map.AddLayer(layer)
276    
277                filename = self.temp_file_name("%s.thuban" % self.id())
278                save_session(session, filename)
279                session.Destroy()
280    
281                file = open(filename)
282                written_contents = file.read()
283                file.close()
284                expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
285                <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
286                <session title="single map&amp;layer"
287                   xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
288                    <map title="Test Map">
289                        <rasterlayer title="My RasterLayer"
290                                filename="../../Data/iceland/island.tif"
291                                visible="true" %s %s>
292                        </rasterlayer>
293                    </map>
294                </session>''' % (opname, maskname)
295                #print written_contents
296                #print "********************************************"
297                #print expected_contents
298                self.compare_xml(written_contents, expected_contents)
299    
300                self.validate_data(written_contents)
301    
302        def testClassifiedLayer(self):
303            """Save a session with a single map with classifications"""
304            # deliberately put an apersand in the title :)
305            session = Session("Map with Classifications")
306            proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
307            map = Map("Test Map", projection = proj)
308            session.AddMap(map)
309            # use shapefile from the example data
310            shpfile = os.path.join(os.path.dirname(__file__),
311                                   os.pardir, "Data", "iceland", "political.shp")
312            layer = Layer("My Layer", session.OpenShapefile(shpfile))
313            map.AddLayer(layer)
314            layer2 = Layer("My Layer", layer.ShapeStore())
315            map.AddLayer(layer2)
316    
317            clazz = layer.GetClassification()
318    
319            layer.SetClassificationColumn("AREA")
320    
321            clazz.AppendGroup(ClassGroupSingleton(42, ClassGroupProperties(),
322                                                  "single"))
323            clazz.AppendGroup(ClassGroupSingleton("text", ClassGroupProperties(),
324                                                  "single-text"))
325    
326            clazz.AppendGroup(ClassGroupRange((0, 42),
327                                               ClassGroupProperties(),
328                                               "range"))
329    
330            range = ClassGroupRange(Range("[0;42]"))
331            range.SetProperties(ClassGroupProperties())
332            range.SetLabel("new-range")
333            clazz.AppendGroup(range)
334    
335    
336            clazz = layer2.GetClassification()
337            layer2.SetClassificationColumn("POPYCOUN")
338    
339            # Classification with Latin 1 text
340            clazz.AppendGroup(ClassGroupSingleton(
341                internal_from_unicode(u'\xe4\xf6\xfc'), # ae, oe, ue
342                ClassGroupProperties(),
343                internal_from_unicode(u'\xdcml\xe4uts'))) # Uemlaeuts
344    
345            # Pattern
346            clazz.AppendGroup(ClassGroupPattern("BUI", ClassGroupProperties(),
347                                                "pattern"))
348    
349            filename = self.temp_file_name("%s.thuban" % self.id())
350            save_session(session, filename)
351    
352          file = open(filename)          file = open(filename)
353          written_contents = file.read()          written_contents = file.read()
354          file.close()          file.close()
355          expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>          expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
356          <!DOCTYPE session SYSTEM "thuban.dtd">          <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
357          <session title="single map&amp;layer">          <session title="Map with Classifications"
358               xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
359                <fileshapesource id="D1"
360                    filename="../../Data/iceland/political.shp"
361                    filetype="shapefile"/>
362              <map title="Test Map">              <map title="Test Map">
363                  <projection>                  <projection name="Unknown">
364                      <parameter value="zone=26"/>                      <parameter value="zone=26"/>
365                      <parameter value="proj=utm"/>                      <parameter value="proj=utm"/>
366                      <parameter value="ellps=clrk66"/>                      <parameter value="ellps=clrk66"/>
367                  </projection>                  </projection>
368                  <layer title="My Layer" filename="%s"                  <layer title="My Layer" shapestore="D1" visible="true">
369                  fill="None" stroke="#000000" stroke_width="1"/>                      <classification field="AREA" field_type="double">
370                            <clnull label="">
371                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
372                            </clnull>
373                            <clpoint value="42" label="single">
374                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
375                            </clpoint>
376                            <clpoint value="text" label="single-text">
377                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
378                            </clpoint>
379                            <clrange range="[0;42[" label="range">
380                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
381                            </clrange>
382                            <clrange range="[0;42]" label="new-range">
383                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
384                            </clrange>
385                        </classification>
386                    </layer>
387                    <layer title="My Layer" shapestore="D1" visible="true">
388                        <classification field="POPYCOUN" field_type="string">
389                            <clnull label="">
390                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
391                            </clnull>
392                            <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
393                                 label="\xc3\x9cml\xc3\xa4uts">
394                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
395                            </clpoint>
396                            <clpattern pattern="BUI" label="pattern">
397                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
398                            </clpattern>
399                        </classification>
400                    </layer>
401              </map>              </map>
402          </session>''' % os.path.join("..", "..", "Data", "iceland",          </session>'''
403                                       "political.shp")  
404          #print written_contents          #print written_contents
405          #print "********************************************"          #print "********************************************"
406          #print expected_contents          #print expected_contents
407          self.compare_xml(written_contents, expected_contents)          self.compare_xml(written_contents, expected_contents)
408    
409            self.validate_data(written_contents)
410    
411            session.Destroy()
412    
413        def test_dbf_table(self):
414            """Test saving a session with a dbf table link"""
415            session = self.session = Session("a DBF Table session")
416            # use shapefile from the example data
417            dbffile = os.path.join(os.path.dirname(__file__),
418                                   os.pardir, "Data", "iceland", "political.dbf")
419            table = session.AddTable(DBFTable(dbffile))
420    
421            filename = self.temp_file_name("save_singletable.thuban")
422            save_session(session, filename)
423    
424            file = open(filename)
425            written_contents = file.read()
426            file.close()
427            expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
428            <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
429            <session title="a DBF Table session"
430               xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
431                <filetable id="D1" filename="../../Data/iceland/political.dbf"
432                    filetype="DBF" title="political"/>
433            </session>'''
434    
435            self.compare_xml(written_contents, expected_contents)
436            self.validate_data(written_contents)
437    
438        def test_joined_table(self):
439            """Test saving a session with joined table"""
440            # Create a simple table to use in the join
441            dbffile = self.temp_file_name("save_joinedtable.dbf")
442            dbf = dbflib.create(dbffile)
443            dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
444            dbf.add_field("TEXT", dbflib.FTString, 10, 0)
445            dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
446            dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
447            dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
448            dbf.close()
449    
450            # Create the session and a map
451            session = Session("A Joined Table session")
452            try:
453                map = Map("Test Map")
454                session.AddMap(map)
455    
456                # Add the dbf file to the session
457                dbftable = session.AddTable(DBFTable(dbffile))
458    
459                # Create a layer with the shapefile to use in the join
460                shpfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
461                                       os.pardir, "Data", "iceland",
462                                       "roads-line.shp")
463                layer = Layer("My Layer", session.OpenShapefile(shpfile))
464                map.AddLayer(layer)
465    
466                # Do the join
467                store = layer.ShapeStore()
468                #for col in store.Table().Columns():
469                #    print col.name
470                joined = TransientJoinedTable(session.TransientDB(),
471                                              store.Table(), "RDLNTYPE",
472                                              dbftable, "RDTYPE",
473                                              outer_join = True)
474                store = session.AddShapeStore(DerivedShapeStore(store, joined))
475                layer.SetShapeStore(store)
476    
477                # Save the session
478                filename = self.temp_file_name("save_joinedtable.thuban")
479                save_session(session, filename)
480    
481                # Read it back and compare
482                file = open(filename)
483                written_contents = file.read()
484                file.close()
485                expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
486                <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
487                <session title="A Joined Table session"
488                 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
489                    <fileshapesource filename="../../Data/iceland/roads-line.shp"
490                                     filetype="shapefile" id="D142197204"/>
491                    <filetable filename="save_joinedtable.dbf"
492                               title="save_joinedtable"
493                               filetype="DBF" id="D141881756"/>
494                    <jointable id="D142180284"
495                               title="Join of roads-line and save_joinedtable"
496                               leftcolumn="RDLNTYPE" left="D142197204"
497                               rightcolumn="RDTYPE" right="D141881756"
498                               jointype="LEFT OUTER" />
499                    <derivedshapesource id="D141915644"
500                                        table="D142180284"
501                                        shapesource="D142197204"/>
502                    <map title="Test Map">
503                        <layer title="My Layer"
504                               shapestore="D141915644" visible="true">
505                            <classification>
506                                <clnull label="">
507                                    <cldata fill="None" stroke="#000000"
508                                            stroke_width="1"/>
509                                </clnull>
510                            </classification>
511                        </layer>
512                    </map>
513                </session>'''
514    
515                self.compare_xml(written_contents, expected_contents)
516                self.validate_data(written_contents)
517            finally:
518                session.Destroy()
519                session = None
520    
521    
522        def test_save_postgis(self):
523            """Test saving a session with a postgis connection"""
524    
525            class NonConnection(PostGISConnection):
526                """connection class that doesn't actually connect """
527                def connect(self):
528                    pass
529    
530            class NonConnectionStore(PostGISShapeStore):
531                """Shapestore that doesn't try to access the server"""
532                def _fetch_table_information(self):
533                    # pretend that we've found a geometry column
534                    self.geometry_column = "the_geom"
535                    # pretend this is a ARC shape type.
536                    self.shape_type = SHAPETYPE_ARC
537                def IDColumn(self):
538                    """Return an object with a name attribute with value 'gid'"""
539                    class dummycol:
540                        name = "gid"
541                    return dummycol
542    
543            session = Session("A PostGIS Session")
544            try:
545                dbconn = NonConnection(dbname="plugh", host="xyzzy", port="42",
546                                       user="grue")
547                session.AddDBConnection(dbconn)
548                map = Map("Test Map")
549                session.AddMap(map)
550                store = NonConnectionStore(dbconn, "roads")
551                session.AddShapeStore(store)
552                layer = Layer("Roads to Nowhere", store)
553                map.AddLayer(layer)
554    
555                # Save the session
556                filename = self.temp_file_name(self.id() + ".thuban")
557                save_session(session, filename)
558    
559                # Read it back and compare
560                file = open(filename)
561                written = file.read()
562                file.close()
563                expected = '''<?xml version="1.0" encoding="UTF-8"?>
564                <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
565                <session title="A PostGIS Session"
566                 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
567                    <dbconnection id="DB"
568                                  dbtype="postgis" dbname="plugh"
569                                  host="xyzzy" port="42"
570                                  user="grue"/>
571                    <dbshapesource id="roads" dbconn="DB" tablename="roads"
572                                   id_column="gid" geometry_column="the_geom"/>
573                    <map title="Test Map">
574                        <layer title="Roads to Nowhere"
575                               shapestore="roads" visible="true">
576                            <classification>
577                                <clnull label="">
578                                    <cldata fill="None" stroke="#000000"
579                                        stroke_width="1"/>
580                                </clnull>
581                            </classification>
582                        </layer>
583                    </map>
584                </session>'''
585                self.compare_xml(written, expected)
586                self.validate_data(written)
587            finally:
588                session.Destroy()
589    
590    
591    class MockDataStore:
592    
593        """A very simple data store that only has dependencies"""
594    
595        def __init__(self, name, *dependencies):
596            self.name = name
597            self.dependencies = dependencies
598    
599        def __repr__(self):
600            return self.name
601    
602        def Dependencies(self):
603            return self.dependencies
604    
605    
606    class TestStoreSort(unittest.TestCase):
607    
608        def check_sort(self, containers, sorted):
609            """Check whether the list of data containers is sorted"""
610            # check whether sorted is in the right order
611            seen = {}
612            for container in sorted:
613                self.failIf(id(container) in seen,
614                            "Container %r at least twice in %r" % (container,
615                                                                   sorted))
616                for dep in container.Dependencies():
617                    self.assert_(id(dep) in seen,
618                                 "Dependency %r of %r not yet seen" % (dep,
619                                                                       container))
620                seen[id(container)] = 1
621            # check whether all of containers is in sorted
622            for container in containers:
623                self.assert_(id(container) in seen,
624                             "Container %r in containers but not in sorted")
625            self.assertEquals(len(containers), len(sorted))
626    
627        def test_sort_data_stores(self):
628            """Test Thuban.Model.save.sort_data_stores"""
629            d1 = MockDataStore("d1")
630            d2 = MockDataStore("d2")
631            d3 = MockDataStore("d3", d1)
632            d4 = MockDataStore("d4", d1, d3)
633    
634            containers = [d4, d1, d2, d3]
635            self.check_sort(containers, sort_data_stores(containers))
636            containers = [d1, d3, d2, d4]
637            self.check_sort(containers, sort_data_stores(containers))
638    
639    
640    
641  if __name__ == "__main__":  if __name__ == "__main__":
642      # Fake the __file__ global because it's needed by a test      # Fake the __file__ global because it's needed by a test
643      import sys      import sys
644      __file__ = sys.argv[0]      __file__ = sys.argv[0]
645      unittest.main()      support.run_tests()

Legend:
Removed from v.494  
changed lines
  Added in v.2688

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26