From 4fad3da5b8d8f4b75212909777b0e9546b7ca2ea Mon Sep 17 00:00:00 2001 From: Richard Schwarting Date: Wed, 22 Aug 2012 11:26:21 -0400 Subject: [PATCH] * split XmlSerializableTest into SerializationTest and SerializableTest --- test/GXmlTest.vala | 3 +- test/Makefile.am | 5 +- test/SerializableTest.vala | 277 ++++++++++++++++++ ...izableTest.vala => SerializationTest.vala} | 256 +--------------- 4 files changed, 284 insertions(+), 257 deletions(-) create mode 100644 test/SerializableTest.vala rename test/{XmlSerializableTest.vala => SerializationTest.vala} (69%) diff --git a/test/GXmlTest.vala b/test/GXmlTest.vala index 2da94af1..3f0daed9 100644 --- a/test/GXmlTest.vala +++ b/test/GXmlTest.vala @@ -12,7 +12,8 @@ class GXmlTest { TextTest.add_tests (); CharacterDataTest.add_tests (); ValaLibxml2Test.add_tests (); - XmlSerializableTest.add_tests (); + SerializationTest.add_tests (); + SerializableTest.add_tests (); // Prevent WARNING from aborting the test suite GLib.Log.set_always_fatal (GLib.LogLevelFlags.LEVEL_ERROR); diff --git a/test/Makefile.am b/test/Makefile.am index 47b1b53a..2191de0c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -28,13 +28,14 @@ gxml_test_SOURCES = \ AttrTest.vala \ CharacterDataTest.vala \ DocumentTest.vala \ + DomNodeTest.vala \ ElementTest.vala \ GXmlTest.vala \ NodeListTest.vala \ TextTest.vala \ ValaLibxml2Test.vala \ - XmlSerializableTest.vala \ - DomNodeTest.vala \ + SerializableTest.vala \ + SerializationTest.vala \ $(NULL) gxml_test.vala.stamp: $(gxml_test_SOURCES) diff --git a/test/SerializableTest.vala b/test/SerializableTest.vala new file mode 100644 index 00000000..200cbf09 --- /dev/null +++ b/test/SerializableTest.vala @@ -0,0 +1,277 @@ +/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +using GXml; +using Gee; + +/** + * Test cases: + * field, property + * primitive, complex, collection, object + * visibility + * + * *. simple field: int, string, double, bool + * *. simple property: int, string, double + * *. collection property: glist, ghashtable, + * *. gee collection property: list, set, hashtable + * *. complex: simple object, complex object, enum, struct etc. + * + * TODO: How do we want to handle the case of A having B and C as properties, and B and C both have D as a property? if we serialize and then deserialize, we'll end up with D1 and D2 separate; we might want to have some memory identifier to tell if we've already deserialised something and then we can just pioint to that. + * + */ + +/* + Test overriding nothing (rely on defaults) + Test overriding {de,}serialize_property + Test overriding list_properties/find_property + Test overriding {set,get}_property +*/ + +public class SerializableTomato : GLib.Object, GXml.Serializable { + public int weight; + private int age { get; set; } + public int height { get; set; } + public string description { get; set; } + + public SerializableTomato (int weight, int age, int height, string description) { + this.weight = weight; + this.age = age; + this.height = height; + this.description = description; + } + + public string to_string () { + return "SerializableTomato {weight:%d, age:%d, height:%d, description:%s}".printf (weight, age, height, description); + } + + public static bool equals (SerializableTomato a, SerializableTomato b) { + bool same = (a.weight == b.weight && + a.age == b.age && + a.height == b.height && + a.description == b.description); + + return same; + } +} + +public class SerializableCapsicum : GLib.Object, GXml.Serializable { + public int weight; + private int age { get; set; } + public int height { get; set; } + public unowned GLib.List ratings { get; set; } + + public string to_string () { + string str = "SerializableCapsicum {weight:%d, age:%d, height:%d, ratings:".printf (weight, age, height); + foreach (int rating in ratings) { + str += "%d ".printf (rating); + } + str += "}"; + return str; + } + + public SerializableCapsicum (int weight, int age, int height, GLib.List ratings) { + this.weight = weight; + this.age = age; + this.height = height; + this.ratings = ratings; + } + + /* TODO: do we really need GLib.Value? or should we modify the object directly? + Want an example using GBoxed too + Perhaps these shouldn't be object methods, perhaps they should be static? + Can't have static methods in an interface :(, right? */ + public bool deserialize_property (string property_name, /* out GLib.Value value, */ + GLib.ParamSpec spec, GXml.DomNode property_node) { + GLib.Value outvalue = GLib.Value (typeof (int)); + + switch (property_name) { + case "ratings": + this.ratings = new GLib.List (); + foreach (GXml.DomNode rating in property_node.child_nodes) { + int64.try_parse (((GXml.Element)rating).content, out outvalue); + this.ratings.append ((int)outvalue.get_int64 ()); + } + return true; + case "height": + int64.try_parse (((GXml.Element)property_node).content, out outvalue); + this.height = (int)outvalue.get_int64 () - 1; + return true; + default: + GLib.error ("Wasn't expecting the SerializableCapsicum property '%s'", property_name); + } + + return false; + } + public GXml.DomNode? serialize_property (string property_name, /*GLib.Value value,*/ GLib.ParamSpec spec, GXml.Document doc) { + GXml.Element c_prop; + GXml.Element rating; + + switch (property_name) { + case "ratings": + GXml.DocumentFragment frag = doc.create_document_fragment (); + foreach (int rating_int in ratings) { + rating = doc.create_element ("rating"); + rating.content = "%d".printf (rating_int); + frag.append_child (rating); + } + return frag; + break; + case "height": + return doc.create_text_node ("%d".printf (height + 1)); + break; + default: + GLib.error ("Wasn't expecting the SerializableCapsicum property '%s'", property_name); + } + + // returning null does a normal serialization + return null; + } +} + + +public class SerializableBanana : GLib.Object, GXml.Serializable { + private int private_field; + public int public_field; + private int private_property { get; set; } + public int public_property { get; set; } + + public SerializableBanana (int private_field, int public_field, int private_property, int public_property) { + this.private_field = private_field; + this.public_field = public_field; + this.private_property = private_property; + this.public_property = public_property; + + } + + public string to_string () { + return "SerializableBanana {private_field:%d, public_field:%d, private_property:%d, public_property:%d}".printf (this.private_field, this.public_field, this.private_property, this.public_property); + } + + public static bool equals (SerializableBanana a, SerializableBanana b) { + return (a.private_field == b.private_field && + a.public_field == b.public_field && + a.private_property == b.private_property && + a.public_property == b.public_property); + } + + private ParamSpec[] properties = null; + public unowned GLib.ParamSpec[] list_properties () { + // TODO: so, if someone implements list_properties, but they don't create there array until called, that could be inefficient if they don't cache. If they create it at construction, then serialising and deserialising will lose it? offer guidance + if (this.properties == null) { + properties = new ParamSpec[4]; + int i = 0; + foreach (string name in new string[] { "private-field", "public-field", "private-property", "public-property" }) { + properties[i] = new ParamSpecInt (name, name, name, int.MIN, int.MAX, 0, ParamFlags.READABLE); // TODO: offer guidance for these fields, esp. ParamFlags + i++; + // TODO: does serialisation use anything other than ParamSpec.name? + } + } + return this.properties; + } + + private GLib.ParamSpec prop; + public unowned GLib.ParamSpec? find_property (string property_name) { + GLib.ParamSpec[] properties = this.list_properties (); + foreach (ParamSpec prop in properties) { + if (prop.name == property_name) { + this.prop = prop; + return this.prop; + } + } + return null; + } + + public void get_property (GLib.ParamSpec spec, ref GLib.Value str_value) { + Value value = Value (typeof (int)); + + switch (spec.name) { + case "private-field": + value.set_int (this.private_field); + break; + case "public-field": + value.set_int (this.public_field); + break; + case "private-property": + value.set_int (this.private_property); + break; + case "public-property": + value.set_int (this.public_property); + break; + default: + ((GLib.Object)this).get_property (spec.name, ref str_value); + return; + } + + value.transform (ref str_value); + return; + } + + public void set_property (GLib.ParamSpec spec, GLib.Value value) { + switch (spec.name) { + case "private-field": + this.private_field = value.get_int (); + break; + case "public-field": + this.public_field = value.get_int (); + break; + case "private-property": + this.private_property = value.get_int (); + break; + case "public-property": + this.public_property = value.get_int (); + break; + default: + ((GLib.Object)this).set_property (spec.name, value); + return; + } + } +} + +class SerializableTest : GXmlTest { + public static void add_tests () { + Test.add_func ("/gxml/serializable/interface_defaults", () => { + SerializableTomato tomato = new SerializableTomato (0, 0, 12, "cats"); + + SerializationTest.test_serialization_deserialization (tomato, "interface_defaults", (GLib.EqualFunc)SerializableTomato.equals, (SerializationTest.StringifyFunc)SerializableTomato.to_string); + }); + Test.add_func ("/gxml/serializable/interface_override_serialization_on_list", () => { + GXml.DomNode node; + SerializableCapsicum capsicum; + SerializableCapsicum capsicum_new; + string expectation; + Regex regex; + GLib.List ratings; + + ratings = new GLib.List (); + ratings.append (8); + ratings.append (13); + ratings.append (21); + + capsicum = new SerializableCapsicum (2, 3, 5, ratings); + node = Serialization.serialize_object (capsicum); + + expectation = "681321"; + + try { + regex = new Regex (expectation); + if (! regex.match (node.to_string ())) { + GLib.warning ("Did not serialize as expected. Got [%s] but expected [%s]", node.to_string (), expectation); + GLib.Test.fail (); + } + + capsicum_new = (SerializableCapsicum)Serialization.deserialize_object (node); + if (capsicum_new.height != 5 || ratings.length () != 3 || ratings.nth_data (0) != 8 || ratings.nth_data (2) != 21) { + GLib.warning ("Did not deserialize as expected. Got [%s] but expected height and ratings from [%s]", capsicum_new.to_string (), capsicum.to_string ()); + GLib.Test.fail (); + } + } catch (RegexError e) { + GLib.warning ("Regular expression [%s] for test failed: %s", + expectation, e.message); + GLib.Test.fail (); + } + }); + Test.add_func ("/gxml/serialization/interface_override_properties_view", () => { + SerializableBanana banana = new SerializableBanana (17, 19, 23, 29); + + SerializationTest.test_serialization_deserialization (banana, "interface_override_properties", (GLib.EqualFunc)SerializableBanana.equals, (SerializationTest.StringifyFunc)SerializableBanana.to_string); + }); + } +} diff --git a/test/XmlSerializableTest.vala b/test/SerializationTest.vala similarity index 69% rename from test/XmlSerializableTest.vala rename to test/SerializationTest.vala index ba2a1f63..2ac6c209 100644 --- a/test/XmlSerializableTest.vala +++ b/test/SerializationTest.vala @@ -25,209 +25,6 @@ using Gee; Test overriding {set,get}_property */ -public class SerializableTomato : GLib.Object, GXml.Serializable { - public int weight; - private int age { get; set; } - public int height { get; set; } - public string description { get; set; } - - public SerializableTomato (int weight, int age, int height, string description) { - this.weight = weight; - this.age = age; - this.height = height; - this.description = description; - } - - public string to_string () { - return "SerializableTomato {weight:%d, age:%d, height:%d, description:%s}".printf (weight, age, height, description); - } - - public static bool equals (SerializableTomato a, SerializableTomato b) { - bool same = (a.weight == b.weight && - a.age == b.age && - a.height == b.height && - a.description == b.description); - - return same; - } -} - -public class SerializableCapsicum : GLib.Object, GXml.Serializable { - public int weight; - private int age { get; set; } - public int height { get; set; } - public unowned GLib.List ratings { get; set; } - - public string to_string () { - string str = "SerializableCapsicum {weight:%d, age:%d, height:%d, ratings:".printf (weight, age, height); - foreach (int rating in ratings) { - str += "%d ".printf (rating); - } - str += "}"; - return str; - } - - public SerializableCapsicum (int weight, int age, int height, GLib.List ratings) { - this.weight = weight; - this.age = age; - this.height = height; - this.ratings = ratings; - } - - /* TODO: do we really need GLib.Value? or should we modify the object directly? - Want an example using GBoxed too - Perhaps these shouldn't be object methods, perhaps they should be static? - Can't have static methods in an interface :(, right? */ - public bool deserialize_property (string property_name, /* out GLib.Value value, */ - GLib.ParamSpec spec, GXml.DomNode property_node) { - GLib.Value outvalue = GLib.Value (typeof (int)); - - switch (property_name) { - case "ratings": - this.ratings = new GLib.List (); - foreach (GXml.DomNode rating in property_node.child_nodes) { - int64.try_parse (((GXml.Element)rating).content, out outvalue); - this.ratings.append ((int)outvalue.get_int64 ()); - } - return true; - case "height": - int64.try_parse (((GXml.Element)property_node).content, out outvalue); - this.height = (int)outvalue.get_int64 () - 1; - return true; - default: - GLib.error ("Wasn't expecting the SerializableCapsicum property '%s'", property_name); - } - - return false; - } - public GXml.DomNode? serialize_property (string property_name, /*GLib.Value value,*/ GLib.ParamSpec spec, GXml.Document doc) { - GXml.Element c_prop; - GXml.Element rating; - - switch (property_name) { - case "ratings": - GXml.DocumentFragment frag = doc.create_document_fragment (); - foreach (int rating_int in ratings) { - rating = doc.create_element ("rating"); - rating.content = "%d".printf (rating_int); - frag.append_child (rating); - } - return frag; - break; - case "height": - return doc.create_text_node ("%d".printf (height + 1)); - break; - default: - GLib.error ("Wasn't expecting the SerializableCapsicum property '%s'", property_name); - } - - // returning null does a normal serialization - return null; - } -} - - -public class SerializableBanana : GLib.Object, GXml.Serializable { - private int private_field; - public int public_field; - private int private_property { get; set; } - public int public_property { get; set; } - - public SerializableBanana (int private_field, int public_field, int private_property, int public_property) { - this.private_field = private_field; - this.public_field = public_field; - this.private_property = private_property; - this.public_property = public_property; - - } - - public string to_string () { - return "SerializableBanana {private_field:%d, public_field:%d, private_property:%d, public_property:%d}".printf (this.private_field, this.public_field, this.private_property, this.public_property); - } - - public static bool equals (SerializableBanana a, SerializableBanana b) { - return (a.private_field == b.private_field && - a.public_field == b.public_field && - a.private_property == b.private_property && - a.public_property == b.public_property); - } - - private ParamSpec[] properties = null; - public unowned GLib.ParamSpec[] list_properties () { - // TODO: so, if someone implements list_properties, but they don't create there array until called, that could be inefficient if they don't cache. If they create it at construction, then serialising and deserialising will lose it? offer guidance - if (this.properties == null) { - properties = new ParamSpec[4]; - int i = 0; - foreach (string name in new string[] { "private-field", "public-field", "private-property", "public-property" }) { - properties[i] = new ParamSpecInt (name, name, name, int.MIN, int.MAX, 0, ParamFlags.READABLE); // TODO: offer guidance for these fields, esp. ParamFlags - i++; - // TODO: does serialisation use anything other than ParamSpec.name? - } - } - return this.properties; - } - - private GLib.ParamSpec prop; - public unowned GLib.ParamSpec? find_property (string property_name) { - GLib.ParamSpec[] properties = this.list_properties (); - foreach (ParamSpec prop in properties) { - if (prop.name == property_name) { - this.prop = prop; - return this.prop; - } - } - return null; - } - - public void get_property (GLib.ParamSpec spec, ref GLib.Value str_value) { - Value value = Value (typeof (int)); - - switch (spec.name) { - case "private-field": - value.set_int (this.private_field); - break; - case "public-field": - value.set_int (this.public_field); - break; - case "private-property": - value.set_int (this.private_property); - break; - case "public-property": - value.set_int (this.public_property); - break; - default: - ((GLib.Object)this).get_property (spec.name, ref str_value); - return; - } - - value.transform (ref str_value); - return; - } - - public void set_property (GLib.ParamSpec spec, GLib.Value value) { - switch (spec.name) { - case "private-field": - this.private_field = value.get_int (); - break; - case "public-field": - this.public_field = value.get_int (); - break; - case "private-property": - this.private_property = value.get_int (); - break; - case "public-property": - this.public_property = value.get_int (); - break; - default: - ((GLib.Object)this).set_property (spec.name, value); - return; - } - } - -} - - - // TODO: if I don't subclass GLib.Object, a Vala class's object can't be serialised? public class Fruit : GLib.Object { string colour; @@ -429,7 +226,7 @@ public class EnumProperties : GLib.Object { } } -class XmlSerializableTest : GXmlTest { +class SerializationTest : GXmlTest { public delegate string StringifyFunc (GLib.Object object); public static GLib.Object test_serialization_deserialization (GLib.Object object, string name, EqualFunc equals, StringifyFunc stringify) { @@ -461,7 +258,7 @@ class XmlSerializableTest : GXmlTest { } return object_new; -} + } public static void add_tests () { Test.add_func ("/gxml/domnode/xml_serialize", () => { @@ -726,54 +523,5 @@ class XmlSerializableTest : GXmlTest { test_serialization_deserialization (obj, "enum_properties", (GLib.EqualFunc)EnumProperties.equals, (StringifyFunc)EnumProperties.to_string); }); // TODO: more to do, for structs and stuff and things that do interfaces - - Test.add_func ("/gxml/serialization/interface_defaults", () => { - SerializableTomato tomato = new SerializableTomato (0, 0, 12, "cats"); - - test_serialization_deserialization (tomato, "interface_defaults", (GLib.EqualFunc)SerializableTomato.equals, (StringifyFunc)SerializableTomato.to_string); - }); - Test.add_func ("/gxml/serialization/interface_overrides_and_list", () => { - GXml.DomNode node; - SerializableCapsicum capsicum; - SerializableCapsicum capsicum_new; - string expectation; - Regex regex; - GLib.List ratings; - - ratings = new GLib.List (); - ratings.append (8); - ratings.append (13); - ratings.append (21); - - capsicum = new SerializableCapsicum (2, 3, 5, ratings); - node = Serialization.serialize_object (capsicum); - - expectation = "681321"; - - try { - regex = new Regex (expectation); - if (! regex.match (node.to_string ())) { - GLib.warning ("Did not serialize as expected. Got [%s] but expected [%s]", node.to_string (), expectation); - GLib.Test.fail (); - } - - capsicum_new = (SerializableCapsicum)Serialization.deserialize_object (node); - if (capsicum_new.height != 5 || ratings.length () != 3 || ratings.nth_data (0) != 8 || ratings.nth_data (2) != 21) { - GLib.warning ("Did not deserialize as expected. Got [%s] but expected height and ratings from [%s]", capsicum_new.to_string (), capsicum.to_string ()); - GLib.Test.fail (); - } - } catch (RegexError e) { - GLib.warning ("Regular expression [%s] for test failed: %s", - expectation, e.message); - GLib.Test.fail (); - } - }); - Test.add_func ("/gxml/serialization/interface_override_properties", () => { - SerializableBanana banana = new SerializableBanana (17, 19, 23, 29); - - test_serialization_deserialization (banana, "interface_override_properties", (GLib.EqualFunc)SerializableBanana.equals, (StringifyFunc)SerializableBanana.to_string); - }); - - } } -- GitLab