@@ -12,6 +12,7 @@ import (
1212 "errors"
1313 "fmt"
1414 "io"
15+ "io/fs"
1516 "mime/multipart"
1617 "net"
1718 "net/http"
@@ -80,6 +81,149 @@ func testErrorResponse(t *testing.T, err error, resp *http.Response, expectedBod
8081 require .Equal (t , expectedBodyError , string (body ), "Response body" )
8182}
8283
84+ type testUploadFS struct {
85+ mkdirPath string
86+ mkdirPerm fs.FileMode
87+ }
88+
89+ func (tfs * testUploadFS ) Open (_ string ) (fs.File , error ) {
90+ _ = tfs
91+ return nil , fs .ErrNotExist
92+ }
93+
94+ func (tfs * testUploadFS ) OpenFile (_ string , _ int , _ fs.FileMode ) (fs.File , error ) {
95+ _ = tfs
96+ return & testUploadFile {buf : & bytes.Buffer {}}, nil
97+ }
98+
99+ func (tfs * testUploadFS ) MkdirAll (path string , perm fs.FileMode ) error {
100+ tfs .mkdirPath = path
101+ tfs .mkdirPerm = perm
102+ return nil
103+ }
104+
105+ func (tfs * testUploadFS ) Remove (_ string ) error {
106+ _ = tfs
107+ return nil
108+ }
109+
110+ type testUploadFile struct {
111+ buf * bytes.Buffer
112+ }
113+
114+ func (tf * testUploadFile ) Read (p []byte ) (int , error ) {
115+ //nolint:wrapcheck // test helper passthrough
116+ return tf .buf .Read (p )
117+ }
118+
119+ func (tf * testUploadFile ) Write (p []byte ) (int , error ) {
120+ //nolint:wrapcheck // test helper passthrough
121+ return tf .buf .Write (p )
122+ }
123+
124+ func (tf * testUploadFile ) Close () error {
125+ _ = tf
126+ return nil
127+ }
128+
129+ func (tf * testUploadFile ) Stat () (fs.FileInfo , error ) {
130+ _ = tf
131+ return testUploadFileInfo {name : "upload" }, nil
132+ }
133+
134+ type testUploadFileInfo struct {
135+ name string
136+ }
137+
138+ func (fi testUploadFileInfo ) Name () string { return fi .name }
139+ func (fi testUploadFileInfo ) Size () int64 {
140+ _ = fi
141+ return 0
142+ }
143+
144+ func (fi testUploadFileInfo ) Mode () fs.FileMode {
145+ _ = fi
146+ return 0
147+ }
148+
149+ func (fi testUploadFileInfo ) ModTime () time.Time {
150+ _ = fi
151+ return time.Time {}
152+ }
153+
154+ func (fi testUploadFileInfo ) IsDir () bool {
155+ _ = fi
156+ return false
157+ }
158+
159+ func (fi testUploadFileInfo ) Sys () any {
160+ _ = fi
161+ return nil
162+ }
163+
164+ func TestRootPermsRootFs (t * testing.T ) {
165+ t .Parallel ()
166+
167+ if runtime .GOOS == "windows" {
168+ t .Skip ("root perms are not validated on Windows in this test" )
169+ }
170+
171+ tests := []struct {
172+ name string
173+ rootPerm fs.FileMode
174+ wantPerm fs.FileMode
175+ }{
176+ {
177+ name : "default" ,
178+ rootPerm : 0 ,
179+ wantPerm : 0o750 ,
180+ },
181+ {
182+ name : "custom" ,
183+ rootPerm : 0o700 ,
184+ wantPerm : 0o700 ,
185+ },
186+ }
187+
188+ for _ , tt := range tests {
189+ t .Run (tt .name , func (t * testing.T ) {
190+ t .Parallel ()
191+
192+ tfs := & testUploadFS {}
193+ New (Config {
194+ RootDir : "uploads" ,
195+ RootFs : tfs ,
196+ RootPerms : tt .rootPerm ,
197+ })
198+
199+ if tfs .mkdirPath != "uploads" {
200+ t .Fatalf ("expected RootFs prefix %q, got %q" , "uploads" , tfs .mkdirPath )
201+ }
202+ if tfs .mkdirPerm != tt .wantPerm {
203+ t .Fatalf ("expected RootPerms %o, got %o" , tt .wantPerm , tfs .mkdirPerm )
204+ }
205+ })
206+ }
207+ }
208+
209+ func TestValidateUploadPathPreservesLeadingDot (t * testing.T ) {
210+ t .Parallel ()
211+
212+ path := filepath .Join (".hidden" , "file.txt" )
213+
214+ normalized , err := validateUploadPath (path )
215+ if err != nil {
216+ t .Fatalf ("expected no error, got %v" , err )
217+ }
218+
219+ if ! strings .HasPrefix (normalized .osPath , "." ) {
220+ t .Fatalf ("expected os path %q to preserve leading dot" , normalized .osPath )
221+ }
222+ if normalized .slashPath != ".hidden/file.txt" {
223+ t .Fatalf ("expected slash path %q, got %q" , ".hidden/file.txt" , normalized .slashPath )
224+ }
225+ }
226+
83227func Test_App_Test_Goroutine_Leak_Compare (t * testing.T ) {
84228 t .Parallel ()
85229
0 commit comments