@@ -19,12 +19,14 @@ package fn_test
1919import (
2020 "bufio"
2121 "bytes"
22+ "fmt"
2223 "io"
2324 "os"
2425 "path/filepath"
2526 "reflect"
2627 "strings"
2728 "testing"
29+ "time"
2830
2931 "github.com/soulteary/ssh-config/internal/fn"
3032)
@@ -247,6 +249,104 @@ func TestReadSSHConfigsErrors(t *testing.T) {
247249 }
248250}
249251
252+ func TestReadSSHConfigs_Walk_InaccessibleDirectory (t * testing.T ) {
253+ tempDir , err := os .MkdirTemp ("" , "ssh-config-inaccessible" )
254+ if err != nil {
255+ t .Fatalf ("Failed to create temp dir: %v" , err )
256+ }
257+ defer os .RemoveAll (tempDir )
258+
259+ restrictedDir := filepath .Join (tempDir , "restricted" )
260+ if err := os .Mkdir (restrictedDir , 0755 ); err != nil {
261+ t .Fatalf ("Failed to create restricted directory: %v" , err )
262+ }
263+ if err := os .Chmod (restrictedDir , 0300 ); err != nil {
264+ t .Fatalf ("Failed to chmod restricted directory: %v" , err )
265+ }
266+ defer os .Chmod (restrictedDir , 0755 )
267+
268+ _ , err = fn .ReadSSHConfigs (tempDir )
269+ if err == nil {
270+ t .Fatal ("Expected error for inaccessible directory, got nil" )
271+ }
272+ if ! strings .Contains (err .Error (), "not accessible" ) && ! strings .Contains (err .Error (), "permission denied" ) {
273+ t .Fatalf ("Expected not accessible or permission denied error, got: %v" , err )
274+ }
275+ }
276+
277+ func TestReadSSHConfigs_Walk_UnreadableFile (t * testing.T ) {
278+ tempDir , err := os .MkdirTemp ("" , "ssh-config-unreadable" )
279+ if err != nil {
280+ t .Fatalf ("Failed to create temp dir: %v" , err )
281+ }
282+ defer os .RemoveAll (tempDir )
283+
284+ configPath := filepath .Join (tempDir , "config" )
285+ content := "Host example\n HostName example.com\n "
286+ if err := os .WriteFile (configPath , []byte (content ), 0600 ); err != nil {
287+ t .Fatalf ("Failed to write config file: %v" , err )
288+ }
289+
290+ if err := os .Chmod (configPath , 0000 ); err != nil {
291+ t .Fatalf ("Failed to chmod config file: %v" , err )
292+ }
293+
294+ if fn .IsConfigFile (configPath ) {
295+ t .Log ("config file detected as valid despite permissions" )
296+ }
297+
298+ cfg , err := fn .ReadSSHConfigs (tempDir )
299+ if err != nil {
300+ t .Fatalf ("Unexpected error: %v" , err )
301+ }
302+ if len (cfg .Configs ) != 0 {
303+ t .Fatalf ("Expected unreadable file to be skipped, got %d configs" , len (cfg .Configs ))
304+ }
305+ }
306+
307+ func TestReadSSHConfigs_Walk_ErrorPropagation (t * testing.T ) {
308+ attempts := 0
309+ for attempts < 5 {
310+ tempDir , err := os .MkdirTemp ("" , "ssh-config-walk-error" )
311+ if err != nil {
312+ t .Fatalf ("Failed to create temp dir: %v" , err )
313+ }
314+
315+ for i := 0 ; i < 200 ; i ++ {
316+ subdir := filepath .Join (tempDir , fmt .Sprintf ("dir_%03d" , i ))
317+ if err := os .MkdirAll (subdir , 0755 ); err != nil {
318+ t .Fatalf ("Failed to create subdir: %v" , err )
319+ }
320+ configPath := filepath .Join (subdir , "config" )
321+ content := fmt .Sprintf ("Host host-%d\n HostName example.com\n " , i )
322+ if err := os .WriteFile (configPath , []byte (content ), 0600 ); err != nil {
323+ t .Fatalf ("Failed to write config file: %v" , err )
324+ }
325+ }
326+
327+ errCh := make (chan struct {})
328+ go func (path string ) {
329+ time .Sleep (5 * time .Millisecond )
330+ os .RemoveAll (path )
331+ close (errCh )
332+ }(tempDir )
333+
334+ _ , err = fn .ReadSSHConfigs (tempDir )
335+ <- errCh
336+
337+ if err != nil {
338+ if strings .Contains (err .Error (), "failed to walk directory" ) {
339+ return
340+ }
341+ }
342+
343+ os .RemoveAll (tempDir )
344+ attempts ++
345+ }
346+
347+ t .Fatal ("expected error propagation from filepath.Walk" )
348+ }
349+
250350func TestReadSSHConfigs_Walk (t * testing.T ) {
251351 // Create a temporary directory for testing
252352 tempDir , err := os .MkdirTemp ("" , "ssh-config-test" )
@@ -442,7 +542,7 @@ func TestReadSingleConfig_ScannerError(t *testing.T) {
442542 defer os .Remove (tmpfile .Name ())
443543
444544 // 写入一些正常数据和一个超长行来触发 scanner 错误
445- longLine := strings .Repeat ("a" , bufio .MaxScanTokenSize + 1 )
545+ longLine := strings .Repeat ("a" , bufio .MaxScanTokenSize * 2 )
446546 content := "Host testhost\n " + longLine
447547
448548 if _ , err := tmpfile .WriteString (content ); err != nil {
@@ -458,7 +558,7 @@ func TestReadSingleConfig_ScannerError(t *testing.T) {
458558
459559 // 验证当发生扫描错误时返回 nil
460560 if result != nil {
461- t .Errorf ("Expected nil result when scanner error occurs, got: %v" , result )
561+ t .Fatalf ("Expected nil result when scanner error occurs, got: %v" , result )
462562 }
463563}
464564
0 commit comments