@@ -63,13 +63,79 @@ func TestFTPContainer(t *testing.T) {
6363 require .NoError (t , os .WriteFile (localPath , content , 0o600 ))
6464 }
6565
66+ t .Run ("Connect" , func (t * testing.T ) {
67+ // test the connect function directly
68+ conn , err := ftpContainer .connect (ctx )
69+ require .NoError (t , err )
70+ require .NotNil (t , conn )
71+
72+ // test connection state
73+ pwd , err := conn .CurrentDir ()
74+ require .NoError (t , err )
75+ require .NotEmpty (t , pwd )
76+
77+ // close properly
78+ err = conn .Quit ()
79+ require .NoError (t , err )
80+ })
81+
82+ t .Run ("SaveAndRestoreCurrentDirectory" , func (t * testing.T ) {
83+ // first we need to make sure the testdir exists
84+ testdirPath := filepath .Join (tempDir , "testdir" )
85+ moreFilePath := filepath .Join (testdirPath , "more.txt" )
86+ require .NoError (t , os .MkdirAll (testdirPath , 0o750 ))
87+ require .NoError (t , os .WriteFile (moreFilePath , []byte ("Test content" ), 0o600 ))
88+ err := ftpContainer .SaveFile (ctx , moreFilePath , "testdir/more.txt" )
89+ require .NoError (t , err , "Failed to create directory for test" )
90+
91+ conn , err := ftpContainer .connect (ctx )
92+ require .NoError (t , err )
93+ defer func () {
94+ err := conn .Quit ()
95+ require .NoError (t , err )
96+ }()
97+
98+ // test saving current directory
99+ originalDir , err := ftpContainer .saveCurrentDirectory (conn )
100+ require .NoError (t , err )
101+ require .NotEmpty (t , originalDir )
102+
103+ // change directory - now testdir should exist
104+ err = conn .ChangeDir ("testdir" )
105+ require .NoError (t , err )
106+
107+ // verify we're in a different directory
108+ currentDir , err := conn .CurrentDir ()
109+ require .NoError (t , err )
110+ require .NotEqual (t , originalDir , currentDir )
111+
112+ // restore to original directory
113+ ftpContainer .restoreWorkingDirectory (conn , originalDir )
114+
115+ // verify we're back in the original directory
116+ restoredDir , err := conn .CurrentDir ()
117+ require .NoError (t , err )
118+ require .Equal (t , originalDir , restoredDir )
119+
120+ // test with empty original directory (should be a no-op)
121+ ftpContainer .restoreWorkingDirectory (conn , "" )
122+ })
123+
66124 t .Run ("Upload" , func (t * testing.T ) {
67125 for filename := range testFiles {
68126 localPath := filepath .Join (tempDir , filename )
69127 remotePath := filename
70128 err := ftpContainer .SaveFile (ctx , localPath , remotePath )
71129 require .NoError (t , err , "Failed to upload file %s" , filename )
72130 }
131+
132+ // test with invalid local path
133+ err := ftpContainer .SaveFile (ctx , "/path/does/not/exist.txt" , "remote.txt" )
134+ require .Error (t , err )
135+
136+ // test with invalid path traversal attempt
137+ err = ftpContainer .SaveFile (ctx , "../../../etc/passwd" , "remote.txt" )
138+ require .Error (t , err )
73139 })
74140
75141 t .Run ("ListHome" , func (t * testing.T ) {
@@ -94,6 +160,15 @@ func TestFTPContainer(t *testing.T) {
94160 assert .True (t , foundFiles ["test1.txt" ], "test1.txt should be in home directory" )
95161 assert .True (t , foundFiles ["test2.txt" ], "test2.txt should be in home directory" )
96162 assert .True (t , foundFiles ["testdir" ], "testdir should be in home directory" )
163+
164+ // test empty path and "." path
165+ emptyEntries , err := ftpContainer .ListFiles (ctx , "" )
166+ require .NoError (t , err )
167+ require .NotEmpty (t , emptyEntries )
168+
169+ dotEntries , err := ftpContainer .ListFiles (ctx , "." )
170+ require .NoError (t , err )
171+ require .NotEmpty (t , dotEntries )
97172 })
98173
99174 t .Run ("ListSubdir" , func (t * testing.T ) {
@@ -135,5 +210,121 @@ func TestFTPContainer(t *testing.T) {
135210 require .Equal (t , originalContent , downloadedContent , "Content mismatch for file %s" , filename )
136211 t .Logf ("Verified content for downloaded file %s" , filename )
137212 }
213+
214+ // test with non-existent remote file
215+ err := ftpContainer .GetFile (ctx , "non-existent-file.txt" , filepath .Join (downloadDir , "non-existent.txt" ))
216+ require .Error (t , err )
217+
218+ // test with path traversal attempt
219+ err = ftpContainer .GetFile (ctx , "file.txt" , "../../../etc/malicious.txt" )
220+ require .Error (t , err )
221+ })
222+
223+ t .Run ("SplitPath" , func (t * testing.T ) {
224+ testCases := []struct {
225+ path string
226+ expected []string
227+ }{
228+ {path : "foo/bar/baz" , expected : []string {"foo" , "bar" , "baz" }},
229+ {path : "/foo/bar/baz" , expected : []string {"foo" , "bar" , "baz" }},
230+ {path : "foo/bar/baz/" , expected : []string {"foo" , "bar" , "baz" }},
231+ {path : "/foo/bar/baz/" , expected : []string {"foo" , "bar" , "baz" }},
232+ {path : "" , expected : []string {}},
233+ {path : "/" , expected : []string {}},
234+ }
235+
236+ for _ , tc := range testCases {
237+ t .Run (tc .path , func (t * testing.T ) {
238+ result := splitPath (tc .path )
239+ require .Equal (t , tc .expected , result )
240+ })
241+ }
138242 })
243+
244+ t .Run ("CreateDirRecursive" , func (t * testing.T ) {
245+ conn , err := ftpContainer .connect (ctx )
246+ require .NoError (t , err )
247+ defer func () {
248+ err := conn .Quit ()
249+ require .NoError (t , err )
250+ }()
251+
252+ // create a deep directory structure
253+ err = ftpContainer .createDirRecursive (conn , "deep/nested/directory/structure" )
254+ require .NoError (t , err )
255+
256+ // verify it exists by listing files
257+ entries , err := ftpContainer .ListFiles (ctx , "deep/nested/directory" )
258+ require .NoError (t , err )
259+
260+ foundStructure := false
261+ for _ , entry := range entries {
262+ if entry .Name == "structure" && entry .Type == 1 {
263+ foundStructure = true
264+ break
265+ }
266+ }
267+ assert .True (t , foundStructure , "deep/nested/directory/structure should exist" )
268+
269+ // test with empty path (should be a no-op)
270+ err = ftpContainer .createDirRecursive (conn , "" )
271+ require .NoError (t , err )
272+ })
273+ }
274+
275+ // TestFTPContainerErrorHandling tests error handling in FTP container
276+ func TestFTPContainerErrorHandling (t * testing.T ) {
277+ t .Run ("TestHandleMakeDirFailure" , func (t * testing.T ) {
278+ if testing .Short () {
279+ t .Skip ("skipping FTP error handling test in short mode" )
280+ }
281+
282+ // create a test container
283+ ctx := context .Background ()
284+ ftpContainer := NewFTPTestContainer (ctx , t )
285+ defer func () {
286+ err := ftpContainer .Close (context .Background ())
287+ require .NoError (t , err )
288+ }()
289+
290+ // connect to the container
291+ conn , err := ftpContainer .connect (ctx )
292+ require .NoError (t , err )
293+ defer conn .Quit ()
294+
295+ // test the handleMakeDirFailure function with a directory that already exists
296+ // first create the directory normally
297+ err = conn .MakeDir ("testdir2" )
298+ require .NoError (t , err )
299+
300+ // now simulate a failure but where the directory actually exists
301+ err = ftpContainer .handleMakeDirFailure (conn , "testdir2" , fmt .Errorf ("simulated error" ))
302+ require .NoError (t , err , "Should handle the case where directory exists but MakeDir failed" )
303+
304+ // test with a non-existent directory
305+ err = ftpContainer .handleMakeDirFailure (conn , "definitely_not_exists_dir" , fmt .Errorf ("simulated error" ))
306+ require .Error (t , err , "Should fail when directory doesn't exist" )
307+ })
308+ }
309+
310+ // Test utility methods separately
311+ func TestSplitPath (t * testing.T ) {
312+ testCases := []struct {
313+ path string
314+ expected []string
315+ }{
316+ {path : "foo/bar/baz" , expected : []string {"foo" , "bar" , "baz" }},
317+ {path : "/foo/bar/baz" , expected : []string {"foo" , "bar" , "baz" }},
318+ {path : "foo/bar/baz/" , expected : []string {"foo" , "bar" , "baz" }},
319+ {path : "/foo/bar/baz/" , expected : []string {"foo" , "bar" , "baz" }},
320+ {path : "" , expected : []string {}},
321+ {path : "/" , expected : []string {}},
322+ }
323+
324+ for _ , tc := range testCases {
325+ t .Run (tc .path , func (t * testing.T ) {
326+ result := splitPath (tc .path )
327+ require .Equal (t , tc .expected , result )
328+ })
329+ }
139330}
0 commit comments