package github import ( "context" "net/http" "net/http/httptest" "strings" "testing" ) func TestEscapePath_ValidPaths(t *testing.T) { t.Parallel() tests := []struct { name string path string want string }{ {"simple file", "file.go", "file.go"}, {"nested path", "path/to/file.go", "path/to/file.go"}, {"special chars", "path/to/my file.go", "path/to/my%20file.go"}, {"leading slash stripped", "/path/to/file.go", "path/to/file.go"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := escapePath(tt.path) if err != nil { t.Fatalf("unexpected error: %v", err) } if got != tt.want { t.Errorf("escapePath(%q) = %q, want %q", tt.path, got, tt.want) } }) } } func TestEscapePath_DotSegments(t *testing.T) { t.Parallel() tests := []struct { name string path string }{ {"single dot", "./file.go"}, {"double dot", "../file.go"}, {"dot in middle", "path/./file.go"}, {"parent traversal", "path/../file.go"}, {"only dots", ".."}, {"nested parent traversal", "a/b/../../c"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() _, err := escapePath(tt.path) if err == nil { t.Fatalf("expected error for path %q, got nil", tt.path) } if !strings.Contains(err.Error(), "dot-segment") { t.Errorf("expected error about dot-segment, got: %v", err) } }) } } func TestGetFileContentAtRef_DotSegmentError(t *testing.T) { // Server should never be called — the error is caught before the request. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { t.Fatal("server should not have been called") })) defer srv.Close() c := NewClient("token", srv.URL) _, err := c.GetFileContentAtRef(context.Background(), "owner", "repo", "foo/../bar.go", "main") if err == nil { t.Fatal("expected error for path with dot-segments") } if !strings.Contains(err.Error(), "invalid file path") { t.Errorf("expected 'invalid file path' error, got: %v", err) } } func TestDecodeBase64Content_SizeLimit(t *testing.T) { t.Parallel() // Create base64 content that would decode to > maxFileContentSize. // maxFileContentSize is 10MB. Base64 of 11MB worth of zeros. // We just need something big enough to trigger the estimated size check. // 14MB of base64 chars (decodes to ~10.5MB). huge := strings.Repeat("A", 14*1024*1024) _, err := decodeBase64Content(huge) if err == nil { t.Fatal("expected error for oversized content") } if !strings.Contains(err.Error(), "too large") { t.Errorf("expected 'too large' error, got: %v", err) } }