package appview import ( "io/fs" "testing" "testing/fstest" ) func TestOverlayFS_Open_UpperWins(t *testing.T) { lower := fstest.MapFS{ "file.txt": &fstest.MapFile{Data: []byte("lower")}, } upper := fstest.MapFS{ "file.txt": &fstest.MapFile{Data: []byte("upper")}, } ofs := newOverlayFS(upper, lower) data, err := fs.ReadFile(ofs, "file.txt") if err != nil { t.Fatal(err) } if string(data) != "upper" { t.Errorf("expected upper content, got %q", data) } } func TestOverlayFS_Open_FallbackToLower(t *testing.T) { lower := fstest.MapFS{ "only-lower.txt": &fstest.MapFile{Data: []byte("lower")}, } upper := fstest.MapFS{} ofs := newOverlayFS(upper, lower) data, err := fs.ReadFile(ofs, "only-lower.txt") if err != nil { t.Fatal(err) } if string(data) != "lower" { t.Errorf("expected lower content, got %q", data) } } func TestOverlayFS_Open_UpperOnly(t *testing.T) { lower := fstest.MapFS{} upper := fstest.MapFS{ "only-upper.txt": &fstest.MapFile{Data: []byte("upper")}, } ofs := newOverlayFS(upper, lower) data, err := fs.ReadFile(ofs, "only-upper.txt") if err != nil { t.Fatal(err) } if string(data) != "upper" { t.Errorf("expected upper content, got %q", data) } } func TestOverlayFS_Open_NotFound(t *testing.T) { lower := fstest.MapFS{} upper := fstest.MapFS{} ofs := newOverlayFS(upper, lower) _, err := ofs.Open("missing.txt") if err == nil { t.Fatal("expected error for missing file") } } func TestOverlayFS_ReadDir_Merge(t *testing.T) { lower := fstest.MapFS{ "dir/a.txt": &fstest.MapFile{Data: []byte("a-lower")}, "dir/b.txt": &fstest.MapFile{Data: []byte("b-lower")}, } upper := fstest.MapFS{ "dir/b.txt": &fstest.MapFile{Data: []byte("b-upper")}, "dir/c.txt": &fstest.MapFile{Data: []byte("c-upper")}, } ofs := newOverlayFS(upper, lower) rdfs, ok := ofs.(fs.ReadDirFS) if !ok { t.Fatal("overlayFS does not implement ReadDirFS") } entries, err := rdfs.ReadDir("dir") if err != nil { t.Fatal(err) } // Should have a.txt (lower), b.txt (upper), c.txt (upper) = 3 entries if len(entries) != 3 { t.Fatalf("expected 3 entries, got %d", len(entries)) } names := make([]string, len(entries)) for i, e := range entries { names[i] = e.Name() } expected := []string{"a.txt", "b.txt", "c.txt"} for i, name := range expected { if names[i] != name { t.Errorf("entry %d: expected %q, got %q", i, name, names[i]) } } // Verify b.txt content comes from upper data, err := fs.ReadFile(ofs, "dir/b.txt") if err != nil { t.Fatal(err) } if string(data) != "b-upper" { t.Errorf("expected b-upper, got %q", data) } } func TestOverlayFS_ReadFile(t *testing.T) { lower := fstest.MapFS{ "file.txt": &fstest.MapFile{Data: []byte("lower")}, } upper := fstest.MapFS{ "file.txt": &fstest.MapFile{Data: []byte("upper")}, } ofs := newOverlayFS(upper, lower) rffs, ok := ofs.(fs.ReadFileFS) if !ok { t.Fatal("overlayFS does not implement ReadFileFS") } data, err := rffs.ReadFile("file.txt") if err != nil { t.Fatal(err) } if string(data) != "upper" { t.Errorf("expected upper, got %q", data) } }