@@ -397,3 +397,187 @@ func TestDirectoryPersistence(t *testing.T) {
397397 t .Fatalf ("'%s' exists but is not a directory" , dirName )
398398 }
399399}
400+
401+ // TestDirectoryWithFiles tests creating directories and adding files to them.
402+ // This covers the common use case of organizing files in subdirectories.
403+ func TestDirectoryWithFiles (t * testing.T ) {
404+ fs , _ , unmount := createTestFS (t , defaultConfig )
405+ defer unmount ()
406+
407+ t .Run ("CreateDirAndAddFile" , func (t * testing.T ) {
408+ // Create a directory
409+ check (t , fs .Mkdir ("mydir" , 0777 ))
410+
411+ // Create a file inside the directory
412+ f , err := fs .OpenFile ("mydir/test.txt" , os .O_CREATE | os .O_WRONLY )
413+ check (t , err )
414+
415+ content := []byte ("Hello from inside a directory!" )
416+ n , err := f .Write (content )
417+ check (t , err )
418+ if n != len (content ) {
419+ t .Fatalf ("expected to write %d bytes, wrote %d" , len (content ), n )
420+ }
421+ check (t , f .Close ())
422+
423+ // Read back and verify
424+ f , err = fs .Open ("mydir/test.txt" )
425+ check (t , err )
426+ buf := make ([]byte , 100 )
427+ n , err = f .Read (buf )
428+ check (t , err )
429+ if string (buf [:n ]) != string (content ) {
430+ t .Fatalf ("content mismatch: got %q, want %q" , string (buf [:n ]), string (content ))
431+ }
432+ check (t , f .Close ())
433+ })
434+
435+ t .Run ("MultipleFilesInDir" , func (t * testing.T ) {
436+ check (t , fs .Mkdir ("multidir" , 0777 ))
437+
438+ files := []string {"file1.txt" , "file2.txt" , "file3.txt" }
439+ for _ , fname := range files {
440+ path := "multidir/" + fname
441+ f , err := fs .OpenFile (path , os .O_CREATE | os .O_WRONLY )
442+ check (t , err )
443+ _ , err = f .Write ([]byte ("content of " + fname ))
444+ check (t , err )
445+ check (t , f .Close ())
446+ }
447+
448+ // Verify all files exist
449+ for _ , fname := range files {
450+ path := "multidir/" + fname
451+ info , err := fs .Stat (path )
452+ check (t , err )
453+ if info .IsDir () {
454+ t .Fatalf ("expected file, got directory: %s" , path )
455+ }
456+ }
457+ })
458+
459+ t .Run ("NestedDirsWithFiles" , func (t * testing.T ) {
460+ // Create nested directory structure
461+ check (t , fs .Mkdir ("level1" , 0777 ))
462+ check (t , fs .Mkdir ("level1/level2" , 0777 ))
463+ check (t , fs .Mkdir ("level1/level2/level3" , 0777 ))
464+
465+ // Add files at each level
466+ levels := []string {"level1" , "level1/level2" , "level1/level2/level3" }
467+ for _ , dir := range levels {
468+ path := dir + "/data.txt"
469+ f , err := fs .OpenFile (path , os .O_CREATE | os .O_WRONLY )
470+ check (t , err )
471+ _ , err = f .Write ([]byte ("data at " + dir ))
472+ check (t , err )
473+ check (t , f .Close ())
474+ }
475+
476+ // Verify all files
477+ for _ , dir := range levels {
478+ path := dir + "/data.txt"
479+ info , err := fs .Stat (path )
480+ check (t , err )
481+ if info .IsDir () {
482+ t .Fatalf ("expected file, got directory: %s" , path )
483+ }
484+ if info .Size () == 0 {
485+ t .Fatalf ("file %s has zero size" , path )
486+ }
487+ }
488+ })
489+ }
490+
491+ // TestDirectoryFilePersistence tests that files in directories persist after unmount/remount.
492+ func TestDirectoryFilePersistence (t * testing.T ) {
493+ bd := tinyfs .NewMemoryDevice (testPageSize , testBlockSize , testBlockCount )
494+ fs := New (bd ).Configure (defaultConfig )
495+
496+ check (t , fs .Format ())
497+ check (t , fs .Mount ())
498+
499+ // Create directory and file
500+ check (t , fs .Mkdir ("persist_dir" , 0777 ))
501+
502+ f , err := fs .OpenFile ("persist_dir/important.txt" , os .O_CREATE | os .O_WRONLY )
503+ check (t , err )
504+ content := []byte ("This data must survive remount!" )
505+ _ , err = f .Write (content )
506+ check (t , err )
507+ check (t , f .Close ())
508+
509+ // Unmount
510+ check (t , fs .Unmount ())
511+
512+ // Remount with new instance
513+ fs2 := New (bd ).Configure (defaultConfig )
514+ check (t , fs2 .Mount ())
515+ defer fs2 .Unmount ()
516+
517+ // Verify directory exists
518+ dirInfo , err := fs2 .Stat ("persist_dir" )
519+ if err != nil {
520+ t .Fatalf ("directory lost after remount: %v" , err )
521+ }
522+ if ! dirInfo .IsDir () {
523+ t .Fatalf ("persist_dir is not a directory" )
524+ }
525+
526+ // Verify file exists and has correct content
527+ f , err = fs2 .Open ("persist_dir/important.txt" )
528+ if err != nil {
529+ t .Fatalf ("file lost after remount: %v" , err )
530+ }
531+ defer f .Close ()
532+
533+ buf := make ([]byte , 100 )
534+ n , err := f .Read (buf )
535+ check (t , err )
536+ if string (buf [:n ]) != string (content ) {
537+ t .Fatalf ("content corrupted after remount: got %q, want %q" , string (buf [:n ]), string (content ))
538+ }
539+ }
540+
541+ // TestDeepNestedDirectories tests creating deeply nested directories and files.
542+ func TestDeepNestedDirectories (t * testing.T ) {
543+ fs , _ , unmount := createTestFS (t , defaultConfig )
544+ defer unmount ()
545+
546+ // Create a deeply nested path
547+ path := "a/b/c/d/e/f/g"
548+ dirs := []string {"a" , "a/b" , "a/b/c" , "a/b/c/d" , "a/b/c/d/e" , "a/b/c/d/e/f" , "a/b/c/d/e/f/g" }
549+
550+ for _ , dir := range dirs {
551+ check (t , fs .Mkdir (dir , 0777 ))
552+ }
553+
554+ // Create file at the deepest level
555+ filePath := path + "/deep_file.txt"
556+ f , err := fs .OpenFile (filePath , os .O_CREATE | os .O_WRONLY )
557+ check (t , err )
558+ content := []byte ("This is a deeply nested file" )
559+ _ , err = f .Write (content )
560+ check (t , err )
561+ check (t , f .Close ())
562+
563+ // Verify file
564+ info , err := fs .Stat (filePath )
565+ check (t , err )
566+ if info .IsDir () {
567+ t .Fatalf ("expected file, got directory" )
568+ }
569+ if info .Size () != int64 (len (content )) {
570+ t .Fatalf ("expected size %d, got %d" , len (content ), info .Size ())
571+ }
572+
573+ // Read and verify content
574+ f , err = fs .Open (filePath )
575+ check (t , err )
576+ buf := make ([]byte , 100 )
577+ n , err := f .Read (buf )
578+ check (t , err )
579+ if string (buf [:n ]) != string (content ) {
580+ t .Fatalf ("content mismatch" )
581+ }
582+ check (t , f .Close ())
583+ }
0 commit comments