From 1b5d49ab42b068dc8311c5c167f446e42cdabf33 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 15 Apr 2010 08:11:11 +0000 Subject: [PATCH] 2010-04-15 Atsushi Enomoto * XamlObjectReader.cs, TypeExtensionMethods.cs : Value serialization improvements. Improved namespace handling. Remove unused code. * XamlObjectReaderTest.cs : add more read tests (lots of them are not fully working yet). * DateTime.xml : new test file. (not working though) svn path=/trunk/mcs/; revision=155479 --- mcs/class/System.Xaml/System.Xaml/ChangeLog | 6 + .../System.Xaml/TypeExtensionMethods.cs | 94 ++++---- .../System.Xaml/XamlObjectReader.cs | 42 +++- .../System.Xaml/Test/System.Xaml/ChangeLog | 5 + .../Test/System.Xaml/XamlObjectReaderTest.cs | 220 ++++++++++++++++-- mcs/class/System.Xaml/Test/XmlFiles/ChangeLog | 4 + .../System.Xaml/Test/XmlFiles/DateTime.xml | 1 + 7 files changed, 293 insertions(+), 79 deletions(-) create mode 100644 mcs/class/System.Xaml/Test/XmlFiles/DateTime.xml diff --git a/mcs/class/System.Xaml/System.Xaml/ChangeLog b/mcs/class/System.Xaml/System.Xaml/ChangeLog index b929c3ecc60..716eac33d20 100644 --- a/mcs/class/System.Xaml/System.Xaml/ChangeLog +++ b/mcs/class/System.Xaml/System.Xaml/ChangeLog @@ -1,3 +1,9 @@ +2010-04-15 Atsushi Enomoto + + * XamlObjectReader.cs, TypeExtensionMethods.cs : + Value serialization improvements. Improved namespace handling. + Remove unused code. + 2010-04-15 Atsushi Enomoto * XamlXmlReader.cs : Return Member. Remove NIE. diff --git a/mcs/class/System.Xaml/System.Xaml/TypeExtensionMethods.cs b/mcs/class/System.Xaml/System.Xaml/TypeExtensionMethods.cs index 2c08a52df41..36807c3f090 100644 --- a/mcs/class/System.Xaml/System.Xaml/TypeExtensionMethods.cs +++ b/mcs/class/System.Xaml/System.Xaml/TypeExtensionMethods.cs @@ -33,6 +33,7 @@ namespace System.Xaml { static class TypeExtensionMethods { + // FIXME: this likely needs to be replaced with XamlTypeName public static string GetXamlName (this Type type) { if (!type.IsNested) @@ -40,6 +41,8 @@ namespace System.Xaml return type.DeclaringType.GetXamlName () + "+" + type.Name; } + #region inheritance search and custom attribute provision + public static T GetCustomAttribute (this ICustomAttributeProvider type, bool inherit) where T : Attribute { foreach (var a in type.GetCustomAttributes (typeof (T), inherit)) @@ -77,10 +80,49 @@ namespace System.Xaml return true; return false; } + + #endregion + + #region type conversion and member value retrieval + + public static object GetStringValue (this XamlType xt, object obj) + { + if (obj == null) + return String.Empty; + if (obj is DateTime) + // FIXME: DateTimeValueSerializer should apply + return TypeDescriptor.GetConverter (typeof (DateTime)).ConvertToInvariantString (obj); + else + return xt.ConvertObject (obj, typeof (string)); + } - public static object GetPropertyOrFieldValue (this XamlMember xm, object target) + public static object ConvertObject (this XamlType xt, object target, Type explicitTargetType) { - // FIXME: consider ValueSerializer etc. + return DoConvert (xt.TypeConverter, target, explicitTargetType ?? xt.UnderlyingType); + } + + public static object GetMemberValue (this XamlMember xm, object target) + { + object native = GetPropertyOrFieldValue (xm, target); + var targetRType = xm.TargetType == null ? null : xm.TargetType.UnderlyingType; + return DoConvert (xm.TypeConverter, native, targetRType); + } + + static object DoConvert (XamlValueConverter converter, object value, Type targetType) + { + // First get member value, then convert it to appropriate target type. + var tc = converter != null ? converter.ConverterInstance : null; + if (tc != null && targetType != null && tc.CanConvertTo (targetType)) + return tc.ConvertTo (value, targetType); + return value; + } + + static object GetPropertyOrFieldValue (this XamlMember xm, object target) + { + // FIXME: should this be done here?? + if (xm == XamlLanguage.Initialization) + return target; + var mi = xm.UnderlyingMember; var fi = mi as FieldInfo; if (fi != null) @@ -88,12 +130,11 @@ namespace System.Xaml var pi = mi as PropertyInfo; if (pi != null) return ((PropertyInfo) mi).GetValue (target, null); - // FIXME: should this be done here?? - if (xm == XamlLanguage.Initialization) - return target; throw new NotImplementedException (); } + + #endregion public static IEnumerable GetAllReadWriteMembers (this XamlType type) { @@ -116,48 +157,5 @@ namespace System.Xaml return false; return true; } - - public static bool ListEquals (this IEnumerable a1, IEnumerable a2) - { - if (a1 == null) - return a2 == null || !a2.GetEnumerator ().MoveNext (); - if (a2 == null) - return false || !a1.GetEnumerator ().MoveNext (); - - var e1 = a1.GetEnumerator (); - var e2 = a2.GetEnumerator (); - while (true) { - if (!e1.MoveNext ()) - return !e2.MoveNext (); - if (!e2.MoveNext ()) - return false; - if(!e1.Current.NameEquals (e2.Current)) - return false; - } - } - - public static bool NameEquals (this XamlType t, XamlTypeName n) - { -//Console.Error.WriteLine ("**** {0} {1} {2} {3}", t.Name, t.Name == n.Name, t.PreferredXamlNamespace == n.Namespace, ListEquals (t.TypeArguments.ToTypeNames (), n.TypeArguments)); - return t.Name == n.Name && t.PreferredXamlNamespace == n.Namespace && ListEquals (t.TypeArguments.ToTypeNames (), n.TypeArguments); - } - - public static IEnumerable ToTypeNames (this IEnumerable types) - { - if (types != null) - foreach (var t in types) - yield return new XamlTypeName (t.PreferredXamlNamespace, t.Name, ToTypeNames (t.TypeArguments)); - } - - public static bool NameEquals (this XamlTypeName n1, XamlTypeName n2) - { - if (n1 == null) - return n2 == null; - if (n2 == null) - return false; - if (n1.Name != n2.Name || n1.Namespace != n2.Namespace || !n1.TypeArguments.ListEquals (n2.TypeArguments)) - return false; - return true; - } } } diff --git a/mcs/class/System.Xaml/System.Xaml/XamlObjectReader.cs b/mcs/class/System.Xaml/System.Xaml/XamlObjectReader.cs index f4564dc10e5..9afefccba0b 100644 --- a/mcs/class/System.Xaml/System.Xaml/XamlObjectReader.cs +++ b/mcs/class/System.Xaml/System.Xaml/XamlObjectReader.cs @@ -23,6 +23,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Windows.Markup; namespace System.Xaml @@ -106,18 +107,23 @@ namespace System.Xaml if (instance is Type) instance = new TypeExtension ((Type) instance); + this.instance = instance; + sctx = schemaContext; + this.settings = settings; + if (instance != null) { // check type validity. Note that some checks are done at Read() phase. var type = instance.GetType (); if (!type.IsPublic) throw new XamlObjectReaderException (String.Format ("instance type '{0}' must be public and non-nested.", type)); + root_type = SchemaContext.GetXamlType (instance.GetType ()); } - this.instance = instance; - sctx = schemaContext; - this.settings = settings; + else + root_type = XamlLanguage.Null; } object instance; + XamlType root_type; XamlSchemaContext sctx; XamlObjectReaderSettings settings; @@ -159,6 +165,8 @@ namespace System.Xaml public override object Value { get { return NodeType == XamlNodeType.Value ? objects.Peek () : null; } } + + List tmp_ns_decls = new List (); public override bool Read () { @@ -171,7 +179,13 @@ namespace System.Xaml case XamlNodeType.None: default: // -> namespaces - namespaces = new NSList (XamlNodeType.StartObject, new NamespaceDeclaration (XamlLanguage.Xaml2006Namespace, "x")).GetEnumerator (); + var rootNS = root_type.PreferredXamlNamespace; + if (rootNS != XamlLanguage.Xaml2006Namespace) + tmp_ns_decls.Add (new NamespaceDeclaration (rootNS, String.Empty)); + tmp_ns_decls.Add (new NamespaceDeclaration (XamlLanguage.Xaml2006Namespace, "x")); + namespaces = new NSList (XamlNodeType.StartObject, tmp_ns_decls.ToArray ()).GetEnumerator (); + tmp_ns_decls.Clear (); + namespaces.MoveNext (); node_type = XamlNodeType.NamespaceDeclaration; return true; @@ -199,8 +213,7 @@ namespace System.Xaml return true; case XamlNodeType.StartMember: - members = members_stack.Peek (); - var obj = members.Current.GetPropertyOrFieldValue (objects.Peek ()); + var obj = GetMemberValueOrRootInstance (); objects.Push (obj); node_type = XamlNodeType.Value; return true; @@ -255,9 +268,8 @@ namespace System.Xaml void StartNextObject () { - var xm = members_stack.Count > 0 ? members_stack.Peek ().Current : null; - var obj = xm != null ? xm.GetPropertyOrFieldValue (objects.Peek ()) : instance; - var xt = obj != null ? SchemaContext.GetXamlType (obj.GetType ()) : XamlLanguage.Null; + var obj = GetMemberValueOrRootInstance (); + var xt = Object.ReferenceEquals (obj, instance) ? root_type : obj != null ? SchemaContext.GetXamlType (obj.GetType ()) : XamlLanguage.Null; // FIXME: enable these lines. // FIXME: if there is an applicable instance descriptor, then it could be still valid. @@ -269,5 +281,17 @@ namespace System.Xaml types.Push (xt); node_type = XamlNodeType.StartObject; } + + object GetMemberValueOrRootInstance () + { + if (objects.Count == 0) + return instance; + + var xm = members_stack.Peek ().Current; + var obj = objects.Peek (); + if (xm == XamlLanguage.Initialization) + return types.Peek ().GetStringValue (obj); + return xm != null ? xm.GetMemberValue (obj) : instance; + } } } diff --git a/mcs/class/System.Xaml/Test/System.Xaml/ChangeLog b/mcs/class/System.Xaml/Test/System.Xaml/ChangeLog index 6a933282226..e6cbb35da49 100644 --- a/mcs/class/System.Xaml/Test/System.Xaml/ChangeLog +++ b/mcs/class/System.Xaml/Test/System.Xaml/ChangeLog @@ -1,3 +1,8 @@ +2010-04-15 Atsushi Enomoto + + * XamlObjectReaderTest.cs : add more read tests (lots of them are + not fully working yet). + 2010-04-14 Atsushi Enomoto * XamlXmlReaderTest.cs : add primitive TimeSpan reader test. diff --git a/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectReaderTest.cs b/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectReaderTest.cs index 751e898656e..2655f71c40c 100644 --- a/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectReaderTest.cs +++ b/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectReaderTest.cs @@ -227,45 +227,74 @@ namespace MonoTests.System.Xaml } [Test] - [Category ("NotWorking")] // namespace node differences + [Category ("NotWorking")] + public void Read_NonPrimitive () + { + var r = new XamlObjectReader (new TestClass3 ()); + Assert.AreEqual (XamlNodeType.None, r.NodeType, "#1"); + Assert.IsTrue (r.Read (), "#6"); + Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "#7"); + Assert.AreEqual (String.Empty, r.Namespace.Prefix, "#7-2"); + Assert.AreEqual ("clr-namespace:MonoTests.System.Xaml;assembly=" + GetType ().Assembly.GetName ().Name, r.Namespace.Namespace, "#7-3"); + + Assert.IsTrue (r.Read (), "#11"); + Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "#12"); + Assert.AreEqual ("x", r.Namespace.Prefix, "#12-2"); + Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "#12-3"); + + Assert.IsTrue (r.Read (), "#16"); + Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "#17"); + var xt = new XamlType (typeof (TestClass3), r.SchemaContext); + Assert.AreEqual (xt, r.Type, "#17-2"); + Assert.IsTrue (r.Instance is TestClass3, "#17-3"); + + Assert.IsTrue (r.Read (), "#21"); + Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "#22"); + Assert.AreEqual (xt.GetMember ("Nested"), r.Member, "#22-2"); + + Assert.IsTrue (r.Read (), "#26"); + Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "#27"); + Assert.AreEqual (XamlLanguage.Null, r.Type, "#27-2"); + Assert.IsNull (r.Instance, "#27-3"); + + Assert.IsTrue (r.Read (), "#31"); + Assert.AreEqual (XamlNodeType.EndObject, r.NodeType, "#32"); + + Assert.IsTrue (r.Read (), "#36"); + Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "#37"); + + Assert.IsTrue (r.Read (), "#41"); + Assert.AreEqual (XamlNodeType.EndObject, r.NodeType, "#42"); + + Assert.IsFalse (r.Read (), "#46"); + Assert.IsTrue (r.IsEof, "#47"); + } + + [Test] + [Category ("NotWorking")] public void Read_Type () { - var r = new XamlObjectReader (typeof (TestClass1)); + var r = new XamlObjectReader (typeof (int)); Read_TypeOrTypeExtension (r); } [Test] - [Category ("NotWorking")] // namespace node differences + [Category ("NotWorking")] public void Read_TypeExtension () { - var r = new XamlObjectReader (new TypeExtension (typeof (TestClass1))); + var r = new XamlObjectReader (new TypeExtension (typeof (int))); Read_TypeOrTypeExtension (r); } void Read_TypeOrTypeExtension (XamlObjectReader r) { - Assert.AreEqual (XamlNodeType.None, r.NodeType, "#1"); - Assert.IsNull (r.Member, "#2"); - Assert.IsNull (r.Namespace, "#3"); - Assert.IsNull (r.Member, "#4"); - Assert.IsNull (r.Type, "#5"); - Assert.IsNull (r.Value, "#6"); - Assert.IsNull (r.Instance, "#7"); - Assert.IsTrue (r.Read (), "#11"); Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "#12"); Assert.IsNotNull (r.Namespace, "#13"); - Assert.AreEqual (String.Empty, r.Namespace.Prefix, "#13-2"); - Assert.AreEqual ("clr-namespace:MonoTests.System.Xaml;assembly=" + GetType ().Assembly.GetName ().Name, r.Namespace.Namespace, "#13-3"); + Assert.AreEqual ("x", r.Namespace.Prefix, "#13-2"); + Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "#13-3"); Assert.IsNull (r.Instance, "#14"); - Assert.IsTrue (r.Read (), "#16"); - Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "#17"); - Assert.IsNotNull (r.Namespace, "#18"); - Assert.AreEqual ("x", r.Namespace.Prefix, "#18-2"); - Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "#18-3"); - Assert.IsNull (r.Instance, "#19"); - Assert.IsTrue (r.Read (), "#21"); Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "#22"); Assert.IsNotNull (r.Type, "#23"); @@ -283,7 +312,7 @@ namespace MonoTests.System.Xaml Assert.IsTrue (r.Read (), "#41"); Assert.AreEqual (XamlNodeType.Value, r.NodeType, "#42"); Assert.IsNotNull (r.Value, "#43"); - Assert.AreEqual ("TestClass1", r.Value, "#43-2"); + Assert.AreEqual ("x:Int32", r.Value, "#43-2"); Assert.IsNull (r.Member, "#44"); Assert.IsNull (r.Instance, "#45"); @@ -300,6 +329,152 @@ namespace MonoTests.System.Xaml Assert.IsFalse (r.Read (), "#71"); Assert.IsTrue (r.IsEof, "#72"); } + + [Test] + [Category ("NotWorking")] // namespace node differences + public void Read_Type2 () + { + var r = new XamlObjectReader (typeof (TestClass1)); + Read_TypeOrTypeExtension2 (r); + } + + [Test] + [Category ("NotWorking")] // namespace node differences + public void Read_TypeExtension2 () + { + var r = new XamlObjectReader (new TypeExtension (typeof (TestClass1))); + Read_TypeOrTypeExtension2 (r); + } + + void Read_TypeOrTypeExtension2 (XamlObjectReader r) + { + Assert.IsTrue (r.Read (), "#11"); + Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "#12"); + Assert.AreEqual (String.Empty, r.Namespace.Prefix, "#13-2"); + Assert.AreEqual ("clr-namespace:MonoTests.System.Xaml;assembly=" + GetType ().Assembly.GetName ().Name, r.Namespace.Namespace, "#13-3"); + + Assert.IsTrue (r.Read (), "#16"); + Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "#17"); + Assert.IsNotNull (r.Namespace, "#18"); + Assert.AreEqual ("x", r.Namespace.Prefix, "#18-2"); + Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "#18-3"); + + Assert.IsTrue (r.Read (), "#21"); + Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "#22"); + Assert.AreEqual (new XamlType (typeof (TypeExtension), r.SchemaContext), r.Type, "#23-2"); + Assert.IsTrue (r.Instance is TypeExtension, "#26"); + + Assert.IsTrue (r.Read (), "#31"); + Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "#32"); + Assert.AreEqual (XamlLanguage.PositionalParameters, r.Member, "#33-2"); + + Assert.IsTrue (r.Read (), "#41"); + Assert.AreEqual (XamlNodeType.Value, r.NodeType, "#42"); + Assert.AreEqual ("TestClass1", r.Value, "#43-2"); + + Assert.IsTrue (r.Read (), "#51"); + Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "#52"); + + Assert.IsTrue (r.Read (), "#61"); + Assert.AreEqual (XamlNodeType.EndObject, r.NodeType, "#62"); + + Assert.IsFalse (r.Read (), "#71"); + Assert.IsTrue (r.IsEof, "#72"); + } + + [Test] + // WTF, It does not give XAML namespace, but XamlSerives.Save() + // serializes DateTime instance in the XAML namespace. + [Category ("NotWorking")] + public void Read_DateTime () + { + var obj = new DateTime (2010, 4, 15); + var r = new XamlObjectReader (obj); + Read_CommonClrType (r, obj); + Assert.AreEqual ("2010-04-15", Read_Initialization (r, null), "#1"); + } + + [Test] + public void Read_TimeSpan () + { + Read_CommonXamlPrimitive (TimeSpan.FromMinutes (4)); + } + + [Test] + public void Read_Uri () + { + Read_CommonXamlPrimitive (new Uri ("urn:foo")); + } + + [Test] + [ExpectedException (typeof (XamlObjectReaderException))] + [Category ("NotWorking")] + public void Read_XData () + { + var r = new XamlObjectReader (new XData () {Text = "xdata text"}); // XmlReader implementation is not visible. + while (!r.IsEof) + r.Read (); + } + + void Read_CommonXamlPrimitive (object obj) + { + var r = new XamlObjectReader (obj); + Read_CommonXamlType (r); + Read_Initialization (r, obj); + } + + // from StartMember of Initialization to EndMember + string Read_Initialization (XamlObjectReader r, object comparableValue) + { + Assert.IsTrue (r.Read (), "init#1"); + Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "init#2"); + Assert.IsNotNull (r.Member, "init#3"); + Assert.AreEqual (XamlLanguage.Initialization, r.Member, "init#3-2"); + Assert.IsTrue (r.Read (), "init#4"); + Assert.AreEqual (XamlNodeType.Value, r.NodeType, "init#5"); + Assert.AreEqual (typeof (string), r.Value.GetType (), "init#6"); + string ret = (string) r.Value; + if (comparableValue != null) + Assert.AreEqual (comparableValue.ToString (), r.Value, "init#6-2"); + Assert.IsTrue (r.Read (), "init#7"); + Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "init#8"); + return ret; + } + + // from initial to StartObject + void Read_CommonXamlType (XamlObjectReader r) + { + Assert.IsTrue (r.Read (), "ct#1"); + Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "ct#2"); + Assert.IsNotNull (r.Namespace, "ct#3"); + Assert.AreEqual ("x", r.Namespace.Prefix, "ct#3-2"); + Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "ct#3-3"); + Assert.IsNull (r.Instance, "ct#4"); + + Assert.IsTrue (r.Read (), "ct#5"); + Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "ct#6"); + } + + // from initial to StartObject + void Read_CommonClrType (XamlObjectReader r, object obj) + { + Assert.IsTrue (r.Read (), "ct#1"); + Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "ct#2"); + Assert.IsNotNull (r.Namespace, "ct#3"); + Assert.AreEqual (String.Empty, r.Namespace.Prefix, "ct#3-2"); + Assert.AreEqual ("clr-namespace:" + obj.GetType ().Namespace + ";assembly=" + obj.GetType ().Assembly.GetName ().Name, r.Namespace.Namespace, "ct#3-3"); + +/* + Assert.IsTrue (r.Read (), "ct#4"); + Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "ct#5"); + Assert.IsNotNull (r.Namespace, "ct#6"); + Assert.AreEqual ("x", r.Namespace.Prefix, "ct#6-2"); + Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "ct#6-3"); +*/ + + Assert.IsTrue (r.Read (), "ct#7"); + Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "ct#8"); + } } class TestClass1 @@ -308,5 +483,6 @@ namespace MonoTests.System.Xaml public class TestClass3 { + public TestClass3 Nested { get; set; } } } diff --git a/mcs/class/System.Xaml/Test/XmlFiles/ChangeLog b/mcs/class/System.Xaml/Test/XmlFiles/ChangeLog index 707057a48a3..7c0de9f5f18 100644 --- a/mcs/class/System.Xaml/Test/XmlFiles/ChangeLog +++ b/mcs/class/System.Xaml/Test/XmlFiles/ChangeLog @@ -1,3 +1,7 @@ +2010-04-15 Atsushi Enomoto + + * DateTime.xml : new test file. (not working though) + 2010-04-14 Atsushi Enomoto * TimeSpan.xml : new test file. diff --git a/mcs/class/System.Xaml/Test/XmlFiles/DateTime.xml b/mcs/class/System.Xaml/Test/XmlFiles/DateTime.xml new file mode 100644 index 00000000000..e4ab8dc7d2a --- /dev/null +++ b/mcs/class/System.Xaml/Test/XmlFiles/DateTime.xml @@ -0,0 +1 @@ +2010-04-14 \ No newline at end of file -- 2.25.1