From b0ffa90c3bd221d69db5976c69e18142ec9458dc Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 7 Oct 2010 22:43:10 +0900 Subject: [PATCH] Significant XamlObjectWriter rewrite for solid state transition. And now it supports Array(Extension) and other MarkupExtension types. --- .../System.Windows.Markup/ArrayExtension.cs | 1 + .../System.Windows.Markup/Reference.cs | 9 +- .../System.Windows.Markup/TypeExtension.cs | 1 + .../TypeExtensionConverter.cs | 9 +- .../System.Xaml.Schema/XamlTypeInvoker.cs | 7 +- .../System.Xaml/XamlObjectWriter.cs | 264 ++++++++++++------ .../System.Xaml/System.Xaml_test.dll.sources | 2 + .../System.Windows.Markup/ReferenceTest.cs | 145 ++++++++++ .../TypeExtensionConverterTest.cs | 128 +++++++++ .../System.Xaml.Schema/XamlTypeInvokerTest.cs | 134 +++++++++ .../Test/System.Xaml/XamlLanguageTest.cs | 2 + .../Test/System.Xaml/XamlObjectWriterTest.cs | 7 + .../Test/System.Xaml/XamlTypeTest.cs | 3 +- .../Test/System.Xaml/XamlXmlReaderTest.cs | 4 +- 14 files changed, 627 insertions(+), 89 deletions(-) create mode 100644 mcs/class/System.Xaml/Test/System.Windows.Markup/ReferenceTest.cs create mode 100644 mcs/class/System.Xaml/Test/System.Windows.Markup/TypeExtensionConverterTest.cs diff --git a/mcs/class/System.Xaml/System.Windows.Markup/ArrayExtension.cs b/mcs/class/System.Xaml/System.Windows.Markup/ArrayExtension.cs index 7b1a929cb91..27b192540a8 100755 --- a/mcs/class/System.Xaml/System.Windows.Markup/ArrayExtension.cs +++ b/mcs/class/System.Xaml/System.Windows.Markup/ArrayExtension.cs @@ -58,6 +58,7 @@ namespace System.Windows.Markup Items = new List (); } + [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] public IList Items { get; private set; } [ConstructorArgument ("arrayType")] diff --git a/mcs/class/System.Xaml/System.Windows.Markup/Reference.cs b/mcs/class/System.Xaml/System.Windows.Markup/Reference.cs index 6d3429e8166..6913ed06dc6 100755 --- a/mcs/class/System.Xaml/System.Windows.Markup/Reference.cs +++ b/mcs/class/System.Xaml/System.Windows.Markup/Reference.cs @@ -51,10 +51,13 @@ namespace System.Windows.Markup throw new ArgumentNullException ("serviceProvider"); if (Name == null) throw new InvalidOperationException ("Name property is not set"); - var r = ((object) serviceProvider) as IXamlNameResolver; + var r = serviceProvider.GetService (typeof (IXamlNameResolver)) as IXamlNameResolver; if (r == null) - throw new ArgumentException ("serviceProvider does not implement IXamlNameResolver"); - return r.Resolve (Name); + throw new InvalidOperationException ("serviceProvider does not implement IXamlNameResolver"); + var ret = r.Resolve (Name); + if (ret == null) + ret = r.GetFixupToken (new string [] {Name}, true); + return ret; } } } diff --git a/mcs/class/System.Xaml/System.Windows.Markup/TypeExtension.cs b/mcs/class/System.Xaml/System.Windows.Markup/TypeExtension.cs index 83c13d3caa7..42da7a13783 100755 --- a/mcs/class/System.Xaml/System.Windows.Markup/TypeExtension.cs +++ b/mcs/class/System.Xaml/System.Windows.Markup/TypeExtension.cs @@ -54,6 +54,7 @@ namespace System.Windows.Markup [ConstructorArgument ("type")] [DefaultValue (null)] public Type Type { get; set; } + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public string TypeName { get; set; } public override object ProvideValue (IServiceProvider serviceProvider) diff --git a/mcs/class/System.Xaml/System.Windows.Markup/TypeExtensionConverter.cs b/mcs/class/System.Xaml/System.Windows.Markup/TypeExtensionConverter.cs index de4e357e52c..7558a047671 100644 --- a/mcs/class/System.Xaml/System.Windows.Markup/TypeExtensionConverter.cs +++ b/mcs/class/System.Xaml/System.Windows.Markup/TypeExtensionConverter.cs @@ -34,7 +34,12 @@ namespace System.Windows.Markup { public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) { - return false; + // unlike implied at http://msdn.microsoft.com/en-us/library/ee621338.aspx , it does not support IXamlTypeResolver. + //if (sourceType == typeof (string) && context != null) { + // var xtr = context.GetService (typeof (IXamlTypeResolver)) as IXamlTypeResolver; + // return xtr != null; + //} + return base.CanConvertFrom (context, sourceType); } public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) @@ -44,7 +49,7 @@ namespace System.Windows.Markup public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) { - throw new NotSupportedException (String.Format ("Conversion from type {0} is not supported", value != null ? value.GetType () : null)); + return base.ConvertFrom (context, culture, value); } public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) diff --git a/mcs/class/System.Xaml/System.Xaml.Schema/XamlTypeInvoker.cs b/mcs/class/System.Xaml/System.Xaml.Schema/XamlTypeInvoker.cs index 09f85b68ab6..afb2e8fc8ca 100644 --- a/mcs/class/System.Xaml/System.Xaml.Schema/XamlTypeInvoker.cs +++ b/mcs/class/System.Xaml/System.Xaml.Schema/XamlTypeInvoker.cs @@ -50,7 +50,7 @@ namespace System.Xaml.Schema void ThrowIfUnknown () { if (type.UnderlyingType == null) - throw new InvalidOperationException (String.Format ("Current operation is valid only when the underlying type on a XamlType is known, but it is unknown for '{0}'", type)); + throw new NotSupportedException (String.Format ("Current operation is valid only when the underlying type on a XamlType is known, but it is unknown for '{0}'", type)); } public EventHandler SetMarkupExtensionHandler { @@ -67,6 +67,11 @@ namespace System.Xaml.Schema throw new ArgumentNullException ("instance"); var t = instance.GetType (); + if (type.UnderlyingType != null) { + if (!type.SchemaContext.GetXamlType (t).IsCollection) // not sure why this check is done only when UnderlyingType exists... + throw new NotSupportedException (String.Format ("Non-collection type '{0}' does not support this operation", t)); + } + MethodInfo mi; if (t.IsGenericType) mi = instance.GetType ().GetMethod ("Add", t.GetGenericArguments ()); diff --git a/mcs/class/System.Xaml/System.Xaml/XamlObjectWriter.cs b/mcs/class/System.Xaml/System.Xaml/XamlObjectWriter.cs index 180b256825a..708f0c9734f 100644 --- a/mcs/class/System.Xaml/System.Xaml/XamlObjectWriter.cs +++ b/mcs/class/System.Xaml/System.Xaml/XamlObjectWriter.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.Windows.Markup; +using System.Xaml.Schema; namespace System.Xaml { @@ -39,6 +40,8 @@ namespace System.Xaml throw new ArgumentNullException ("schemaContext"); this.sctx = schemaContext; this.settings = settings ?? new XamlObjectWriterSettings (); + + service_provider = new XamlObjectWriterServiceProvider (this); } XamlSchemaContext sctx; @@ -47,17 +50,24 @@ namespace System.Xaml XamlWriterStateManager manager = new XamlWriterStateManager (false); object result; int line = -1, column = -1; - Stack objects = new Stack (); - Stack types = new Stack (); Stack members = new Stack (); - List arguments = new List (); // FIXME: so far it has no contents. - string factory_method; - bool object_instantiated; - Stack> contents_stack = new Stack> (); - List objects_from_getter = new List (); - Stack> written_properties_stack = new Stack> (); - XamlNameResolver name_resolver = new XamlNameResolver (); + List namespaces = new List (); + IServiceProvider service_provider; + Stack object_states = new Stack (); + + class ObjectState + { + public XamlType Type; + public object Value; + public List Contents = new List (); + public List WrittenProperties = new List (); + public bool IsInstantiated; + public bool IsGetObject; + + public string FactoryMethod; + public List Arguments = new List (); + } public virtual object Result { get { return result; } @@ -85,9 +95,9 @@ namespace System.Xaml if (!disposing) return; - while (types.Count > 0) { + while (object_states.Count > 0) { WriteEndObject (); - if (types.Count > 0) + if (object_states.Count > 0) WriteEndMember (); } } @@ -126,7 +136,7 @@ namespace System.Xaml if (member.IsDirective) return; if (!OnSetValue (this, member, value)) - member.Invoker.SetValue (objects.Peek (), value); + member.Invoker.SetValue (object_states.Peek ().Value, value); } public void SetLineInfo (int lineNumber, int linePosition) @@ -141,39 +151,53 @@ namespace System.Xaml manager.EndMember (); var xm = members.Pop (); - var xt = xm.Type; - var contents = contents_stack.Peek (); + var state = object_states.Peek (); + var xt = state.Type; + var contents = state.Contents; if (xm == XamlLanguage.Arguments) { - InitializeObjectWithArguments (contents.ToArray ()); + throw new NotImplementedException (); } else if (xm == XamlLanguage.Initialization) { // ... and no need to do anything. The object value to pop *is* the return value. - } else if (xt.IsArray) { + } else if (xm.Type.IsArray) { throw new NotImplementedException (); - } else if (xt.IsCollection) { - var obj = objects.Peek (); + } else if (xm == XamlLanguage.Items) { + var coll = state.Value; foreach (var content in contents) - xt.Invoker.AddToCollection (obj, content); - } else if (xt.IsDictionary) { + xm.Type.Invoker.AddToCollection (coll, content); + } else if (xm.Type.IsDictionary) { throw new NotImplementedException (); } else { if (contents.Count > 1) - throw new XamlDuplicateMemberException (String.Format ("Value for {0} is assigned more than once", xm.Name)); + throw new XamlDuplicateMemberException (String.Format ("Property '{0}' is already set to this '{1}' object", xm, state.Type)); if (contents.Count == 1) { - var value = GetCorrectlyTypedValue (xm.Type, contents [0]); - if (!objects_from_getter.Remove (value)) + var value = contents [0]; + if (!xm.Type.IsCollection || !xm.IsReadOnly) // exclude read-only object. SetValue (xm, value); } } contents.Clear (); - written_properties_stack.Peek ().Add (xm); + + if (object_states.Count > 0) + object_states.Peek ().WrittenProperties.Add (xm); + //written_properties_stack.Peek ().Add (xm); } object GetCorrectlyTypedValue (XamlType xt, object value) { + // FIXME: this could be generalized by some means, but I cannot find any. + if (xt.UnderlyingType == typeof (Type)) + xt = XamlLanguage.Type; + if (xt == XamlLanguage.Type && value is string) + value = new TypeExtension ((string) value); + + if (value is MarkupExtension) + value = ((MarkupExtension) value).ProvideValue (service_provider); + if (IsAllowedType (xt, value)) return value; + if (xt.TypeConverter != null && value != null) { var tc = xt.TypeConverter.ConverterInstance; if (tc != null && tc.CanConvertFrom (value.GetType ())) @@ -181,30 +205,35 @@ namespace System.Xaml if (IsAllowedType (xt, value)) return value; } - throw new XamlObjectWriterException (String.Format ("Value is not of type {0}", xt)); + + throw new XamlObjectWriterException (String.Format ("Value '{1}' (of type {2}) is not of or convertible to type {0}", xt, value, value != null ? (object) value.GetType () : "(null)")); } bool IsAllowedType (XamlType xt, object value) { - return xt == null || xt.UnderlyingType == null || xt.UnderlyingType.IsInstanceOfType (value); + return xt == null || + xt.UnderlyingType == null || + xt.UnderlyingType.IsInstanceOfType (value) || + value == null && xt == XamlLanguage.Null || + xt.IsMarkupExtension && IsAllowedType (xt.MarkupExtensionReturnType, value); } public override void WriteEndObject () { - manager.EndObject (types.Count > 0); - - InitializeObjectIfRequired (null); // this is required for such case that there was no StartMember call. - - types.Pop (); - contents_stack.Pop (); - written_properties_stack.Pop (); - var obj = objects.Pop (); - if (members.Count > 0) - contents_stack.Peek ().Add (obj); - if (objects.Count == 0) { - var ext = obj as MarkupExtension; - result = ext != null ? ext.ProvideValue (name_resolver) : obj; + manager.EndObject (object_states.Count > 0); + + InitializeObjectIfRequired (false); // this is required for such case that there was no StartMember call. + + var state = object_states.Pop (); + var xt = state.Type; + var obj = GetCorrectlyTypedValue (state.Type, state.Value); + if (members.Count > 0) { + var pstate = object_states.Peek (); + pstate.Contents.Add (obj); + pstate.WrittenProperties.Add (members.Peek ()); } + if (object_states.Count == 0) + result = obj; } public override void WriteGetObject () @@ -212,18 +241,16 @@ namespace System.Xaml manager.GetObject (); var xm = members.Peek (); - // see GetObjectOnNonNullString() test + // see GetObjectOnNonNullString() test. Below is invalid. //if (!xm.Type.IsCollection) // throw new XamlObjectWriterException (String.Format ("WriteGetObject method can be invoked only when current member '{0}' is of collection type", xm.Name)); - var obj = xm.Invoker.GetValue (objects.Peek ()); - if (obj == null) + var instance = xm.Invoker.GetValue (object_states.Peek ().Value); + if (instance == null) throw new XamlObjectWriterException (String.Format ("The value for '{0}' property is null", xm.Name)); - types.Push (SchemaContext.GetXamlType (obj.GetType ())); - contents_stack.Push (new List ()); - ObjectInitialized (obj); - objects_from_getter.Add (obj); + var state = new ObjectState () {Type = SchemaContext.GetXamlType (instance.GetType ()), Value = instance, IsInstantiated = true, IsGetObject = true}; + object_states.Push (state); } public override void WriteNamespace (NamespaceDeclaration namespaceDeclaration) @@ -233,7 +260,7 @@ namespace System.Xaml manager.Namespace (); - // FIXME: find out what to do. + namespaces.Add (namespaceDeclaration); } public override void WriteStartMember (XamlMember property) @@ -243,34 +270,34 @@ namespace System.Xaml manager.StartMember (); - var wpl = written_properties_stack.Peek (); - if (wpl.Contains (property)) - throw new XamlDuplicateMemberException (String.Format ("Property '{0}' is already set to this '{1}' object", property.Name, types.Peek ().Name)); - wpl.Add (property); + var wpl = object_states.Peek ().WrittenProperties; + // FIXME: enable this. Duplicate property check should + // be differentiate from duplicate contents (both result + // in XamlDuplicateMemberException though). + // Now it is done at WriteStartObject/WriteValue, but + // it is simply wrong. +// if (wpl.Contains (property)) +// throw new XamlDuplicateMemberException (String.Format ("Property '{0}' is already set to this '{1}' object", property, object_states.Peek ().Type)); +// wpl.Add (property); members.Push (property); } - void InitializeObjectWithArguments (object [] args) - { - var obj = types.Peek ().Invoker.CreateInstance (args); - ObjectInitialized (obj); - } - - void InitializeObjectIfRequired (XamlMember property) + void InitializeObjectIfRequired (bool isStart) { - if (object_instantiated) + var state = object_states.Peek (); + if (state.IsInstantiated) return; // FIXME: "The default techniques in absence of a factory method are to attempt to find a default constructor, then attempt to find an identified type converter on type, member, or destination type." // http://msdn.microsoft.com/en-us/library/system.xaml.xamllanguage.factorymethod%28VS.100%29.aspx object obj; - var args = arguments.ToArray (); - if (factory_method != null) // FIXME: it must be verified with tests. - obj = types.Peek ().UnderlyingType.GetMethod (factory_method).Invoke (null, args); + if (state.FactoryMethod != null) // FIXME: it must be implemented and verified with tests. + throw new NotImplementedException (); else - obj = types.Peek ().Invoker.CreateInstance (args); - ObjectInitialized (obj); + obj = state.Type.Invoker.CreateInstance (null); + state.Value = obj; + state.IsInstantiated = true; } public override void WriteStartObject (XamlType xamlType) @@ -280,15 +307,20 @@ namespace System.Xaml manager.StartObject (); - types.Push (xamlType); - contents_stack.Push (new List ()); - - object_instantiated = false; + var xm = members.Count > 0 ? members.Peek () : null; + var pstate = xm != null ? object_states.Peek () : null; + var wpl = xm != null && xm != XamlLanguage.Items ? pstate.WrittenProperties : null; + if (wpl != null && wpl.Contains (xm)) + throw new XamlDuplicateMemberException (String.Format ("Property '{0}' is already set to this '{1}' object", xm, pstate.Type)); - written_properties_stack.Push (new List ()); + var cstate = new ObjectState () {Type = xamlType, IsInstantiated = false}; + object_states.Push (cstate); - if (!xamlType.IsContentValue ()) // FIXME: there could be more conditions. - InitializeObjectIfRequired (null); + if (!xamlType.IsContentValue ()) // FIXME: there could be more conditions e.g. the type requires Arguments. + InitializeObjectIfRequired (true); + + if (wpl != null) // note that this adds to the *owner* object's properties. + wpl.Add (xm); } public override void WriteValue (object value) @@ -296,21 +328,93 @@ namespace System.Xaml manager.Value (); var xm = members.Peek (); + var state = object_states.Peek (); - if (xm == XamlLanguage.Initialization) - ObjectInitialized (GetCorrectlyTypedValue (types.Peek (), value)); + var wpl = xm != null && xm != XamlLanguage.Items ? state.WrittenProperties : null; + if (wpl != null && wpl.Contains (xm)) + throw new XamlDuplicateMemberException (String.Format ("Property '{0}' is already set to this '{1}' object", xm, state.Type)); + + if (xm == XamlLanguage.Initialization || + xm == state.Type.ContentProperty) { + value = GetCorrectlyTypedValue (state.Type, value); + state.Value = value; + state.IsInstantiated = true; + } else if (xm == XamlLanguage.FactoryMethod) - factory_method = (string) value; + state.FactoryMethod = (string) value; +// else if (xm.Type.IsCollection) + else if (xm == XamlLanguage.Items) // FIXME: am not sure which is good yet. + state.Contents.Add (GetCorrectlyTypedValue (xm.Type.ItemType, value)); else - contents_stack.Peek ().Add (value); + state.Contents.Add (GetCorrectlyTypedValue (xm.Type, value)); + if (wpl != null) + wpl.Add (xm); } - void ObjectInitialized (object obj) + class XamlObjectWriterServiceProvider : IServiceProvider { - objects.Push (obj); - object_instantiated = true; - arguments.Clear (); - factory_method = null; + XamlNameResolver name_resolver = new XamlNameResolver (); + XamlTypeResolver type_resolver; + NamespaceResolver namespace_resolver; + + public XamlObjectWriterServiceProvider (XamlObjectWriter writer) + { + namespace_resolver = new NamespaceResolver (writer.namespaces); + type_resolver = new XamlTypeResolver (namespace_resolver, writer.SchemaContext); + } + + public object GetService (Type serviceType) + { + if (serviceType == typeof (IXamlNamespaceResolver)) + return namespace_resolver; + if (serviceType == typeof (IXamlNameResolver)) + return name_resolver; + if (serviceType == typeof (IXamlTypeResolver)) + return type_resolver; + return null; + } + } + + internal class XamlTypeResolver : IXamlTypeResolver + { + NamespaceResolver ns_resolver; + XamlSchemaContext schema_context; + + public XamlTypeResolver (NamespaceResolver namespaceResolver, XamlSchemaContext schemaContext) + { + ns_resolver = namespaceResolver; + schema_context = schemaContext; + } + + public Type Resolve (string typeName) + { + var tn = XamlTypeName.Parse (typeName, ns_resolver); + var xt = schema_context.GetXamlType (tn); + return xt != null ? xt.UnderlyingType : null; + } + } + + internal class NamespaceResolver : IXamlNamespaceResolver + { + public NamespaceResolver (List source) + { + this.source = source; + } + + List source; + + public string GetNamespace (string prefix) + { + foreach (var nsd in source) + if (nsd.Prefix == prefix) + return nsd.Namespace; + return null; + } + + public IEnumerable GetNamespacePrefixes () + { + return source; + } } } } diff --git a/mcs/class/System.Xaml/System.Xaml_test.dll.sources b/mcs/class/System.Xaml/System.Xaml_test.dll.sources index 8a65b0d22ef..50a21d889f8 100644 --- a/mcs/class/System.Xaml/System.Xaml_test.dll.sources +++ b/mcs/class/System.Xaml/System.Xaml_test.dll.sources @@ -1,5 +1,7 @@ System.Windows.Markup/ArrayExtensionTest.cs +System.Windows.Markup/ReferenceTest.cs System.Windows.Markup/StaticExtensionTest.cs +System.Windows.Markup/TypeExtensionConverterTest.cs System.Windows.Markup/TypeExtensionTest.cs System.Windows.Markup/ValueSerializerTest.cs System.Windows.Markup/XDataTest.cs diff --git a/mcs/class/System.Xaml/Test/System.Windows.Markup/ReferenceTest.cs b/mcs/class/System.Xaml/Test/System.Windows.Markup/ReferenceTest.cs new file mode 100644 index 00000000000..03403b711e9 --- /dev/null +++ b/mcs/class/System.Xaml/Test/System.Windows.Markup/ReferenceTest.cs @@ -0,0 +1,145 @@ +// +// 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Windows.Markup; +using System.Xaml; +using System.Xaml.Schema; +using NUnit.Framework; + +using Category = NUnit.Framework.CategoryAttribute; + +namespace MonoTests.System.Windows.Markup +{ + [TestFixture] + public class ReferenceTest + { + [Test] + public void ConstructorNullName () + { + new Reference ((string) null); // it is somehow allowed + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void ProvideValueWithoutTypeOrName () + { + new Reference ().ProvideValue (null); + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void ProvideValueWithNameWithoutResolver () + { + var x = new Reference ("X"); + x.ProvideValue (null); // serviceProvider is required. + } + + [Test] + [ExpectedException (typeof (InvalidOperationException))] + public void ProvideValueWithNameWithProviderNoResolver () + { + var x = new Reference ("X"); + x.ProvideValue (new NameServiceProvider (false, false)); + } + + [Test] + public void ProvideValueWithNameWithProviderResolveFail () + { + var x = new Reference ("X"); + var r = new NameServiceProvider (true, false); + Assert.AreEqual ("BAR", x.ProvideValue (r), "#1"); + } + + [Test] + public void ProvideValueWithNameWithProviderResolveSuccess () + { + var x = new Reference ("X"); + var r = new NameServiceProvider (true, true); + Assert.AreEqual ("FOO", x.ProvideValue (r), "#1"); + } + + class NameServiceProvider : IServiceProvider + { + Resolver resolver; + + public NameServiceProvider (bool worksFine, bool resolvesFine) + { + resolver = worksFine ? new Resolver (resolvesFine) : null; + } + + public object GetService (Type serviceType) + { + Assert.AreEqual (typeof (IXamlNameResolver), serviceType, "TypeToResolve"); + return resolver; + } + } + + class Resolver : IXamlNameResolver + { + bool resolves; + + public Resolver (bool resolvesFine) + { + resolves = resolvesFine; + } + + public IEnumerable> GetAllNamesAndValuesInScope () + { + throw new Exception (); + } + + public object GetFixupToken (IEnumerable names) + { + throw new NotImplementedException (); + } + + public object GetFixupToken (IEnumerable names, bool canAssignDirectly) + { + Assert.IsTrue (canAssignDirectly, "canAssignDirectly"); + Assert.AreEqual (1, names.Count (), "Count"); + return "BAR"; + } + + public bool IsFixupTokenAvailable { + get { throw new NotImplementedException (); } + } + + public event EventHandler OnNameScopeInitializationComplete; + + public object Resolve (string name) + { + return resolves ? "FOO" : null; + } + + public object Resolve (string name, out bool isFullyInitialized) + { + throw new NotImplementedException (); + } + } + } +} diff --git a/mcs/class/System.Xaml/Test/System.Windows.Markup/TypeExtensionConverterTest.cs b/mcs/class/System.Xaml/Test/System.Windows.Markup/TypeExtensionConverterTest.cs new file mode 100644 index 00000000000..f7d7a13439f --- /dev/null +++ b/mcs/class/System.Xaml/Test/System.Windows.Markup/TypeExtensionConverterTest.cs @@ -0,0 +1,128 @@ +// +// 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Reflection; +using System.Windows.Markup; +using System.Xaml; +using System.Xaml.Schema; +using NUnit.Framework; + +using Category = NUnit.Framework.CategoryAttribute; + +namespace MonoTests.System.Windows.Markup +{ + [TestFixture] + public class TypeExtensionConverterTest + { + class XamlTypeResolver : IXamlTypeResolver + { + public Type Resolve (string qualifiedTypeName) + { + throw new NotImplementedException (); + } + } + + class TypeDescriptorContext : ITypeDescriptorContext + { + public object Service { get; set; } + + public object GetService (Type serviceType) + { + return Service != null && serviceType.IsAssignableFrom (Service.GetType ()) ? Service : null; + } + + public void OnComponentChanged () + { + } + + public bool OnComponentChanging () + { + return true; + } + + public IContainer Container { get; set; } + + public object Instance { get; set; } + + public PropertyDescriptor PropertyDescriptor { get; set; } + } + + [Test] + public void CanConvertFrom () + { + var tc = XamlLanguage.Type.TypeConverter.ConverterInstance; + Assert.IsFalse (tc.CanConvertFrom (null, typeof (string)), "#1"); + Assert.IsFalse (tc.CanConvertFrom (null, typeof (Type)), "#2"); + Assert.IsFalse (tc.CanConvertFrom (null, typeof (Type)), "#3"); + Assert.IsTrue (tc.CanConvertFrom (null, typeof (InstanceDescriptor)), "#4"); + + var idc = new TypeDescriptorContext () {Instance = "x:Int32", Service = new XamlTypeResolver ()}; // gives no difference ... + Assert.IsFalse (tc.CanConvertFrom (idc, typeof (string)), "#5"); + Assert.IsFalse (tc.CanConvertFrom (idc, typeof (Type)), "#6"); + Assert.IsFalse (tc.CanConvertFrom (idc, typeof (TypeExtension)), "#7"); + } + + [Test] + public void CanConvertTo () + { + var tc = XamlLanguage.Type.TypeConverter.ConverterInstance; + Assert.IsTrue (tc.CanConvertTo (null, typeof (string)), "#1"); + Assert.IsFalse (tc.CanConvertTo (null, typeof (Type)), "#2"); + Assert.IsFalse (tc.CanConvertTo (null, typeof (TypeExtension)), "#3"); + + var idc = new TypeDescriptorContext () {Instance = "x:Int32", Service = new XamlTypeResolver ()}; // gives no differences... + Assert.IsTrue (tc.CanConvertTo (idc, typeof (string)), "#5"); + Assert.IsFalse (tc.CanConvertTo (idc, typeof (Type)), "#6"); + Assert.IsFalse (tc.CanConvertTo (idc, typeof (TypeExtension)), "#7"); + } + + [Test] + public void ConvertTo () + { + var tc = XamlLanguage.Type.TypeConverter.ConverterInstance; + Assert.AreEqual ("x:Int32", tc.ConvertTo (null, null, "x:Int32", typeof (string)), "#1"); + Assert.AreEqual ("System.Int32", tc.ConvertTo (null, null, typeof (int), typeof (string)), "#2"); + Assert.AreEqual ("System.Type", tc.ConvertTo (null, null, typeof (Type), typeof (string)), "#3"); + } + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void ConvertToFail () + { + var tc = XamlLanguage.Type.TypeConverter.ConverterInstance; + tc.ConvertTo (null, null, typeof (int), typeof (Type)); + } + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void ConvertToFail2 () + { + var tc = XamlLanguage.Type.TypeConverter.ConverterInstance; + tc.ConvertTo (null, null, "x:Int32", typeof (TypeExtension)); + } + } +} diff --git a/mcs/class/System.Xaml/Test/System.Xaml.Schema/XamlTypeInvokerTest.cs b/mcs/class/System.Xaml/Test/System.Xaml.Schema/XamlTypeInvokerTest.cs index d8c0c4051b2..4184e0f1a5a 100644 --- a/mcs/class/System.Xaml/Test/System.Xaml.Schema/XamlTypeInvokerTest.cs +++ b/mcs/class/System.Xaml/Test/System.Xaml.Schema/XamlTypeInvokerTest.cs @@ -58,6 +58,8 @@ namespace MonoTests.System.Xaml.Schema { } + // SetMarkupExtensionHandler + [Test] [ExpectedException (typeof (ArgumentException))] public void SetHandleMarkupExtensionInvalid () @@ -116,6 +118,8 @@ namespace MonoTests.System.Xaml.Schema Assert.IsNotNull (i.SetMarkupExtensionHandler, "#1"); } + // SetTypeConverterHandler + [XamlSetTypeConverter ("HandleTypeConverter")] public class TestClassTypeConverter1 { @@ -178,5 +182,135 @@ namespace MonoTests.System.Xaml.Schema var i = new XamlTypeInvoker (new XamlType (typeof (TestClassTypeConverter4), sctx)); Assert.IsNotNull (i.SetTypeConverterHandler, "#1"); } + + // AddToCollection + + [Test] + public void AddToCollectionNoUnderlyingType () + { + var i = new XamlTypeInvoker (new XamlType ("urn:foo", "FooType", null, sctx)); + i.AddToCollection (new List (), 5); // ... passes. + } + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void AddToCollectionArrayExtension () + { + var i = XamlLanguage.Array.Invoker; + var ax = new ArrayExtension (); + i.AddToCollection (ax, 5); + } + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void AddToCollectionArrayInstance () + { + var i = new XamlTypeInvoker (new XamlType (typeof (int []), sctx)); + var ax = new ArrayExtension (); + i.AddToCollection (ax, 5); + } + + [Test] + public void AddToCollectionList_ObjectTypeMismatch () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + try { + i.AddToCollection (new ArrayExtension (), 5); + Assert.Fail ("not supported operation."); + } catch (NotSupportedException) { + } catch (TargetException) { + // .NET throws this, but the difference should not really matter. + } + } + + [Test] + public void AddToCollectionList_ObjectTypeMismatch2 () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + i.AddToCollection (new List (), 5); // it is allowed. + } + + [Test] + public void AddToCollectionList_ObjectTypeMismatch3 () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + i.AddToCollection (new List (), 5); // it is allowed too. + } + + [Test] + public void AddToCollectionList_ObjectTypeMismatch4 () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + i.AddToCollection (new List (), TimeSpan.Zero); // it is allowed too. + } + + [Test] + public void AddToCollectionList_NonCollectionType () + { + // so, the source collection type is not checked at all. + var i = new XamlTypeInvoker (new XamlType (typeof (Uri), sctx)); + i.AddToCollection (new List (), TimeSpan.Zero); // it is allowed too. + } + + [Test] + public void AddToCollectionList () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + var l = new List (); + i.AddToCollection (l, 5); + i.AddToCollection (l, 3); + i.AddToCollection (l, -12); + Assert.AreEqual (3, l.Count, "#1"); + Assert.AreEqual (-12, l [2], "#2"); + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void AddToCollectionTypeMismatch () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + var l = new List (); + i.AddToCollection (l, "5"); + } + + // CreateInstance + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void CreateInstanceNoUnderlyingType () + { + var i = new XamlTypeInvoker (new XamlType ("urn:foo", "FooType", null, sctx)); + i.CreateInstance (new object [0]); // unkown type is not supported + } + + [Test] + public void CreateInstanceArrayExtension () + { + var i = XamlLanguage.Array.Invoker; + i.CreateInstance (new object [0]); + } + + [Test] + [ExpectedException (typeof (MissingMethodException))] + public void CreateInstanceArray () + { + var i = new XamlTypeInvoker (new XamlType (typeof (int []), sctx)); + i.CreateInstance (new object [0]); // no default constructor. + } + + [Test] + [ExpectedException (typeof (MissingMethodException))] + public void CreateInstanceList_ArgumentMismatch () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + i.CreateInstance (new object [] {"foo"}); + } + + [Test] + public void CreateInstanceList () + { + var i = new XamlTypeInvoker (new XamlType (typeof (List), sctx)); + i.CreateInstance (new object [0]); + } } } \ No newline at end of file diff --git a/mcs/class/System.Xaml/Test/System.Xaml/XamlLanguageTest.cs b/mcs/class/System.Xaml/Test/System.Xaml/XamlLanguageTest.cs index 529e706a61f..76170aa03ae 100644 --- a/mcs/class/System.Xaml/Test/System.Xaml/XamlLanguageTest.cs +++ b/mcs/class/System.Xaml/Test/System.Xaml/XamlLanguageTest.cs @@ -445,6 +445,7 @@ namespace MonoTests.System.Xaml { var m = XamlLanguage.Type.GetMember ("Type"); TestMemberCommon (m, "Type", typeof (Type), typeof (TypeExtension), true); + Assert.AreNotEqual (XamlLanguage.Type, m.Type, "#1"); } // primitive types @@ -802,6 +803,7 @@ namespace MonoTests.System.Xaml Assert.IsNotNull (t.TypeConverter, "#25"); Assert.IsNotNull (t.MarkupExtensionReturnType, "#29"); Assert.AreEqual (extReturnType, t.MarkupExtensionReturnType.UnderlyingType, "#29-2"); + Assert.IsNull (t.Invoker.SetMarkupExtensionHandler, "#31"); // orly? } void TestMemberCommon (XamlMember m, string name, Type type, Type declType, bool hasSetter) diff --git a/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectWriterTest.cs b/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectWriterTest.cs index e1af489ef92..d7b53829704 100644 --- a/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectWriterTest.cs +++ b/mcs/class/System.Xaml/Test/System.Xaml/XamlObjectWriterTest.cs @@ -254,6 +254,7 @@ namespace MonoTests.System.Xaml } [Test] + [ExpectedException (typeof (XamlDuplicateMemberException))] public void ValueAfterObject2 () { var xw = new XamlObjectWriter (sctx, null); @@ -263,6 +264,8 @@ namespace MonoTests.System.Xaml xw.WriteEndObject (); // passes here, but should be rejected later. xw.WriteValue ("foo"); + + xw.WriteEndMember (); // Though this raises an error. } [Test] @@ -280,6 +283,7 @@ namespace MonoTests.System.Xaml [Test] [ExpectedException (typeof (XamlDuplicateMemberException))] + [Category ("NotWorking")] public void DuplicateAssignment2 () { var xw = new XamlObjectWriter (sctx, null); @@ -432,6 +436,7 @@ namespace MonoTests.System.Xaml } [Test] + [ExpectedException (typeof (XamlDuplicateMemberException))] // duplicate member assignment public void ObjectContainsObjectAndValue () { var xw = new XamlObjectWriter (sctx, null); @@ -440,6 +445,8 @@ namespace MonoTests.System.Xaml xw.WriteStartObject (xt3); xw.WriteEndObject (); xw.WriteValue ("foo"); // but this is allowed ... + + xw.WriteEndMember (); // Though this raises an error. } [Test] diff --git a/mcs/class/System.Xaml/Test/System.Xaml/XamlTypeTest.cs b/mcs/class/System.Xaml/Test/System.Xaml/XamlTypeTest.cs index 60ba8b3f6a3..cbf96911a4a 100644 --- a/mcs/class/System.Xaml/Test/System.Xaml/XamlTypeTest.cs +++ b/mcs/class/System.Xaml/Test/System.Xaml/XamlTypeTest.cs @@ -344,8 +344,7 @@ namespace MonoTests.System.Xaml Assert.IsFalse (t.IsAmbient, "#22"); Assert.IsNull (t.AllowedContentTypes, "#23"); Assert.IsNull (t.ContentWrappers, "#24"); - // FIXME: enable this when we fixed TypeConverter for Type. - //Assert.IsNotNull (t.TypeConverter, "#25"); // TypeTypeConverter + Assert.IsNotNull (t.TypeConverter, "#25"); // TypeTypeConverter Assert.IsNull (t.ValueSerializer, "#26"); Assert.IsNull (t.ContentProperty, "#27"); //Assert.IsNull (t.DeferringLoader, "#28"); diff --git a/mcs/class/System.Xaml/Test/System.Xaml/XamlXmlReaderTest.cs b/mcs/class/System.Xaml/Test/System.Xaml/XamlXmlReaderTest.cs index 91435a968c6..fa9d98661b7 100644 --- a/mcs/class/System.Xaml/Test/System.Xaml/XamlXmlReaderTest.cs +++ b/mcs/class/System.Xaml/Test/System.Xaml/XamlXmlReaderTest.cs @@ -115,7 +115,9 @@ namespace MonoTests.System.Xaml public void Read_ArrayInt32 () { ReadTest ("Array_Int32.xml"); - //LoadTest ("Array_Int32.xml"); + var ret = LoadTest ("Array_Int32.xml"); + Assert.AreEqual (5, ret.Length, "#1"); + Assert.AreEqual (2147483647, ret [4], "#2"); } [Test] -- GitLab