Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.ComponentModel.Composition / Tests / ComponentModelUnitTest / System / ComponentModel / Composition / ComposablePartExtensibilityTests.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.Composition;\r
7 using System.Linq;\r
8 using System.Reflection;\r
9 using Microsoft.VisualStudio.TestTools.UnitTesting;\r
10 using System.ComponentModel.Composition.Factories;\r
11 using System.ComponentModel.Composition.Hosting;\r
12 using System.ComponentModel.Composition.Primitives;\r
13 using System.ComponentModel.Composition.UnitTesting;\r
14 using System.UnitTesting;\r
15 \r
16 namespace System.ComponentModel.Composition\r
17 {\r
18     [TestClass]\r
19     public class ComposablePartExtensibilityTests\r
20     {\r
21         [TestMethod]\r
22         public void PhaseTest()\r
23         {\r
24             CompositionContainer container = ContainerFactory.Create();\r
25             CompositionBatch batch = new CompositionBatch();\r
26 \r
27             var part = new OrderingTestComposablePart();\r
28             part.AddImport("Import1", ImportCardinality.ExactlyOne, true, false);\r
29             part.AddExport("Export1", 1);\r
30             part.CallOrder.Enqueue("Import:Import1");\r
31             part.CallOrder.Enqueue("OnComposed");\r
32 \r
33             batch.AddExportedValue("Import1", 20);\r
34             batch.AddPart(part);\r
35             container.Compose(batch);\r
36 \r
37             // Export shouldn't be called until it is pulled on by someone.\r
38             var export = container.GetExport<object>("Export1");\r
39 \r
40             part.CallOrder.Enqueue("Export:Export1");\r
41             Assert.AreEqual(1, export.Value);\r
42 \r
43             Assert.IsTrue(part.CallOrder.Count == 0);\r
44         }\r
45 \r
46         [TestMethod]\r
47         public void ImportTest()\r
48         {\r
49             var exporter = new TestExportBinder();\r
50             var importer = new TestImportBinder();\r
51 \r
52             CompositionContainer container = ContainerFactory.Create();\r
53             CompositionBatch batch = new CompositionBatch();\r
54 \r
55             batch.AddPart(importer);\r
56             batch.AddPart(exporter);\r
57             container.Compose(batch);\r
58 \r
59             ExportsAssert.AreEqual(importer.SetImports["single"], 42);\r
60             ExportsAssert.AreEqual(importer.SetImports["multi"], 1, 2, 3);\r
61         }\r
62 \r
63         [TestMethod]\r
64         public void ConstructorInjectionSimpleCase()\r
65         {\r
66             var container = ContainerFactory.Create();\r
67             CompositionBatch batch = new CompositionBatch();\r
68 \r
69             batch.AddPart(new ConstructorInjectionComposablePart(typeof(Foo)));\r
70             batch.AddExportedValue<IBar>(new Bar("Bar Value"));\r
71             container.Compose(batch);\r
72 \r
73             var import = container.GetExport<Foo>();\r
74             var foo = import.Value;\r
75 \r
76             Assert.AreEqual("Bar Value", foo.Bar.Value);\r
77         }\r
78 \r
79         [TestMethod]\r
80         public void ConstructorInjectionCycle()\r
81         {\r
82             var container = ContainerFactory.Create();\r
83             CompositionBatch batch = new CompositionBatch();\r
84 \r
85             batch.AddPart(new ConstructorInjectionComposablePart(typeof(AClass)));\r
86             batch.AddPart(new ConstructorInjectionComposablePart(typeof(BClass)));\r
87 \r
88             CompositionAssert.ThrowsErrors(ErrorId.ImportEngine_PartCannotSetImport,\r
89                                            ErrorId.ImportEngine_PartCannotSetImport, RetryMode.DoNotRetry, () =>\r
90             {\r
91                 container.Compose(batch);\r
92             });\r
93         }\r
94     }\r
95 \r
96     internal class OrderingTestComposablePart : ConcreteComposablePart\r
97     {\r
98         public Queue<string> CallOrder = new Queue<string>();\r
99 \r
100         public OrderingTestComposablePart()\r
101         {\r
102         }\r
103 \r
104         public new  void AddExport(string contractName, object value)\r
105         {\r
106             var export = ExportFactory.Create(contractName, () =>\r
107             {\r
108                 this.OnGetExport(contractName); return value;\r
109             });\r
110 \r
111             base.AddExport(export);\r
112         }\r
113 \r
114         private void OnGetExport(string contractName)\r
115         {\r
116             Assert.AreEqual("Export:" + contractName, CallOrder.Dequeue());\r
117         }\r
118 \r
119         public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)\r
120         {\r
121             ContractBasedImportDefinition contractBasedImportDefinition = (ContractBasedImportDefinition)definition;\r
122             Assert.AreEqual("Import:" + contractBasedImportDefinition.ContractName, CallOrder.Dequeue());\r
123             base.SetImport(definition, exports);\r
124         }\r
125 \r
126         public override void Activate()\r
127         {\r
128             Assert.AreEqual("OnComposed", CallOrder.Dequeue());\r
129             base.Activate();\r
130         }\r
131     }\r
132 \r
133     internal class TestExportBinder : ConcreteComposablePart\r
134     {\r
135         public TestExportBinder()\r
136         {\r
137             AddExport("single", 42);\r
138             AddExport("multi", 1);\r
139             AddExport("multi", 2);\r
140             AddExport("multi", 3);\r
141         }\r
142     }\r
143 \r
144     internal class TestImportBinder : ConcreteComposablePart\r
145     {\r
146         public TestImportBinder()\r
147         {\r
148             AddImport("single", ImportCardinality.ExactlyOne, true, false);\r
149             AddImport("multi", ImportCardinality.ZeroOrMore, true, false);\r
150         }\r
151     }\r
152 \r
153     public class Foo\r
154     {\r
155         public Foo(IBar bar)\r
156         {\r
157             Bar = bar;\r
158         }\r
159 \r
160         public IBar Bar { get; private set; }\r
161     }\r
162 \r
163     public interface IBar\r
164     {\r
165         string Value { get; }\r
166     }\r
167 \r
168     public class Bar : IBar\r
169     {\r
170         public Bar(string value)\r
171         {\r
172             Value = value;\r
173         }\r
174         public string Value { get; private set; }\r
175     }\r
176 \r
177     public class FooBar\r
178     {\r
179         [Import("Foo")]\r
180         public Foo Foo { get; set; }\r
181     }\r
182 \r
183     public class AClass\r
184     {\r
185         public AClass(BClass b)\r
186         {\r
187         }\r
188 \r
189         public BClass B { get; private set; }\r
190     }\r
191 \r
192     public class BClass\r
193     {\r
194         public BClass(AClass a)\r
195         {\r
196             this.A = a;\r
197         }\r
198 \r
199         public AClass A { get; private set; }\r
200     }\r
201 \r
202     internal class ConstructorInjectionComposablePart : ConcreteComposablePart\r
203     {\r
204         private Type _type;\r
205         private ConstructorInfo _constructor;\r
206         private Dictionary<ImportDefinition, object> _imports;\r
207         private bool currentlyExecuting = false;\r
208 \r
209         public ConstructorInjectionComposablePart(Type type)\r
210         {\r
211             this._type = type;\r
212 \r
213             // Note that this just blindly takes the first constructor...\r
214             this._constructor = this._type.GetConstructors().FirstOrDefault();\r
215             Assert.IsNotNull(this._constructor);\r
216 \r
217             foreach (var param in this._constructor.GetParameters())\r
218             {\r
219                 string name = AttributedModelServices.GetContractName(param.ParameterType);\r
220                 AddImport(name, ImportCardinality.ExactlyOne, true, true);\r
221             }\r
222 \r
223             string contractName = AttributedModelServices.GetContractName(type);\r
224             string typeIdentity = AttributedModelServices.GetTypeIdentity(type);\r
225             var metadata = new Dictionary<string, object>();\r
226             metadata.Add(CompositionConstants.ExportTypeIdentityMetadataName, typeIdentity);\r
227             \r
228             Export composableExport = ExportFactory.Create(\r
229                 contractName,\r
230                 metadata,\r
231                 GetInstance);\r
232             this.AddExport(composableExport);\r
233 \r
234             this._imports = new Dictionary<ImportDefinition, object>();\r
235         }\r
236 \r
237         private object GetInstance()\r
238         {\r
239             var result = CompositionResult.SucceededResult;\r
240 \r
241             // We only need this guard if we are pulling on the lazy exports during this call\r
242             // but if we do the pulling in SetImport it isn't needed.\r
243             //if (currentlyExecuting)\r
244             //{\r
245             //    var issue = CompositionError.Create("CM:CreationCycleDetected",\r
246             //        "This failed because there is a creation cycle");\r
247             //    return result.MergeIssue(issue).ToResult<object>(null);\r
248             //}\r
249 \r
250             try\r
251             {\r
252                 currentlyExecuting = true;\r
253 \r
254                 List<object> constructorArgs = new List<object>();\r
255 \r
256                 foreach (ImportDefinition import in this.ImportDefinitions\r
257                     .Where(i => i.IsPrerequisite))\r
258                 {\r
259                     object importValue;\r
260                     if (!this._imports.TryGetValue(import, out importValue))\r
261                     {\r
262                         result = result.MergeError(CompositionError.Create(CompositionErrorId.ImportNotSetOnPart,\r
263                             "The import '{0}' is required for construction of '{1}'", import.ToString(), _type.FullName));\r
264 \r
265                         continue;\r
266                     }\r
267 \r
268                     constructorArgs.Add(importValue);\r
269                 }\r
270 \r
271                 if (!result.Succeeded)\r
272                 {\r
273                     throw new CompositionException(result.Errors);\r
274                 }\r
275 \r
276                 object obj = this._constructor.Invoke(constructorArgs.ToArray());\r
277 \r
278                 return obj;\r
279             }\r
280             finally\r
281             {\r
282                 currentlyExecuting = false;\r
283             }\r
284         }\r
285 \r
286         public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)\r
287         {\r
288             _imports[definition] = exports.First().Value;\r
289         }\r
290     }\r
291 }\r
292 \r