1+ package embedfs
2+
3+ import (
4+ "io"
5+ "testing"
6+
7+ "github.com/go-git/go-billy/v6"
8+ "github.com/go-git/go-billy/v6/embedfs_testdata"
9+ "github.com/stretchr/testify/assert"
10+ "github.com/stretchr/testify/require"
11+ )
12+
13+ func TestChroot_Basic (t * testing.T ) {
14+ t .Parallel ()
15+
16+ fs := New (embedfs_testdata .GetTestData ())
17+
18+ // Test chroot to existing directory
19+ chrootFS , err := fs .Chroot ("testdata" )
20+ require .NoError (t , err )
21+ require .NotNil (t , chrootFS )
22+
23+ // Test that we can access files in the chrooted filesystem
24+ f , err := chrootFS .Open ("file1.txt" )
25+ require .NoError (t , err )
26+ defer f .Close ()
27+
28+ content , err := io .ReadAll (f )
29+ require .NoError (t , err )
30+ assert .Equal (t , "Hello from embedfs!" , string (content ))
31+ }
32+
33+ func TestChroot_NestedDirectory (t * testing.T ) {
34+ t .Parallel ()
35+
36+ fs := New (embedfs_testdata .GetTestData ())
37+
38+ // Test chroot to nested directory
39+ chrootFS , err := fs .Chroot ("testdata/subdir" )
40+ require .NoError (t , err )
41+ require .NotNil (t , chrootFS )
42+
43+ // Test that we can access nested files from the chrooted root
44+ f , err := chrootFS .Open ("nested.txt" )
45+ require .NoError (t , err )
46+ defer f .Close ()
47+
48+ content , err := io .ReadAll (f )
49+ require .NoError (t , err )
50+ assert .Equal (t , "Nested file content" , string (content ))
51+ }
52+
53+ func TestChroot_StatInChroot (t * testing.T ) {
54+ t .Parallel ()
55+
56+ fs := New (embedfs_testdata .GetTestData ())
57+
58+ chrootFS , err := fs .Chroot ("testdata" )
59+ require .NoError (t , err )
60+
61+ // Test stat on files that exist in chrooted directory
62+ fi , err := chrootFS .Stat ("file1.txt" )
63+ require .NoError (t , err )
64+ assert .Equal (t , "file1.txt" , fi .Name ())
65+ assert .False (t , fi .IsDir ())
66+
67+ // Test stat on directories that exist in chrooted directory
68+ fi , err = chrootFS .Stat ("subdir" )
69+ require .NoError (t , err )
70+ assert .Equal (t , "subdir" , fi .Name ())
71+ assert .True (t , fi .IsDir ())
72+
73+ // Test stat with absolute path in chrooted filesystem
74+ fi , err = chrootFS .Stat ("/file2.txt" )
75+ require .NoError (t , err )
76+ assert .Equal (t , "file2.txt" , fi .Name ())
77+ assert .False (t , fi .IsDir ())
78+ }
79+
80+ func TestChroot_ReadDirInChroot (t * testing.T ) {
81+ t .Parallel ()
82+
83+ fs := New (embedfs_testdata .GetTestData ())
84+
85+ chrootFS , err := fs .Chroot ("testdata" )
86+ require .NoError (t , err )
87+
88+ // Test reading directory contents from chrooted root
89+ entries , err := chrootFS .ReadDir ("/" )
90+ require .NoError (t , err )
91+
92+ expectedFiles := []string {"empty.txt" , "file1.txt" , "file2.txt" , "subdir" }
93+ assert .Len (t , entries , len (expectedFiles ))
94+
95+ foundFiles := make (map [string ]bool )
96+ for _ , entry := range entries {
97+ foundFiles [entry .Name ()] = true
98+ }
99+
100+ for _ , expected := range expectedFiles {
101+ assert .True (t , foundFiles [expected ], "Expected file %s not found" , expected )
102+ }
103+
104+ // Test reading subdirectory from chrooted filesystem
105+ entries , err = chrootFS .ReadDir ("subdir" )
106+ require .NoError (t , err )
107+ assert .Len (t , entries , 1 )
108+ assert .Equal (t , "nested.txt" , entries [0 ].Name ())
109+ }
110+
111+ func TestChroot_PathNormalization (t * testing.T ) {
112+ t .Parallel ()
113+
114+ fs := New (embedfs_testdata .GetTestData ())
115+
116+ // Test chroot with different path formats
117+ tests := []struct {
118+ name string
119+ chrootPath string
120+ openPath string
121+ expectFile string
122+ }{
123+ {
124+ name : "absolute chroot path" ,
125+ chrootPath : "/testdata" ,
126+ openPath : "file1.txt" ,
127+ expectFile : "file1.txt" ,
128+ },
129+ {
130+ name : "relative chroot path" ,
131+ chrootPath : "testdata" ,
132+ openPath : "file1.txt" ,
133+ expectFile : "file1.txt" ,
134+ },
135+ {
136+ name : "absolute open path in chroot" ,
137+ chrootPath : "testdata" ,
138+ openPath : "/file1.txt" ,
139+ expectFile : "file1.txt" ,
140+ },
141+ {
142+ name : "nested chroot" ,
143+ chrootPath : "testdata/subdir" ,
144+ openPath : "nested.txt" ,
145+ expectFile : "nested.txt" ,
146+ },
147+ }
148+
149+ for _ , tt := range tests {
150+ t .Run (tt .name , func (t * testing.T ) {
151+ chrootFS , err := fs .Chroot (tt .chrootPath )
152+ require .NoError (t , err )
153+
154+ f , err := chrootFS .Open (tt .openPath )
155+ require .NoError (t , err )
156+ defer f .Close ()
157+
158+ assert .Equal (t , tt .expectFile , f .Name ())
159+ })
160+ }
161+ }
162+
163+ func TestChroot_NonExistentPath (t * testing.T ) {
164+ t .Parallel ()
165+
166+ fs := New (embedfs_testdata .GetTestData ())
167+
168+ // Test chroot to non-existent directory - billy's chroot helper allows this
169+ chrootFS , err := fs .Chroot ("nonexistent" )
170+ require .NoError (t , err )
171+ require .NotNil (t , chrootFS )
172+
173+ // But accessing files within the non-existent chroot should fail
174+ _ , err = chrootFS .Open ("anyfile.txt" )
175+ assert .Error (t , err )
176+ }
177+
178+ func TestChroot_Join (t * testing.T ) {
179+ t .Parallel ()
180+
181+ fs := New (embedfs_testdata .GetTestData ())
182+ chrootFS , err := fs .Chroot ("testdata" )
183+ require .NoError (t , err )
184+
185+ // Test Join operation in chrooted filesystem
186+ joined := chrootFS .Join ("subdir" , "nested.txt" )
187+ assert .Equal (t , "subdir/nested.txt" , joined )
188+
189+ // Test that joined path can be used to open file
190+ f , err := chrootFS .Open (joined )
191+ require .NoError (t , err )
192+ defer f .Close ()
193+
194+ content , err := io .ReadAll (f )
195+ require .NoError (t , err )
196+ assert .Equal (t , "Nested file content" , string (content ))
197+ }
198+
199+ func TestChroot_UnsupportedOperations (t * testing.T ) {
200+ t .Parallel ()
201+
202+ fs := New (embedfs_testdata .GetTestData ())
203+ chrootFS , err := fs .Chroot ("testdata" )
204+ require .NoError (t , err )
205+
206+ // Test that write operations still fail in chrooted embedfs
207+ _ , err = chrootFS .Create ("newfile.txt" )
208+ require .ErrorIs (t , err , billy .ErrReadOnly )
209+
210+ err = chrootFS .Remove ("file1.txt" )
211+ require .ErrorIs (t , err , billy .ErrReadOnly )
212+
213+ err = chrootFS .Rename ("file1.txt" , "renamed.txt" )
214+ require .ErrorIs (t , err , billy .ErrReadOnly )
215+
216+ err = chrootFS .MkdirAll ("newdir" , 0755 )
217+ require .ErrorIs (t , err , billy .ErrReadOnly )
218+ }
219+
220+ func TestChroot_NestedChroot (t * testing.T ) {
221+ t .Parallel ()
222+
223+ fs := New (embedfs_testdata .GetTestData ())
224+
225+ // Test creating nested chrootfs
226+ firstChroot , err := fs .Chroot ("testdata" )
227+ require .NoError (t , err )
228+
229+ secondChroot , err := firstChroot .Chroot ("subdir" )
230+ require .NoError (t , err )
231+
232+ // Test that nested chroot works correctly
233+ f , err := secondChroot .Open ("nested.txt" )
234+ require .NoError (t , err )
235+ defer f .Close ()
236+
237+ content , err := io .ReadAll (f )
238+ require .NoError (t , err )
239+ assert .Equal (t , "Nested file content" , string (content ))
240+
241+ // Test that we can't access parent directory from nested chroot
242+ entries , err := secondChroot .ReadDir ("/" )
243+ require .NoError (t , err )
244+ assert .Len (t , entries , 1 )
245+ assert .Equal (t , "nested.txt" , entries [0 ].Name ())
246+ }
247+
248+ func TestChroot_FileOperations (t * testing.T ) {
249+ t .Parallel ()
250+
251+ fs := New (embedfs_testdata .GetTestData ())
252+ chrootFS , err := fs .Chroot ("testdata" )
253+ require .NoError (t , err )
254+
255+ // Test file operations in chrooted filesystem
256+ f , err := chrootFS .Open ("file2.txt" )
257+ require .NoError (t , err )
258+ defer f .Close ()
259+
260+ // Test Read
261+ buf := make ([]byte , 10 )
262+ n , err := f .Read (buf )
263+ require .NoError (t , err )
264+ assert .Equal (t , "Another te" , string (buf [:n ]))
265+
266+ // Test Seek
267+ _ , err = f .Seek (0 , io .SeekStart )
268+ require .NoError (t , err )
269+
270+ // Test ReadAt
271+ buf2 := make ([]byte , 7 )
272+ n , err = f .ReadAt (buf2 , 8 )
273+ require .NoError (t , err )
274+ assert .Equal (t , "test fi" , string (buf2 [:n ]))
275+
276+ // Test that file position wasn't affected by ReadAt
277+ n , err = f .Read (buf )
278+ require .NoError (t , err )
279+ assert .Equal (t , "Another te" , string (buf [:n ]))
280+ }
281+
282+ func TestChroot_Lstat (t * testing.T ) {
283+ t .Parallel ()
284+
285+ fs := New (embedfs_testdata .GetTestData ())
286+ chrootFS , err := fs .Chroot ("testdata" )
287+ require .NoError (t , err )
288+
289+ // Test Lstat in chrooted filesystem (should behave same as Stat for embedfs)
290+ fi , err := chrootFS .Lstat ("file1.txt" )
291+ require .NoError (t , err )
292+ assert .Equal (t , "file1.txt" , fi .Name ())
293+ assert .False (t , fi .IsDir ())
294+ }
0 commit comments