Saturday, 29 January 2011

A Test Case

SceneEdit, Boo. Test Case. Why isn't the image tag loading from XML?

        [Test]
        def load_background2():
                source = detab("""
                <scene name="GameStart" default="" desc="wibble wibble">
                 <narrative name="waking_up" desc="In which our hero ...">
                  <image path="data/images/foo.png" />
                  <image path="data/images/bar.png" />
                 </narrative>
                </scene>
                """)

                sr = StringReader(source)
                r = XmlReader.Create(sr)
                scene = Scene()
                scene.load(r)
/*
 *              make sure we have a narrative
 */
                Assert.AreEqual(1, scene.narratives.Count)
/*
 *              get the narrative, check the name
 */
                n as Narrative
                n = scene.narratives[0]
                Assert.AreEqual("waking_up", n.name)
/*
 *              now - it should have two narrative items attached
 */
                Assert.AreEqual(2, n.items.Count)


And that fails: there are zero items in the narrative. Also of interest is an error message in the test output saying "name image not handled". I missed that in the general output chatter when running the app itself.

A bit of grepping tracks that down to the Narrative class:

        def load(r as XmlReader):
                _name = gatt(r, "name")
                _desc = gatt(r, "desc")

                while r.Read():
                        if r.NodeType == XmlNodeType.Whitespace:
                                continue
                        if r.NodeType == XmlNodeType.EndElement:
                                if r.Name == "narrative":
                                        break
                                continue
                        if r.NodeType != XmlNodeType.Element:
                                print "unexpected node type: ${r.NodeType}"
                                break
                        if r.Name == "narrative":
                                break
                        if r.Name == "snippet":
                                sn = Snippet()
                                sn.load(r)
                                _items.Add(sn)
                                continue
                        print "name ${r.Name} not handled"


So I need to add a case to that loop for every tag I intend to read. Tedious, but at least I found it.

Incidentally, that's lousy O-O methodology. One of the basic ideas behind OO is that you have subclasses so you don't need to have ifs or switches like this. The trouble is that this kind of breaks down when you're reading text data.

The OO way to do it would be to have a factory method, typed as NarrativeItem that took the class name as a string and returned the appropriate item. You'd have a reader class specific to each tag and register them with the factory so it knew what objects mapped to what strings.

Really though, life's too short. Getting all that working and debugged is a task in its own right, and for something as minor as this, it just isn't worth it.

Of course, all that may change as the code evolves. For now though, we'll go with the old-fashioned approach.

No comments: