diff --git a/.gitlab/test.sh b/.gitlab/test.sh
index d168241..3b38e26 100755
--- a/.gitlab/test.sh
+++ b/.gitlab/test.sh
@@ -1,7 +1,5 @@
-#dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=../artifacts/{assembly}-test-result.xml;MethodFormat=Default;FailureBodyFormat=Verbose" --collect:"XPlat Code Coverage"
-#dotnet new tool-manifest
-#dotnet tool install dotnet-reportgenerator-globaltool
-#dotnet tool run reportgenerator -reports:tests/*/TestResults/*/coverage.cobertura.xml -targetdir:./coverage "-reporttypes:Cobertura;TextSummary"
-#grep "Line coverage" coverage/Summary.txt
-
-echo "Line coverage 0.00%"
+dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=../artifacts/{assembly}-test-result.xml;MethodFormat=Default;FailureBodyFormat=Verbose" --collect:"XPlat Code Coverage"
+dotnet new tool-manifest
+dotnet tool install dotnet-reportgenerator-globaltool
+dotnet tool run reportgenerator -reports:tests/*/TestResults/*/coverage.cobertura.xml -targetdir:./coverage "-reporttypes:Cobertura;TextSummary"
+grep "Line coverage" coverage/Summary.txt
diff --git a/MfGames.IO.sln b/MfGames.IO.sln
index 6d456f6..2b3a24e 100644
--- a/MfGames.IO.sln
+++ b/MfGames.IO.sln
@@ -7,6 +7,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1C957FCA-B9A
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.IO", "src\MfGames.IO\MfGames.IO.csproj", "{D4386FAC-E9E0-4FBF-9423-5F3699F19920}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{6F7CE793-DD94-4AD7-B3CB-94ECF2BA77A6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.IO.Tests", "tests\MfGames.IO.Tests\MfGames.IO.Tests.csproj", "{4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -32,8 +36,21 @@ Global
{D4386FAC-E9E0-4FBF-9423-5F3699F19920}.Release|x64.Build.0 = Release|Any CPU
{D4386FAC-E9E0-4FBF-9423-5F3699F19920}.Release|x86.ActiveCfg = Release|Any CPU
{D4386FAC-E9E0-4FBF-9423-5F3699F19920}.Release|x86.Build.0 = Release|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Debug|x64.Build.0 = Debug|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Debug|x86.Build.0 = Debug|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Release|x64.ActiveCfg = Release|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Release|x64.Build.0 = Release|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Release|x86.ActiveCfg = Release|Any CPU
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{D4386FAC-E9E0-4FBF-9423-5F3699F19920} = {1C957FCA-B9AA-4A64-BF20-E215EAE5C4E4}
+ {4E3B0E55-A1A0-4007-8CF2-C02396FBBB22} = {6F7CE793-DD94-4AD7-B3CB-94ECF2BA77A6}
EndGlobalSection
EndGlobal
diff --git a/README.md b/README.md
index 8f108f2..f7b3674 100644
--- a/README.md
+++ b/README.md
@@ -90,3 +90,13 @@ The same as `File.WriteAllText(file.GetFullPath, text)`.
#### `void WriteAllText(this FileInfo file, string text, Encoding encoding)`
The same as `File.WriteAllText(file.GetFullPath, text, encoding)`.
+
+### Type Extensions
+
+#### `DirectoryInfo? GetDirectory(this Type? type)`
+
+Gets a directory containing the type's assembly directory.
+
+#### `FileInfo? GetFile(this Type? type)`
+
+Gets a file representing the type's assembly's `Location` property or null.
diff --git a/src/MfGames.IO/Extensions/DirectoryInfoExtensions.cs b/src/MfGames.IO/Extensions/DirectoryInfoExtensions.cs
index ae5cbe9..fe02a0e 100644
--- a/src/MfGames.IO/Extensions/DirectoryInfoExtensions.cs
+++ b/src/MfGames.IO/Extensions/DirectoryInfoExtensions.cs
@@ -86,7 +86,7 @@ namespace MfGames.IO.Extensions
// If the directory is null, just return null. Same with
// non-existing directories. We don't use directory.Exists here
// because it seems to be cached and we get incorrect data.
- if (directory == null || !File.Exists(directory.FullName))
+ if (directory == null || !Directory.Exists(directory.FullName))
{
return null;
}
diff --git a/src/MfGames.IO/Extensions/TypeExtensions.cs b/src/MfGames.IO/Extensions/TypeExtensions.cs
new file mode 100644
index 0000000..5849b11
--- /dev/null
+++ b/src/MfGames.IO/Extensions/TypeExtensions.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace MfGames.IO.Extensions
+{
+ ///
+ /// Additional methods for types.
+ ///
+ public static class TypeExtensions
+ {
+ ///
+ /// Gets the directory for a given type.
+ ///
+ /// The type assembly to get the directory.
+ /// The directory or null if the assembly or location is null.
+ public static DirectoryInfo? GetDirectory(this Type? type)
+ {
+ return type?.Assembly.GetDirectory();
+ }
+
+ ///
+ /// Gets the file for a given type's assembly.
+ ///
+ /// The type assembly to get the directory.
+ /// The directory or null if the assembly or location is null.
+ public static FileInfo? GetFile(this Type? type)
+ {
+ return type?.Assembly.GetFile();
+ }
+ }
+}
diff --git a/tests/MfGames.IO.Tests/AssemblyExtensionsTests.cs b/tests/MfGames.IO.Tests/AssemblyExtensionsTests.cs
new file mode 100644
index 0000000..a3973a7
--- /dev/null
+++ b/tests/MfGames.IO.Tests/AssemblyExtensionsTests.cs
@@ -0,0 +1,29 @@
+using System.IO;
+
+using MfGames.IO.Extensions;
+
+using Xunit;
+
+namespace MfGames.IO.Tests
+{
+ public class AssemblyExtensionsTests
+ {
+ [Fact]
+ public void DirectoryExists()
+ {
+ DirectoryInfo? dir = this.GetType().Assembly.GetDirectory();
+
+ Assert.NotNull(dir);
+ Assert.True(dir!.Exists);
+ }
+
+ [Fact]
+ public void FileExists()
+ {
+ FileInfo? file = this.GetType().Assembly.GetFile();
+
+ Assert.NotNull(file);
+ Assert.True(file!.Exists);
+ }
+ }
+}
diff --git a/tests/MfGames.IO.Tests/GitRootTests.cs b/tests/MfGames.IO.Tests/GitRootTests.cs
new file mode 100644
index 0000000..84b02b1
--- /dev/null
+++ b/tests/MfGames.IO.Tests/GitRootTests.cs
@@ -0,0 +1,21 @@
+using System.IO;
+
+using MfGames.IO.Extensions;
+
+using Xunit;
+
+namespace MfGames.IO.Tests
+{
+ public class GitRootTests
+ {
+ [Fact]
+ public void FindGitRoot()
+ {
+ DirectoryInfo? dir = this.GetType().GetDirectory();
+ DirectoryInfo? git = dir.FindGitRoot();
+
+ Assert.NotNull(git);
+ Assert.True(git!.GetDirectories(".git").Length > 0);
+ }
+ }
+}
diff --git a/tests/MfGames.IO.Tests/MfGames.IO.Tests.csproj b/tests/MfGames.IO.Tests/MfGames.IO.Tests.csproj
new file mode 100644
index 0000000..704204a
--- /dev/null
+++ b/tests/MfGames.IO.Tests/MfGames.IO.Tests.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net5.0
+ enable
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+