11using System ;
22using System . IO ;
3+ using System . Linq ;
34using System . Reflection ;
4- using System . Runtime . InteropServices ;
55using FluentAssertions ;
66using Xunit ;
77
88namespace Pathy . Specs ;
99
1010public class ChainablePathSpecs
1111{
12- private readonly char slash = Path . DirectorySeparatorChar ;
12+ private static readonly char Slash = Path . DirectorySeparatorChar ;
1313 private readonly ChainablePath testFolder ;
1414
1515 public ChainablePathSpecs ( )
1616 {
17- testFolder = ChainablePath . Temp / nameof ( ChainablePathSpecs ) / Environment . Version . ToString ( ) ;
17+ testFolder = ChainablePath . Temp / nameof ( ChainablePathSpecs ) / Environment . Version . ToString ( ) ;
1818 testFolder . DeleteFileOrDirectory ( ) ;
1919 testFolder . CreateDirectoryRecursively ( ) ;
2020 }
@@ -57,7 +57,7 @@ public void Can_build_a_path_from_a_drive_letter(string drive)
5757 var path = ChainablePath . From ( drive ) ;
5858
5959 // Assert
60- path . ToString ( ) . Should ( ) . BeEquivalentTo ( "C:" + slash ) ;
60+ path . ToString ( ) . Should ( ) . BeEquivalentTo ( "C:" + Slash ) ;
6161 path . IsRooted . Should ( ) . BeTrue ( ) ;
6262 }
6363
@@ -93,15 +93,15 @@ public void A_trailing_slash_is_fine()
9393 public void Can_build_from_a_path_with_reverse_traversals ( )
9494 {
9595 // Arrange
96- var nestedPath = Directory . CreateDirectory ( testFolder . ToString ( ) + "/dir1" + slash + "dir2" + slash + "dir3/" ) ;
96+ var nestedPath = Directory . CreateDirectory ( testFolder . ToString ( ) + "/dir1" + Slash + "dir2" + Slash + "dir3/" ) ;
9797
9898 string location = nestedPath . FullName + "/../../.." ;
9999
100100 // Act
101101 var path = ChainablePath . From ( location ) ;
102102
103103 // Assert
104- path . ToString ( ) . Should ( ) . Be ( testFolder . ToString ( ) . Trim ( slash ) ) ;
104+ path . ToString ( ) . Should ( ) . Be ( testFolder . ToString ( ) . Trim ( Slash ) ) ;
105105 path . IsRooted . Should ( ) . BeTrue ( ) ;
106106 }
107107
@@ -164,7 +164,7 @@ public void Can_start_with_an_empty_path()
164164 var path = ChainablePath . New / "c:" / "temp" / "somefile.txt" ;
165165
166166 // Assert
167- path . ToString ( ) . Should ( ) . Be ( "c:" + slash + "temp" + slash + "somefile.txt" ) ;
167+ path . ToString ( ) . Should ( ) . Be ( "c:" + Slash + "temp" + Slash + "somefile.txt" ) ;
168168 }
169169
170170 [ Fact ]
@@ -178,7 +178,7 @@ public void Can_chain_a_relative_path_to_an_absolute_path()
178178 var path = absolutePath / relativePath ;
179179
180180 // Assert
181- path . ToString ( ) . Should ( ) . Be ( testFolder + slash + "dir1" + slash + "somefile.txt" ) ;
181+ path . ToString ( ) . Should ( ) . Be ( testFolder + Slash + "dir1" + Slash + "somefile.txt" ) ;
182182 }
183183
184184 [ Fact ]
@@ -188,7 +188,7 @@ public void Can_be_assigned_to_a_string()
188188 string result = ChainablePath . From ( "temp/somefile.txt" ) ;
189189
190190 // Assert
191- result . Should ( ) . Be ( "temp" + slash + "somefile.txt" ) ;
191+ result . Should ( ) . Be ( "temp" + Slash + "somefile.txt" ) ;
192192 }
193193
194194 [ Fact ]
@@ -201,7 +201,7 @@ public void Can_chain_multiple_directories()
201201 var result = temp / "dir1" / "dir2" / "dir3" ;
202202
203203 // Assert
204- result . DirectoryName . Should ( ) . Be ( temp + slash + "dir1" + slash + "dir2" ) ;
204+ result . DirectoryName . Should ( ) . Be ( temp + Slash + "dir1" + Slash + "dir2" ) ;
205205 result . Name . Should ( ) . Be ( "dir3" ) ;
206206 }
207207
@@ -235,7 +235,7 @@ public void Can_chain_directories_and_files()
235235 var result = testFolder / "dir1" / "dir2" / "dir3" / "file.txt" ;
236236
237237 // Assert
238- result . DirectoryName . Should ( ) . Be ( testFolder + slash + "dir1" + slash + "dir2" + slash + "dir3" ) ;
238+ result . DirectoryName . Should ( ) . Be ( testFolder + Slash + "dir1" + Slash + "dir2" + Slash + "dir3" ) ;
239239 result . Name . Should ( ) . Be ( "file.txt" ) ;
240240 }
241241
@@ -246,7 +246,7 @@ public void Ignores_superfluous_slashes()
246246 var result = testFolder / "dir1" / "dir2/" / "dir3/" / "file.txt" ;
247247
248248 // Assert
249- result . DirectoryName . Should ( ) . Be ( testFolder + slash + "dir1" + slash + "dir2" + slash + "dir3" ) ;
249+ result . DirectoryName . Should ( ) . Be ( testFolder + Slash + "dir1" + Slash + "dir2" + Slash + "dir3" ) ;
250250 result . Name . Should ( ) . Be ( "file.txt" ) ;
251251 }
252252
@@ -341,10 +341,9 @@ public void A_trailing_slash_does_not_affect_the_directory(string path)
341341 var result = ChainablePath . From ( path ) ;
342342
343343 // Assert
344- result . Directory ! . ToString ( ) . Should ( ) . Be ( "C:" + slash ) ;
344+ result . Directory ! . ToString ( ) . Should ( ) . Be ( "C:" + Slash ) ;
345345 }
346346
347-
348347 [ Fact ]
349348 public void The_root_does_not_have_a_parent_directory ( )
350349 {
@@ -513,4 +512,159 @@ public void Can_determine_if_a_path_refers_to_a_directory()
513512 path . IsFile . Should ( ) . BeFalse ( ) ;
514513 path . IsDirectory . Should ( ) . BeTrue ( ) ;
515514 }
515+
516+ [ Fact ]
517+ public void Can_find_the_first_existing_file_using_a_string_path ( )
518+ {
519+ // Arrange
520+ var existingFile = testFolder / "existing.txt" ;
521+ var nonExistingFile = testFolder / "nonexisting.txt" ;
522+ File . WriteAllText ( existingFile , "content" ) ;
523+
524+ // Act
525+ var result = ChainablePath . FindFirst ( nonExistingFile . ToString ( ) , existingFile . ToString ( ) ) ;
526+
527+ // Assert
528+ result . ToString ( ) . Should ( ) . Be ( existingFile . ToString ( ) ) ;
529+ result . FileExists . Should ( ) . BeTrue ( ) ;
530+ }
531+
532+ [ Fact ]
533+ public void Can_find_the_first_existing_file_using_a_chainable_path ( )
534+ {
535+ // Arrange
536+ var existingFile = testFolder / "existing.txt" ;
537+ var nonExistingFile = testFolder / "nonexisting.txt" ;
538+ File . WriteAllText ( existingFile , "content" ) ;
539+
540+ // Act
541+ var result = ChainablePath . FindFirst ( nonExistingFile , existingFile ) ;
542+
543+ // Assert
544+ result . ToString ( ) . Should ( ) . Be ( existingFile . ToString ( ) ) ;
545+ result . FileExists . Should ( ) . BeTrue ( ) ;
546+ }
547+
548+ [ Fact ]
549+ public void Can_find_the_first_existing_directory_using_a_string_path ( )
550+ {
551+ // Arrange
552+ var existingDir = testFolder / "existing-dir" ;
553+ var nonExistingDir = testFolder / "nonexisting-dir" ;
554+ existingDir . CreateDirectoryRecursively ( ) ;
555+
556+ // Act
557+ var result = ChainablePath . FindFirst ( nonExistingDir . ToString ( ) , existingDir . ToString ( ) ) ;
558+
559+ // Assert
560+ result . ToString ( ) . Should ( ) . Be ( existingDir . ToString ( ) ) ;
561+ result . DirectoryExists . Should ( ) . BeTrue ( ) ;
562+ }
563+
564+ [ Fact ]
565+ public void Can_find_the_first_existing_directory_using_a_chainable_path ( )
566+ {
567+ // Arrange
568+ var existingDir = testFolder / "existing-dir" ;
569+ var nonExistingDir = testFolder / "nonexisting-dir" ;
570+ existingDir . CreateDirectoryRecursively ( ) ;
571+
572+ // Act
573+ var result = ChainablePath . FindFirst ( nonExistingDir , existingDir ) ;
574+
575+ // Assert
576+ result . ToString ( ) . Should ( ) . Be ( existingDir . ToString ( ) ) ;
577+ result . DirectoryExists . Should ( ) . BeTrue ( ) ;
578+ }
579+
580+ [ Fact ]
581+ public void Returns_empty_for_non_existing_string_paths ( )
582+ {
583+ // Arrange
584+ var nonExistingFile1 = testFolder / "nonexisting1.txt" ;
585+ var nonExistingFile2 = testFolder / "nonexisting2.txt" ;
586+
587+ // Act
588+ var result = ChainablePath . FindFirst ( nonExistingFile1 . ToString ( ) , nonExistingFile2 . ToString ( ) ) ;
589+
590+ // Assert
591+ result . Should ( ) . Be ( ChainablePath . Empty ) ;
592+ }
593+
594+ [ Fact ]
595+ public void Returns_empty_for_non_existing_paths ( )
596+ {
597+ // Arrange
598+ var nonExistingFile1 = testFolder / "nonexisting1.txt" ;
599+ var nonExistingFile2 = testFolder / "nonexisting2.txt" ;
600+
601+ // Act
602+ var result = ChainablePath . FindFirst ( nonExistingFile1 , nonExistingFile2 ) ;
603+
604+ // Assert
605+ result . Should ( ) . Be ( ChainablePath . Empty ) ;
606+ }
607+
608+ [ Fact ]
609+ public void Cannot_find_the_first_existing_path_from_a_null_as_string_array ( )
610+ {
611+ // Act
612+ var act = ( ) => ChainablePath . FindFirst ( ( string [ ] ) null ) ;
613+
614+ // Assert
615+ act . Should ( ) . Throw < ArgumentNullException > ( ) . WithParameterName ( "paths" ) ;
616+ }
617+
618+ [ Fact ]
619+ public void Cannot_find_the_first_existing_path_from_a_null_array ( )
620+ {
621+ // Act & Assert
622+ var act = ( ) => ChainablePath . FindFirst ( ( ChainablePath [ ] ) null ) ;
623+
624+ // Assert
625+ act . Should ( ) . Throw < ArgumentNullException > ( ) . WithParameterName ( "paths" ) ;
626+ }
627+
628+ [ Fact ]
629+ public void Cannot_find_the_first_existing_path_from_an_empty_string_array ( )
630+ {
631+ // Act & Assert
632+ var act = ( ) =>
633+ ChainablePath . FindFirst ( new string [ 0 ] ) ;
634+
635+ // Assert
636+ act . Should ( ) . Throw < ArgumentException > ( )
637+ . WithMessage ( "*At least one path must be provided*" )
638+ . WithParameterName ( "paths" ) ;
639+ }
640+
641+ [ Fact ]
642+ public void Cannot_find_the_first_existing_path_from_an_empty_array ( )
643+ {
644+ // Act & Assert
645+ var act = ( ) =>
646+ ChainablePath . FindFirst ( new ChainablePath [ 0 ] ) ;
647+
648+ act . Should ( ) . Throw < ArgumentException > ( )
649+ . WithMessage ( "*At least one path must be provided*" )
650+ . WithParameterName ( "paths" ) ;
651+ }
652+
653+ [ Theory ]
654+ [ InlineData ( "config.json" , ".subdirectory/config.json" ) ]
655+ [ InlineData ( "app.config" , "config/app.config" , ".config/app.config" ) ]
656+ public void FromFirstExisting_usage_examples_work_as_expected ( params string [ ] paths )
657+ {
658+ // Arrange - create the second path in each case
659+ var testPath = testFolder / paths [ 1 ] ;
660+ testPath . Directory . CreateDirectoryRecursively ( ) ;
661+ File . WriteAllText ( testPath , "configuration content" ) ;
662+
663+ // Act
664+ var result = ChainablePath . FindFirst ( paths . Select ( p => testFolder / p ) . Select ( p => p . ToString ( ) ) . ToArray ( ) ) ;
665+
666+ // Assert
667+ result . ToString ( ) . Should ( ) . Be ( testPath . ToString ( ) ) ;
668+ result . FileExists . Should ( ) . BeTrue ( ) ;
669+ }
516670}
0 commit comments