Rewrote ValueSerializer.GetSerializerFor() with couple of tests.
authorAtsushi Eno <atsushi@ximian.com>
Wed, 17 Nov 2010 17:36:33 +0000 (02:36 +0900)
committerAtsushi Eno <atsushi@ximian.com>
Wed, 17 Nov 2010 17:36:33 +0000 (02:36 +0900)
mcs/class/System.Xaml/System.Windows.Markup/ValueSerializer.cs
mcs/class/System.Xaml/System.Xaml.Schema/XamlTypeTypeConverter.cs
mcs/class/System.Xaml/System.Xaml_test.dll.sources
mcs/class/System.Xaml/Test/System.Windows.Markup/ValueSerializerTest.cs
mcs/class/System.Xaml/Test/System.Xaml.Schema/XamlTypeTypeConverterTest.cs
mcs/class/System.Xaml/Test/System.Xaml/DummyValueSerializerContext.cs [new file with mode: 0644]

index b625bb984449e6e618305ccf5aff73a1476bdd2e..25128ddce44f6a62319a0f56b17da15d565af186 100644 (file)
@@ -43,26 +43,63 @@ namespace System.Windows.Markup
                        return GetSerializerFor (type, null);
                }
 
+               // untested
                public static ValueSerializer GetSerializerFor (PropertyDescriptor descriptor, IValueSerializerContext context)
                {
-                       throw new NotImplementedException ();
+                       if (descriptor == null)
+                               throw new ArgumentNullException ("descriptor");
+                       if (context != null)
+                               return context.GetValueSerializerFor (descriptor);
+
+                       var tc = descriptor.Converter;
+                       if (tc != null && tc.GetType () != typeof (TypeConverter))
+                               return new TypeConverterValueSerializer (tc);
+                       return null;
                }
 
                public static ValueSerializer GetSerializerFor (Type type, IValueSerializerContext context)
                {
                        if (type == null)
                                throw new ArgumentNullException ("type");
-                       // weird, but .NET also throws NIE(!)
                        if (context != null)
-                               throw new NotImplementedException ();
+                               return context.GetValueSerializerFor (type);
 
                        // Standard MarkupExtensions are serialized without ValueSerializer.
                        if (typeof (MarkupExtension).IsAssignableFrom (type) && XamlLanguage.AllTypes.Any (x => x.UnderlyingType == type))
                                return null;
 
-                       var tc = TypeDescriptor.GetConverter (type);
-                       if (tc != null && tc.GetType () != typeof (TypeConverter))
-                               return new TypeConverterValueSerializer (type);
+                       // DateTime is documented as special.
+                       if (type == typeof (DateTime))
+                               return new DateTimeValueSerializer ();
+                       // String too.
+                       if (type == typeof (string))
+                               return new StringValueSerializer ();
+
+                       // FIXME: this is hack. The complete condition is fully documented at http://msdn.microsoft.com/en-us/library/ms590363.aspx
+                       if (type.GetCustomAttribute<TypeConverterAttribute> (true) != null) {
+                               var tc = TypeDescriptor.GetConverter (type);
+                               if (tc != null && tc.GetType () != typeof (TypeConverter))
+                                       return new TypeConverterValueSerializer (tc);
+                       }
+
+                       // Undocumented, but System.Type seems also special. While other MarkupExtension returned types are not handled specially, this method returns a valid instance for System.Type. Note that it doesn't for TypeExtension.
+                       if (type == typeof (Type))
+                               // Since System.Type does not have a valid TypeConverter, I use TypeExtensionConverter (may sound funny considering the above notes!) for this serializer.
+                               return new TypeConverterValueSerializer (new TypeExtensionConverter ());
+
+                       // Undocumented, but several primitive types get a valid serializer while it does not have TypeConverter.
+                       switch (Type.GetTypeCode (type)) {
+                       case TypeCode.Object:
+                       case TypeCode.DBNull:
+                               break;
+                       default:
+                               return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
+                       }
+
+                       // There is still exceptional type! TimeSpan. Why aren't they documented?
+                       if (type == typeof (TimeSpan))
+                               return new TypeConverterValueSerializer (TypeDescriptor.GetConverter (type));
+
                        return null;
                }
 
@@ -80,27 +117,27 @@ namespace System.Windows.Markup
 
                public virtual object ConvertFromString (string value, IValueSerializerContext context)
                {
-                       throw new NotSupportedException (String.Format ("Conversion from string '{0}' is not supported", value));
+                       throw GetConvertFromException (value);
                }
 
                public virtual string ConvertToString (object value,     IValueSerializerContext context)
                {
-                       throw new NotSupportedException (String.Format ("Conversion from '{0}' to string is not supported", value != null ? value.GetType ().Name : "(null)"));
+                       throw GetConvertToException (value, typeof (string));
                }
 
                protected Exception GetConvertFromException (object value)
                {
-                       throw new NotImplementedException ();
+                       return new NotSupportedException (String.Format ("Conversion from string '{0}' is not supported", value));
                }
 
                protected Exception GetConvertToException (object value, Type destinationType)
                {
-                       throw new NotImplementedException ();
+                       return new NotSupportedException (String.Format ("Conversion from '{0}' to {1} is not supported", value != null ? value.GetType ().Name : "(null)", destinationType));
                }
 
                public virtual IEnumerable<Type> TypeReferences (object value, IValueSerializerContext context)
                {
-                       throw new NotImplementedException ();
+                       yield break;
                }
        }
 
@@ -134,19 +171,11 @@ namespace System.Windows.Markup
 
        #region Internal implementations.
 
-       internal class TypeConverterValueSerializer<T> : TypeConverterValueSerializer
-       {
-               public TypeConverterValueSerializer ()
-                       : base (typeof (T))
-               {
-               }
-       }
-
        internal class TypeConverterValueSerializer : ValueSerializer
        {
-               public TypeConverterValueSerializer (Type type)
+               public TypeConverterValueSerializer (TypeConverter typeConverter)
                {
-                       c = TypeDescriptor.GetConverter (type);
+                       c = typeConverter;
                }
 
                TypeConverter c;
index d4a435beac3c208e0db21aec535579f909416457..dc5333ad3f20f4d5feabded887cb35ddddaa8695 100644 (file)
@@ -48,6 +48,9 @@ namespace System.Xaml.Schema
 
                public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
                {
+                       if (!CanConvertTo (context, destinationType))
+                               throw new NotSupportedException (String.Format ("Conversion to type {0} is not supported", destinationType));
+
                        var vctx = (IValueSerializerContext) context;
                        var lookup = vctx != null ? (INamespacePrefixLookup) vctx.GetService (typeof (INamespacePrefixLookup)) : null;
                        var xt = value as XamlType;
index a2242d58997d4b7a83eabd015f90c2e111555ef5..4bc27f70c9fc21ee9fc6766e1f1cbc1733f1e755 100644 (file)
@@ -12,6 +12,7 @@ System.Xaml.Schema/XamlTypeTypeConverterTest.cs
 System.Xaml.Schema/XamlValueConverterTest.cs
 System.Xaml/AmbientPropertyValueTest.cs
 System.Xaml/AttachableMemberIdentifierTest.cs
+System.Xaml/DummyValueSerializerContext.cs
 System.Xaml/NamespaceDeclarationTest.cs
 System.Xaml/TestedTypes.cs
 System.Xaml/XamlDirectiveTest.cs
index 551934759802da342d9c48ab378ae16e1de73ee4..a8c7a8d574b5cfd64338b93043c87e5bf0a56485 100644 (file)
@@ -31,6 +31,7 @@ using System.Windows.Markup;
 using System.Xaml;
 using System.Xaml.Schema;
 using NUnit.Framework;
+using MonoTests.System.Xaml;
 
 using Category = NUnit.Framework.CategoryAttribute;
 
@@ -103,6 +104,25 @@ namespace MonoTests.System.Windows.Markup
                        }
                }
 
+               [Test]
+               public void GetSerializerFor ()
+               {
+                       Assert.IsNull (ValueSerializer.GetSerializerFor (typeof (Array)), "#1");
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (Uri)), "#2");
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (Type)), "#3"); // has no TypeConverter (undocumented behavior)
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (string)), "#4"); // documented as special
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (DateTime)), "#5"); // documented as special
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (bool)), "#6"); // has no TypeConverter (undocumented behavior)
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (byte)), "#7"); // has no TypeConverter (undocumented behavior)
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (char)), "#8"); // has no TypeConverter (undocumented behavior)
+                       Assert.IsNull (ValueSerializer.GetSerializerFor (typeof (DBNull)), "#9"); // TypeCode.DBNull
+                       Assert.IsNull (ValueSerializer.GetSerializerFor (typeof (object)), "#10");
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (TimeSpan)), "#11"); // has no TypeConverter (undocumented behavior), TypeCode.Object -> unexpectedly has non-null serializer!
+                       Assert.IsNull (ValueSerializer.GetSerializerFor (typeof (DateTimeOffset)), "#12"); // has no TypeConverter (undocumented behavior), TypeCode.Object -> expected
+                       Assert.IsNull (ValueSerializer.GetSerializerFor (typeof (MyExtension)), "#13");
+                       Assert.IsNotNull (ValueSerializer.GetSerializerFor (typeof (MyExtension4)), "#14"); // has TypeConverter.
+               }
+
                [Test]
                public void DefaultImplementation ()
                {
@@ -129,10 +149,23 @@ namespace MonoTests.System.Windows.Markup
                                } catch (NotSupportedException) {
                                }
                        }
+                       
+                       Assert.AreEqual (typeof (NotSupportedException), v.CallGetConvertFromException (null).GetType (), "#1");
+                       Assert.AreEqual (typeof (NotSupportedException), v.CallGetConvertToException (null, typeof (int)).GetType (), "#2");
+                       Assert.IsFalse (v.TypeReferences (null, null).GetEnumerator ().MoveNext (), "#3");
                }
 
                class MyValueSerializer : ValueSerializer
                {
+                       public Exception CallGetConvertFromException (object value)
+                       {
+                               return GetConvertFromException (value);
+                       }
+
+                       public Exception CallGetConvertToException (object value, Type destinationType)
+                       {
+                               return GetConvertToException (value, destinationType);
+                       }
                }
        }
 }
index bffd20eb37d4703d2e2837514272ede203d76e52..95642d2bc4439d212d08e7b061dddfa2b5c4c6e9 100644 (file)
@@ -41,13 +41,13 @@ namespace MonoTests.System.Xaml.Schema
                XamlSchemaContext sctx = new XamlSchemaContext (null, null);
 
                [Test]
-               [Ignore ("It should return True for XamlType")]
                public void CanConvertFrom ()
                {
                        Assert.IsFalse (c.CanConvertFrom (null, typeof (XamlType)), "#1");
                        Assert.IsTrue (c.CanConvertFrom (null, typeof (string)), "#2");
                        Assert.IsFalse (c.CanConvertFrom (null, typeof (int)), "#3");
                        Assert.IsFalse (c.CanConvertFrom (null, typeof (object)), "#4");
+                       Assert.IsFalse (c.CanConvertFrom (new DummyValueSerializerContext (), typeof (XamlType)), "#5");
                }
 
                [Test]
@@ -57,6 +57,7 @@ namespace MonoTests.System.Xaml.Schema
                        Assert.IsTrue (c.CanConvertTo (null, typeof (string)), "#2");
                        Assert.IsFalse (c.CanConvertTo (null, typeof (int)), "#3");
                        Assert.IsFalse (c.CanConvertTo (null, typeof (object)), "#4");
+                       Assert.IsFalse (c.CanConvertTo (new DummyValueSerializerContext (), typeof (XamlType)), "#5");
                }
 
                // ConvertFrom() is not supported in either way.
@@ -82,6 +83,13 @@ namespace MonoTests.System.Xaml.Schema
                        Assert.AreEqual ("", c.ConvertTo (null, null, XamlLanguage.String, typeof (XamlType)), "#1");
                }
 
+               [Test]
+               [ExpectedException (typeof (NotSupportedException))]
+               public void ConvertXamlTypeToXamlType2 ()
+               {
+                       Assert.AreEqual ("", c.ConvertTo (new DummyValueSerializerContext (), null, XamlLanguage.String, typeof (XamlType)), "#1");
+               }
+
                [Test]
                [ExpectedException (typeof (NotSupportedException))]
                public void ConvertXamlTypeToType ()
@@ -109,5 +117,12 @@ namespace MonoTests.System.Xaml.Schema
                {
                        Assert.AreEqual ("5", c.ConvertTo (null, null, 5, typeof (string)), "#1");
                }
+
+               [Test]
+               [ExpectedException (typeof (NotSupportedException))]
+               public void ConvertStringToXamlType ()
+               {
+                       Assert.AreEqual ("", c.ConvertTo (new DummyValueSerializerContext (), null, "System.String", typeof (XamlType)), "#1");
+               }
        }
 }
\ No newline at end of file
diff --git a/mcs/class/System.Xaml/Test/System.Xaml/DummyValueSerializerContext.cs b/mcs/class/System.Xaml/Test/System.Xaml/DummyValueSerializerContext.cs
new file mode 100644 (file)
index 0000000..a555fb4
--- /dev/null
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2010 Novell Inc. http://novell.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Windows.Markup;
+using System.Xaml;
+using System.Xaml.Schema;
+using System.Xml;
+
+namespace MonoTests.System.Xaml
+{
+       public class DummyValueSerializerContext : IValueSerializerContext
+       {
+               public DummyValueSerializerContext ()
+               {
+               }
+
+               public object GetService (Type serviceType)
+               {
+                       throw new NotImplementedException ();
+               }
+               public IContainer Container {
+                       get { throw new NotImplementedException (); }
+               }
+               public object Instance {
+                       get { throw new NotImplementedException (); }
+               }
+               public PropertyDescriptor PropertyDescriptor {
+                       get { throw new NotImplementedException (); }
+               }
+               public void OnComponentChanged ()
+               {
+                       throw new NotImplementedException ();
+               }
+               public bool OnComponentChanging ()
+               {
+                       throw new NotImplementedException ();
+               }
+               public ValueSerializer GetValueSerializerFor (PropertyDescriptor descriptor)
+               {
+                       throw new NotImplementedException ();
+               }
+               public ValueSerializer GetValueSerializerFor (Type type)
+               {
+                       throw new NotImplementedException ();
+               }
+       }
+}