1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
7 using System.Collections.Generic;
\r
8 using System.ComponentModel.Composition.Hosting;
\r
9 using System.ComponentModel.Composition.Factories;
\r
12 using System.Linq.Expressions;
\r
13 using System.UnitTesting;
\r
14 using Microsoft.VisualStudio.TestTools.UnitTesting;
\r
15 using System.ComponentModel.Composition.Primitives;
\r
16 using System.Reflection;
\r
18 namespace System.ComponentModel.Composition
\r
21 public class DirectoryCatalogTests
\r
23 internal const string NonExistentSearchPattern = "*.NonExistentSearchPattern";
\r
26 public void ICompositionElementDisplayName_ShouldIncludeCatalogTypeNameAndDirectoryPath()
\r
28 var paths = GetPathExpectations();
\r
30 foreach (var path in paths)
\r
32 var catalog = (ICompositionElement)CreateDirectoryCatalog(path, NonExistentSearchPattern);
\r
34 string expected = string.Format("DirectoryCatalog (Path=\"{0}\")", path);
\r
36 Assert.AreEqual(expected, catalog.DisplayName);
\r
41 public void ICompositionElementDisplayName_ShouldIncludeDerivedCatalogTypeNameAndAssemblyFullName()
\r
43 var paths = GetPathExpectations();
\r
45 foreach (var path in paths)
\r
47 var catalog = (ICompositionElement)new DerivedDirectoryCatalog(path, NonExistentSearchPattern);
\r
49 string expected = string.Format("DerivedDirectoryCatalog (Path=\"{0}\")", path);
\r
51 Assert.AreEqual(expected, catalog.DisplayName);
\r
56 public void ToString_ShouldReturnICompositionElementDisplayName()
\r
58 var paths = GetPathExpectations();
\r
60 foreach (var path in paths)
\r
62 var catalog = (ICompositionElement)CreateDirectoryCatalog(path, NonExistentSearchPattern);
\r
64 Assert.AreEqual(catalog.DisplayName, catalog.ToString());
\r
69 public void ICompositionElementDisplayName_WhenCatalogDisposed_ShouldNotThrow()
\r
71 var catalog = CreateDirectoryCatalog();
\r
74 var displayName = ((ICompositionElement)catalog).DisplayName;
\r
78 public void ICompositionElementOrigin_WhenCatalogDisposed_ShouldNotThrow()
\r
80 var catalog = CreateDirectoryCatalog();
\r
83 var origin = ((ICompositionElement)catalog).Origin;
\r
87 public void Parts_WhenCatalogDisposed_ShouldThrowObjectDisposed()
\r
89 var catalog = CreateDirectoryCatalog();
\r
92 ExceptionAssert.ThrowsDisposed(catalog, () =>
\r
94 var parts = catalog.Parts;
\r
99 public void GetExports_WhenCatalogDisposed_ShouldThrowObjectDisposed()
\r
101 var catalog = CreateDirectoryCatalog();
\r
103 var definition = ImportDefinitionFactory.Create();
\r
105 ExceptionAssert.ThrowsDisposed(catalog, () =>
\r
107 catalog.GetExports(definition);
\r
112 public void Refresh_WhenCatalogDisposed_ShouldThrowObjectDisposed()
\r
114 var catalog = CreateDirectoryCatalog();
\r
117 ExceptionAssert.ThrowsDisposed(catalog, () =>
\r
124 public void ToString_WhenCatalogDisposed_ShouldNotThrow()
\r
126 var catalog = CreateDirectoryCatalog();
\r
129 catalog.ToString();
\r
133 public void GetExports_NullAsConstraintArgument_ShouldThrowArgumentNull()
\r
135 var catalog = CreateDirectoryCatalog();
\r
137 ExceptionAssert.ThrowsArgument<ArgumentNullException>("definition", () =>
\r
139 catalog.GetExports((ImportDefinition)null);
\r
145 public void Dispose_ShouldNotThrow()
\r
147 using (var catalog = CreateDirectoryCatalog())
\r
153 public void Dispose_CanBeCalledMultipleTimes()
\r
155 var catalog = CreateDirectoryCatalog();
\r
163 public void AddAssembly1_NonExistentUriAsAssemblyFileNameArgument_ShouldNotSupportedException()
\r
165 ExceptionAssert.Throws<NotSupportedException>(() =>
\r
167 var catalog = new DirectoryCatalog("http://microsoft.com/myassembly.dll");
\r
172 public void AddAssembly1_NullPathArgument_ShouldThrowArugmentNull()
\r
174 ExceptionAssert.Throws<ArgumentNullException>(() =>
\r
175 new DirectoryCatalog((string)null));
\r
179 public void AddAssembly1_EmptyPathArgument_ShouldThrowArugment()
\r
181 ExceptionAssert.Throws<ArgumentException>(() =>
\r
182 new DirectoryCatalog(""));
\r
186 public void AddAssembly1_InvalidPathName_ShouldThrowDirectoryNotFound()
\r
188 ExceptionAssert.Throws<ArgumentException>(() =>
\r
190 var c1 = new DirectoryCatalog("*");
\r
195 public void AddAssembly1_TooLongPathNameArgument_ShouldThrowPathTooLongException()
\r
197 ExceptionAssert.Throws<PathTooLongException>(() =>
\r
199 var c1 = new DirectoryCatalog(@"c:\This is a very long path\And Just to make sure\We will continue to make it very long\This is a very long path\And Just to make sure\We will continue to make it very long\This is a very long path\And Just to make sure\We will continue to make it very long\myassembly.dll");
\r
205 public void Parts()
\r
207 using (var directory = CreateTemporaryDirectory())
\r
209 var catalog = new DirectoryCatalog(directory.DirectoryPath);
\r
210 Assert.IsNotNull(catalog.Parts);
\r
211 Assert.IsTrue(catalog.Parts.Count() > 0);
\r
216 public void Parts_ShouldSetDefinitionOriginToCatalogItself()
\r
218 using (var directory = CreateTemporaryDirectory())
\r
220 var catalog = new DirectoryCatalog(directory.DirectoryPath);
\r
221 Assert.IsTrue(catalog.Parts.Count() > 0);
\r
223 foreach (ICompositionElement definition in catalog.Parts)
\r
225 Assert.AreSame(catalog, definition.Origin);
\r
231 public void Path_ValidPath_ShouldBeFine()
\r
233 using (var directory = CreateTemporaryDirectory())
\r
235 var expectations = new ExpectationCollection<string, string>();
\r
237 expectations.Add(".", ".");
\r
238 expectations.Add(FileIO.RootTemporaryDirectoryName, FileIO.RootTemporaryDirectoryName);
\r
239 expectations.Add(FileIO.GetRootTemporaryDirectory(), FileIO.GetRootTemporaryDirectory());
\r
240 expectations.Add(directory.DirectoryPath, directory.DirectoryPath);
\r
242 foreach (var e in expectations)
\r
244 var cat = CreateDirectoryCatalog(e.Input, NonExistentSearchPattern);
\r
246 Assert.AreEqual(e.Output, cat.Path);
\r
252 public void FullPath_ValidPath_ShouldBeFine()
\r
254 using (var directory = CreateTemporaryDirectory())
\r
256 var expectations = new ExpectationCollection<string, string>();
\r
258 // Ensure the path is always normalized properly.
\r
259 string rootTempPath = Path.GetFullPath(FileIO.GetRootTemporaryDirectory()).ToUpperInvariant();
\r
261 // Note: These relative paths work properly because the unit test temporary directories are always
\r
262 // created as a subfolder off the AppDomain.CurrentDomain.BaseDirectory.
\r
263 expectations.Add(".", Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ".")).ToUpperInvariant());
\r
264 expectations.Add(FileIO.RootTemporaryDirectoryName, rootTempPath);
\r
265 expectations.Add(FileIO.GetRootTemporaryDirectory(), rootTempPath);
\r
266 expectations.Add(directory.DirectoryPath, Path.GetFullPath(directory.DirectoryPath).ToUpperInvariant());
\r
268 foreach (var e in expectations)
\r
270 var cat = CreateDirectoryCatalog(e.Input, NonExistentSearchPattern);
\r
272 Assert.AreEqual(e.Output, cat.FullPath);
\r
278 public void LoadedFiles_EmptyDirectory_ShouldBeFine()
\r
280 using (var directory = new TemporaryDirectory())
\r
282 var cat = new DirectoryCatalog(directory.DirectoryPath);
\r
284 Assert.AreEqual(0, cat.LoadedFiles.Count);
\r
289 public void LoadedFiles_ContainsMultipleDllsAndSomeNonDll_ShouldOnlyContainDlls()
\r
291 using (var directory = new TemporaryDirectory())
\r
293 // Add one text file
\r
294 using (File.CreateText(Path.Combine(directory.DirectoryPath, "Test.txt"))) { }
\r
297 string dll1 = Path.Combine(directory.DirectoryPath, "Test1.dll");
\r
298 string dll2 = Path.Combine(directory.DirectoryPath, "Test2.dll");
\r
299 File.Copy(Assembly.GetExecutingAssembly().Location, dll1);
\r
300 File.Copy(Assembly.GetExecutingAssembly().Location, dll2);
\r
302 var cat = new DirectoryCatalog(directory.DirectoryPath);
\r
304 CollectionAssert.AreEquivalent(new string[] { dll1.ToUpperInvariant(), dll2.ToUpperInvariant() },
\r
310 public void Constructor_InvalidAssembly_ShouldBeFine()
\r
312 using (var directory = CreateTemporaryDirectory())
\r
314 using (File.CreateText(Path.Combine(directory.DirectoryPath, "Test.dll"))) { }
\r
315 var cat = new DirectoryCatalog(directory.DirectoryPath);
\r
320 public void Constructor_NonExistentDirectory_ShouldThrow()
\r
322 using (var directory = CreateTemporaryDirectory())
\r
324 ExceptionAssert.Throws<DirectoryNotFoundException>( () =>
\r
325 new DirectoryCatalog(directory.DirectoryPath + @"\NonexistentDirectoryWithoutEndingSlash"));
\r
327 ExceptionAssert.Throws<DirectoryNotFoundException>( () =>
\r
328 new DirectoryCatalog(directory.DirectoryPath + @"\NonexistentDirectoryWithEndingSlash\"));
\r
334 public void Constructor_PassExistingFileName_ShouldThrow()
\r
336 using (var directory = CreateTemporaryDirectory())
\r
338 using (File.CreateText(Path.Combine(directory.DirectoryPath, "Test.txt"))) { }
\r
339 ExceptionAssert.Throws<IOException>(() =>
\r
340 new DirectoryCatalog(Path.Combine(directory.DirectoryPath, "Test.txt")));
\r
345 public void Constructor_PassNonExistingFileName_ShouldThrow()
\r
347 using (var directory = CreateTemporaryDirectory())
\r
349 ExceptionAssert.Throws<DirectoryNotFoundException>(() =>
\r
350 new DirectoryCatalog(Path.Combine(directory.DirectoryPath, "NonExistingFile.txt")));
\r
355 public void Refresh_AssemblyAdded_ShouldFireOnChanged()
\r
357 using (var directory = new TemporaryDirectory())
\r
359 bool changedFired = false;
\r
360 bool changingFired = false;
\r
361 var cat = new DirectoryCatalog(directory.DirectoryPath);
\r
363 Assert.AreEqual(0, cat.Parts.Count(), "Catalog should initially be empty");
\r
365 cat.Changing += new EventHandler<ComposablePartCatalogChangeEventArgs>((o, e) =>
\r
367 Assert.AreEqual(0, cat.Parts.Count(), "Catalog changes should NOT have been completeed yet");
\r
368 changingFired = true;
\r
371 cat.Changed += new EventHandler<ComposablePartCatalogChangeEventArgs>((o, e) =>
\r
373 Assert.AreNotEqual(0, cat.Parts.Count(), "Catalog changes should have been completeed");
\r
374 changedFired = true;
\r
378 File.Copy(Assembly.GetExecutingAssembly().Location, Path.Combine(directory.DirectoryPath, "Test.dll"));
\r
382 Assert.IsTrue(changingFired);
\r
383 Assert.IsTrue(changedFired);
\r
388 public void Refresh_AssemblyRemoved_ShouldFireOnChanged()
\r
390 using (var directory = CreateTemporaryDirectory())
\r
392 string file = Path.Combine(directory.DirectoryPath, "Test.dll");
\r
393 File.Copy(Assembly.GetExecutingAssembly().Location, file);
\r
394 bool changedFired = false;
\r
395 var cat = new DirectoryCatalog(directory.DirectoryPath);
\r
397 cat.Changed += new EventHandler<ComposablePartCatalogChangeEventArgs>((o, e) =>
\r
398 changedFired = true);
\r
400 // This assembly can be deleted because it was already loaded by the CLR in another context
\r
401 // in another location so it isn't locked on disk.
\r
406 Assert.IsTrue(changedFired);
\r
411 public void Refresh_NoChanges_ShouldNotFireOnChanged()
\r
413 using (var directory = CreateTemporaryDirectory())
\r
415 var cat = new DirectoryCatalog(directory.DirectoryPath);
\r
417 cat.Changed += new EventHandler<ComposablePartCatalogChangeEventArgs>((o, e) =>
\r
418 Assert.Fail("Should not recieve any change notifications"));
\r
425 public void Refresh_DirectoryRemoved_ShouldThrowDirectoryNotFound()
\r
427 DirectoryCatalog cat;
\r
428 using (var directory = CreateTemporaryDirectory())
\r
430 cat = new DirectoryCatalog(directory.DirectoryPath);
\r
433 ExceptionAssert.Throws<DirectoryNotFoundException>(RetryMode.DoNotRetry, () =>
\r
438 public void GetExports()
\r
440 using (var directory = CreateTemporaryDirectory())
\r
442 var catalog = new AggregateCatalog();
\r
443 Expression<Func<ExportDefinition, bool>> constraint = (ExportDefinition exportDefinition) => exportDefinition.ContractName == AttributedModelServices.GetContractName(typeof(MyExport));
\r
444 IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> matchingExports = null;
\r
446 matchingExports = catalog.GetExports(constraint);
\r
447 Assert.IsNotNull(matchingExports);
\r
448 Assert.IsTrue(matchingExports.Count() == 0);
\r
450 var testsDirectoryCatalog = new DirectoryCatalog(directory.DirectoryPath);
\r
451 catalog.Catalogs.Add(testsDirectoryCatalog);
\r
452 matchingExports = catalog.GetExports(constraint);
\r
454 Assert.IsNotNull(matchingExports);
\r
455 Assert.IsTrue(matchingExports.Count() >= 0);
\r
457 IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> expectedMatchingExports = catalog.Parts
\r
458 .SelectMany(part => part.ExportDefinitions, (part, export) => new Tuple<ComposablePartDefinition, ExportDefinition>(part, export))
\r
459 .Where(partAndExport => partAndExport.Item2.ContractName == AttributedModelServices.GetContractName(typeof(MyExport)));
\r
461 Assert.IsTrue(matchingExports.SequenceEqual(expectedMatchingExports));
\r
463 catalog.Catalogs.Remove(testsDirectoryCatalog);
\r
464 matchingExports = catalog.GetExports(constraint);
\r
465 Assert.IsNotNull(matchingExports);
\r
466 Assert.IsTrue(matchingExports.Count() == 0);
\r
471 public void AddAndRemoveDirectory()
\r
473 using (var directory = CreateTemporaryDirectory())
\r
475 var cat = new AggregateCatalog();
\r
476 var container = new CompositionContainer(cat);
\r
478 Assert.IsFalse(container.IsPresent<MyExport>());
\r
480 var dir1 = new DirectoryCatalog(directory.DirectoryPath);
\r
481 cat.Catalogs.Add(dir1);
\r
482 Assert.IsTrue(container.IsPresent<MyExport>());
\r
484 cat.Catalogs.Remove(dir1);
\r
486 Assert.IsFalse(container.IsPresent<MyExport>());
\r
491 public void AddDirectoryNotFoundException()
\r
493 ExceptionAssert.Throws<DirectoryNotFoundException>(() =>
\r
495 var cat = new DirectoryCatalog("Directory That Should Never Exist tadfasdfasdfsdf");
\r
500 public void ExecuteOnCreationThread()
\r
502 // Add a proper test for event notification on caller thread
\r
506 private DirectoryCatalog CreateDirectoryCatalog()
\r
508 return CreateDirectoryCatalog(FileIO.GetNewTemporaryDirectory());
\r
511 private DirectoryCatalog CreateDirectoryCatalog(string path)
\r
513 return new DirectoryCatalog(path);
\r
516 private DirectoryCatalog CreateDirectoryCatalog(string path, string searchPattern)
\r
518 return new DirectoryCatalog(path, searchPattern);
\r
521 private TemporaryDirectory CreateTemporaryDirectory()
\r
523 return new TemporaryFileCopier(typeof(DirectoryCatalogTests).Assembly.Location);
\r
526 public IEnumerable<string> GetPathExpectations()
\r
528 yield return AppDomain.CurrentDomain.BaseDirectory;
\r
529 yield return AppDomain.CurrentDomain.BaseDirectory + @"\";
\r
533 private class DerivedDirectoryCatalog : DirectoryCatalog
\r
535 public DerivedDirectoryCatalog(string path, string searchPattern)
\r
536 : base(path, searchPattern)
\r