LifetimeTests.cs 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273
  1. // -----------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // -----------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel.Composition;
  7. using System.ComponentModel.Composition.Factories;
  8. using System.ComponentModel.Composition.Hosting;
  9. using System.ComponentModel.Composition.UnitTesting;
  10. using System.Linq;
  11. using System.Reflection;
  12. using System.UnitTesting;
  13. using Microsoft.VisualStudio.TestTools.UnitTesting;
  14. namespace Tests.Integration
  15. {
  16. [TestClass]
  17. public class LifetimeTests
  18. {
  19. [Export]
  20. public class AnyPartSimple
  21. {
  22. }
  23. [Export]
  24. public class AnyPartDisposable : IDisposable
  25. {
  26. public bool IsDisposed { get; set; }
  27. public void Dispose()
  28. {
  29. Assert.IsFalse(IsDisposed);
  30. IsDisposed = true;
  31. }
  32. }
  33. [Export]
  34. public class AnyPartRecomposable
  35. {
  36. [Import("Value", AllowRecomposition = true)]
  37. public int Value { get; set; }
  38. }
  39. [Export]
  40. public class AnyPartDisposableRecomposable : IDisposable
  41. {
  42. [Import("Value", AllowRecomposition = true)]
  43. public int Value { get; set; }
  44. public bool IsDisposed { get; set; }
  45. public void Dispose()
  46. {
  47. Assert.IsFalse(IsDisposed);
  48. IsDisposed = true;
  49. }
  50. }
  51. [TestMethod]
  52. public void PartAddedViaAddExportedValue_ShouldNotBeDisposedWithContainer()
  53. {
  54. var container = new CompositionContainer();
  55. var disposablePart = new AnyPartDisposable();
  56. var batch = new CompositionBatch();
  57. batch.AddPart(batch);
  58. container.Compose(batch);
  59. container.Dispose();
  60. Assert.IsFalse(disposablePart.IsDisposed);
  61. }
  62. [TestMethod]
  63. public void PartAddedTwice_AppearsTwice()
  64. {
  65. // You probably shouldn't be adding a part to the container twice, but it's not something we're going to check for and throw an exception on
  66. var container = new CompositionContainer();
  67. var disposable = new AnyPartDisposable();
  68. var part = AttributedModelServices.CreatePart(disposable);
  69. var batch = new CompositionBatch();
  70. batch.AddPart(part);
  71. container.Compose(batch);
  72. batch = new CompositionBatch();
  73. batch.AddPart(part);
  74. container.Compose(batch);
  75. var exports = container.GetExports<AnyPartDisposable>();
  76. Assert.AreEqual(2, exports.Count());
  77. container.Dispose();
  78. }
  79. [TestMethod]
  80. public void AnyPart_Simple_ShouldNotBeCollected()
  81. {
  82. var catalog = new TypeCatalog(typeof(AnyPartSimple));
  83. var container = new CompositionContainer(catalog);
  84. var refTracker = new ReferenceTracker();
  85. refTracker.AddReferencesNotExpectedToBeCollected(
  86. container.GetExportedValue<AnyPartSimple>());
  87. refTracker.CollectAndAssert();
  88. GC.KeepAlive(container);
  89. }
  90. [TestMethod]
  91. public void AnyPart_Disposable_ShouldNotBeCollected()
  92. {
  93. var catalog = new TypeCatalog(typeof(AnyPartDisposable));
  94. var container = new CompositionContainer(catalog);
  95. var refTracker = new ReferenceTracker();
  96. refTracker.AddReferencesNotExpectedToBeCollected(
  97. container.GetExportedValue<AnyPartDisposable>());
  98. GC.KeepAlive(container);
  99. }
  100. [TestMethod]
  101. public void AnyPart_Disposable_ShouldBeDisposedWithContainer()
  102. {
  103. var catalog = new TypeCatalog(typeof(AnyPartDisposable));
  104. var container = new CompositionContainer(catalog);
  105. var exportedValue = container.GetExportedValue<AnyPartDisposable>();
  106. Assert.IsFalse(exportedValue.IsDisposed);
  107. container.Dispose();
  108. Assert.IsTrue(exportedValue.IsDisposed, "AnyPart should be disposed with the container!");
  109. }
  110. [TestMethod]
  111. public void AnyPart_RecomposabeImport_ShouldNotBeCollected()
  112. {
  113. var catalog = new TypeCatalog(typeof(AnyPartRecomposable));
  114. var container = new CompositionContainer(catalog);
  115. // Setup dependency
  116. CompositionBatch batch = new CompositionBatch();
  117. var valueKey = batch.AddExportedValue("Value", 21);
  118. container.Compose(batch);
  119. batch = null;
  120. var refTracker = new ReferenceTracker();
  121. refTracker.AddReferencesNotExpectedToBeCollected(
  122. container.GetExportedValue<AnyPartRecomposable>());
  123. refTracker.CollectAndAssert();
  124. // Lets make sure recomposition doesn't blow anything up here.
  125. batch = new CompositionBatch();
  126. batch.RemovePart(valueKey);
  127. batch.AddExportedValue("Value", 42);
  128. container.Compose(batch);
  129. batch = null;
  130. var exportedValue = (AnyPartRecomposable)refTracker.ReferencesNotExpectedToBeCollected[0].Target;
  131. Assert.AreEqual(42, exportedValue.Value);
  132. GC.KeepAlive(container);
  133. }
  134. [TestMethod]
  135. public void AnyPart_DisposableRecomposabeImport_ShouldNotBeCollected()
  136. {
  137. var catalog = new TypeCatalog(typeof(AnyPartDisposableRecomposable));
  138. var container = new CompositionContainer(catalog);
  139. // Setup dependency
  140. CompositionBatch batch = new CompositionBatch();
  141. var valueKey = batch.AddExportedValue("Value", 21);
  142. container.Compose(batch);
  143. batch = null;
  144. var refTracker = new ReferenceTracker();
  145. refTracker.AddReferencesNotExpectedToBeCollected(
  146. container.GetExportedValue<AnyPartDisposableRecomposable>());
  147. refTracker.CollectAndAssert();
  148. // Lets make sure recomposition doesn't blow anything up here.
  149. batch = new CompositionBatch();
  150. batch.RemovePart(valueKey);
  151. batch.AddExportedValue("Value", 42);
  152. container.Compose(batch);
  153. batch = null;
  154. var exportedValue = (AnyPartDisposableRecomposable)refTracker.ReferencesNotExpectedToBeCollected[0].Target;
  155. Assert.AreEqual(42, exportedValue.Value);
  156. GC.KeepAlive(container);
  157. container.Dispose();
  158. Assert.IsTrue(exportedValue.IsDisposed, "Any parts should be disposed with the container!");
  159. }
  160. [Export]
  161. [PartCreationPolicy(CreationPolicy.Shared)]
  162. public class SharedPartSimple
  163. {
  164. }
  165. [Export]
  166. [PartCreationPolicy(CreationPolicy.Shared)]
  167. public class SharedPartDisposable : IDisposable
  168. {
  169. public bool IsDisposed { get; set; }
  170. public void Dispose()
  171. {
  172. Assert.IsFalse(IsDisposed);
  173. IsDisposed = true;
  174. }
  175. }
  176. [Export]
  177. [PartCreationPolicy(CreationPolicy.Shared)]
  178. public class SharedPartRecomposable
  179. {
  180. [Import("Value", AllowRecomposition = true)]
  181. public int Value { get; set; }
  182. }
  183. [Export]
  184. [PartCreationPolicy(CreationPolicy.Shared)]
  185. public class SharedPartDisposableRecomposable : IDisposable
  186. {
  187. [Import("Value", AllowRecomposition = true)]
  188. public int Value { get; set; }
  189. public bool IsDisposed { get; set; }
  190. public void Dispose()
  191. {
  192. Assert.IsFalse(IsDisposed);
  193. IsDisposed = true;
  194. }
  195. }
  196. [TestMethod]
  197. public void SharedPart_Simple_ShouldNotBeCollected()
  198. {
  199. var catalog = new TypeCatalog(typeof(SharedPartSimple));
  200. var container = new CompositionContainer(catalog);
  201. var refTracker = new ReferenceTracker();
  202. refTracker.AddReferencesNotExpectedToBeCollected(
  203. container.GetExportedValue<SharedPartSimple>());
  204. refTracker.CollectAndAssert();
  205. GC.KeepAlive(container);
  206. }
  207. [TestMethod]
  208. public void SharedPart_Disposable_ShouldNotBeCollected()
  209. {
  210. var catalog = new TypeCatalog(typeof(SharedPartDisposable));
  211. var container = new CompositionContainer(catalog);
  212. var refTracker = new ReferenceTracker();
  213. refTracker.AddReferencesNotExpectedToBeCollected(
  214. container.GetExportedValue<SharedPartDisposable>());
  215. refTracker.CollectAndAssert();
  216. GC.KeepAlive(container);
  217. }
  218. [TestMethod]
  219. public void SharedPart_Disposable_ShouldBeDisposedWithContainer()
  220. {
  221. var catalog = new TypeCatalog(typeof(SharedPartDisposable));
  222. var container = new CompositionContainer(catalog);
  223. var export = container.GetExportedValue<SharedPartDisposable>();
  224. Assert.IsFalse(export.IsDisposed);
  225. container.Dispose();
  226. Assert.IsTrue(export.IsDisposed, "SharedPart should be disposed with the container!");
  227. }
  228. [TestMethod]
  229. public void SharedPart_RecomposabeImport_ShouldNotBeCollected()
  230. {
  231. var catalog = new TypeCatalog(typeof(SharedPartRecomposable));
  232. var container = new CompositionContainer(catalog);
  233. // Setup dependency
  234. CompositionBatch batch = new CompositionBatch();
  235. var valueKey = batch.AddExportedValue("Value", 21);
  236. container.Compose(batch);
  237. batch = null;
  238. var refTracker = new ReferenceTracker();
  239. refTracker.AddReferencesNotExpectedToBeCollected(
  240. container.GetExportedValue<SharedPartRecomposable>());
  241. refTracker.CollectAndAssert();
  242. // Lets make sure recomposition doesn't blow anything up here.
  243. batch = new CompositionBatch();
  244. batch.RemovePart(valueKey);
  245. batch.AddExportedValue("Value", 42);
  246. container.Compose(batch);
  247. batch = null;
  248. var exportedValue = (SharedPartRecomposable)refTracker.ReferencesNotExpectedToBeCollected[0].Target;
  249. Assert.AreEqual(42, exportedValue.Value);
  250. GC.KeepAlive(container);
  251. }
  252. [TestMethod]
  253. public void SharedPart_DisposableRecomposabeImport_ShouldNotBeCollected()
  254. {
  255. var catalog = new TypeCatalog(typeof(SharedPartDisposableRecomposable));
  256. var container = new CompositionContainer(catalog);
  257. // Setup dependency
  258. CompositionBatch batch = new CompositionBatch();
  259. var valueKey = batch.AddExportedValue("Value", 21);
  260. container.Compose(batch);
  261. batch = null;
  262. var refTracker = new ReferenceTracker();
  263. refTracker.AddReferencesNotExpectedToBeCollected(
  264. container.GetExportedValue<SharedPartDisposableRecomposable>());
  265. refTracker.CollectAndAssert();
  266. // Lets make sure recomposition doesn't blow anything up here.
  267. batch = new CompositionBatch();
  268. batch.RemovePart(valueKey);
  269. batch.AddExportedValue("Value", 42);
  270. container.Compose(batch);
  271. batch = null;
  272. var exportedValue = (SharedPartDisposableRecomposable)refTracker.ReferencesNotExpectedToBeCollected[0].Target;
  273. Assert.AreEqual(42, exportedValue.Value);
  274. container.Dispose();
  275. Assert.IsTrue(exportedValue.IsDisposed, "Any parts should be disposed with the container!");
  276. }
  277. [Export]
  278. [PartCreationPolicy(CreationPolicy.NonShared)]
  279. public class NonSharedPartSimple
  280. {
  281. }
  282. [Export]
  283. [PartCreationPolicy(CreationPolicy.NonShared)]
  284. public class NonSharedPartRecomposable
  285. {
  286. [Import("Value", AllowRecomposition = true)]
  287. public int Value { get; set; }
  288. }
  289. [Export]
  290. [PartCreationPolicy(CreationPolicy.NonShared)]
  291. public class NonSharedPartDisposable : IDisposable
  292. {
  293. public bool IsDisposed { get; set; }
  294. public void Dispose()
  295. {
  296. Assert.IsFalse(IsDisposed);
  297. IsDisposed = true;
  298. }
  299. }
  300. [Export]
  301. [PartCreationPolicy(CreationPolicy.NonShared)]
  302. public class NonSharedPartDisposableRecomposable : IDisposable
  303. {
  304. private int _value;
  305. [Import("Value", AllowRecomposition = true)]
  306. public int Value
  307. {
  308. get
  309. {
  310. if (this.IsDisposed) throw new ObjectDisposedException(this.GetType().Name);
  311. return this._value;
  312. }
  313. set
  314. {
  315. if (this.IsDisposed) throw new ObjectDisposedException(this.GetType().Name);
  316. this._value = value;
  317. }
  318. }
  319. public bool IsDisposed { get; set; }
  320. public void Dispose()
  321. {
  322. Assert.IsFalse(IsDisposed);
  323. IsDisposed = true;
  324. }
  325. }
  326. [TestMethod]
  327. public void NonSharedPart_Disposable_ShouldNotBeCollected()
  328. {
  329. var catalog = new TypeCatalog(typeof(NonSharedPartDisposable));
  330. var container = new CompositionContainer(catalog);
  331. var refTracker = new ReferenceTracker();
  332. refTracker.AddReferencesNotExpectedToBeCollected(
  333. container.GetExportedValue<NonSharedPartDisposable>());
  334. refTracker.CollectAndAssert();
  335. GC.KeepAlive(container);
  336. }
  337. [TestMethod]
  338. public void NonSharedPart_Disposable_ShouldBeDisposedWithContainer()
  339. {
  340. var catalog = new TypeCatalog(typeof(NonSharedPartDisposable));
  341. var container = new CompositionContainer(catalog);
  342. var export = container.GetExportedValue<NonSharedPartDisposable>();
  343. Assert.IsFalse(export.IsDisposed);
  344. container.Dispose();
  345. Assert.IsTrue(export.IsDisposed, "NonSharedParts should be disposed with the container!");
  346. }
  347. [TestMethod]
  348. public void NonSharedPart_RecomposableImport_WithReference_ShouldNotBeCollected()
  349. {
  350. var catalog = new TypeCatalog(typeof(NonSharedPartRecomposable));
  351. var container = new CompositionContainer(catalog);
  352. // Setup dependency
  353. CompositionBatch batch = new CompositionBatch();
  354. var valueKey = batch.AddExportedValue("Value", 21);
  355. container.Compose(batch);
  356. batch = null;
  357. var exportedValue = container.GetExportedValue<NonSharedPartRecomposable>();
  358. var refTracker = new ReferenceTracker();
  359. refTracker.AddReferencesNotExpectedToBeCollected(exportedValue);
  360. refTracker.CollectAndAssert();
  361. // Recompose should work because we are still holding a reference to the exported value.
  362. batch = new CompositionBatch();
  363. batch.RemovePart(valueKey);
  364. batch.AddExportedValue("Value", 42);
  365. container.Compose(batch);
  366. batch = null;
  367. Assert.AreEqual(42, exportedValue.Value, "Value should have been recomposed");
  368. GC.KeepAlive(container);
  369. }
  370. [TestMethod]
  371. public void NonSharedPart_DisposableRecomposabeImport_NoReference_ShouldNotBeCollected()
  372. {
  373. var catalog = new TypeCatalog(typeof(NonSharedPartDisposableRecomposable));
  374. var container = new CompositionContainer(catalog);
  375. // Setup dependency
  376. CompositionBatch batch = new CompositionBatch();
  377. var valueKey = batch.AddExportedValue("Value", 21);
  378. container.Compose(batch);
  379. batch = null;
  380. var refTracker = new ReferenceTracker();
  381. refTracker.AddReferencesNotExpectedToBeCollected(
  382. container.GetExportedValue<NonSharedPartDisposableRecomposable>());
  383. refTracker.CollectAndAssert();
  384. // Recompose just to ensure we don't blow up, even though we don't expect anything to happen.
  385. batch = new CompositionBatch();
  386. batch.RemovePart(valueKey);
  387. batch.AddExportedValue("Value", 42);
  388. container.Compose(batch);
  389. batch = null;
  390. var exportedValue = (NonSharedPartDisposableRecomposable)refTracker.ReferencesNotExpectedToBeCollected[0].Target;
  391. Assert.AreEqual(42, exportedValue.Value, "Value shoudl ahve been recomposed.");
  392. GC.KeepAlive(container);
  393. }
  394. [Export]
  395. public class SharedState
  396. {
  397. public static int instanceNumber = 0;
  398. public SharedState()
  399. {
  400. MyInstanceNumber = instanceNumber++;
  401. }
  402. public int MyInstanceNumber { get; private set; }
  403. }
  404. [PartCreationPolicy(CreationPolicy.NonShared)]
  405. public class NonSharedState
  406. {
  407. [Import(AllowRecomposition = true)]
  408. public SharedState State { set { ExportState = value; } }
  409. [Export("SharedFromNonShared")]
  410. public SharedState ExportState { get; private set; }
  411. }
  412. [TestMethod]
  413. public void NonSharedPart_TwoRecomposablePartsSameExportedValue()
  414. {
  415. // This test is primarily used to ensure that we allow for multiple parts to be associated
  416. // with the same exported value.
  417. var catalog = new TypeCatalog(typeof(SharedState), typeof(NonSharedState));
  418. var container = new CompositionContainer(catalog);
  419. var export1 = container.GetExportedValue<SharedState>("SharedFromNonShared");
  420. var export2 = container.GetExportedValue<SharedState>("SharedFromNonShared");
  421. // Same exported value that comes from two different recomposable part instances.
  422. Assert.AreEqual(export1.MyInstanceNumber, export2.MyInstanceNumber, "Should be the same shared object!");
  423. }
  424. [Export]
  425. [PartCreationPolicy(CreationPolicy.NonShared)]
  426. public class SharedImporter
  427. {
  428. [Import(RequiredCreationPolicy = CreationPolicy.Shared)]
  429. public AnyPartSimple AnyPartSimple { get; set; }
  430. [Import(RequiredCreationPolicy = CreationPolicy.Shared)]
  431. public AnyPartDisposable AnyPartDisposable { get; set; }
  432. [Import(RequiredCreationPolicy = CreationPolicy.Shared)]
  433. public AnyPartRecomposable AnyPartRecomposable { get; set; }
  434. [Import(RequiredCreationPolicy = CreationPolicy.Shared)]
  435. public AnyPartDisposableRecomposable AnyPartDisposableRecomposable { get; set; }
  436. }
  437. [Export]
  438. [PartCreationPolicy(CreationPolicy.NonShared)]
  439. public class NonSharedImporter
  440. {
  441. [Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
  442. public AnyPartSimple AnyPartSimple { get; set; }
  443. [Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
  444. public AnyPartDisposable AnyPartDisposable { get; set; }
  445. [Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
  446. public AnyPartRecomposable AnyPartRecomposable { get; set; }
  447. [Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
  448. public AnyPartDisposableRecomposable AnyPartDisposableRecomposable { get; set; }
  449. }
  450. private static CompositionContainer GetContainer()
  451. {
  452. var container = ContainerFactory.CreateWithAttributedCatalog(
  453. typeof(LifetimeTests).GetNestedTypes(BindingFlags.Public));
  454. CompositionBatch batch = new CompositionBatch();
  455. batch.AddExportedValue("Value", 21);
  456. container.Compose(batch);
  457. return container;
  458. }
  459. [TestMethod]
  460. public void GetReleaseExport_SharedRoot_ShouldNotDisposeChain()
  461. {
  462. var container = GetContainer();
  463. var export = container.GetExport<SharedImporter, IDictionary<string, object>>();
  464. var exportedValue = export.Value;
  465. container.ReleaseExport(export);
  466. Assert.IsFalse(exportedValue.AnyPartDisposable.IsDisposed);
  467. Assert.IsFalse(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  468. }
  469. [TestMethod]
  470. public void AddRemovePart_SharedRoot_ShouldNotDisposeChain()
  471. {
  472. var container = GetContainer();
  473. var exportedValue = new SharedImporter();
  474. CompositionBatch batch = new CompositionBatch();
  475. var part = batch.AddPart(exportedValue);
  476. container.Compose(batch);
  477. batch = new CompositionBatch();
  478. batch.RemovePart(part);
  479. container.Compose(batch);
  480. Assert.IsFalse(exportedValue.AnyPartDisposable.IsDisposed);
  481. Assert.IsFalse(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  482. }
  483. [TestMethod]
  484. public void ContainerDispose_SharedRoot_ShouldDisposeChain()
  485. {
  486. var container = GetContainer();
  487. var export = container.GetExport<SharedImporter>();
  488. var exportedValue = export.Value;
  489. container.Dispose();
  490. Assert.IsTrue(exportedValue.AnyPartDisposable.IsDisposed);
  491. Assert.IsTrue(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  492. }
  493. [TestMethod]
  494. public void GetReleaseExport_NonSharedRoot_ShouldDisposeChain()
  495. {
  496. var container = GetContainer();
  497. var exports = new List<Lazy<NonSharedImporter>>();
  498. var exportedValues = new List<NonSharedImporter>();
  499. // Executing this 100 times to help uncover any GC bugs
  500. for (int i = 0; i < 100; i++)
  501. {
  502. var export = container.GetExport<NonSharedImporter>();
  503. var exportedValue = export.Value;
  504. exports.Add(export);
  505. exportedValues.Add(exportedValue);
  506. }
  507. for (int i = 0; i < 100; i++)
  508. {
  509. var export = exports[i];
  510. var exportedValue = exportedValues[i];
  511. container.ReleaseExport(export);
  512. Assert.IsTrue(exportedValue.AnyPartDisposable.IsDisposed);
  513. Assert.IsTrue(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  514. }
  515. }
  516. public void GetReleaseExport_NonSharedRoot_ShouldDisposeChain_WithMetadata()
  517. {
  518. var container = GetContainer();
  519. var exports = new List<Lazy<NonSharedImporter, IDictionary<string, object>>>();
  520. var exportedValues = new List<NonSharedImporter>();
  521. // Executing this 100 times to help uncover any GC bugs
  522. for (int i = 0; i < 100; i++)
  523. {
  524. var export = container.GetExport<NonSharedImporter, IDictionary<string, object>>();
  525. var exportedValue = export.Value;
  526. exports.Add(export);
  527. exportedValues.Add(exportedValue);
  528. }
  529. for (int i = 0; i < 100; i++)
  530. {
  531. var export = exports[i];
  532. var exportedValue = exportedValues[i];
  533. container.ReleaseExport(export);
  534. Assert.IsTrue(exportedValue.AnyPartDisposable.IsDisposed);
  535. Assert.IsTrue(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  536. }
  537. }
  538. [TestMethod]
  539. public void ReleaseExports_ShouldDispose_NonSharedParts()
  540. {
  541. var container = GetContainer();
  542. var export1 = container.GetExport<NonSharedImporter>();
  543. var exportedValue1 = export1.Value;
  544. var export2 = container.GetExport<NonSharedImporter>();
  545. var exportedValue2 = export2.Value;
  546. container.ReleaseExports(new[] { export1, export2 });
  547. Assert.IsTrue(exportedValue1.AnyPartDisposable.IsDisposed);
  548. Assert.IsTrue(exportedValue1.AnyPartDisposableRecomposable.IsDisposed);
  549. Assert.IsTrue(exportedValue2.AnyPartDisposable.IsDisposed);
  550. Assert.IsTrue(exportedValue2.AnyPartDisposableRecomposable.IsDisposed);
  551. }
  552. [TestMethod]
  553. public void AddRemovePart_NonSharedRoot_ShouldDisposeChain()
  554. {
  555. var container = GetContainer();
  556. var exportedValue = new NonSharedImporter();
  557. CompositionBatch batch = new CompositionBatch();
  558. var part = batch.AddPart(exportedValue);
  559. container.Compose(batch);
  560. batch = new CompositionBatch();
  561. batch.RemovePart(part);
  562. container.Compose(batch);
  563. Assert.IsTrue(exportedValue.AnyPartDisposable.IsDisposed);
  564. Assert.IsTrue(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  565. }
  566. [TestMethod]
  567. public void ContainerDispose_NonSharedRoot_ShouldNotDisposeChain()
  568. {
  569. var container = GetContainer();
  570. var export = container.GetExport<NonSharedImporter>();
  571. var exportedValue = export.Value;
  572. container.Dispose();
  573. Assert.IsTrue(exportedValue.AnyPartDisposable.IsDisposed);
  574. Assert.IsTrue(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  575. }
  576. [TestMethod]
  577. public void GetReleaseExport_NonSharedPart_ShouldNotRecomposeAfterRelease()
  578. {
  579. var catalog = new TypeCatalog(typeof(NonSharedPartRecomposable));
  580. var container = new CompositionContainer(catalog);
  581. // Setup dependency
  582. CompositionBatch batch = new CompositionBatch();
  583. var valueKey = batch.AddExportedValue("Value", 21);
  584. container.Compose(batch);
  585. var export = container.GetExport<NonSharedPartRecomposable>();
  586. var exportedValue = export.Value;
  587. Assert.AreEqual(21, exportedValue.Value);
  588. container.ReleaseExport(export);
  589. // Recompose just to ensure we don't blow up, even though we don't expect anything to happen.
  590. batch = new CompositionBatch();
  591. batch.RemovePart(valueKey);
  592. batch.AddExportedValue("Value", 42);
  593. container.Compose(batch);
  594. Assert.AreEqual(21, exportedValue.Value, "Value should not be recomposed after ReleaseExport is called on it.");
  595. }
  596. [TestMethod]
  597. public void GetExportManualDisposeThenRecompose_NonSharedDisposableRecomposablePart_ShouldThrowComposition()
  598. {
  599. var catalog = new TypeCatalog(typeof(NonSharedPartDisposableRecomposable));
  600. var container = new CompositionContainer(catalog);
  601. // Setup dependency
  602. CompositionBatch batch = new CompositionBatch();
  603. var valueKey = batch.AddExportedValue("Value", 21);
  604. container.Compose(batch);
  605. var export = container.GetExport<NonSharedPartDisposableRecomposable>();
  606. var exportedValue = export.Value;
  607. Assert.AreEqual(21, exportedValue.Value);
  608. exportedValue.Dispose();
  609. // Recompose should cause a ObjectDisposedException.
  610. batch = new CompositionBatch();
  611. batch.RemovePart(valueKey);
  612. batch.AddExportedValue("Value", 42);
  613. CompositionAssert.ThrowsError(
  614. ErrorId.ImportEngine_PartCannotActivate, // Cannot activate part because
  615. ErrorId.ReflectionModel_ImportThrewException, // Import threw an exception
  616. RetryMode.DoNotRetry,
  617. () =>
  618. {
  619. container.Compose(batch);
  620. });
  621. }
  622. [Export]
  623. public class MyImporter
  624. {
  625. [Import(AllowDefault = true, AllowRecomposition = true, RequiredCreationPolicy = CreationPolicy.NonShared)]
  626. public AnyPartDisposable AnyPartDisposable { get; set; }
  627. }
  628. [TestMethod]
  629. public void RecomposeCausesOldImportedValuesToBeDisposed()
  630. {
  631. var cat = new AggregateCatalog();
  632. var cat1 = new TypeCatalog(typeof(AnyPartDisposable));
  633. cat.Catalogs.Add(new TypeCatalog(typeof (MyImporter)));
  634. cat.Catalogs.Add(cat1);
  635. var container = new CompositionContainer(cat);
  636. var importer = container.GetExportedValue<MyImporter>();
  637. var anyPart = importer.AnyPartDisposable;
  638. Assert.IsFalse(anyPart.IsDisposed);
  639. Assert.IsInstanceOfType(anyPart, typeof(AnyPartDisposable));
  640. // Remove the instance of MyClass1
  641. cat.Catalogs.Remove(cat1);
  642. Assert.IsNull(importer.AnyPartDisposable);
  643. Assert.IsTrue(anyPart.IsDisposed);
  644. }
  645. private static CompositionContainer CreateParentChildContainerWithNonSharedImporter()
  646. {
  647. var parentCat = CatalogFactory.CreateAttributed(typeof(AnyPartDisposable),
  648. typeof(AnyPartDisposableRecomposable),
  649. typeof(AnyPartRecomposable),
  650. typeof(AnyPartSimple));
  651. var parent = new CompositionContainer(parentCat);
  652. CompositionBatch batch = new CompositionBatch();
  653. batch.AddExportedValue("Value", 21);
  654. parent.Compose(batch);
  655. var childCat = CatalogFactory.CreateAttributed(typeof(NonSharedImporter));
  656. var child = new CompositionContainer(childCat, parent);
  657. return child;
  658. }
  659. [TestMethod]
  660. public void ChildContainerGetReleaseExport_NonSharedRoot_ShouldDisposeChain()
  661. {
  662. var child = CreateParentChildContainerWithNonSharedImporter();
  663. var export = child.GetExport<NonSharedImporter>();
  664. var exportedValue = export.Value;
  665. child.ReleaseExport(export);
  666. Assert.IsTrue(exportedValue.AnyPartDisposable.IsDisposed);
  667. Assert.IsTrue(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  668. }
  669. [TestMethod]
  670. public void ChildContainerAddRemovePart_NonSharedRoot_ShouldDisposeChain()
  671. {
  672. var child = CreateParentChildContainerWithNonSharedImporter();
  673. var exportedValue = new NonSharedImporter();
  674. CompositionBatch batch = new CompositionBatch();
  675. var part = batch.AddPart(exportedValue);
  676. child.Compose(batch);
  677. batch = new CompositionBatch();
  678. batch.RemovePart(part);
  679. child.Compose(batch);
  680. Assert.IsTrue(exportedValue.AnyPartDisposable.IsDisposed);
  681. Assert.IsTrue(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  682. }
  683. [TestMethod]
  684. public void ChildContainerAddRemovePart_NonSharedRoot_ShouldNotDisposeChain()
  685. {
  686. var child = CreateParentChildContainerWithNonSharedImporter();
  687. var exportedValue = child.GetExportedValue<NonSharedImporter>();
  688. child.Dispose();
  689. Assert.IsFalse(exportedValue.AnyPartDisposable.IsDisposed);
  690. Assert.IsFalse(exportedValue.AnyPartDisposableRecomposable.IsDisposed);
  691. }
  692. #if CLR40
  693. [TestMethod]
  694. public void NonSharedPart_Simple_ShouldBeCollected()
  695. {
  696. var catalog = new TypeCatalog(typeof(NonSharedPartSimple));
  697. var container = new CompositionContainer(catalog);
  698. var refTracker = new ReferenceTracker();
  699. refTracker.AddReferencesExpectedToBeCollected(
  700. container.GetExportedValue<NonSharedPartSimple>());
  701. refTracker.CollectAndAssert();
  702. GC.KeepAlive(container);
  703. }
  704. [TestMethod]
  705. public void ContainerDispose_SharedPart_ShouldCollectWholeObjectChain()
  706. {
  707. // Test only works properly with while using the real ConditionalWeakTable
  708. var container = GetContainer();
  709. var export = container.GetExport<SharedImporter>();
  710. var exportedValue = export.Value;
  711. container.Dispose();
  712. var refTracker = new ReferenceTracker();
  713. refTracker.AddReferencesExpectedToBeCollected(
  714. exportedValue,
  715. exportedValue.AnyPartDisposable,
  716. exportedValue.AnyPartDisposableRecomposable,
  717. exportedValue.AnyPartRecomposable,
  718. exportedValue.AnyPartSimple);
  719. export = null;
  720. exportedValue = null;
  721. refTracker.CollectAndAssert();
  722. GC.KeepAlive(container);
  723. }
  724. [TestMethod]
  725. public void AddRemovePart_SharedPart_ShouldCollectOnlyRoot()
  726. {
  727. var container = GetContainer();
  728. var exportedValue = new SharedImporter();
  729. CompositionBatch batch = new CompositionBatch();
  730. var part = batch.AddPart(exportedValue);
  731. container.Compose(batch);
  732. batch = null;
  733. batch = new CompositionBatch();
  734. batch.RemovePart(part);
  735. container.Compose(batch);
  736. batch = null;
  737. var refTracker = new ReferenceTracker();
  738. refTracker.AddReferencesExpectedToBeCollected(
  739. exportedValue);
  740. refTracker.AddReferencesNotExpectedToBeCollected(
  741. exportedValue.AnyPartDisposable,
  742. exportedValue.AnyPartDisposableRecomposable,
  743. exportedValue.AnyPartRecomposable,
  744. exportedValue.AnyPartSimple);
  745. part = null;
  746. exportedValue = null;
  747. refTracker.CollectAndAssert();
  748. GC.KeepAlive(container);
  749. }
  750. [TestMethod]
  751. public void AddRemovePart_NonSharedPart_ShouldCollectWholeObjectChain()
  752. {
  753. var container = GetContainer();
  754. var exportedValue = new NonSharedImporter();
  755. CompositionBatch batch = new CompositionBatch();
  756. var part = batch.AddPart(exportedValue);
  757. container.Compose(batch);
  758. batch = null;
  759. batch = new CompositionBatch();
  760. batch.RemovePart(part);
  761. container.Compose(batch);
  762. batch = null;
  763. var refTracker = new ReferenceTracker();
  764. refTracker.AddReferencesExpectedToBeCollected(
  765. exportedValue,
  766. exportedValue.AnyPartDisposable,
  767. exportedValue.AnyPartDisposableRecomposable,
  768. exportedValue.AnyPartRecomposable,
  769. exportedValue.AnyPartSimple);
  770. part = null;
  771. exportedValue = null;
  772. refTracker.CollectAndAssert();
  773. GC.KeepAlive(container);
  774. }
  775. [TestMethod]
  776. public void ContainerDispose_NonSharedPart_ShouldCollectWholeObjectChain()
  777. {
  778. // Test only works properly with while using the real ConditionalWeakTable
  779. var container = GetContainer();
  780. var export = container.GetExport<NonSharedImporter>();
  781. var exportedValue = export.Value;
  782. container.Dispose();
  783. var refTracker = new ReferenceTracker();
  784. refTracker.AddReferencesExpectedToBeCollected(
  785. exportedValue,
  786. exportedValue.AnyPartDisposable,
  787. exportedValue.AnyPartDisposableRecomposable,
  788. exportedValue.AnyPartRecomposable,
  789. exportedValue.AnyPartSimple);
  790. export = null;
  791. exportedValue = null;
  792. refTracker.CollectAndAssert();
  793. GC.KeepAlive(container);
  794. }
  795. [TestMethod]
  796. public void NonSharedImporter_ReleaseReference_ShouldCollectWholeChain()
  797. {
  798. var container = GetContainer();
  799. var export = container.GetExport<NonSharedImporter>();
  800. var exportedValue = export.Value;
  801. var refTracker = new ReferenceTracker();
  802. // Non-Disposable references in the chain should be GC'ed
  803. refTracker.AddReferencesExpectedToBeCollected(
  804. exportedValue,
  805. exportedValue.AnyPartRecomposable,
  806. exportedValue.AnyPartSimple);
  807. // Disposable references in the chain should NOT be GC'ed
  808. refTracker.AddReferencesNotExpectedToBeCollected(
  809. exportedValue.AnyPartDisposable,
  810. exportedValue.AnyPartDisposableRecomposable);
  811. export = null;
  812. exportedValue = null;
  813. refTracker.CollectAndAssert();
  814. GC.KeepAlive(container);
  815. }
  816. [TestMethod]
  817. public void ChildContainerDispose_NonSharedPart_ShouldOnlyCleanupChildAndSimpleNonShared()
  818. {
  819. var child = CreateParentChildContainerWithNonSharedImporter();
  820. var exportedValue = child.GetExportedValue<NonSharedImporter>();
  821. child.Dispose();
  822. var refTracker = new ReferenceTracker();
  823. refTracker.AddReferencesExpectedToBeCollected(
  824. exportedValue, // object in child
  825. exportedValue.AnyPartSimple, // No reference parent so collected.
  826. exportedValue.AnyPartRecomposable);
  827. // These are in the parent and will not be cleaned out
  828. refTracker.AddReferencesNotExpectedToBeCollected(
  829. exportedValue.AnyPartDisposable,
  830. exportedValue.AnyPartDisposableRecomposable);
  831. exportedValue = null;
  832. refTracker.CollectAndAssert();
  833. GC.KeepAlive(child);
  834. }
  835. [TestMethod]
  836. public void ChildContainerGetReleaseExport_NonSharedPart_ShouldCollectWholeObjectChain()
  837. {
  838. var child = CreateParentChildContainerWithNonSharedImporter();
  839. var export = child.GetExport<NonSharedImporter>();
  840. var exportedValue = export.Value;
  841. child.ReleaseExport(export);
  842. var refTracker = new ReferenceTracker();
  843. refTracker.AddReferencesExpectedToBeCollected(
  844. exportedValue,
  845. exportedValue.AnyPartDisposable,
  846. exportedValue.AnyPartDisposableRecomposable,
  847. exportedValue.AnyPartRecomposable,
  848. exportedValue.AnyPartSimple);
  849. export = null;
  850. exportedValue = null;
  851. refTracker.CollectAndAssert();
  852. GC.KeepAlive(child);
  853. }
  854. [TestMethod]
  855. public void NonSharedPart_RecomposableImport_NoReference_ShouldBeCollected()
  856. {
  857. var catalog = new TypeCatalog(typeof(NonSharedPartRecomposable));
  858. var container = new CompositionContainer(catalog);
  859. // Setup dependency
  860. CompositionBatch batch = new CompositionBatch();
  861. var valueKey = batch.AddExportedValue("Value", 21);
  862. container.Compose(batch);
  863. batch = null;
  864. var refTracker = new ReferenceTracker();
  865. refTracker.AddReferencesExpectedToBeCollected(
  866. container.GetExportedValue<NonSharedPartRecomposable>());
  867. refTracker.CollectAndAssert();
  868. // Recompose just to ensure we don't blow up, even though we don't expect anything to happen.
  869. batch = new CompositionBatch();
  870. batch.RemovePart(valueKey);
  871. batch.AddExportedValue("Value", 42);
  872. container.Compose(batch);
  873. batch = null;
  874. GC.KeepAlive(container);
  875. }
  876. [TestMethod]
  877. public void ChildContainerAddRemovePart_NonSharedPart_ShouldCollectWholeObjectChain()
  878. {
  879. var child = CreateParentChildContainerWithNonSharedImporter();
  880. var exportedValue = new NonSharedImporter();
  881. CompositionBatch batch = new CompositionBatch();
  882. var part = batch.AddPart(exportedValue);
  883. child.Compose(batch);
  884. batch = null;
  885. batch = new CompositionBatch();
  886. batch.RemovePart(part);
  887. child.Compose(batch);
  888. batch = null;
  889. var refTracker = new ReferenceTracker();
  890. refTracker.AddReferencesExpectedToBeCollected(
  891. exportedValue,
  892. exportedValue.AnyPartDisposable,
  893. exportedValue.AnyPartDisposableRecomposable,
  894. exportedValue.AnyPartRecomposable,
  895. exportedValue.AnyPartSimple);
  896. part = null;
  897. exportedValue = null;
  898. refTracker.CollectAndAssert();
  899. GC.KeepAlive(child);
  900. }
  901. [TestMethod]
  902. public void GetReleaseExport_SharedPart_ShouldCollectOnlyRoot()
  903. {
  904. var container = GetContainer();
  905. var export = container.GetExport<SharedImporter>();
  906. var exportedValue = export.Value;
  907. container.ReleaseExport(export);
  908. var refTracker = new ReferenceTracker();
  909. refTracker.AddReferencesExpectedToBeCollected(
  910. exportedValue);
  911. refTracker.AddReferencesNotExpectedToBeCollected(
  912. exportedValue.AnyPartDisposable,
  913. exportedValue.AnyPartDisposableRecomposable,
  914. exportedValue.AnyPartRecomposable,
  915. exportedValue.AnyPartSimple);
  916. export = null;
  917. exportedValue = null;
  918. refTracker.CollectAndAssert();
  919. GC.KeepAlive(container);
  920. }
  921. [TestMethod]
  922. public void GetReleaseExport_NonSharedPart_ShouldCollectWholeObjectChain()
  923. {
  924. var container = GetContainer();
  925. var export = container.GetExport<NonSharedImporter>();
  926. var exportedValue = export.Value;
  927. container.ReleaseExport(export);
  928. var refTracker = new ReferenceTracker();
  929. refTracker.AddReferencesExpectedToBeCollected(
  930. exportedValue,
  931. exportedValue.AnyPartDisposable,
  932. exportedValue.AnyPartDisposableRecomposable,
  933. exportedValue.AnyPartRecomposable,
  934. exportedValue.AnyPartSimple);
  935. export = null;
  936. exportedValue = null;
  937. refTracker.CollectAndAssert();
  938. GC.KeepAlive(container);
  939. }
  940. [TestMethod]
  941. public void ReleaseExports_ShouldWorkWithExportCollection()
  942. {
  943. var container = GetContainer();
  944. var exports = container.GetExports<NonSharedImporter>();
  945. Assert.IsTrue(exports.Count() > 0);
  946. var exportedValues = exports.Select(export => export.Value).ToList();
  947. container.ReleaseExports(exports);
  948. foreach (var obj in exportedValues)
  949. {
  950. Assert.IsTrue(obj.AnyPartDisposable.IsDisposed);
  951. Assert.IsTrue(obj.AnyPartDisposableRecomposable.IsDisposed);
  952. }
  953. }
  954. #endif
  955. }
  956. }