@@ -97,4 +97,88 @@ public void WhenBatchRenamingPhotosWithDateTimeAndNoAllowedExtensionsExist_ThenN
9797 // Assert
9898 Assert . Equal ( existingFiles , updatedFiles ) ;
9999 }
100- }
100+
101+ [ Fact ]
102+ public void WhenTwoPhotosShareACreationSecond_ThenBothAreRenamedWithoutCollision ( )
103+ {
104+ var first = Path . Combine ( _tempDirectory , "a.jpg" ) ;
105+ var second = Path . Combine ( _tempDirectory , "b.jpg" ) ;
106+ File . Create ( first ) . Close ( ) ;
107+ File . Create ( second ) . Close ( ) ;
108+ var sameSecond = new DateTime ( 2025 , 6 , 1 , 10 , 30 , 0 ) ;
109+ File . SetCreationTime ( first , sameSecond ) ;
110+ File . SetCreationTime ( second , sameSecond ) ;
111+
112+ // Act
113+ ImageRenameService . RenameImagesWithDateTime ( _tempDirectory ) ;
114+
115+ // Assert
116+ var names = Directory . GetFiles ( _tempDirectory ) . Select ( f => Path . GetFileName ( f ) ) . Order ( StringComparer . Ordinal ) . ToArray ( ) ;
117+ Assert . Equal ( [ "Image_2025-06-01_103000.jpg" , "Image_2025-06-01_103000_1.jpg" ] , names ) ;
118+ }
119+
120+ [ Fact ]
121+ public void WhenBatchRenameRunsTwice_ThenSecondRunChangesNothing ( )
122+ {
123+ var sameSecond = new DateTime ( 2025 , 6 , 1 , 10 , 30 , 0 ) ;
124+ foreach ( var name in new [ ] { "a.jpg" , "b.jpg" } )
125+ {
126+ var path = Path . Combine ( _tempDirectory , name ) ;
127+ File . Create ( path ) . Close ( ) ;
128+ File . SetCreationTime ( path , sameSecond ) ;
129+ }
130+ ImageRenameService . RenameImagesWithDateTimeUsingFileInfo ( _tempDirectory ) ;
131+ var afterFirstRun = Directory . GetFiles ( _tempDirectory ) . Order ( ) . ToArray ( ) ;
132+
133+ // Act
134+ ImageRenameService . RenameImagesWithDateTimeUsingFileInfo ( _tempDirectory ) ;
135+
136+ // Assert
137+ Assert . Equal ( afterFirstRun , Directory . GetFiles ( _tempDirectory ) . Order ( ) . ToArray ( ) ) ;
138+ }
139+
140+ [ Fact ]
141+ public void GivenExistingFolder_WhenRenamingFolder_ThenContentMovesWithIt ( )
142+ {
143+ var oldFolder = Path . Combine ( _tempDirectory , "Invoices2025" ) ;
144+ Directory . CreateDirectory ( oldFolder ) ;
145+ File . WriteAllText ( Path . Combine ( oldFolder , "invoice-001.pdf" ) , "content" ) ;
146+ var newFolder = Path . Combine ( _tempDirectory , "Invoices-2025" ) ;
147+
148+ // Act
149+ FolderRenameService . RenameFolder ( oldFolder , newFolder ) ;
150+
151+ // Assert
152+ Assert . False ( Directory . Exists ( oldFolder ) ) ;
153+ Assert . True ( File . Exists ( Path . Combine ( newFolder , "invoice-001.pdf" ) ) ) ;
154+ }
155+
156+ [ Fact ]
157+ public void GivenTextFile_WhenChangingExtension_ThenOnlyExtensionChanges ( )
158+ {
159+ var filePath = Path . Combine ( _tempDirectory , "notes.txt" ) ;
160+ File . WriteAllText ( filePath , "content" ) ;
161+
162+ // Act
163+ var newFilePath = FileRenameService . ChangeExtension ( filePath , ".md" ) ;
164+
165+ // Assert
166+ Assert . Equal ( Path . Combine ( _tempDirectory , "notes.md" ) , newFilePath ) ;
167+ Assert . True ( File . Exists ( newFilePath ) ) ;
168+ Assert . False ( File . Exists ( filePath ) ) ;
169+ }
170+
171+ [ Fact ]
172+ public void GivenExistingDestination_WhenMovingWithoutOverwrite_ThenIOException ( )
173+ {
174+ var source = Path . Combine ( _tempDirectory , "a.txt" ) ;
175+ var destination = Path . Combine ( _tempDirectory , "b.txt" ) ;
176+ File . WriteAllText ( source , "new" ) ;
177+ File . WriteAllText ( destination , "old" ) ;
178+
179+ Assert . Throws < IOException > ( ( ) => File . Move ( source , destination ) ) ;
180+
181+ File . Move ( source , destination , overwrite : true ) ;
182+ Assert . Equal ( "new" , File . ReadAllText ( destination ) ) ;
183+ }
184+ }
0 commit comments