diff --git a/src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileReaderTests2.cs b/src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileReaderTests2.cs
deleted file mode 100644
index dd05a39d0..000000000
--- a/src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileReaderTests2.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
-
-using NSubstitute;
-using NUnit.Engine.Internal.FileSystemAccess;
-using NUnit.Framework;
-using System.IO;
-
-namespace NUnit.Engine.Internal.Tests
-{
- ///
- /// Tests the implementation of .
- ///
- /// All tests in this fixture modify the file-system.
- [TestFixture, Category("WritesToDisk"), NonParallelizable]
- public class AddinsFileReaderTests2
- {
- private readonly string tempFileLocation;
-
- public AddinsFileReaderTests2()
- {
- string[] content = new string[]
- {
- "# This line is a comment and is ignored. The next (blank) line is ignored as well.",
- "",
- "*.dll # include all dlls in the same directory",
- "addins/*.dll # include all dlls in the addins directory too",
- "special/myassembly.dll # include a specific dll in a special directory",
- "some/other/directory/ # process another directory, which may contain its own addins file",
- "# note that an absolute path is allowed, but is probably not a good idea in most cases",
- "/unix/absolute/directory"
- };
-
- this.tempFileLocation = Path.GetTempFileName();
-
- using (var writer = new StreamWriter(this.tempFileLocation))
- {
- foreach (var line in content)
- {
- writer.WriteLine(line);
- }
- }
- }
-
- [TearDown]
- public void DeleteTestFile()
- {
- File.Delete(this.tempFileLocation);
- }
-
- [Test]
- public void Read_IFile()
- {
- var reader = new AddinsFileReader();
- var file = Substitute.For();
- file.FullName.Returns(this.tempFileLocation);
-
- var result = reader.Read(file);
-
- Assert.That(result, Has.Count.EqualTo(5));
- Assert.That(result, Contains.Item("*.dll"));
- Assert.That(result, Contains.Item("addins/*.dll"));
- Assert.That(result, Contains.Item("special/myassembly.dll"));
- Assert.That(result, Contains.Item("some/other/directory/"));
- Assert.That(result, Contains.Item("/unix/absolute/directory"));
- }
- }
-}
diff --git a/src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileReaderTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileTests.cs
similarity index 51%
rename from src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileReaderTests.cs
rename to src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileTests.cs
index 0c46db71e..25d4363b1 100644
--- a/src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileReaderTests.cs
+++ b/src/NUnitEngine/nunit.engine.core.tests/Internal/AddinsFileTests.cs
@@ -5,28 +5,27 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Text;
namespace NUnit.Engine.Internal.Tests
{
///
- /// Tests the implementation of .
+ /// Tests the implementation of .
///
[TestFixture]
- public class AddinsFileReaderTests
+ public class AddinsFileTests
{
[Test]
public void Read_IFile_Null()
{
- var reader = new AddinsFileReader();
-
- Assert.That(() => reader.Read((IFile)null), Throws.ArgumentNullException);
+ Assert.That(() => AddinsFile.Read((IFile)null), Throws.ArgumentNullException);
}
[Test]
public void Read_Stream()
{
- var input = string.Join(Environment.NewLine, new string[]
+ var content = new[]
{
"# This line is a comment and is ignored. The next (blank) line is ignored as well.",
"",
@@ -36,59 +35,59 @@ public void Read_Stream()
"some/other/directory/ # process another directory, which may contain its own addins file",
"# note that an absolute path is allowed, but is probably not a good idea in most cases",
"/unix/absolute/directory"
- });
-
- IEnumerable result;
+ };
- using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(input)))
+ using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, content))))
{
- // Act
- result = AddinsFileReader.Read(stream);
+ var result = AddinsFile.Read(stream);
+
+ Assert.That(result, Has.Count.EqualTo(8));
+ for (int i = 0; i < 8; i++)
+ Assert.That(result[i], Is.EqualTo(
+ new AddinsFileEntry(i + 1, content[i])));
}
+ }
- Assert.That(result, Has.Count.EqualTo(5));
- Assert.That(result, Contains.Item("*.dll"));
- Assert.That(result, Contains.Item("addins/*.dll"));
- Assert.That(result, Contains.Item("special/myassembly.dll"));
- Assert.That(result, Contains.Item("some/other/directory/"));
- Assert.That(result, Contains.Item("/unix/absolute/directory"));
+ [Test]
+ public void Read_InvalidEntry()
+ {
+ var content = "// This is not valid";
+ using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
+ {
+ Assert.That(() => AddinsFile.Read(stream), Throws.Exception);
+ }
}
[Test]
[Platform("win")]
public void Read_Stream_TransformBackslash_Windows()
{
- var input = string.Join(Environment.NewLine, new string[]
- {
- "c:\\windows\\absolute\\directory"
- });
+ var content = "c:\\windows\\absolute\\directory";
- IEnumerable result;
-
- using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(input)))
+ using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
{
- // Act
- result = AddinsFileReader.Read(stream);
- }
+ var result = AddinsFile.Read(stream);
- Assert.That(result, Has.Count.EqualTo(1));
- Assert.That(result, Contains.Item("c:/windows/absolute/directory"));
+ Assert.That(result, Has.Count.EqualTo(1));
+ Assert.That(result[0], Is.EqualTo(new AddinsFileEntry(1, content)));
+ Assert.That(result[0].Text, Is.EqualTo("c:/windows/absolute/directory"));
+ }
}
[Test]
[Platform("linux,macosx,unix")]
public void Read_Stream_TransformBackslash_NonWindows()
{
- IEnumerable result;
+ var content = "this/is/a\\ path\\ with\\ spaces/";
- using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("this/is/a\\ path\\ with\\ spaces/")))
+ using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
{
- // Act
- result = AddinsFileReader.Read(stream);
- }
+ var result = AddinsFile.Read(stream);
- Assert.That(result, Has.Count.EqualTo(1));
- Assert.That(result, Contains.Item("this/is/a\\ path\\ with\\ spaces/"));
+ Assert.That(result, Has.Count.EqualTo(1));
+ Assert.That(result[0], Is.EqualTo(new AddinsFileEntry(1, content)));
+ Assert.That(result[0].Text, Is.EqualTo(content));
+ }
}
}
}
diff --git a/src/NUnitEngine/nunit.engine.core.tests/Internal/Backports/PathTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Internal/Backports/PathTests.cs
deleted file mode 100644
index 19034cf35..000000000
--- a/src/NUnitEngine/nunit.engine.core.tests/Internal/Backports/PathTests.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
-
-using NUnit.Framework;
-
-namespace NUnit.Engine.Internal.Backports.Tests
-{
- [TestFixture]
- public sealed class PathTests
- {
- [Platform("win")]
- [TestCase("c:\\", ExpectedResult = true)]
- [TestCase("c:\\foo\\bar\\", ExpectedResult = true)]
- [TestCase("c:/foo/bar/", ExpectedResult = true)]
- [TestCase("c:\\foo\\bar", ExpectedResult = true)]
- [TestCase("c:/foo/bar", ExpectedResult = true)]
- [TestCase("c:bar\\", ExpectedResult = false)]
- [TestCase("c:bar/", ExpectedResult = false)]
- [TestCase("c:bar", ExpectedResult = false)]
- [TestCase("ä:\\bar", ExpectedResult = false)]
- [TestCase("ä://bar", ExpectedResult = false)]
- [TestCase("\\\\server01\\foo", ExpectedResult = true)]
- [TestCase("\\server01\\foo", ExpectedResult = false)]
- [TestCase("c:", ExpectedResult = false)]
- [TestCase("/foo/bar", ExpectedResult = false)]
- [TestCase("/", ExpectedResult = false)]
- [TestCase("\\a\\b", ExpectedResult = false)]
- public bool IsPathFullyQualified_Windows(string path)
- {
- return Path.IsPathFullyQualified(path);
- }
-
- [Platform("linux,macosx,unix")]
- [TestCase("/foo/bar", ExpectedResult = true)]
- [TestCase("/", ExpectedResult = true)]
- [TestCase("/z", ExpectedResult = true)]
- [TestCase("c:\\foo\\bar\\", ExpectedResult = false)]
- [TestCase("c:/foo/bar/", ExpectedResult = false)]
- [TestCase("c:\\foo\\bar", ExpectedResult = false)]
- [TestCase("c:/foo/bar", ExpectedResult = false)]
- [TestCase("c:bar\\", ExpectedResult = false)]
- [TestCase("c:bar/", ExpectedResult = false)]
- [TestCase("c:bar", ExpectedResult = false)]
- [TestCase("ä:\\bar", ExpectedResult = false)]
- [TestCase("ä://bar", ExpectedResult = false)]
- [TestCase("\\\\server01\\foo", ExpectedResult = false)]
- [TestCase("\\server01\\foo", ExpectedResult = false)]
- [TestCase("c:", ExpectedResult = false)]
- [TestCase("\\a\\b", ExpectedResult = false)]
- public bool IsPathFullyQualified_NonWindows(string path)
- {
- return Path.IsPathFullyQualified(path);
- }
-
- [Test]
- public void IsPathFullyQualified_PathIsNull()
- {
- Assert.That(() => Path.IsPathFullyQualified(null), Throws.ArgumentNullException);
- }
- }
-}
diff --git a/src/NUnitEngine/nunit.engine.core.tests/Internal/PathUtilTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Internal/PathUtilTests.cs
index 44cc4799c..c8d6fd1d4 100644
--- a/src/NUnitEngine/nunit.engine.core.tests/Internal/PathUtilTests.cs
+++ b/src/NUnitEngine/nunit.engine.core.tests/Internal/PathUtilTests.cs
@@ -63,9 +63,36 @@ public void IsFullyQualifiedWindowsPath_PathIsNull()
{
Assert.That(() => PathUtils.IsFullyQualifiedWindowsPath(null), Throws.ArgumentNullException);
}
+
+ [TestCase("X")]
+ [TestCase("X/")]
+ [TestCase("/X/")]
+ [TestCase("\\X\\")]
+ [TestCase("X/Y/Z")]
+ [TestCase("X/Y/Z/")]
+ [TestCase("/X/Y/Z")]
+ [TestCase("/X/Y/Z/")]
+ [TestCase("\\X\\Y\\Z\\")]
+ [TestCase("C:X/Y/Z/")]
+ [TestCase("C:/X/Y/Z")]
+ [TestCase("C:/X/Y/Z/")]
+ [TestCase("C:\\X\\Y\\Z\\")]
+ public void IsValidPath(string path)
+ {
+ Assert.That(PathUtils.IsValidPath(path), Is.True);
+ }
+
+ [TestCase(":")]
+ [TestCase("?")]
+ [TestCase("*")]
+ [TestCase("// Spurious comment")]
+ public void IsValidPath_Fails(string path)
+ {
+ Assert.That(PathUtils.IsValidPath(path), Is.False);
+ }
}
- [TestFixture]
+ [TestFixture]
public class PathUtilDefaultsTests : PathUtils
{
[Test]
diff --git a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs
index c74972521..14afab18b 100644
--- a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs
+++ b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionManagerTests.cs
@@ -37,39 +37,53 @@ public class ExtensionManagerTests
};
private static readonly int[] KnownExtensionPointCounts = { 1, 1, 1, 2, 1, 1 };
+
+ private readonly string[] KnownExtensions = {
+ "NUnit.Engine.Tests.DummyFrameworkDriverExtension",
+ "NUnit.Engine.Tests.DummyProjectLoaderExtension",
+ "NUnit.Engine.Tests.DummyResultWriterExtension",
+ "NUnit.Engine.Tests.DummyEventListenerExtension",
+ "NUnit.Engine.Tests.DummyServiceExtension",
+ "NUnit.Engine.Tests.DummyDisabledExtension",
+ "NUnit.Engine.Tests.V2DriverExtension"
+ };
#pragma warning restore 414
[SetUp]
- public void CreateService()
+ public void CreateExtensionManager()
{
_extensionManager = new ExtensionManager();
- // Rather than actually starting the service, which would result
- // in finding the extensions actually in use on the current system,
- // we simulate the start using this assemblies dummy extensions.
+ // Find actual extension points.
_extensionManager.FindExtensionPoints(typeof(CoreEngine).Assembly);
_extensionManager.FindExtensionPoints(typeof(ITestEngine).Assembly);
+ // Find dummy extensions in this test assembly.
_extensionManager.FindExtensionsInAssembly(new ExtensionAssembly(GetType().Assembly.Location, false));
}
[Test]
- public void StartService_UseFileSystemAbstraction()
+ public void AllKnownExtensionPointsAreFound()
{
- var addinsReader = Substitute.For();
- var fileSystem = Substitute.For();
- var service = new ExtensionService(addinsReader, fileSystem);
- var workingDir = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
-
- service.StartService();
+ Assert.That(_extensionManager.ExtensionPoints.Select(ep => ep.Path),
+ Is.EquivalentTo(KnownExtensionPointPaths));
+ }
- fileSystem.Received().GetDirectory(workingDir);
+ [Test]
+ public void AllKnownExtensionsAreFound()
+ {
+ Assert.That(_extensionManager.Extensions.Select(ext => ext.TypeName),
+ Is.EquivalentTo(KnownExtensions));
}
[Test]
- public void AllExtensionPointsAreKnown()
+ public void AllKnownExtensionsAreEnabledAsRequired()
{
- Assert.That(_extensionManager.ExtensionPoints.Select(ep => ep.Path), Is.EquivalentTo(KnownExtensionPointPaths));
+ foreach (var node in _extensionManager.Extensions)
+ {
+ var shouldBeEnabled = node.TypeName != "NUnit.Engine.Tests.DummyDisabledExtension";
+ Assert.That(node.Enabled, Is.EqualTo(shouldBeEnabled));
+ }
}
[Test, Sequential]
@@ -94,25 +108,6 @@ public void CanGetExtensionPointByType(
Assert.That(ep.TypeName, Is.EqualTo(type.FullName));
}
-#pragma warning disable 414
- private static readonly string[] KnownExtensions = {
- "NUnit.Engine.Tests.DummyFrameworkDriverExtension",
- "NUnit.Engine.Tests.DummyProjectLoaderExtension",
- "NUnit.Engine.Tests.DummyResultWriterExtension",
- "NUnit.Engine.Tests.DummyEventListenerExtension",
- "NUnit.Engine.Tests.DummyServiceExtension",
- "NUnit.Engine.Tests.V2DriverExtension"
- };
-#pragma warning restore 414
-
- [TestCaseSource(nameof(KnownExtensions))]
- public void CanListExtensions(string typeName)
- {
- Assert.That(_extensionManager.Extensions,
- Has.One.Property(nameof(ExtensionNode.TypeName)).EqualTo(typeName)
- .And.Property(nameof(ExtensionNode.Enabled)).True);
- }
-
[Test, Sequential]
public void ExtensionsAreAddedToExtensionPoint(
[ValueSource(nameof(KnownExtensionPointPaths))] string path,
@@ -280,477 +275,5 @@ private static string GetSiblingDirectory(string dir)
var file = new FileInfo(typeof(ExtensionManagerTests).Assembly.Location);
return Path.Combine(file.Directory.Parent.FullName, dir);
}
-
- [Test]
- public void StartService_ReadsAddinsFile()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem);
-
- // Act
- sut.StartService();
-
- // Assert
- startDirectory.Received().GetFiles("*.addins");
- addinsReader.Received().Read(addinsFile);
- }
-
- [Test]
- public void StartService_ReadsAddinsFilesFromMultipleDirectories()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var subdirectoryPath = Path.Combine(startDirectoryPath, "subdirectory");
- var subdirectory = Substitute.For();
- subdirectory.FullName.Returns(subdirectoryPath);
- subdirectory.GetDirectories(Arg.Any(), Arg.Any()).Returns(new IDirectory[] { });
- subdirectory.GetFiles(Arg.Any()).Returns(new IFile[] { });
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- var addinsFile2 = Substitute.For();
- addinsFile2.Parent.Returns(subdirectory);
- addinsFile2.FullName.Returns(Path.Combine(subdirectoryPath, "second.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- startDirectory.GetDirectories("subdirectory", SearchOption.TopDirectoryOnly).Returns(new[] { subdirectory });
- subdirectory.GetFiles(Arg.Any()).Returns(ci => (string)ci[0] == "*.addins" ? new[] { addinsFile2 } : new IFile[] { });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- fileSystem.GetDirectory(subdirectoryPath).Returns(subdirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { "subdirectory/" });
- var sut = new ExtensionService(addinsReader, fileSystem);
-
- // Act
- sut.StartService();
-
- // Assert
- startDirectory.Received().GetFiles("*.addins");
- addinsReader.Received().Read(addinsFile);
- subdirectory.Received().GetFiles("*.addins");
- addinsReader.Received().Read(addinsFile2);
- }
-
- [Test]
- public void ProcessAddinsFile_RelativePaths()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(
- new[]
- {
- "path/to/directory/",
- "directory2/",
- "**/wildcard-directory/",
- "path/to/file/file1.dll",
- "file2.dll",
- "**/wildcard-file.dll"
- });
- var directoryFinder = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- addinsReader.Received().Read(addinsFile);
- directoryFinder.Received().GetDirectories(startDirectory, "path/to/directory/");
- directoryFinder.Received().GetDirectories(startDirectory, "directory2/");
- directoryFinder.Received().GetDirectories(startDirectory, "**/wildcard-directory/");
- directoryFinder.Received().GetFiles(startDirectory, "path/to/file/file1.dll");
- directoryFinder.Received().GetFiles(startDirectory, "file2.dll");
- directoryFinder.Received().GetFiles(startDirectory, "**/wildcard-file.dll");
- }
-
- [Test]
- [Platform("win")]
- public void ProcessAddinsFile_AbsolutePath_Windows()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var metamorphosatorDirectoryPath = "c:/tools/metamorphosator";
- var metamorphosatorDirectory = Substitute.For();
- metamorphosatorDirectory.FullName.Returns(metamorphosatorDirectoryPath);
- var toolsDirectoryPath = "d:/tools";
- var toolsDirectory = Substitute.For();
- toolsDirectory.FullName.Returns(toolsDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- fileSystem.GetDirectory(metamorphosatorDirectoryPath + "/").Returns(metamorphosatorDirectory);
- fileSystem.GetDirectory("d:\\tools").Returns(toolsDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { "c:/tools/metamorphosator/", "d:/tools/frobuscator.dll" });
- var directoryFinder = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- addinsReader.Received().Read(addinsFile);
- directoryFinder.Received().GetDirectories(metamorphosatorDirectory, string.Empty);
- directoryFinder.Received().GetFiles(toolsDirectory, "frobuscator.dll");
- directoryFinder.DidNotReceive().GetDirectories(toolsDirectory, Arg.Is(s => s != "frobuscator.dll"));
- }
-
- [Test]
- [Platform("linux,macosx,unix")]
- public void ProcessAddinsFile_AbsolutePath_NonWindows()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var metamorphosatorDirectoryPath = "/tmp/tools/metamorphosator";
- var metamorphosatorDirectory = Substitute.For();
- metamorphosatorDirectory.FullName.Returns(metamorphosatorDirectoryPath);
- var usrDirectoryPath = "/usr";
- var toolsDirectory = Substitute.For();
- toolsDirectory.FullName.Returns(usrDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- fileSystem.GetDirectory(metamorphosatorDirectoryPath + "/").Returns(metamorphosatorDirectory);
- fileSystem.GetDirectory(usrDirectoryPath).Returns(toolsDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { "/tmp/tools/metamorphosator/", "/usr/frobuscator.dll" });
- var directoryFinder = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- addinsReader.Received().Read(addinsFile);
- directoryFinder.Received().GetDirectories(metamorphosatorDirectory, string.Empty);
- directoryFinder.Received().GetFiles(toolsDirectory, "frobuscator.dll");
- directoryFinder.DidNotReceive().GetDirectories(toolsDirectory, Arg.Is(s => s != "frobuscator.dll"));
- }
-
- [Test]
- [Platform("win")]
- public void ProcessAddinsFile_InvalidAbsolutePathToFile_Windows()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { "/absolute/unix/path" });
- var directoryFinder = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- addinsReader.Received().Read(addinsFile);
- directoryFinder.Received().GetFiles(startDirectory, "/absolute/unix/path");
- }
-
- [Test]
- [Platform("win")]
- public void ProcessAddinsFile_InvalidAbsolutePathToDirectory_Windows()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { "/absolute/unix/path/" });
- var directoryFinder = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- addinsReader.Received().Read(addinsFile);
- directoryFinder.Received().GetDirectories(startDirectory, "/absolute/unix/path/");
- }
-
- [TestCase("c:/absolute/windows/path")]
- [TestCase("c:\\absolute\\windows\\path")]
- [TestCase("c:\\absolute\\windows\\path\\")]
- [Platform("linux,macosx,unix")]
- public void ProcessAddinsFile_InvalidAbsolutePathToFile_NonWindows(string windowsPath)
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { windowsPath });
- var directoryFinder = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- addinsReader.Received().Read(addinsFile);
- directoryFinder.Received().GetFiles(startDirectory, windowsPath);
- }
-
- [TestCase("c:/absolute/windows/path/")]
- [Platform("linux,macosx,unix")]
- public void ProcessAddinsFile_InvalidAbsolutePathToDirectory_NonWindows(string windowsPath)
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { windowsPath });
- var directoryFinder = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- addinsReader.Received().Read(addinsFile);
- directoryFinder.Received().GetDirectories(startDirectory, windowsPath);
- }
-
- [Test]
- public void StartService_ReadsMultipleAddinsFilesFromSingleDirectory()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var addinsFile1 = Substitute.For();
- addinsFile1.Parent.Returns(startDirectory);
- addinsFile1.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile1 });
- var addinsFile2 = Substitute.For();
- addinsFile1.Parent.Returns(startDirectory);
- addinsFile1.FullName.Returns(Path.Combine(startDirectoryPath, "test2.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile1, addinsFile2 });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- var sut = new ExtensionService(addinsReader, fileSystem);
-
- // Act
- sut.StartService();
-
- // Assert
- startDirectory.Received().GetFiles("*.addins");
- addinsReader.Received().Read(addinsFile1);
- addinsReader.Received().Read(addinsFile2);
- }
-
- [Test]
- public void ProcessAddinsFile_ReadsAddinsFileFromReferencedDirectory()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
- var referencedDirectoryPath = Path.Combine(startDirectoryPath, "metamorphosator");
- var referencedDirectory = Substitute.For();
- referencedDirectory.FullName.Returns(referencedDirectoryPath);
- referencedDirectory.Parent.Returns(startDirectory);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "test.addins"));
- var referencedAddinsFile = Substitute.For();
- referencedAddinsFile.Parent.Returns(referencedDirectory);
- referencedAddinsFile.FullName.Returns(Path.Combine(referencedDirectoryPath, "test2.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- referencedDirectory.GetFiles("*.addins").Returns(new[] { referencedAddinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(referencedDirectoryPath).Returns(referencedDirectory);
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- addinsReader.Read(addinsFile).Returns(new[] { "./metamorphosator/" });
- var directoryFinder = Substitute.For();
- directoryFinder.GetDirectories(startDirectory, "./metamorphosator/").Returns(new[] { referencedDirectory });
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- startDirectory.Received().GetFiles("*.addins");
- addinsReader.Received().Read(addinsFile);
- referencedDirectory.Received().GetFiles("*.addins");
- addinsReader.Received().Read(referencedAddinsFile);
- }
-
- [Test]
- [Platform("win")]
- public void ProcessAddinsFile_Issue915_AddinsFilePointsToContainingDirectory_Windows()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
-
- // Faking the presence of the assembly is required to reproduce the error described in GitHub issue 915...
- var testAssembly = Substitute.For();
- testAssembly.Parent.Returns(startDirectory);
- testAssembly.FullName.Returns(typeof(ExtensionService).Assembly.Location);
- startDirectory.GetFiles("*.dll").Returns(new[] { testAssembly });
-
- var parentPath = new DirectoryInfo(startDirectoryPath).Parent.FullName;
- var parentDirectory = Substitute.For();
- parentDirectory.FullName.Returns(parentPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "my.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- var addinsReader = Substitute.For();
- var addinsContent = new[] {
- "./",
- startDirectoryPath + Path.DirectorySeparatorChar,
- $"..{Path.DirectorySeparatorChar}{Path.GetFileName(startDirectoryPath)}{Path.DirectorySeparatorChar}",
- @"*\..\",
- @"**\..\",
- @"**\.\"
- };
- addinsReader.Read(addinsFile).Returns(addinsContent);
- var directoryFinder = Substitute.For();
- directoryFinder.GetDirectories(startDirectory, "./").Returns(new[] { startDirectory });
- directoryFinder.GetFiles(startDirectory, string.Empty).Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, $"..{Path.DirectorySeparatorChar}{Path.GetFileName(startDirectoryPath)}{Path.DirectorySeparatorChar}").Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, @"*\..\").Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, @"**\..\").Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, @"**\.\").Returns(new[] { testAssembly });
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- startDirectory.Received().GetFiles("*.addins");
- startDirectory.DidNotReceive().GetFiles("*.dll");
- parentDirectory.DidNotReceive().GetFiles("*.dll");
- directoryFinder.Received().GetDirectories(startDirectory, "./");
- directoryFinder.Received().GetFiles(startDirectory, string.Empty);
- directoryFinder.Received().GetFiles(startDirectory, $"..{Path.DirectorySeparatorChar}{Path.GetFileName(startDirectoryPath)}{Path.DirectorySeparatorChar}");
- directoryFinder.Received().GetFiles(startDirectory, @"*\..\");
- directoryFinder.Received().GetFiles(startDirectory, @"**\..\");
- directoryFinder.Received().GetFiles(startDirectory, @"**\.\");
- addinsReader.Received().Read(addinsFile);
- }
-
- [Test]
- [Platform("linux,macosx,unix")]
- public void ProcessAddinsFile_Issue915_AddinsFilePointsToContainingDirectory_NonWindows()
- {
- // Arrange
- var startDirectoryPath = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
- var startDirectory = Substitute.For();
- startDirectory.FullName.Returns(startDirectoryPath);
-
- // Faking the presence of the assembly is required to reproduce the error described in GitHub issue 915...
- var testAssembly = Substitute.For();
- testAssembly.Parent.Returns(startDirectory);
- testAssembly.FullName.Returns(typeof(ExtensionService).Assembly.Location);
- startDirectory.GetFiles("*.dll").Returns(new[] { testAssembly });
-
- var parentPath = new DirectoryInfo(startDirectoryPath).Parent.FullName;
- var parentDirectory = Substitute.For();
- parentDirectory.FullName.Returns(parentPath);
- var addinsFile = Substitute.For();
- addinsFile.Parent.Returns(startDirectory);
- addinsFile.FullName.Returns(Path.Combine(startDirectoryPath, "my.addins"));
- startDirectory.GetFiles("*.addins").Returns(new[] { addinsFile });
- var fileSystem = Substitute.For();
- fileSystem.GetDirectory(startDirectoryPath).Returns(startDirectory);
- fileSystem.GetDirectory(startDirectoryPath + "/").Returns(startDirectory);
- var addinsReader = Substitute.For();
- var addinsContent = new[] {
- "./",
- startDirectoryPath + "/",
- $"../{Path.GetFileName(startDirectoryPath)}/",
- "*/../",
- "**/../",
- "**/./"
- };
- addinsReader.Read(addinsFile).Returns(addinsContent);
- var directoryFinder = Substitute.For();
- directoryFinder.GetDirectories(startDirectory, "./").Returns(new[] { startDirectory });
- directoryFinder.GetFiles(startDirectory, string.Empty).Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, $"../{Path.GetFileName(startDirectoryPath)}/").Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, "*/../").Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, "**/../").Returns(new[] { testAssembly });
- directoryFinder.GetFiles(startDirectory, "**/./").Returns(new[] { testAssembly });
- var sut = new ExtensionService(addinsReader, fileSystem, directoryFinder);
-
- // Act
- sut.StartService();
-
- // Assert
- startDirectory.Received().GetFiles("*.addins");
- addinsReader.Received().Read(addinsFile);
- startDirectory.DidNotReceive().GetFiles("*.dll");
- parentDirectory.DidNotReceive().GetFiles("*.dll");
- directoryFinder.Received().GetDirectories(startDirectory, "./");
- directoryFinder.Received().GetDirectories(startDirectory, string.Empty);
- directoryFinder.Received().GetDirectories(startDirectory, $"../{Path.GetFileName(startDirectoryPath)}/");
- directoryFinder.Received().GetDirectories(startDirectory, "*/../");
- directoryFinder.Received().GetDirectories(startDirectory, "**/../");
- directoryFinder.Received().GetDirectories(startDirectory, "**/./");
- }
}
}
diff --git a/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionServiceTests.cs b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionServiceTests.cs
new file mode 100644
index 000000000..3f6a5664f
--- /dev/null
+++ b/src/NUnitEngine/nunit.engine.core.tests/Services/ExtensionServiceTests.cs
@@ -0,0 +1,106 @@
+// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using NSubstitute;
+using NUnit.Engine.Extensibility;
+using NUnit.Engine.Internal;
+using NUnit.Engine.Internal.FileSystemAccess;
+using NUnit.Framework;
+
+namespace NUnit.Engine.Services.Tests
+{
+ public class ExtensionServiceTests
+ {
+ private ExtensionManager _extensionManager;
+ private ExtensionService _extensionService;
+
+#pragma warning disable 414
+ private static readonly string[] KnownExtensionPointPaths = {
+ "/NUnit/Engine/TypeExtensions/IDriverFactory",
+ "/NUnit/Engine/TypeExtensions/IProjectLoader",
+ "/NUnit/Engine/TypeExtensions/IResultWriter",
+ "/NUnit/Engine/TypeExtensions/ITestEventListener",
+ "/NUnit/Engine/TypeExtensions/IService",
+ "/NUnit/Engine/NUnitV2Driver"
+ };
+
+ private static readonly Type[] KnownExtensionPointTypes = {
+ typeof(IDriverFactory),
+ typeof(IProjectLoader),
+ typeof(IResultWriter),
+ typeof(ITestEventListener),
+ typeof(IService),
+ typeof(IFrameworkDriver)
+ };
+
+ private static readonly int[] KnownExtensionPointCounts = { 1, 1, 1, 2, 1, 1 };
+#pragma warning restore 414
+
+ [SetUp]
+ public void CreateService()
+ {
+ _extensionManager = Substitute.For();
+ _extensionService = new ExtensionService(_extensionManager);
+ }
+
+ [Test]
+ public void StartServiceInitializesExtensionManager()
+ {
+ var workingDir = AssemblyHelper.GetDirectoryName(typeof(ExtensionService).Assembly);
+
+ _extensionService.StartService();
+
+ _extensionManager.ReceivedWithAnyArgs().FindExtensionPoints(typeof(ExtensionService).Assembly, typeof(ITestEngine).Assembly);
+ _extensionManager.Received().FindExtensions(workingDir);
+ Assert.That(_extensionService.Status, Is.EqualTo(ServiceStatus.Started));
+ }
+
+ [Test]
+ public void GetExtensionPointCallsExtensionManager()
+ {
+ ((IExtensionService)_extensionService).GetExtensionPoint("SOMEPATH");
+ _extensionManager.Received().GetExtensionPoint("SOMEPATH");
+ }
+
+ [Test]
+ public void GetExtensionNodesCallsExtensionManager()
+ {
+ ((IExtensionService)_extensionService).GetExtensionNodes("SOMEPATH");
+ _extensionManager.Received().GetExtensionNodes("SOMEPATH");
+ }
+
+ [Test]
+ public void EnableExtensionCallsExtensionManager()
+ {
+ _extensionService.EnableExtension("TYPENAME", true);
+ _extensionManager.Received().EnableExtension("TYPENAME", true);
+ }
+
+ [Test]
+ public void GetExtensionsTCallsExtensionManager()
+ {
+ _extensionService.GetExtensions();
+ _extensionManager.Received().GetExtensions();
+ }
+
+ [Test]
+ public void GetExtensionNodeCallsExtensionManager()
+ {
+ _extensionService.GetExtensionNode("SOMEPATH");
+ _extensionManager.Received().GetExtensionNode("SOMEPATH");
+ }
+
+ [Test]
+ public void GetExtensionNodesTCallsExtensionManager()
+ {
+ _extensionService.GetExtensionNodes();
+ _extensionManager.Received().GetExtensionNodes();
+ }
+
+ }
+}
diff --git a/src/NUnitEngine/nunit.engine.core/Drivers/NUnit2DriverFactory.cs b/src/NUnitEngine/nunit.engine.core/Drivers/NUnit2DriverFactory.cs
index 6bc490cc8..5ab8ffa2f 100644
--- a/src/NUnitEngine/nunit.engine.core/Drivers/NUnit2DriverFactory.cs
+++ b/src/NUnitEngine/nunit.engine.core/Drivers/NUnit2DriverFactory.cs
@@ -3,6 +3,7 @@
#if NETFRAMEWORK
using System;
using System.Collections.Generic;
+using System.Configuration.Assemblies;
using System.Reflection;
using NUnit.Engine.Extensibility;
using NUnit.Engine.Internal;
@@ -13,13 +14,13 @@ public class NUnit2DriverFactory : IDriverFactory
{
private const string NUNIT_FRAMEWORK = "nunit.framework";
private const string NUNITLITE_FRAMEWORK = "nunitlite";
- private ExtensionNode _driverNode;
+ private IExtensionNode _driverNode;
// TODO: This should be a central service but for now it's local
private ProvidedPathsAssemblyResolver _resolver;
bool _resolverInstalled;
- public NUnit2DriverFactory(ExtensionNode driverNode)
+ public NUnit2DriverFactory(IExtensionNode driverNode)
{
_driverNode = driverNode;
_resolver = new ProvidedPathsAssemblyResolver();
@@ -55,7 +56,9 @@ public IFrameworkDriver GetDriver(AppDomain domain, AssemblyName reference)
_resolver.AddPathFromFile(_driverNode.AssemblyPath);
}
- return _driverNode.CreateExtensionObject(domain) as IFrameworkDriver;
+ return AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(
+ _driverNode.AssemblyPath, _driverNode.TypeName,
+ false, 0, null, null, null, null) as IFrameworkDriver;
}
}
}
diff --git a/src/NUnitEngine/nunit.engine.core/Internal/AddinsFile.cs b/src/NUnitEngine/nunit.engine.core/Internal/AddinsFile.cs
new file mode 100644
index 000000000..6b090c318
--- /dev/null
+++ b/src/NUnitEngine/nunit.engine.core/Internal/AddinsFile.cs
@@ -0,0 +1,85 @@
+// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using NUnit.Engine.Internal.FileSystemAccess;
+
+namespace NUnit.Engine.Internal
+{
+ internal class AddinsFile : List
+ {
+ public static AddinsFile Read(IFile file)
+ {
+ if (file == null)
+ throw new ArgumentNullException(nameof(file));
+
+ using (var stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ return Read(stream, file.FullName);
+ }
+ }
+
+ ///
+ /// Reads the content of an addins-file from a stream.
+ ///
+ /// Input stream. Must be readable and positioned at the beginning of the file.
+ /// All entries contained in the file.
+ /// cannot be read
+ /// If the executing system uses backslashes ('\') to separate directories, these will be substituted with slashes ('/').
+ internal static AddinsFile Read(Stream stream, string fullName = null)
+ {
+ using (var reader = new StreamReader(stream))
+ {
+ var addinsFile = new AddinsFile();
+
+ int lineNumber = 0;
+ while (!reader.EndOfStream)
+ {
+ var entry = new AddinsFileEntry(++lineNumber, reader.ReadLine());
+ if (entry.Text != "" && !entry.IsValid)
+ {
+ string msg = $"Invalid Entry in {fullName ?? "addins file"}:\r\n {entry}";
+ throw new InvalidOperationException(msg);
+ }
+
+ addinsFile.Add(entry);
+ }
+
+ return addinsFile;
+ }
+ }
+
+ private AddinsFile() { }
+
+ public override string ToString()
+ {
+ var sb = new StringBuilder("AddinsFile:");
+ foreach (var entry in this)
+ sb.Append($" {entry}");
+ return sb.ToString();
+ }
+
+ public override bool Equals(object obj)
+ {
+ var other = obj as AddinsFile;
+ if (other == null) return false;
+
+ if (Count != other.Count) return false;
+
+ for (int i = 0; i < Count; i++)
+ if (this[i] != other[i]) return false;
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+ }
+}
diff --git a/src/NUnitEngine/nunit.engine.core/Internal/AddinsFileEntry.cs b/src/NUnitEngine/nunit.engine.core/Internal/AddinsFileEntry.cs
new file mode 100644
index 000000000..3bf6470d5
--- /dev/null
+++ b/src/NUnitEngine/nunit.engine.core/Internal/AddinsFileEntry.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+
+namespace NUnit.Engine.Internal
+{
+ // Class representing a single line in an Addins file
+ internal class AddinsFileEntry
+ {
+ public int LineNumber { get; }
+ public string RawText { get; }
+ public string Text { get; }
+
+ public bool IsFullyQualified => PathUtils.IsFullyQualifiedPath(Text);
+ public bool IsDirectory => Text.EndsWith("/");
+ public bool IsPattern => Text.Contains("*");
+ public bool IsValid => PathUtils.IsValidPath(Text.Replace('*', 'X'));
+
+ public string DirectoryName => Path.GetDirectoryName(Text);
+ public string FileName => Path.GetFileName(Text);
+
+ public AddinsFileEntry(int lineNumber, string rawText)
+ {
+ LineNumber = lineNumber;
+ RawText = rawText;
+ Text = rawText.Split(new char[] { '#' })[0].Trim()
+ .Replace(Path.DirectorySeparatorChar, '/');
+ }
+
+ public override string ToString()
+ {
+ return $"{LineNumber}: {RawText}";
+ }
+
+ public override bool Equals(object obj)
+ {
+ var other = obj as AddinsFileEntry;
+ if (other == null) return false;
+
+ return LineNumber == other.LineNumber && RawText == other.RawText;
+ }
+
+ public override int GetHashCode()
+ {
+ return LineNumber.GetHashCode() ^ RawText.GetHashCode();
+ }
+ }
+}
diff --git a/src/NUnitEngine/nunit.engine.core/Internal/AddinsFileReader.cs b/src/NUnitEngine/nunit.engine.core/Internal/AddinsFileReader.cs
deleted file mode 100644
index 3e0407898..000000000
--- a/src/NUnitEngine/nunit.engine.core/Internal/AddinsFileReader.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
-
-using NUnit.Engine.Internal.FileSystemAccess;
-using System;
-using System.Collections.Generic;
-using System.IO;
-
-namespace NUnit.Engine.Internal
-{
- ///
- /// A reader for NUnit addins-files.
- ///
- ///
- /// The format of an addins-file can be found at https://docs.nunit.org/articles/nunit-engine/extensions/Installing-Extensions.html.
- ///
- internal sealed class AddinsFileReader : IAddinsFileReader
- {
- ///
- public IEnumerable Read(IFile file)
- {
- if (file == null)
- {
- throw new ArgumentNullException(nameof(file));
- }
-
- using (var reader = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- return Read(reader);
- }
- }
-
- ///
- /// Reads the content of an addins-file from a stream.
- ///
- /// Input stream. Must be readable and positioned at the beginning of the file.
- /// All entries contained in the file.
- /// cannot be read
- /// If the executing system uses backslashes ('\') to separate directories, these will be substituted with slashes ('/').
- internal static IEnumerable Read(Stream stream)
- {
- var result = new List();
- using (var reader = new StreamReader(stream))
- {
- for(var line = reader.ReadLine(); line != null; line = reader.ReadLine())
- {
- line = line.Split(new char[] { '#' })[0].Trim();
- if (line != string.Empty)
- {
- result.Add(line.Replace(Path.DirectorySeparatorChar, '/'));
- }
- }
- }
-
- return result;
- }
- }
-}
diff --git a/src/NUnitEngine/nunit.engine.core/Internal/Backports/Path.cs b/src/NUnitEngine/nunit.engine.core/Internal/Backports/Path.cs
deleted file mode 100644
index 2d800d68a..000000000
--- a/src/NUnitEngine/nunit.engine.core/Internal/Backports/Path.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
-
-using System;
-
-namespace NUnit.Engine.Internal.Backports
-{
- ///
- /// Backports of functionality that is only available in newer .NET versions.
- ///
- public static class Path
- {
- ///
- /// Returns a value that indicates whether the specified file path is absolute or not.
- ///
- /// Path to check
- /// if is an absolute or UNC path; otherwhise, false.
- ///
- /// See https://docs.microsoft.com/en-us/dotnet/api/system.io.path.ispathfullyqualified for original implementation.
- public static bool IsPathFullyQualified(string path)
- {
- if (path == null)
- {
- throw new ArgumentNullException(nameof(path));
- }
-
- return RunningOnWindows() ? PathUtils.IsFullyQualifiedWindowsPath(path) : PathUtils.IsFullyQualifiedUnixPath(path);
- }
-
- private static bool RunningOnWindows()
- {
- return System.IO.Path.DirectorySeparatorChar == '\\';
- }
- }
-}
diff --git a/src/NUnitEngine/nunit.engine.core/Internal/IAddinsFileReader.cs b/src/NUnitEngine/nunit.engine.core/Internal/IAddinsFileReader.cs
deleted file mode 100644
index 511b38b1a..000000000
--- a/src/NUnitEngine/nunit.engine.core/Internal/IAddinsFileReader.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
-
-using NUnit.Engine.Internal.FileSystemAccess;
-using System.Collections.Generic;
-
-namespace NUnit.Engine.Internal
-{
- ///
- /// A reader for NUnit addins-files.
- ///
- ///
- /// The format of an addins-file can be found at https://docs.nunit.org/articles/nunit-engine/extensions/Installing-Extensions.html.
- ///
- internal interface IAddinsFileReader
- {
- ///
- /// Reads all entries from an addins-file.
- ///
- /// Location of the file.
- /// All entries contained in the file.
- /// is
- /// cannot be found or read
- IEnumerable Read(IFile file);
- }
-}
diff --git a/src/NUnitEngine/nunit.engine.core/Internal/PathUtils.cs b/src/NUnitEngine/nunit.engine.core/Internal/PathUtils.cs
index b7d0c2220..bec00090b 100644
--- a/src/NUnitEngine/nunit.engine.core/Internal/PathUtils.cs
+++ b/src/NUnitEngine/nunit.engine.core/Internal/PathUtils.cs
@@ -144,10 +144,10 @@ public static bool SamePathOrUnder( string path1, string path2 )
// if lengths are the same, check for equality
if ( length1 == length2 )
- return string.Compare( path1, path2, IsWindows() ) == 0;
+ return string.Compare( path1, path2, RunningOnWindows ) == 0;
// path 2 is longer than path 1: see if initial parts match
- if ( string.Compare( path1, path2.Substring( 0, length1 ), IsWindows() ) != 0 )
+ if ( string.Compare( path1, path2.Substring( 0, length1 ), RunningOnWindows ) != 0 )
return false;
// must match through or up to a directory separator boundary
@@ -167,7 +167,20 @@ public static string Combine(string path1, params string[] morePaths)
}
///
- /// Returns a value that indicates whether the specified file path is absolute or not on Windows operating systems.
+ /// Returns a value that indicates whether the specified file path is fully qualified.
+ ///
+ /// Path to check
+ /// if is an absolute path; otherwhise, false.
+ ///
+ public static bool IsFullyQualifiedPath(string path )
+ {
+ return RunningOnWindows
+ ? IsFullyQualifiedWindowsPath(path)
+ : IsFullyQualifiedUnixPath(path);
+ }
+
+ ///
+ /// Returns a value that indicates whether the specified file path is fully qualified or not on Windows operating systems.
///
/// Path to check
/// if is an absolute or UNC path; otherwhise, false.
@@ -206,6 +219,27 @@ public static bool IsFullyQualifiedUnixPath(string path)
return path.Length > 0 && path[0] == '/';
}
+ public static bool IsValidPath(string path)
+ {
+ try
+ {
+ var info = GetFileSystemInfo(path);
+#if NETCOREAPP2_1_OR_GREATER
+ var creation = info.CreationTime;
+#endif
+ return true; // Whether it exists or not!
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ private static FileSystemInfo GetFileSystemInfo(string path) =>
+ path.EndsWith("/") || path.EndsWith(@"\\")
+ ? new DirectoryInfo(path) as FileSystemInfo
+ : new FileInfo(path) as FileSystemInfo;
+
private static bool IsWindowsDirectorySeparator(char c)
{
return c == '\\' || c == '/';
@@ -216,14 +250,11 @@ private static bool IsValidDriveSpecifier(char c)
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
}
- private static bool IsWindows()
- {
- return PathUtils.DirectorySeparatorChar == '\\';
- }
+ private static bool RunningOnWindows => DirectorySeparatorChar == '\\';
private static string[] SplitPath(string path)
{
- char[] separators = new char[] { PathUtils.DirectorySeparatorChar, PathUtils.AltDirectorySeparatorChar };
+ char[] separators = new char[] { DirectorySeparatorChar, AltDirectorySeparatorChar };
string[] trialSplit = path.Split(separators);
@@ -246,7 +277,7 @@ private static string[] SplitPath(string path)
private static bool PathsEqual(string path1, string path2)
{
- if (PathUtils.IsWindows())
+ if (RunningOnWindows)
return path1.ToLower().Equals(path2.ToLower());
else
return path1.Equals(path2);
diff --git a/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs b/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs
index 40fb360e2..476ceaee5 100644
--- a/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs
+++ b/src/NUnitEngine/nunit.engine.core/Services/ExtensionManager.cs
@@ -2,28 +2,24 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Reflection;
using TestCentric.Metadata;
using NUnit.Engine.Extensibility;
using NUnit.Engine.Internal;
using NUnit.Engine.Internal.FileSystemAccess;
using NUnit.Engine.Internal.FileSystemAccess.Default;
-
-#if NET462 || NETSTANDARD2_0
-using Path = NUnit.Engine.Internal.Backports.Path;
-#else
-using Path = System.IO.Path;
-#endif
+using System.Linq;
namespace NUnit.Engine.Services
{
- public sealed class ExtensionManager : IDisposable
+ public class ExtensionManager : IExtensionManager
{
static readonly Logger log = InternalTrace.GetLogger(typeof(ExtensionService));
static readonly Version ENGINE_VERSION = typeof(ExtensionService).Assembly.GetName().Version;
private readonly IFileSystem _fileSystem;
- private readonly IAddinsFileReader _addinsReader;
+ //private readonly IAddinsFileReader _addinsReader;
private readonly IDirectoryFinder _directoryFinder;
private readonly List _extensionPoints = new List();
@@ -33,32 +29,22 @@ public sealed class ExtensionManager : IDisposable
private readonly List _assemblies = new List();
public ExtensionManager()
- : this(new AddinsFileReader(), new FileSystem())
+ : this(new FileSystem())
{
}
- internal ExtensionManager(IAddinsFileReader addinsReader, IFileSystem fileSystem)
- : this(addinsReader, fileSystem, new DirectoryFinder(fileSystem))
+ internal ExtensionManager(IFileSystem fileSystem)
+ : this(fileSystem, new DirectoryFinder(fileSystem))
{
}
- internal ExtensionManager(IAddinsFileReader addinsReader, IFileSystem fileSystem, IDirectoryFinder directoryFinder)
+ internal ExtensionManager(IFileSystem fileSystem, IDirectoryFinder directoryFinder)
{
- _addinsReader = addinsReader;
_fileSystem = fileSystem;
_directoryFinder = directoryFinder;
}
- internal void FindExtensions(string startDir)
- {
- // Create the list of possible extension assemblies,
- // eliminating duplicates, start in the provided directory.
- FindExtensionAssemblies(_fileSystem.GetDirectory(startDir));
-
- // Check each assembly to see if it contains extensions
- foreach (var candidate in _assemblies)
- FindExtensionsInAssembly(candidate);
- }
+ #region IExtensionManager Implementation
///
/// Gets an enumeration of all ExtensionPoints in the engine.
@@ -76,82 +62,10 @@ public IEnumerable Extensions
get { return _extensions.ToArray(); }
}
- ///
- /// Enable or disable an extension
- ///
- public void EnableExtension(string typeName, bool enabled)
- {
- foreach (var node in _extensions)
- if (node.TypeName == typeName)
- node.Enabled = enabled;
- }
-
- ///
- /// Get an ExtensionPoint based on its unique identifying path.
- ///
- public ExtensionPoint GetExtensionPoint(string path)
- {
- return _pathIndex.ContainsKey(path) ? _pathIndex[path] : null;
- }
-
- ///
- /// Get an ExtensionPoint based on the required Type for extensions.
- ///
- public ExtensionPoint GetExtensionPoint(Type type)
- {
- foreach (var ep in _extensionPoints)
- if (ep.TypeName == type.FullName)
- return ep;
-
- return null;
- }
-
- ///
- /// Get an ExtensionPoint based on a Cecil TypeReference.
- ///
- public ExtensionPoint GetExtensionPoint(TypeReference type)
- {
- foreach (var ep in _extensionPoints)
- if (ep.TypeName == type.FullName)
- return ep;
-
- return null;
- }
-
- public IEnumerable GetExtensionNodes(string path)
- {
- var ep = GetExtensionPoint(path);
- if (ep != null)
- foreach (var node in ep.Extensions)
- yield return node;
- }
-
- public ExtensionNode GetExtensionNode(string path)
- {
- var ep = GetExtensionPoint(path);
-
- return ep != null && ep.Extensions.Count > 0 ? ep.Extensions[0] : null;
- }
-
- public IEnumerable GetExtensionNodes(bool includeDisabled = false)
- {
- var ep = GetExtensionPoint(typeof(T));
- if (ep != null)
- foreach (var node in ep.Extensions)
- if (includeDisabled || node.Enabled)
- yield return node;
- }
-
- public IEnumerable GetExtensions()
- {
- foreach (var node in GetExtensionNodes())
- yield return (T)node.ExtensionObject;
- }
-
///
/// Find the extension points in a loaded assembly.
///
- public void FindExtensionPoints(params Assembly[] targetAssemblies)
+ public virtual void FindExtensionPoints(params Assembly[] targetAssemblies)
{
foreach (var assembly in targetAssemblies)
{
@@ -206,6 +120,92 @@ public void FindExtensionPoints(params Assembly[] targetAssemblies)
}
}
+ public void FindExtensions(string startDir)
+ {
+ // Create the list of possible extension assemblies,
+ // eliminating duplicates, start in the provided directory.
+ FindExtensionAssemblies(_fileSystem.GetDirectory(startDir));
+
+ // Check each assembly to see if it contains extensions
+ foreach (var candidate in _assemblies)
+ FindExtensionsInAssembly(candidate);
+ }
+
+ ///
+ /// Get an ExtensionPoint based on its unique identifying path.
+ ///
+ public IExtensionPoint GetExtensionPoint(string path)
+ {
+ return _pathIndex.ContainsKey(path) ? _pathIndex[path] : null;
+ }
+
+ public IEnumerable GetExtensionNodes(string path)
+ {
+ var ep = GetExtensionPoint(path);
+ if (ep != null)
+ foreach (var node in ep.Extensions)
+ yield return node;
+ }
+
+ public IExtensionNode GetExtensionNode(string path)
+ {
+ // TODO: Remove need for the cast
+ var ep = GetExtensionPoint(path) as ExtensionPoint;
+
+ return ep != null && ep.Extensions.Count > 0 ? ep.Extensions[0] : null;
+ }
+
+ public IEnumerable GetExtensionNodes(bool includeDisabled = false)
+ {
+ var ep = GetExtensionPoint(typeof(T));
+ if (ep != null)
+ foreach (var node in ep.Extensions)
+ if (includeDisabled || node.Enabled)
+ yield return node;
+ }
+
+ public IEnumerable GetExtensions()
+ {
+ foreach (var node in GetExtensionNodes())
+ yield return (T)((ExtensionNode)node).ExtensionObject; // HACK
+ }
+
+ ///
+ /// Enable or disable an extension
+ ///
+ public void EnableExtension(string typeName, bool enabled)
+ {
+ foreach (var node in _extensions)
+ if (node.TypeName == typeName)
+ node.Enabled = enabled;
+ }
+
+ #endregion
+
+ ///
+ /// Get an ExtensionPoint based on the required Type for extensions.
+ ///
+ public ExtensionPoint GetExtensionPoint(Type type)
+ {
+ foreach (var ep in _extensionPoints)
+ if (ep.TypeName == type.FullName)
+ return ep;
+
+ return null;
+ }
+
+ ///
+ /// Get an ExtensionPoint based on a Cecil TypeReference.
+ ///
+ public ExtensionPoint GetExtensionPoint(TypeReference type)
+ {
+ foreach (var ep in _extensionPoints)
+ if (ep.TypeName == type.FullName)
+ return ep;
+
+ return null;
+ }
+
///
/// Deduce the extension point based on the Type of an extension.
/// Returns null if no extension point can be found that would
@@ -278,14 +278,12 @@ private int ProcessAddinsFiles(IDirectory startDir, bool fromWildCard)
var addinsFiles = startDir.GetFiles("*.addins");
var addinsFileCount = 0;
- if (addinsFiles.Any())
+ foreach (var file in addinsFiles)
{
- foreach (var file in addinsFiles)
- {
- ProcessAddinsFile(startDir, file, fromWildCard);
- addinsFileCount += 1;
- }
+ ProcessAddinsFile(file, fromWildCard);
+ addinsFileCount++;
}
+
return addinsFileCount;
}
@@ -295,56 +293,43 @@ private int ProcessAddinsFiles(IDirectory startDir, bool fromWildCard)
/// path or a wildcard pattern used to find assemblies. Blank
/// lines and comments started by # are ignored.
///
- private void ProcessAddinsFile(IDirectory baseDir, IFile addinsFile, bool fromWildCard)
+ private void ProcessAddinsFile(IFile addinsFile, bool fromWildCard)
{
log.Info("Processing file " + addinsFile.FullName);
- foreach (var entry in _addinsReader.Read(addinsFile))
+ foreach (var entry in AddinsFile.Read(addinsFile).Where(e => e.Text != string.Empty))
{
- bool isWild = fromWildCard || entry.Contains("*");
- var args = GetBaseDirAndPattern(baseDir, entry);
- // TODO: See if we can handle '/tools/*/' efficiently by examining every
- // assembly in the directory. Otherwise try this approach:
- // 1. Check entry for ending with '/tools/*/'
- // 2. If so, examine the directory name to see if it matches a tfm.
- // 3. If it does, check to see if the implied runtime would be loadable.
- // 4. If so, process it, if not, skip it.
- if (entry.EndsWith("/"))
+ bool isWild = fromWildCard || entry.IsPattern;
+ IDirectory baseDir = addinsFile.Parent;
+ string entryDir = entry.DirectoryName;
+ string entryFile = entry.FileName;
+
+ if (entry.IsDirectory)
{
- foreach (var dir in _directoryFinder.GetDirectories(args.Item1, args.Item2))
+ if (entry.IsFullyQualified)
{
- ProcessDirectory(dir, isWild);
+ baseDir = _fileSystem.GetDirectory(entry.Text);
+ foreach (var dir in _directoryFinder.GetDirectories(_fileSystem.GetDirectory(entryDir), ""))
+ ProcessDirectory(dir, isWild);
}
+ else
+ foreach (var dir in _directoryFinder.GetDirectories(baseDir, entry.Text))
+ ProcessDirectory(dir, isWild);
}
else
{
- foreach (var file in _directoryFinder.GetFiles(args.Item1, args.Item2))
+ if (entry.IsFullyQualified)
{
- ProcessCandidateAssembly(file.FullName, isWild);
+ foreach (var file in _directoryFinder.GetFiles(_fileSystem.GetDirectory(entryDir), entryFile))
+ ProcessCandidateAssembly(file.FullName, isWild);
}
+ else
+ foreach (var file in _directoryFinder.GetFiles(baseDir, entry.Text))
+ ProcessCandidateAssembly(file.FullName, isWild);
}
}
}
- private Tuple GetBaseDirAndPattern(IDirectory baseDir, string path)
- {
- if (Path.IsPathFullyQualified(path))
- {
- if (path.EndsWith("/"))
- {
- return new Tuple(_fileSystem.GetDirectory(path), string.Empty);
- }
- else
- {
- return new Tuple(_fileSystem.GetDirectory(System.IO.Path.GetDirectoryName(path)), System.IO.Path.GetFileName(path));
- }
- }
- else
- {
- return new Tuple(baseDir, path);
- }
- }
-
private void ProcessCandidateAssembly(string filePath, bool fromWildCard)
{
if (WasVisited(filePath, fromWildCard))
@@ -483,7 +468,8 @@ internal void FindExtensionsInAssembly(ExtensionAssembly assembly)
}
else
{
- ep = GetExtensionPoint(node.Path);
+ // TODO: Remove need for the cast
+ ep = GetExtensionPoint(node.Path) as ExtensionPoint;
if (ep == null)
{
string msg = string.Format(
diff --git a/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs b/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs
index af3af5665..74ef1abcf 100644
--- a/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs
+++ b/src/NUnitEngine/nunit.engine.core/Services/ExtensionService.cs
@@ -6,17 +6,9 @@
using TestCentric.Metadata;
using NUnit.Engine.Extensibility;
using NUnit.Engine.Internal;
-using NUnit.Engine.Internal.Backports;
using NUnit.Engine.Internal.FileSystemAccess;
using NUnit.Engine.Internal.FileSystemAccess.Default;
-using Backports = NUnit.Engine.Internal.Backports;
-#if NETFRAMEWORK || NETSTANDARD2_0
-using Path = NUnit.Engine.Internal.Backports.Path;
-#else
-using Path = System.IO.Path;
-#endif
-
namespace NUnit.Engine.Services
{
///
@@ -26,22 +18,27 @@ namespace NUnit.Engine.Services
///
public class ExtensionService : Service, IExtensionService
{
- private readonly ExtensionManager _extensionManager;
+ private readonly IExtensionManager _extensionManager;
public ExtensionService()
{
_extensionManager = new ExtensionManager();
}
- internal ExtensionService(IAddinsFileReader addinsReader, IFileSystem fileSystem)
- : this(addinsReader, fileSystem, new DirectoryFinder(fileSystem))
+ public ExtensionService(ExtensionManager extensionManager)
+ {
+ _extensionManager = extensionManager;
+ }
+
+ internal ExtensionService(IFileSystem fileSystem)
+ : this(fileSystem, new DirectoryFinder(fileSystem))
{
- _extensionManager = new ExtensionManager(addinsReader, fileSystem);
+ _extensionManager = new ExtensionManager(fileSystem);
}
- internal ExtensionService(IAddinsFileReader addinsReader, IFileSystem fileSystem, IDirectoryFinder directoryFinder)
+ internal ExtensionService(IFileSystem fileSystem, IDirectoryFinder directoryFinder)
{
- _extensionManager = new ExtensionManager(addinsReader, fileSystem, directoryFinder);
+ _extensionManager = new ExtensionManager(fileSystem, directoryFinder);
}
public IEnumerable ExtensionPoints => _extensionManager.ExtensionPoints;
@@ -72,7 +69,7 @@ public void EnableExtension(string typeName, bool enabled)
public IEnumerable GetExtensions() => _extensionManager.GetExtensions();
- public ExtensionNode GetExtensionNode(string path) => _extensionManager.GetExtensionNode(path);
+ public IExtensionNode GetExtensionNode(string path) => _extensionManager.GetExtensionNode(path);
public IEnumerable GetExtensionNodes() => _extensionManager.GetExtensionNodes();
diff --git a/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs b/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs
new file mode 100644
index 000000000..c02704d5a
--- /dev/null
+++ b/src/NUnitEngine/nunit.engine.core/Services/IExtensionManager.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+using NUnit.Engine.Extensibility;
+
+namespace NUnit.Engine.Services
+{
+ public interface IExtensionManager : IDisposable
+ {
+ IEnumerable ExtensionPoints { get; }
+ IEnumerable Extensions { get; }
+
+ void FindExtensionPoints(params Assembly[] targetAssemblies);
+ void FindExtensions(string startDir);
+
+ IExtensionPoint GetExtensionPoint(string path);
+
+ IEnumerable GetExtensions();
+
+ IEnumerable GetExtensionNodes(string path);
+ IExtensionNode GetExtensionNode(string path);
+ ///
+ /// Returns all extension nodes for a given Type.
+ ///
+ /// The Type of the node
+ /// If true, disabled nodes are included
+ /// An enumeration of ExtensionNodes
+ ///
+ /// Unlike other methods, this method returns an actual ExtensionNode rather
+ /// than an IExtensionNode. It is required in order for classes that support
+ /// extensions to create the actual extension object.
+ ///
+ ///
+ // NOTE:
+ IEnumerable GetExtensionNodes(bool includeDisabled = false);
+
+ void EnableExtension(string typeName, bool enabled);
+ }
+
+}