1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.UnitTesting;
\r
6 using System.ComponentModel.Composition;
\r
7 using System.ComponentModel.Composition.Factories;
\r
8 using System.ComponentModel.Composition.Hosting;
\r
9 using Microsoft.VisualStudio.TestTools.UnitTesting;
\r
10 using System.ComponentModel.Composition.Primitives;
\r
12 namespace System.ComponentModel.Composition
\r
15 public class ImportEngineTests
\r
18 public void PreviewImports_Successful_NoAtomicComposition_ShouldBlockChanges()
\r
20 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
21 var engine = new ImportEngine(exportProvider);
\r
23 var import = ImportDefinitionFactory.Create("Value");
\r
24 var importer = PartFactory.CreateImporter(import);
\r
26 exportProvider.AddExport("Value", 21);
\r
28 engine.PreviewImports(importer, null);
\r
30 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
31 exportProvider.AddExport("Value", 22));
\r
33 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
34 exportProvider.RemoveExport("Value"));
\r
36 GC.KeepAlive(importer);
\r
40 public void PreviewImports_Unsuccessful_NoAtomicComposition_ShouldNotBlockChanges()
\r
42 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
43 var engine = new ImportEngine(exportProvider);
\r
45 var import = ImportDefinitionFactory.Create("Value");
\r
46 var importer = PartFactory.CreateImporter(import);
\r
48 ExceptionAssert.Throws<CompositionException>(() =>
\r
49 engine.PreviewImports(importer, null));
\r
51 exportProvider.AddExport("Value", 22);
\r
52 exportProvider.AddExport("Value", 23);
\r
53 exportProvider.RemoveExport("Value");
\r
55 GC.KeepAlive(importer);
\r
59 public void PreviewImports_Successful_AtomicComposition_Completeted_ShouldBlockChanges()
\r
61 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
62 var engine = new ImportEngine(exportProvider);
\r
64 var import = ImportDefinitionFactory.Create("Value");
\r
65 var importer = PartFactory.CreateImporter(import);
\r
67 exportProvider.AddExport("Value", 21);
\r
69 using (var atomicComposition = new AtomicComposition())
\r
71 engine.PreviewImports(importer, atomicComposition);
\r
72 atomicComposition.Complete();
\r
75 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
76 exportProvider.AddExport("Value", 22));
\r
78 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
79 exportProvider.RemoveExport("Value"));
\r
81 GC.KeepAlive(importer);
\r
85 public void PreviewImports_Successful_AtomicComposition_RolledBack_ShouldNotBlockChanges()
\r
87 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
88 var engine = new ImportEngine(exportProvider);
\r
90 var import = ImportDefinitionFactory.Create("Value");
\r
91 var importer = PartFactory.CreateImporter(import);
\r
93 exportProvider.AddExport("Value", 21);
\r
95 using (var atomicComposition = new AtomicComposition())
\r
97 engine.PreviewImports(importer, atomicComposition);
\r
99 // Let atomicComposition get disposed thus rolledback
\r
102 exportProvider.AddExport("Value", 22);
\r
103 exportProvider.RemoveExport("Value");
\r
105 GC.KeepAlive(importer);
\r
109 public void PreviewImports_Unsuccessful_AtomicComposition_ShouldNotBlockChanges()
\r
111 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
112 var engine = new ImportEngine(exportProvider);
\r
114 var import = ImportDefinitionFactory.Create("Value");
\r
115 var importer = PartFactory.CreateImporter(import);
\r
117 using (var atomicComposition = new AtomicComposition())
\r
119 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
120 engine.PreviewImports(importer, atomicComposition));
\r
123 exportProvider.AddExport("Value", 22);
\r
124 exportProvider.AddExport("Value", 23);
\r
125 exportProvider.RemoveExport("Value");
\r
127 GC.KeepAlive(importer);
\r
131 public void PreviewImports_ReleaseImports_ShouldNotBlockChanges()
\r
133 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
134 var engine = new ImportEngine(exportProvider);
\r
136 var import = ImportDefinitionFactory.Create("Value");
\r
137 var importer = PartFactory.CreateImporter(import);
\r
139 exportProvider.AddExport("Value", 21);
\r
141 engine.PreviewImports(importer, null);
\r
143 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
144 exportProvider.AddExport("Value", 22));
\r
146 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
147 exportProvider.RemoveExport("Value"));
\r
149 engine.ReleaseImports(importer, null);
\r
151 exportProvider.AddExport("Value", 22);
\r
152 exportProvider.RemoveExport("Value");
\r
154 GC.KeepAlive(importer);
\r
158 public void PreviewImports_MissingOptionalImport_ShouldSucceed()
\r
160 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
161 var engine = new ImportEngine(exportProvider);
\r
163 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrOne);
\r
164 var importer = PartFactory.CreateImporter(import);
\r
166 engine.PreviewImports(importer, null);
\r
168 GC.KeepAlive(importer);
\r
172 public void PreviewImports_ZeroCollectionImport_ShouldSucceed()
\r
174 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
175 var engine = new ImportEngine(exportProvider);
\r
177 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrMore);
\r
178 var importer = PartFactory.CreateImporter(import);
\r
180 engine.PreviewImports(importer, null);
\r
182 GC.KeepAlive(importer);
\r
186 public void PreviewImports_MissingOptionalImport_NonRecomposable_ShouldNotBlockChanges()
\r
188 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
189 var engine = new ImportEngine(exportProvider);
\r
191 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrOne, false, false);
\r
192 var importer = PartFactory.CreateImporter(import);
\r
194 engine.PreviewImports(importer, null);
\r
196 exportProvider.AddExport("Value", 21);
\r
197 exportProvider.AddExport("Value", 22);
\r
198 exportProvider.RemoveExport("Value");
\r
200 GC.KeepAlive(importer);
\r
204 public void PreviewImports_ZeroCollectionImport_NonRecomposable_ShouldNotBlockChanges()
\r
206 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
207 var engine = new ImportEngine(exportProvider);
\r
209 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrMore, false, false);
\r
210 var importer = PartFactory.CreateImporter(import);
\r
212 engine.PreviewImports(importer, null);
\r
214 exportProvider.AddExport("Value", 21);
\r
215 exportProvider.AddExport("Value", 22);
\r
216 exportProvider.RemoveExport("Value");
\r
218 GC.KeepAlive(importer);
\r
222 public void SatisfyImports_NonRecomposable_ValueShouldNotChange()
\r
224 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
225 var engine = new ImportEngine(exportProvider);
\r
227 exportProvider.AddExport("Value", 21);
\r
229 var import = ImportDefinitionFactory.Create("Value", false);
\r
230 var importer = PartFactory.CreateImporter(import);
\r
232 engine.SatisfyImports(importer);
\r
234 Assert.AreEqual(21, importer.GetImport(import));
\r
236 // After rejection batch failures throw ChangeRejectedException to indicate that
\r
237 // the failure did not affect the container
\r
238 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
239 exportProvider.ReplaceExportValue("Value", 42));
\r
241 Assert.AreEqual(21, importer.GetImport(import), "Value should not change!");
\r
243 GC.KeepAlive(importer);
\r
247 public void SatisfyImports_Recomposable_ValueShouldChange()
\r
249 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
250 var engine = new ImportEngine(exportProvider);
\r
252 exportProvider.AddExport("Value", 21);
\r
254 var import = ImportDefinitionFactory.Create("Value", true);
\r
255 var importer = PartFactory.CreateImporter(import);
\r
257 engine.SatisfyImports(importer);
\r
259 Assert.AreEqual(21, importer.GetImport(import));
\r
261 exportProvider.ReplaceExportValue("Value", 42);
\r
263 Assert.AreEqual(42, importer.GetImport(import), "Value should change!");
\r
265 GC.KeepAlive(importer);
\r
269 public void SatisfyImports_NonRecomposable_Prerequisite_ValueShouldNotChange()
\r
271 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
272 var engine = new ImportEngine(exportProvider);
\r
274 var import = ImportDefinitionFactory.Create("Value", false, true);
\r
275 var importer = PartFactory.CreateImporter(import);
\r
277 exportProvider.AddExport("Value", 21);
\r
279 engine.SatisfyImports(importer);
\r
281 Assert.AreEqual(21, importer.GetImport(import));
\r
283 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
284 exportProvider.ReplaceExportValue("Value", 42));
\r
286 Assert.AreEqual(21, importer.GetImport(import), "Value should NOT change!");
\r
288 GC.KeepAlive(importer);
\r
292 public void SatisfyImports_Recomposable_Prerequisite_ValueShouldChange()
\r
294 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
295 var engine = new ImportEngine(exportProvider);
\r
297 var import = ImportDefinitionFactory.Create("Value", true, true);
\r
298 var importer = PartFactory.CreateImporter(import);
\r
300 exportProvider.AddExport("Value", 21);
\r
302 engine.SatisfyImports(importer);
\r
304 Assert.AreEqual(21, importer.GetImport(import));
\r
306 exportProvider.ReplaceExportValue("Value", 42);
\r
308 Assert.AreEqual(42, importer.GetImport(import), "Value should change!");
\r
310 GC.KeepAlive(importer);
\r
314 public void SatisfyImports_OneRecomposable_OneNotRecomposable()
\r
316 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
317 var engine = new ImportEngine(exportProvider);
\r
319 var import1 = ImportDefinitionFactory.Create("Value", true);
\r
320 var import2 = ImportDefinitionFactory.Create("Value", false);
\r
321 var importer = PartFactory.CreateImporter(import1, import2);
\r
323 exportProvider.AddExport("Value", 21);
\r
325 engine.SatisfyImports(importer);
\r
327 // Initial compose values should be 21
\r
328 Assert.AreEqual(21, importer.GetImport(import1));
\r
329 Assert.AreEqual(21, importer.GetImport(import2));
\r
331 // Reset value to ensure it doesn't get set to same value again
\r
332 importer.ResetImport(import1);
\r
333 importer.ResetImport(import2);
\r
335 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
336 exportProvider.ReplaceExportValue("Value", 42));
\r
338 Assert.AreEqual(null, importer.GetImport(import1), "Value should NOT have been set!");
\r
339 Assert.AreEqual(null, importer.GetImport(import2), "Value should NOT have been set!");
\r
341 GC.KeepAlive(importer);
\r
345 public void SatisfyImports_TwoRecomposables_SingleExportValueChanged()
\r
347 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
348 var engine = new ImportEngine(exportProvider);
\r
350 var import1 = ImportDefinitionFactory.Create("Value1", true);
\r
351 var import2 = ImportDefinitionFactory.Create("Value2", true);
\r
352 var importer = PartFactory.CreateImporter(import1, import2);
\r
354 exportProvider.AddExport("Value1", 21);
\r
355 exportProvider.AddExport("Value2", 23);
\r
357 engine.SatisfyImports(importer);
\r
359 Assert.AreEqual(21, importer.GetImport(import1));
\r
360 Assert.AreEqual(23, importer.GetImport(import2));
\r
362 importer.ResetImport(import1);
\r
363 importer.ResetImport(import2);
\r
365 // Only change Value1
\r
366 exportProvider.ReplaceExportValue("Value1", 42);
\r
368 Assert.AreEqual(42, importer.GetImport(import1), "Value should have been set!");
\r
370 Assert.AreEqual(null, importer.GetImport(import2), "Value should NOT have changed to the value in the container.");
\r
372 GC.KeepAlive(importer);
\r
376 public void SatisfyImports_Recomposable_Unregister_ValueShouldChangeOnce()
\r
378 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
379 var engine = new ImportEngine(exportProvider);
\r
381 exportProvider.AddExport("Value", 21);
\r
383 var import = ImportDefinitionFactory.Create("Value", true);
\r
384 var importer = PartFactory.CreateImporter(import);
\r
386 engine.SatisfyImports(importer);
\r
388 Assert.AreEqual(21, importer.GetImport(import));
\r
390 exportProvider.ReplaceExportValue("Value", 42);
\r
392 Assert.AreEqual(42, importer.GetImport(import), "Value should change!");
\r
394 engine.ReleaseImports(importer, null);
\r
396 exportProvider.ReplaceExportValue("Value", 666);
\r
398 Assert.AreEqual(42, importer.GetImport(import), "Value should not change!");
\r
400 GC.KeepAlive(importer);
\r
404 public void SatisfyImports_MissingOptionalImport_NonRecomposable_ShouldNotBlockChanges()
\r
406 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
407 var engine = new ImportEngine(exportProvider);
\r
409 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrOne, false, false);
\r
410 var importer = PartFactory.CreateImporter(import);
\r
412 exportProvider.AddExport("Value", 20);
\r
414 engine.SatisfyImports(importer);
\r
416 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
417 exportProvider.AddExport("Value", 21));
\r
419 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
420 exportProvider.RemoveExport("Value"));
\r
422 GC.KeepAlive(importer);
\r
426 public void SatisfyImports_ZeroCollectionImport_NonRecomposable_ShouldNotBlockChanges()
\r
428 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
429 var engine = new ImportEngine(exportProvider);
\r
431 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrMore, false, false);
\r
432 var importer = PartFactory.CreateImporter(import);
\r
434 exportProvider.AddExport("Value", 20);
\r
436 engine.SatisfyImports(importer);
\r
438 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
439 exportProvider.AddExport("Value", 21));
\r
441 ExceptionAssert.Throws<ChangeRejectedException>(() =>
\r
442 exportProvider.RemoveExport("Value"));
\r
444 GC.KeepAlive(importer);
\r
448 public void SatisfyImports_MissingOptionalImport_Recomposable_ShouldNotBlockChanges()
\r
450 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
451 var engine = new ImportEngine(exportProvider);
\r
453 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrOne, true, false);
\r
454 var importer = PartFactory.CreateImporter(import);
\r
456 exportProvider.AddExport("Value", 20);
\r
458 engine.SatisfyImports(importer);
\r
460 exportProvider.AddExport("Value", 21);
\r
461 exportProvider.RemoveExport("Value");
\r
463 GC.KeepAlive(importer);
\r
467 public void SatisfyImports_ZeroCollectionImport_Recomposable_ShouldNotBlockChanges()
\r
469 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
470 var engine = new ImportEngine(exportProvider);
\r
472 var import = ImportDefinitionFactory.Create("Value", ImportCardinality.ZeroOrMore, true, false);
\r
473 var importer = PartFactory.CreateImporter(import);
\r
475 exportProvider.AddExport("Value", 20);
\r
477 engine.SatisfyImports(importer);
\r
479 exportProvider.AddExport("Value", 21);
\r
480 exportProvider.RemoveExport("Value");
\r
482 GC.KeepAlive(importer);
\r
486 public void SatisfyImportsOnce_Recomposable_ValueShouldNotChange_NoRecompositionRequested()
\r
488 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
489 var engine = new ImportEngine(exportProvider);
\r
491 exportProvider.AddExport("Value", 21);
\r
493 var import = ImportDefinitionFactory.Create("Value", true);
\r
494 var importer = PartFactory.CreateImporter(import);
\r
496 engine.SatisfyImportsOnce(importer);
\r
498 Assert.AreEqual(21, importer.GetImport(import));
\r
500 exportProvider.ReplaceExportValue("Value", 42);
\r
502 Assert.AreEqual(21, importer.GetImport(import), "Value should not change!");
\r
504 GC.KeepAlive(importer);
\r
508 public void SatisifyImportsOnce_Recomposable_ValueShouldNotChange_NoRecompositionRequested_ViaNonArgumentSignature()
\r
510 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
511 var engine = new ImportEngine(exportProvider);
\r
513 exportProvider.AddExport("Value", 21);
\r
515 var import = ImportDefinitionFactory.Create("Value", true);
\r
516 var importer = PartFactory.CreateImporter(import);
\r
518 engine.SatisfyImportsOnce(importer);
\r
520 Assert.AreEqual(21, importer.GetImport(import));
\r
522 exportProvider.ReplaceExportValue("Value", 42);
\r
524 Assert.AreEqual(21, importer.GetImport(import), "Value should not change!");
\r
526 GC.KeepAlive(importer);
\r
530 public void SatisfyImportsOnce_Successful_ShouldNotBlockChanges()
\r
532 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
533 var engine = new ImportEngine(exportProvider);
\r
535 var import = ImportDefinitionFactory.Create("Value");
\r
536 var importer = PartFactory.CreateImporter(import);
\r
538 exportProvider.AddExport("Value", 21);
\r
540 engine.SatisfyImportsOnce(importer);
\r
542 exportProvider.AddExport("Value", 22);
\r
543 exportProvider.RemoveExport("Value");
\r
545 GC.KeepAlive(importer);
\r
549 public void SatisfyImportsOnce_Unsuccessful_ShouldNotBlockChanges()
\r
551 var exportProvider = ExportProviderFactory.CreateRecomposable();
\r
552 var engine = new ImportEngine(exportProvider);
\r
554 var import = ImportDefinitionFactory.Create("Value");
\r
555 var importer = PartFactory.CreateImporter(import);
\r
557 ExceptionAssert.Throws<CompositionException>(() =>
\r
558 engine.SatisfyImportsOnce(importer));
\r
560 exportProvider.AddExport("Value", 22);
\r
561 exportProvider.AddExport("Value", 23);
\r
562 exportProvider.RemoveExport("Value");
\r
564 GC.KeepAlive(importer);
\r