2024-11-25 16:52:49 -05:00
using System ;
2026-03-22 15:35:11 -04:00
using System.Collections.Generic ;
2024-11-25 16:52:49 -05:00
using System.IO ;
using System.Text ;
2024-03-05 10:45:31 -05:00
using Xunit ;
2026-03-18 15:47:44 -04:00
namespace SabreTools.IO.Extensions.Test
2024-03-05 10:45:31 -05:00
{
public class IOExtensionsTests
{
2026-03-18 13:44:43 -04:00
#region EnsureDirectory
2024-11-25 16:52:49 -05:00
[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData(" ", " ")] // TODO: This is a bad result
[InlineData("dirname", "dirname")]
[InlineData("\"dirname\"", "dirname")]
2026-03-18 13:44:43 -04:00
public void EnsureDirectoryTest ( string? dir , string? expected )
2024-11-25 16:52:49 -05:00
{
// Handle test setup
expected ? ? = PathTool . GetRuntimeDirectory ( ) ;
2026-01-25 17:04:11 -05:00
if ( expected is not null )
2024-11-25 16:52:49 -05:00
expected = Path . GetFullPath ( expected ) ;
2026-03-18 13:44:43 -04:00
string actual = dir . EnsureDirectory ( create : false ) ;
2024-11-25 16:52:49 -05:00
Assert . Equal ( expected , actual ) ;
}
#endregion
2026-03-22 15:35:11 -04:00
#region GetDirectoriesOnly
[Fact]
public void GetDirectoriesOnly_NoAppendParent ( )
{
string expectedParent = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
string expectedCurrent = Path . Combine ( expectedParent , "Subdirectory" ) ;
List < string > inputs =
[
string . Empty ,
Path . Combine ( Environment . CurrentDirectory , "TestData" ) ,
Path . Combine ( Environment . CurrentDirectory , "TestData" , "Subdir*" ) ,
] ;
var actual = IOExtensions . GetDirectoriesOnly ( inputs , appendParent : true ) ;
Assert . NotEmpty ( actual ) ;
var first = actual [ 0 ] ;
Assert . Equal ( expectedCurrent , first . CurrentPath ) ;
Assert . Equal ( expectedParent , first . ParentPath ) ;
}
[Fact]
public void GetDirectoriesOnly_AppendParent ( )
{
string expectedParent = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
string expectedCurrent = Path . Combine ( expectedParent , "Subdirectory" ) ;
List < string > inputs =
[
string . Empty ,
Path . Combine ( Environment . CurrentDirectory , "TestData" ) ,
Path . Combine ( Environment . CurrentDirectory , "TestData" , "Subdir*" ) ,
] ;
var actual = IOExtensions . GetDirectoriesOnly ( inputs , appendParent : false ) ;
Assert . NotEmpty ( actual ) ;
var first = actual [ 0 ] ;
Assert . Equal ( expectedCurrent , first . CurrentPath ) ;
Assert . Equal ( string . Empty , first . ParentPath ) ;
}
#endregion
#region ListEmpty
[Fact]
public void ListEmpty_NullDirectory ( )
{
string? dir = null ;
var empty = dir . ListEmpty ( ) ;
Assert . Null ( empty ) ;
}
[Fact]
public void ListEmpty_InvalidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" , "INVALID" ) ;
var empty = dir . ListEmpty ( ) ;
Assert . Null ( empty ) ;
}
[Fact]
public void ListEmpty_ValidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var empty = dir . ListEmpty ( ) ;
Assert . NotNull ( empty ) ;
Assert . Empty ( empty ) ;
}
#endregion
2026-03-24 09:57:40 -04:00
#region Concatenate
[Fact]
public void Concatenate_EmptyList_False ( )
{
List < string > paths = [ ] ;
string output = string . Empty ;
bool actual = IOExtensions . Concatenate ( paths , output ) ;
Assert . False ( actual ) ;
}
[Fact]
public void Concatenate_InvalidOutput_False ( )
{
List < string > paths = [ "a" ] ;
string output = string . Empty ;
bool actual = IOExtensions . Concatenate ( paths , output ) ;
Assert . False ( actual ) ;
}
[Fact]
public void Concatenate_FilledList_True ( )
{
List < string > paths = [
Path . Combine ( Environment . CurrentDirectory , "TestData" , "ascii.txt" ) ,
Path . Combine ( Environment . CurrentDirectory , "TestData" , "file-to-compress.bin" ) ,
] ;
string output = Guid . NewGuid ( ) . ToString ( ) ;
bool actual = IOExtensions . Concatenate ( paths , output ) ;
Assert . True ( actual ) ;
string text = File . ReadAllText ( output ) ;
Assert . Equal ( "This doesn't match anythingThis is just a file that has a known set of hashes to make sure that everything with hashing is still working as anticipated." , text ) ;
File . Delete ( output ) ;
}
#endregion
2026-03-22 15:35:11 -04:00
#region GetEncoding
2024-11-25 16:52:49 -05:00
[Fact]
public void GetEncoding_EmptyPath ( )
{
string path = "" ;
Encoding expected = Encoding . Default ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
[Fact]
public void GetEncoding_InvalidPath ( )
{
string path = Path . Combine ( Environment . CurrentDirectory , "TestData" , "INVALID" ) ;
Encoding expected = Encoding . Default ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
// Disable warning about UTF7 usage
#pragma warning disable SYSLIB0001
[Fact]
public void GetEncoding_UTF7 ( )
{
string path = Path . Combine ( Environment . CurrentDirectory , "TestData" , "utf7bom.txt" ) ;
Encoding expected = Encoding . UTF7 ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
#pragma warning restore SYSLIB0001
[Fact]
public void GetEncoding_UTF8 ( )
{
string path = Path . Combine ( Environment . CurrentDirectory , "TestData" , "utf8bom.txt" ) ;
Encoding expected = Encoding . UTF8 ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
[Fact]
public void GetEncoding_Unicode ( )
{
string path = Path . Combine ( Environment . CurrentDirectory , "TestData" , "utf16lebom.txt" ) ;
Encoding expected = Encoding . Unicode ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
[Fact]
public void GetEncoding_BigEndianUnicode ( )
{
string path = Path . Combine ( Environment . CurrentDirectory , "TestData" , "utf16bebom.txt" ) ;
Encoding expected = Encoding . BigEndianUnicode ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
[Fact]
public void GetEncoding_UTF32 ( )
{
string path = Path . Combine ( Environment . CurrentDirectory , "TestData" , "utf32bom.txt" ) ;
Encoding expected = Encoding . UTF32 ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
[Fact]
public void GetEncoding_ASCII ( )
{
string path = Path . Combine ( Environment . CurrentDirectory , "TestData" , "ascii.txt" ) ;
Encoding expected = Encoding . Default ;
var actual = path . GetEncoding ( ) ;
Assert . Equal ( expected , actual ) ;
}
#endregion
2026-03-22 15:35:11 -04:00
#region GetFilesOnly
[Fact]
public void GetFilesOnly_NoAppendParent ( )
{
string expectedParent = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
string expectedCurrent = Path . Combine ( expectedParent , "ascii.txt" ) ;
List < string > inputs =
[
string . Empty ,
Path . Combine ( Environment . CurrentDirectory , "TestData" ) ,
Path . Combine ( Environment . CurrentDirectory , "TestData" , "Subdir*" ) ,
Path . Combine ( Environment . CurrentDirectory , "TestData" , "utf8bom.txt" ) ,
] ;
var actual = IOExtensions . GetFilesOnly ( inputs , appendParent : true ) ;
Assert . NotEmpty ( actual ) ;
var first = actual [ 0 ] ;
Assert . Equal ( expectedCurrent , first . CurrentPath ) ;
Assert . Equal ( expectedParent , first . ParentPath ) ;
}
[Fact]
public void GetFilesOnly_AppendParent ( )
{
string expectedParent = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
string expectedCurrent = Path . Combine ( expectedParent , "ascii.txt" ) ;
List < string > inputs =
[
string . Empty ,
Path . Combine ( Environment . CurrentDirectory , "TestData" ) ,
Path . Combine ( Environment . CurrentDirectory , "TestData" , "Subdir*" ) ,
Path . Combine ( Environment . CurrentDirectory , "TestData" , "utf8bom.txt" ) ,
] ;
var actual = IOExtensions . GetFilesOnly ( inputs , appendParent : false ) ;
Assert . NotEmpty ( actual ) ;
var first = actual [ 0 ] ;
Assert . Equal ( expectedCurrent , first . CurrentPath ) ;
Assert . Equal ( string . Empty , first . ParentPath ) ;
}
#endregion
2026-03-22 17:17:13 -04:00
#region FileSize
[Fact]
public void FileSize_Null_Invalid ( )
{
string? filename = null ;
long actual = filename . GetFileSize ( ) ;
Assert . Equal ( - 1 , actual ) ;
}
[Fact]
public void FileSize_Empty_Invalid ( )
{
string? filename = string . Empty ;
long actual = filename . GetFileSize ( ) ;
Assert . Equal ( - 1 , actual ) ;
}
[Fact]
public void FileSize_Invalid_Invalid ( )
{
string? filename = "INVALID" ;
long actual = filename . GetFileSize ( ) ;
Assert . Equal ( - 1 , actual ) ;
}
#endregion
2026-03-22 15:35:11 -04:00
#region GetNormalizedExtension
2024-11-25 16:52:49 -05:00
2024-03-05 10:45:31 -05:00
[Theory]
[InlineData(null, null)]
[InlineData("", null)]
[InlineData(" ", null)]
[InlineData("no-extension", null)]
[InlineData("NO-EXTENSION", null)]
[InlineData("no-extension.", null)]
[InlineData("NO-EXTENSION.", null)]
[InlineData("filename.ext", "ext")]
[InlineData("FILENAME.EXT", "ext")]
2024-11-25 16:52:49 -05:00
public void GetNormalizedExtensionTest ( string? path , string? expected )
2024-03-05 10:45:31 -05:00
{
string? actual = path . GetNormalizedExtension ( ) ;
Assert . Equal ( expected , actual ) ;
}
2024-11-25 16:52:49 -05:00
#endregion
2026-03-22 15:35:11 -04:00
#region NormalizeFilePath
2026-03-18 13:44:43 -04:00
[Theory]
[InlineData(null, false, "")]
[InlineData(null, true, "")]
[InlineData("", false, "")]
[InlineData("", true, "")]
[InlineData("filename.bin", false, "filename.bin")]
[InlineData("filename.bin", true, "filename.bin")]
[InlineData("\"filename.bin\"", false, "filename.bin")]
[InlineData("\"filename.bin\"", true, "filename.bin")]
[InlineData("<filename.bin>", false, "filename.bin")]
[InlineData("<filename.bin>", true, "filename.bin")]
[InlineData("1.2.3.4..bin", false, "1.2.3.4..bin")]
[InlineData("1.2.3.4..bin", true, "1.2.3.4..bin")]
[InlineData("dir/filename.bin", false, "dir/filename.bin")]
[InlineData("dir/filename.bin", true, "dir/filename.bin")]
[InlineData(" dir / filename.bin", false, "dir/filename.bin")]
[InlineData(" dir / filename.bin", true, "dir/filename.bin")]
[InlineData("\0dir/\0filename.bin", false, "_dir/_filename.bin")]
[InlineData("\0dir/\0filename.bin", true, "_dir/_filename.bin")]
public void NormalizeOutputPathsTest ( string? path , bool getFullPath , string expected )
{
// Modify expected to account for test data if necessary
if ( getFullPath & & ! string . IsNullOrEmpty ( expected ) )
expected = Path . GetFullPath ( expected ) ;
string actual = path . NormalizeFilePath ( getFullPath ) ;
Assert . Equal ( expected , actual ) ;
}
#endregion
2026-07-02 10:01:18 -04:00
#region ResolvePath
[Theory]
[InlineData(null)]
[InlineData("")]
public void ResolvePath_NullOrEmpty_ReturnsNull ( string? path )
{
string? actual = path . ResolvePath ( ) ;
Assert . Null ( actual ) ;
}
// TODO: Add tests for home path without modifying the runner's home path
[Fact]
2026-07-02 10:21:15 -04:00
public void ResolvePath_AbsolutePath_Exists_ReturnsFullPath ( )
2026-07-02 10:01:18 -04:00
{
2026-07-02 10:21:15 -04:00
string filename = Guid . NewGuid ( ) . ToString ( ) ;
string path = Path . Combine ( Environment . CurrentDirectory , filename ) ;
2026-07-02 10:01:18 -04:00
2026-07-02 10:21:15 -04:00
File . WriteAllBytes ( path , [ ] ) ;
try
{
string? actual = filename . ResolvePath ( ) ;
Assert . Equal ( path , actual ) ;
}
finally
{
File . Delete ( path ) ;
}
2026-07-02 10:01:18 -04:00
}
[Fact]
public void ResolvePath_AbsolutePath_Missing_ReturnsNull ( )
{
2026-07-02 10:21:15 -04:00
string filename = Guid . NewGuid ( ) . ToString ( ) ;
string path = Path . Combine ( Environment . CurrentDirectory , filename ) ;
2026-07-02 10:01:18 -04:00
string? actual = path . ResolvePath ( ) ;
Assert . Null ( actual ) ;
}
2026-07-02 10:21:15 -04:00
[Fact]
public void ResolvePath_RelativePath_Exists_ReturnsFullPath ( )
{
string filename = Guid . NewGuid ( ) . ToString ( ) ;
string subDir = "RELATIVE" ;
string path = Path . Combine ( subDir , filename ) ;
string expected = Path . Combine ( Environment . CurrentDirectory , path ) ;
Directory . CreateDirectory ( subDir ) ;
File . WriteAllBytes ( path , [ ] ) ;
try
{
string? actual = path . ResolvePath ( ) ;
Assert . Equal ( expected , actual ) ;
}
finally
{
Directory . Delete ( subDir , recursive : true ) ;
}
}
2026-07-02 10:01:18 -04:00
[Fact]
public void ResolvePath_RelativePath_Missing_ReturnsNull ( )
{
2026-07-02 10:21:15 -04:00
string filename = Guid . NewGuid ( ) . ToString ( ) ;
string subDir = "INVALID" ;
string path = Path . Combine ( subDir , filename ) ;
2026-07-02 10:01:18 -04:00
string? actual = path . ResolvePath ( ) ;
Assert . Null ( actual ) ;
}
[Fact]
public void ResolvePath_BareName_RuntimeDirectory_ReturnsFullPath ( )
{
2026-07-02 10:21:15 -04:00
string filename = Guid . NewGuid ( ) . ToString ( ) ;
2026-07-02 10:01:18 -04:00
string path = Path . Combine ( AppContext . BaseDirectory , filename ) ;
File . WriteAllBytes ( path , [ ] ) ;
try
{
string? actual = filename . ResolvePath ( ) ;
Assert . Equal ( path , actual ) ;
}
finally
{
File . Delete ( path ) ;
}
}
[Fact]
public void ResolvePath_BareName_Path_ReturnsFullPath ( )
{
2026-07-02 10:21:15 -04:00
string filename = Guid . NewGuid ( ) . ToString ( ) ;
string subDir = Path . GetFullPath ( "TEMP" ) ;
string path = Path . Combine ( subDir , filename ) ;
string expected = Path . Combine ( Environment . CurrentDirectory , path ) ;
2026-07-02 10:01:18 -04:00
2026-07-02 10:21:15 -04:00
Directory . CreateDirectory ( subDir ) ;
2026-07-02 10:01:18 -04:00
File . WriteAllBytes ( path , [ ] ) ;
// Prepend the temp directory to PATH and check it exists
// TODO: See if there's a way around changing the actual environment variables
string? originalPath = Environment . GetEnvironmentVariable ( "PATH" ) ;
try
{
2026-07-02 10:21:15 -04:00
Environment . SetEnvironmentVariable ( "PATH" , subDir + Path . PathSeparator + ( originalPath ? ? string . Empty ) ) ;
2026-07-02 10:01:18 -04:00
string? actual = filename . ResolvePath ( ) ;
2026-07-02 10:21:15 -04:00
Assert . Equal ( expected , actual ) ;
2026-07-02 10:01:18 -04:00
}
finally
{
Environment . SetEnvironmentVariable ( "PATH" , originalPath ) ;
2026-07-02 10:21:15 -04:00
Directory . Delete ( subDir , recursive : true ) ;
2026-07-02 10:01:18 -04:00
}
}
[Fact]
public void ResolvePath_BareName_Missing_ReturnsNull ( )
{
2026-07-02 10:21:15 -04:00
string filename = Guid . NewGuid ( ) . ToString ( ) ;
2026-07-02 10:01:18 -04:00
string? actual = filename . ResolvePath ( ) ;
Assert . Null ( actual ) ;
}
#endregion
2026-03-22 15:35:11 -04:00
#region SafeGetDirectories
2024-11-25 16:52:49 -05:00
[Fact]
public void SafeGetDirectories_ValidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var dirs = dir . SafeGetDirectories ( ) ;
Assert . Single ( dirs ) ;
}
[Fact]
public void SafeGetDirectories_ValidDirectory_Pattern ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var dirs = dir . SafeGetDirectories ( "*" ) ;
Assert . Single ( dirs ) ;
}
[Fact]
public void SafeGetDirectories_ValidDirectory_PatternOption ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var dirs = dir . SafeGetDirectories ( "*" , SearchOption . AllDirectories ) ;
Assert . Single ( dirs ) ;
}
2025-07-23 10:25:19 -04:00
2026-03-22 15:35:11 -04:00
#endregion
#region SafeGetFiles
2024-11-25 16:52:49 -05:00
[Fact]
public void SafeGetFiles_ValidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var files = dir . SafeGetFiles ( ) ;
Assert . NotEmpty ( files ) ;
}
[Fact]
public void SafeGetFiles_ValidDirectory_Pattern ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var files = dir . SafeGetFiles ( "*" ) ;
Assert . NotEmpty ( files ) ;
}
[Fact]
public void SafeGetFiles_ValidDirectory_PatternOption ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var files = dir . SafeGetFiles ( "*" , SearchOption . AllDirectories ) ;
Assert . NotEmpty ( files ) ;
}
2026-03-22 15:35:11 -04:00
#endregion
#region SafeGetFileSystemEntries
2024-11-25 16:52:49 -05:00
[Fact]
public void SafeGetFileSystemEntries_ValidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var entries = dir . SafeGetFileSystemEntries ( ) ;
Assert . NotEmpty ( entries ) ;
}
[Fact]
public void SafeGetFileSystemEntries_ValidDirectory_Pattern ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var entries = dir . SafeGetFileSystemEntries ( "*" ) ;
Assert . NotEmpty ( entries ) ;
}
[Fact]
public void SafeGetFileSystemEntries_ValidDirectory_PatternOption ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var entries = dir . SafeGetFileSystemEntries ( "*" , SearchOption . AllDirectories ) ;
Assert . NotEmpty ( entries ) ;
}
2026-03-22 15:35:11 -04:00
#endregion
#region SafeEnumerateDirectories
2024-11-25 16:52:49 -05:00
[Fact]
public void SafeEnumerateDirectories_ValidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var dirs = dir . SafeEnumerateDirectories ( ) ;
Assert . Single ( dirs ) ;
}
[Fact]
public void SafeEnumerateDirectories_ValidDirectory_Pattern ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var dirs = dir . SafeEnumerateDirectories ( "*" ) ;
Assert . Single ( dirs ) ;
}
[Fact]
public void SafeEnumerateDirectories_ValidDirectory_PatternOption ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var dirs = dir . SafeEnumerateDirectories ( "*" , SearchOption . AllDirectories ) ;
Assert . Single ( dirs ) ;
}
2025-07-23 10:25:19 -04:00
2026-03-22 15:35:11 -04:00
#endregion
#region SafeEnumerateFiles
2024-11-25 16:52:49 -05:00
[Fact]
public void SafeEnumerateFiles_ValidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var files = dir . SafeEnumerateFiles ( ) ;
Assert . NotEmpty ( files ) ;
}
[Fact]
public void SafeEnumerateFiles_ValidDirectory_Pattern ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var files = dir . SafeEnumerateFiles ( "*" ) ;
Assert . NotEmpty ( files ) ;
}
[Fact]
public void SafeEnumerateFiles_ValidDirectory_PatternOption ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var files = dir . SafeEnumerateFiles ( "*" , SearchOption . AllDirectories ) ;
Assert . NotEmpty ( files ) ;
}
2026-03-22 15:35:11 -04:00
#endregion
#region SafeEnumerateFileSystemEntries
2024-11-25 16:52:49 -05:00
[Fact]
public void SafeEnumerateFileSystemEntries_ValidDirectory ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var entries = dir . SafeEnumerateFileSystemEntries ( ) ;
Assert . NotEmpty ( entries ) ;
}
[Fact]
public void SafeEnumerateFileSystemEntries_ValidDirectory_Pattern ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var entries = dir . SafeEnumerateFileSystemEntries ( "*" ) ;
Assert . NotEmpty ( entries ) ;
}
[Fact]
public void SafeEnumerateFileSystemEntries_ValidDirectory_PatternOption ( )
{
string dir = Path . Combine ( Environment . CurrentDirectory , "TestData" ) ;
var entries = dir . SafeEnumerateFileSystemEntries ( "*" , SearchOption . AllDirectories ) ;
Assert . NotEmpty ( entries ) ;
}
#endregion
2024-03-05 10:45:31 -05:00
}
2025-07-23 10:25:19 -04:00
}