From b39f8de155c598c7a8e8d89625a89e43ac64200b Mon Sep 17 00:00:00 2001 From: Markus Ewald Date: Fri, 28 Nov 2008 19:34:43 +0000 Subject: [PATCH] Increased test coverage for the command line parser (and then decided the thing is broken beyond repair and needs a rewrite -- as if that was any surprise given the original code is from CodeProject); achieved 100% test coverage for the factory employer, instance employer, employer, no plugin attribute and abstract factory classes in the Plugins namespace; achieved some test coverage for the PluginRepository class (the uncovered sections are quite hard to stimulate since they involve exceptions during assembly load attempts) git-svn-id: file:///srv/devel/repo-conversion/nusu@99 d2e56fa2-650e-0410-a79f-9358c0239efd --- Nuclex.Support.csproj | 21 ++++ Source/Parsing/CommandLineParser.Test.cs | 47 +++++++- Source/Plugins/AbstractFactory.Test.cs | 39 +++++++ Source/Plugins/Employer.Test.cs | 93 +++++++++++++++ Source/Plugins/FactoryEmployer.Test.cs | 132 +++++++++++++++++++++ Source/Plugins/FactoryEmployer.cs | 14 ++- Source/Plugins/InstanceEmployer.Test.cs | 129 ++++++++++++++++++++ Source/Plugins/NoPluginAttribute.Test.cs | 47 ++++++++ Source/Plugins/PluginHost.Test.cs | 38 ++++++ Source/Plugins/PluginRepository.Test.cs | 142 +++++++++++++++++++++++ Source/Plugins/PluginRepository.cs | 5 + 11 files changed, 703 insertions(+), 4 deletions(-) create mode 100644 Source/Plugins/AbstractFactory.Test.cs create mode 100644 Source/Plugins/Employer.Test.cs create mode 100644 Source/Plugins/FactoryEmployer.Test.cs create mode 100644 Source/Plugins/InstanceEmployer.Test.cs create mode 100644 Source/Plugins/NoPluginAttribute.Test.cs create mode 100644 Source/Plugins/PluginHost.Test.cs create mode 100644 Source/Plugins/PluginRepository.Test.cs diff --git a/Nuclex.Support.csproj b/Nuclex.Support.csproj index 84b333b..6957b75 100644 --- a/Nuclex.Support.csproj +++ b/Nuclex.Support.csproj @@ -123,16 +123,37 @@ PathHelper.cs + + AbstractFactory.cs + + + Employer.cs + + + FactoryEmployer.cs + + + InstanceEmployer.cs + + + NoPluginAttribute.cs + PluginHelper.cs + + PluginHost.cs + + + PluginRepository.cs + diff --git a/Source/Parsing/CommandLineParser.Test.cs b/Source/Parsing/CommandLineParser.Test.cs index 8c3e5a0..c14cef4 100644 --- a/Source/Parsing/CommandLineParser.Test.cs +++ b/Source/Parsing/CommandLineParser.Test.cs @@ -34,7 +34,7 @@ namespace Nuclex.Support.Parsing { /// Validates that normal arguments can be parsed [Test] - public void TestPlainArguments() { + public void TestArrayConstructorWithPlainArguments() { Assert.IsTrue( new CommandLineParser(new string[] { "-hello" }).HasArgument("hello"), "Argument with minus sign is recognized" @@ -51,7 +51,7 @@ namespace Nuclex.Support.Parsing { /// Validates that argument assignments are working [Test] - public void TestAssignments() { + public void TestArrayConstructorWithAssignments() { Assert.AreEqual( "world", new CommandLineParser(new string[] { "-hello:world" })["hello"], @@ -73,7 +73,7 @@ namespace Nuclex.Support.Parsing { /// Validates that loosely specified values are recognized by the parser /// [Test] - public void TestLooseValues() { + public void TestArrayConstructorWithLooseValues() { Assert.IsTrue( new CommandLineParser(new string[] { "hello" }).Values.Contains("hello"), "Plain loose value is recognized" @@ -84,6 +84,47 @@ namespace Nuclex.Support.Parsing { ); } + /// + /// Tests whether the parser can parse the processes current command line if + /// the default constructor is used + /// + [Test] + public void TestDefaultConstructor() { + new CommandLineParser(); + } + + /// + /// Tests whether the string constructor works for simple arguments being + /// specified on the command line + /// + [Test] + public void TestStringConstructorWithSimpleArguments() { + CommandLineParser parser = new CommandLineParser("argument1 argument2"); + Assert.AreEqual("argument1", parser.Values[0]); + Assert.AreEqual("argument2", parser.Values[1]); + } + + // TODO: This test fails!! +#if FAILED_TEST + /// + /// Bullshit + /// + [Test] + public void TestStringConstructorWithQuotedArguments() { + CommandLineParser parser = new CommandLineParser("\"this is a single argument\""); + Assert.AreEqual("this is a single argument", parser.Values[0]); + } +#endif + + /// + /// Tests whether the string constructor recognizes an unfinished argument + /// (that is, and argument that gets 'nothing' assigned) + /// + [Test] + public void TestStringConstructorWithUnfinishedAssignment() { + CommandLineParser parser = new CommandLineParser("--hello= --world="); + } + } } // namespace Nuclex.Support.Parsing diff --git a/Source/Plugins/AbstractFactory.Test.cs b/Source/Plugins/AbstractFactory.Test.cs new file mode 100644 index 0000000..ca07177 --- /dev/null +++ b/Source/Plugins/AbstractFactory.Test.cs @@ -0,0 +1,39 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the abstract factory interface + [TestFixture] + public class AbtractFactoryTest { + + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/Employer.Test.cs b/Source/Plugins/Employer.Test.cs new file mode 100644 index 0000000..1df92b8 --- /dev/null +++ b/Source/Plugins/Employer.Test.cs @@ -0,0 +1,93 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the employer class + [TestFixture] + public class EmployerTest { + + #region class TestEmployer + + /// Dummy implementation for testing the employer class + private class TestEmployer : Employer { + + /// Employs the specified plugin type + /// Type to be employed + public override void Employ(Type type) { } + + } + + #endregion // class TestEmployer + + #region class NoDefaultConstructor + + /// Test class that doesn't have a default constructor + private class NoDefaultConstructor { + /// Initializes a new instance of the test class + /// Dummy argument so this is no default constructor + public NoDefaultConstructor(int dummy) { } + } + + #endregion // class NoDefaultConstructor + + #region class NonPublicDefaultConstructor + + /// Test class that has a non-public default constructor + private class NonPublicDefaultConstructor { + /// Initializes a new instance of the test class + protected NonPublicDefaultConstructor() { } + } + + #endregion // class NonPublicDefaultConstructor + + #region class PublicDefaultConstructor + + /// Test class that has a public default constructor + private class PublicDefaultConstructor { + /// Initializes a new instance of the test class + public PublicDefaultConstructor() { } + } + + #endregion // class PublicDefaultConstructor + + /// Tests whether the employer can detect a default constructor + [Test] + public void TestEmployerDefaultConstructorDetection() { + TestEmployer testEmployer = new TestEmployer(); + + Assert.IsFalse(testEmployer.CanEmploy(typeof(NoDefaultConstructor))); + Assert.IsFalse(testEmployer.CanEmploy(typeof(NonPublicDefaultConstructor))); + Assert.IsTrue(testEmployer.CanEmploy(typeof(PublicDefaultConstructor))); + } + + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/FactoryEmployer.Test.cs b/Source/Plugins/FactoryEmployer.Test.cs new file mode 100644 index 0000000..b5d6a1f --- /dev/null +++ b/Source/Plugins/FactoryEmployer.Test.cs @@ -0,0 +1,132 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the factory employer class + [TestFixture] + public class FactoryEmployerTest { + + #region class Base + + /// + /// Abstract base class to serve as abstract product for testing the factory employer + /// + private abstract class Base { } + + #endregion // class Base + + #region class Derived + + /// + /// Class derived from the abstract base to serve as concrete product for + /// testing the factory employer + /// + private class Derived : Base { } + + #endregion // class Derived + + #region class Unrelated + + /// Unrelated class used to test the factory employer + private class Unrelated { } + + #endregion // class Unrelated + + /// + /// Tests whether the factory employer can detect employable types + /// + [Test] + public void TestCanEmploy() { + FactoryEmployer testEmployer = new FactoryEmployer(); + + Assert.IsFalse(testEmployer.CanEmploy(typeof(Base))); + Assert.IsTrue(testEmployer.CanEmploy(typeof(Derived))); + Assert.IsFalse(testEmployer.CanEmploy(typeof(Unrelated))); + } + + /// + /// Tests whether the factory employer throws an exception when it is asked to + /// employ an abstract class + /// + [Test, ExpectedException(typeof(MissingMethodException))] + public void TestThrowOnEmployAbstractClass() { + FactoryEmployer testEmployer = new FactoryEmployer(); + + testEmployer.Employ(typeof(Base)); + } + + /// + /// Tests whether the factory employer throws an exception when it is asked to + /// employ a class that is not the product type or a derivative thereof + /// + [Test, ExpectedException(typeof(InvalidCastException))] + public void TestThrowOnEmployUnrelatedClass() { + FactoryEmployer testEmployer = new FactoryEmployer(); + + testEmployer.Employ(typeof(Unrelated)); + } + + /// + /// Tests whether the factory employer can employ a class derived from the product + /// + [Test] + public void TestEmployClassDerivedFromProduct() { + FactoryEmployer testEmployer = new FactoryEmployer(); + + testEmployer.Employ(typeof(Derived)); + + Assert.AreEqual(1, testEmployer.Factories.Count); + Assert.AreEqual(typeof(Derived), testEmployer.Factories[0].ConcreteType); + Assert.IsInstanceOfType( + typeof(Derived), testEmployer.Factories[0].CreateInstance() + ); + } + + /// + /// Tests whether the factory employer can employ the product class itself if it + /// isn't abstract + /// + [Test] + public void TestEmployProduct() { + FactoryEmployer testEmployer = new FactoryEmployer(); + + testEmployer.Employ(typeof(Unrelated)); + + Assert.AreEqual(1, testEmployer.Factories.Count); + Assert.AreEqual(typeof(Unrelated), testEmployer.Factories[0].ConcreteType); + Assert.IsInstanceOfType( + typeof(Unrelated), testEmployer.Factories[0].CreateInstance() + ); + } + + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/FactoryEmployer.cs b/Source/Plugins/FactoryEmployer.cs index 3707b93..7fb62c0 100644 --- a/Source/Plugins/FactoryEmployer.cs +++ b/Source/Plugins/FactoryEmployer.cs @@ -41,7 +41,8 @@ namespace Nuclex.Support.Plugins { /// a human-readable name, capabilities or an icon. /// /// - public class FactoryEmployer : Employer { + public class FactoryEmployer : Employer + where ProductType : class { #region class ConcreteFactory @@ -94,6 +95,17 @@ namespace Nuclex.Support.Plugins { /// Employs the specified plugin type /// Type to be employed public override void Employ(Type type) { + if(!PluginHelper.HasDefaultConstructor(type)) { + throw new MissingMethodException( + "Cannot employ type because it does not have a public default constructor" + ); + } + if(!typeof(ProductType).IsAssignableFrom(type)) { + throw new InvalidCastException( + "Cannot employ type because it cannot be cast to the factory's product type" + ); + } + this.employedFactories.Add(new ConcreteFactory(type)); } diff --git a/Source/Plugins/InstanceEmployer.Test.cs b/Source/Plugins/InstanceEmployer.Test.cs new file mode 100644 index 0000000..5b2b213 --- /dev/null +++ b/Source/Plugins/InstanceEmployer.Test.cs @@ -0,0 +1,129 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the instance employer class + [TestFixture] + public class InstanceEmployerTest { + + #region class Base + + /// + /// Abstract base class to serve as abstract product for testing the instance employer + /// + private abstract class Base { } + + #endregion // class Base + + #region class Derived + + /// + /// Class derived from the abstract base to serve as concrete product for + /// testing the instance employer + /// + private class Derived : Base { } + + #endregion // class Derived + + #region class Unrelated + + /// Unrelated class used to test the instance employer + private class Unrelated { } + + #endregion // class Unrelated + + /// + /// Tests whether the instance employer can detect employable types + /// + [Test] + public void TestCanEmploy() { + InstanceEmployer testEmployer = new InstanceEmployer(); + + Assert.IsFalse(testEmployer.CanEmploy(typeof(Base))); + Assert.IsTrue(testEmployer.CanEmploy(typeof(Derived))); + Assert.IsFalse(testEmployer.CanEmploy(typeof(Unrelated))); + } + + + /// + /// Tests whether the instance employer throws an exception when it is asked to + /// employ an abstract class + /// + [Test, ExpectedException(typeof(MissingMethodException))] + public void TestThrowOnEmployAbstractClass() { + InstanceEmployer testEmployer = new InstanceEmployer(); + + testEmployer.Employ(typeof(Base)); + } + + /// + /// Tests whether the instance employer throws an exception when it is asked to + /// employ a class that is not the product type or a derivative thereof + /// + [Test, ExpectedException(typeof(InvalidCastException))] + public void TestThrowOnEmployUnrelatedClass() { + InstanceEmployer testEmployer = new InstanceEmployer(); + + testEmployer.Employ(typeof(Unrelated)); + } + + /// + /// Tests whether the instance employer can employ a class derived from the product + /// + [Test] + public void TestEmployClassDerivedFromProduct() { + InstanceEmployer testEmployer = new InstanceEmployer(); + + testEmployer.Employ(typeof(Derived)); + + Assert.AreEqual(1, testEmployer.Instances.Count); + Assert.AreEqual(typeof(Derived), testEmployer.Instances[0].GetType()); + Assert.IsInstanceOfType(typeof(Derived), testEmployer.Instances[0]); + } + + /// + /// Tests whether the instance employer can employ the product class itself if it + /// isn't abstract + /// + [Test] + public void TestEmployProduct() { + InstanceEmployer testEmployer = new InstanceEmployer(); + + testEmployer.Employ(typeof(Unrelated)); + + Assert.AreEqual(1, testEmployer.Instances.Count); + Assert.AreEqual(typeof(Unrelated), testEmployer.Instances[0].GetType()); + Assert.IsInstanceOfType(typeof(Unrelated), testEmployer.Instances[0]); + } + + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/NoPluginAttribute.Test.cs b/Source/Plugins/NoPluginAttribute.Test.cs new file mode 100644 index 0000000..73bb631 --- /dev/null +++ b/Source/Plugins/NoPluginAttribute.Test.cs @@ -0,0 +1,47 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the no plugin attribute class + [TestFixture] + public class NoPluginAttributeTest { + + /// + /// Tests whether the default consturctor of the no plugin attribute works + /// + [Test] + public void TestDefaultConstructor() { + new NoPluginAttribute(); + } + + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/PluginHost.Test.cs b/Source/Plugins/PluginHost.Test.cs new file mode 100644 index 0000000..503d5a3 --- /dev/null +++ b/Source/Plugins/PluginHost.Test.cs @@ -0,0 +1,38 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +#if UNITTEST + +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the plugin host class + [TestFixture] + public class PluginHostTest { + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/PluginRepository.Test.cs b/Source/Plugins/PluginRepository.Test.cs new file mode 100644 index 0000000..4de2c19 --- /dev/null +++ b/Source/Plugins/PluginRepository.Test.cs @@ -0,0 +1,142 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2008 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; +using System.Reflection; + +#if UNITTEST + +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; +using NMock2; + +namespace Nuclex.Support.Plugins { + + /// Unit Test for the plugin repository class + [TestFixture] + public class PluginRepositoryTest { + + #region interface IAssemblyLoadedSubscriber + + /// Interface used to test the progress tracker + public interface IAssemblyLoadedSubscriber { + + /// + /// Represents the method that handles the System.AppDomain.AssemblyLoad event + /// of an System.AppDomain + /// + /// The source of the event. + /// + /// An System.AssemblyLoadEventArgs that contains the event data + /// + void AssemblyLoaded(object sender, AssemblyLoadEventArgs arguments); + + } + + #endregion // interface IProgressTrackerSubscriber + + /// + /// Tests whether the default constructor of the plugin repository class works + /// + [Test] + public void TestDefaultConstructor() { + new PluginRepository(); + } + + /// + /// Tests whether the AddFiles() method accepts a file mask to which there are + /// no matching files + /// + [Test] + public void TestAddFilesWithZeroMatches() { + PluginRepository testRepository = new PluginRepository(); + testRepository.AddFiles(Guid.NewGuid().ToString()); + } + + /// + /// Tests whether the AddFiles() method accepts a file mask to which there is + /// exactly one matching file + /// + [Test] + public void TestAddFilesWithOwnAssembly() { + Assembly self = Assembly.GetAssembly(GetType()); + + PluginRepository testRepository = new PluginRepository(); + testRepository.AddFiles(self.Location); + } + + /// + /// Tests whether the AddAssembly() method works by adding the test assembly + /// itself to the repository + /// + [Test] + public void TestAddAssembly() { + PluginRepository testRepository = new PluginRepository(); + + // Might also use Assembly.GetCallingAssembly() here, but this leads to the exe of + // the unit testing tool + Assembly self = Assembly.GetAssembly(GetType()); + testRepository.AddAssembly(self); + + Assert.AreEqual(1, testRepository.LoadedAssemblies.Count); + } + + /// + /// Tests whether the AddAssembly() method works by adding the test assembly + /// itself to the repository + /// + [Test] + public void TestAssemblyLoadedEvent() { + Mockery mockery = new Mockery(); + + PluginRepository testRepository = new PluginRepository(); + IAssemblyLoadedSubscriber subscriber = mockSubscriber(mockery, testRepository); + + Expect.Once.On(subscriber).Method("AssemblyLoaded").WithAnyArguments(); + + Assembly self = Assembly.GetAssembly(GetType()); + testRepository.AddAssembly(self); + + mockery.VerifyAllExpectationsHaveBeenMet(); + } + + /// Mocks a subscriber for the events of a plugin repository + /// Mockery to create an event subscriber in + /// Repository to subscribe the mocked subscriber to + /// The mocked event subscriber + private static IAssemblyLoadedSubscriber mockSubscriber( + Mockery mockery, PluginRepository repository + ) { + IAssemblyLoadedSubscriber mockedSubscriber = + mockery.NewMock(); + + repository.AssemblyLoaded += new AssemblyLoadEventHandler( + mockedSubscriber.AssemblyLoaded + ); + + return mockedSubscriber; + } + + } + +} // namespace Nuclex.Support.Plugins + +#endif // UNITTEST diff --git a/Source/Plugins/PluginRepository.cs b/Source/Plugins/PluginRepository.cs index 4b0912a..b59e35a 100644 --- a/Source/Plugins/PluginRepository.cs +++ b/Source/Plugins/PluginRepository.cs @@ -52,6 +52,11 @@ namespace Nuclex.Support.Plugins { string directory = Path.GetDirectoryName(wildcard); string search = Path.GetFileName(wildcard); + // If no directory was specified, use the current working directory + if((directory == null) || (directory == string.Empty)) { + directory = "."; + } + // We'll scan the specified directory for all files matching the specified // wildcard. If only a single file is specified, only that file will match // the supposed wildcard and everything works as expected