Implement MachineKey.Protect and MachineKey.Unprotect
[mono.git] / mcs / class / System.ComponentModel.Composition / Tests / ComponentModelUnitTest / System / ComponentModel / Composition / DynamicMetadata.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.ComponentModel;\r
7 using System.ComponentModel.Composition;\r
8 using System.Linq;\r
9 using System.Reflection;\r
10 using Microsoft.VisualStudio.TestTools.UnitTesting;\r
11 using System.ComponentModel.Composition.Hosting;\r
12 \r
13 namespace System.ComponentModel.Composition\r
14 {\r
15     [TestClass]\r
16     public class DynamicMetadata\r
17     {\r
18         [TestMethod]\r
19         public void SimpleAttachment()\r
20         {\r
21             MetadataStore.Container = new CompositionContainer();\r
22             DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");\r
23 \r
24             var notYetAttached = TypeDescriptor.GetConverter(val);\r
25             Assert.IsFalse(notYetAttached.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");\r
26 \r
27             MetadataStore.AddAttribute(\r
28                 typeof(DynamicMetadataTestClass),\r
29                 ( type, attributes) => \r
30                     Enumerable.Concat(\r
31                         attributes,\r
32                         new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }\r
33                     )\r
34             );\r
35             var attached = TypeDescriptor.GetConverter(val);\r
36             Assert.IsTrue(attached.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");\r
37         }\r
38 \r
39         [TestMethod]\r
40         public void LocalContainer()\r
41         {\r
42             var container1 = new CompositionContainer();\r
43             TypeDescriptorServices dat = new TypeDescriptorServices();\r
44             CompositionBatch batch = new CompositionBatch();\r
45             batch.AddPart(dat);\r
46             container1.Compose(batch);\r
47             MetadataStore.AddAttribute(\r
48                 typeof(DynamicMetadataTestClass),\r
49                 ( type, attributes) => \r
50                     Enumerable.Concat(\r
51                         attributes,\r
52                         new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }\r
53                     ),\r
54                 container1\r
55             );\r
56             DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");\r
57 \r
58             var notYetAttached = TypeDescriptor.GetConverter(val.GetType());\r
59             Assert.IsFalse(notYetAttached.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");\r
60 \r
61             var attached = dat.GetConverter(val.GetType());\r
62             Assert.IsTrue(attached.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");\r
63         }\r
64 \r
65         [TestMethod]\r
66         public void DualContainers()\r
67         {\r
68             var container1 = new CompositionContainer();\r
69             TypeDescriptorServices dat1 = new TypeDescriptorServices();\r
70             CompositionBatch batch = new CompositionBatch();\r
71             batch.AddPart(dat1);\r
72             container1.Compose(batch);\r
73             MetadataStore.AddAttribute(\r
74                 typeof(DynamicMetadataTestClass),\r
75                 ( type, attributes) => \r
76                     Enumerable.Concat(\r
77                         attributes,\r
78                         new Attribute[] { new TypeConverterAttribute(typeof(DynamicMetadataTestClassConverter)) }\r
79                     ),\r
80                 container1\r
81             );\r
82 \r
83 \r
84             var container2 = new CompositionContainer();\r
85             CompositionBatch batch2 = new CompositionBatch();\r
86             TypeDescriptorServices dat2 = new TypeDescriptorServices();\r
87             batch2.AddPart(dat2);\r
88             container2.Compose(batch2);\r
89 \r
90             DynamicMetadataTestClass val = DynamicMetadataTestClass.Get("42");\r
91 \r
92             var attached1 = dat1.GetConverter(val.GetType());\r
93             Assert.IsTrue(attached1.CanConvertFrom(typeof(string)), "The new type converter for DynamicMetadataTestClass should support round tripping");\r
94 \r
95             var attached2 = dat2.GetConverter(val.GetType());\r
96             Assert.IsFalse(attached2.CanConvertFrom(typeof(string)), "The default type converter for DynamicMetadataTestClass shouldn't support round tripping");\r
97         }\r
98 \r
99         [TestCleanup]\r
100         public void ResetContainer()\r
101         {\r
102             MetadataStore.Container = null;\r
103         }\r
104     }\r
105 \r
106 \r
107     [Export]\r
108     public class TypeDescriptorServices\r
109     {\r
110         Dictionary<Type, TypeDescriptionProvider> providers = new Dictionary<Type, TypeDescriptionProvider>();\r
111 \r
112         internal Dictionary<Type, TypeDescriptionProvider> Providers\r
113         {\r
114             get { return providers; }\r
115             set { providers = value; }\r
116         }\r
117 \r
118         public ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)\r
119         {\r
120             if (Providers.ContainsKey(objectType))\r
121             {\r
122                 return Providers[objectType].GetTypeDescriptor(objectType);\r
123             }\r
124             else\r
125             {\r
126                 return null;\r
127             }\r
128         }\r
129         public void AddProvider(TypeDescriptionProvider provider, Type type)\r
130         {\r
131             Providers[type] = provider;\r
132         }\r
133         public TypeConverter GetConverter(Type type)\r
134         {\r
135             var ictd = GetTypeDescriptor(type, null);\r
136             if (ictd != null)\r
137             {\r
138                 return ictd.GetConverter();\r
139             }\r
140             else\r
141             {\r
142                 return TypeDescriptor.GetConverter(type);\r
143             }\r
144         }\r
145     }\r
146 \r
147     public static class MetadataStore\r
148     {\r
149         public static CompositionContainer Container { get; set; }\r
150         static Dictionary<Type, TypeDescriptionProvider> registeredRedirect = new Dictionary<Type, TypeDescriptionProvider>();\r
151 \r
152         public static void AddAttribute(Type target, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)\r
153         {\r
154             AddAttribute(target, provider, MetadataStore.Container);\r
155         }\r
156         public static void AddAttribute(Type target, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider, CompositionContainer container)\r
157         {\r
158             ContainerUnawareProviderRedirect.GetRedirect(container)[target] = new MetadataStoreProvider(target, provider);\r
159             RegisterTypeDescriptorInterop(target);\r
160         }\r
161         private static void RegisterTypeDescriptorInterop(Type target)\r
162         {\r
163             if (!registeredRedirect.ContainsKey(target))\r
164             {\r
165                 var r = new ContainerUnawareProviderRedirect(target);\r
166                 TypeDescriptor.AddProvider(r, target);\r
167                 registeredRedirect[target] = r;\r
168             }\r
169             else\r
170             {\r
171                 // force a uncache of the information from TypeDescriptor\r
172                 //\r
173                 TypeDescriptor.RemoveProvider(registeredRedirect[target], target);\r
174                 TypeDescriptor.AddProvider(registeredRedirect[target], target);\r
175             }\r
176         }\r
177         public static TypeDescriptorServices GetTypeDescriptorServicesForContainer(CompositionContainer container)\r
178         {\r
179             if (container != null)\r
180             {\r
181                 var result = container.GetExportedValueOrDefault<TypeDescriptorServices>();\r
182                 if (result == null)\r
183                 {\r
184                     var v = new TypeDescriptorServices();\r
185                     CompositionBatch batch = new CompositionBatch();\r
186                     batch.AddPart(v);\r
187                     container.Compose(batch);\r
188                     return v;\r
189                 }\r
190                 \r
191                 return result;\r
192             }\r
193             return null;\r
194         }\r
195 \r
196         private class ContainerUnawareProviderRedirect : TypeDescriptionProvider\r
197         {\r
198             public ContainerUnawareProviderRedirect(Type forType)\r
199                 : base(TypeDescriptor.GetProvider(forType))\r
200             {\r
201             }\r
202             public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)\r
203             {\r
204                 var datd = GetTypeDescriptorServicesForContainer(MetadataStore.Container);\r
205                 if (datd == null || !datd.Providers.ContainsKey(objectType))\r
206                 {\r
207                     return base.GetTypeDescriptor(objectType, instance);\r
208                 }\r
209                 else\r
210                 {\r
211                     return datd.GetTypeDescriptor(objectType, instance);\r
212                 }\r
213             }\r
214 \r
215             internal static Dictionary<Type, TypeDescriptionProvider> GetRedirect(CompositionContainer container)\r
216             {\r
217                 TypeDescriptorServices v = GetTypeDescriptorServicesForContainer(container);\r
218                 return v != null ? v.Providers : null;\r
219             }\r
220         }\r
221 \r
222         private class MetadataStoreProvider : TypeDescriptionProvider\r
223         {\r
224             Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider;\r
225             public MetadataStoreProvider(Type forType, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)\r
226                 : base(TypeDescriptor.GetProvider(forType))\r
227             {\r
228                 this.provider = provider;\r
229             }\r
230             public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)\r
231             {\r
232                 ICustomTypeDescriptor descriptor = base.GetTypeDescriptor(objectType, instance);\r
233                 descriptor = new MetadataStoreTypeDescriptor(objectType, descriptor, provider);\r
234                 return descriptor;\r
235             }\r
236 \r
237         }\r
238 \r
239         private class MetadataStoreTypeDescriptor : CustomTypeDescriptor\r
240         {\r
241             Type targetType;\r
242             Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider;\r
243             public MetadataStoreTypeDescriptor(Type targetType, ICustomTypeDescriptor parent, Func<MemberInfo, IEnumerable<Attribute>, IEnumerable<Attribute>> provider)\r
244                 : base(parent)\r
245             {\r
246                 this.targetType = targetType;\r
247                 this.provider = provider;\r
248             }\r
249             public override TypeConverter GetConverter()\r
250             {\r
251                 TypeConverterAttribute attribute = (TypeConverterAttribute)GetAttributes()[typeof(TypeConverterAttribute)];\r
252                 if (attribute != null)\r
253                 {\r
254                     Type c = this.GetTypeFromName(attribute.ConverterTypeName);\r
255                     if ((c != null) && typeof(TypeConverter).IsAssignableFrom(c))\r
256                     {\r
257                         return (TypeConverter)Activator.CreateInstance(c);\r
258                     }\r
259                 }\r
260                 return base.GetConverter();\r
261             }\r
262             private Type GetTypeFromName(string typeName)\r
263             {\r
264                 if ((typeName == null) || (typeName.Length == 0))\r
265                 {\r
266                     return null;\r
267                 }\r
268                 int length = typeName.IndexOf(',');\r
269                 Type type = null;\r
270                 if (length == -1)\r
271                 {\r
272                     type = targetType.Assembly.GetType(typeName);\r
273                 }\r
274                 if (type == null)\r
275                 {\r
276                     type = Type.GetType(typeName);\r
277                 }\r
278                 if ((type == null) && (length != -1))\r
279                 {\r
280                     type = Type.GetType(typeName.Substring(0, length));\r
281                 }\r
282                 return type;\r
283             }\r
284             public override AttributeCollection GetAttributes()\r
285             {\r
286                 var n = new List<Attribute>();\r
287                 foreach (var attr in provider(targetType, base.GetAttributes().OfType<Attribute>()))\r
288                 {\r
289                     n.Add(attr);\r
290                 }\r
291                 return new AttributeCollection(n.ToArray());\r
292             }\r
293         }\r
294     }\r
295 \r
296     public class DynamicMetadataTestClass\r
297     {\r
298         int i;\r
299 \r
300         private DynamicMetadataTestClass(int i)\r
301         {\r
302             this.i = i;\r
303         }\r
304 \r
305         public override string ToString()\r
306         {\r
307             return i.ToString();\r
308         }\r
309 \r
310         public static DynamicMetadataTestClass Get(string s)\r
311         {\r
312             return new DynamicMetadataTestClass(Int32.Parse(s));\r
313         }\r
314     }\r
315 \r
316     public class DynamicMetadataTestClassConverter : TypeConverter\r
317     {\r
318         public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)\r
319         {\r
320             return sourceType == typeof(string);\r
321         }\r
322         public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)\r
323         {\r
324             return ((DynamicMetadataTestClass)value).ToString();\r
325         }\r
326         public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)\r
327         {\r
328             return DynamicMetadataTestClass.Get((string)value);\r
329         }\r
330         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)\r
331         {\r
332             return destinationType == typeof(string);\r
333         }\r
334     }\r
335 }\r