package bnp import ( "context" "fmt" "os" "path/filepath" "strings" "testing" ) // presentationFixture extends the codeless fixture with a root preview.png // and a screenshots/ dir. func presentationFixture(t *testing.T) string { t.Helper() dir := codelessFixture(t) writeFixture(t, dir, map[string]string{ "preview.png": "not-really-png-but-bytes", "screenshots/01-home.png": "home-bytes", "screenshots/02-blog.jpg": "blog-bytes", "screenshots/03-page.webp": "page-bytes", }) return dir } func TestCodelessBuildPacksPresentationMembers(t *testing.T) { dir := presentationFixture(t) out := filepath.Join(t.TempDir(), "fixture-theme-0.1.0.bnp") res, err := BuildCodeless(context.Background(), BuildOptions{Dir: dir, Output: out}) if err != nil { t.Fatalf("BuildCodeless: %v", err) } if !res.PreviewIncluded || res.ScreenshotCount != 3 { t.Errorf("result preview=%t screenshots=%d; want true/3", res.PreviewIncluded, res.ScreenshotCount) } found := false for _, d := range res.IncludedDirs { if d == dirScreenshots { found = true } } if !found { t.Errorf("IncludedDirs %v missing %q", res.IncludedDirs, dirScreenshots) } v, err := Verify(out) if err != nil { t.Fatalf("Verify: %v", err) } if !v.HasPreview || v.ScreenshotCount != 3 { t.Errorf("verify preview=%t screenshots=%d; want true/3", v.HasPreview, v.ScreenshotCount) } } func TestCodelessBuildWithoutPresentationMembers(t *testing.T) { dir := codelessFixture(t) out := filepath.Join(t.TempDir(), "fixture-theme-0.1.0.bnp") res, err := BuildCodeless(context.Background(), BuildOptions{Dir: dir, Output: out}) if err != nil { t.Fatalf("BuildCodeless: %v", err) } if res.PreviewIncluded || res.ScreenshotCount != 0 { t.Errorf("result preview=%t screenshots=%d; want false/0", res.PreviewIncluded, res.ScreenshotCount) } v, err := Verify(out) if err != nil { t.Fatalf("Verify: %v", err) } if v.HasPreview || v.ScreenshotCount != 0 { t.Errorf("verify preview=%t screenshots=%d; want false/0", v.HasPreview, v.ScreenshotCount) } } func TestValidateScreenshotsDirRejections(t *testing.T) { build := func(t *testing.T, mutate func(dir string)) error { t.Helper() dir := codelessFixture(t) mutate(dir) out := filepath.Join(t.TempDir(), "out.bnp") _, err := BuildCodeless(context.Background(), BuildOptions{Dir: dir, Output: out}) return err } t.Run("bad extension", func(t *testing.T) { err := build(t, func(dir string) { writeFixture(t, dir, map[string]string{"screenshots/readme.txt": "nope"}) }) if err == nil || !strings.Contains(err.Error(), "unsupported image type") { t.Fatalf("err = %v; want unsupported image type", err) } }) t.Run("subdirectory", func(t *testing.T) { err := build(t, func(dir string) { writeFixture(t, dir, map[string]string{"screenshots/sub/x.png": "nope"}) }) if err == nil || !strings.Contains(err.Error(), "subdirectories are not allowed") { t.Fatalf("err = %v; want subdirectory rejection", err) } }) t.Run("too many", func(t *testing.T) { err := build(t, func(dir string) { files := map[string]string{} for i := range maxScreenshotFiles + 1 { files[fmt.Sprintf("screenshots/%02d.png", i)] = "x" } writeFixture(t, dir, files) }) if err == nil || !strings.Contains(err.Error(), "gallery cap") { t.Fatalf("err = %v; want gallery cap rejection", err) } }) t.Run("oversized image", func(t *testing.T) { err := build(t, func(dir string) { big := filepath.Join(dir, dirScreenshots, "big.png") if mkErr := os.MkdirAll(filepath.Dir(big), 0o755); mkErr != nil { t.Fatal(mkErr) } f, cErr := os.Create(big) if cErr != nil { t.Fatal(cErr) } if tErr := f.Truncate(maxScreenshotBytes + 1); tErr != nil { t.Fatal(tErr) } _ = f.Close() }) if err == nil || !strings.Contains(err.Error(), "per-image cap") { t.Fatalf("err = %v; want per-image cap rejection", err) } }) t.Run("oversized preview", func(t *testing.T) { err := build(t, func(dir string) { big := filepath.Join(dir, filePreview) f, cErr := os.Create(big) if cErr != nil { t.Fatal(cErr) } if tErr := f.Truncate(maxScreenshotBytes + 1); tErr != nil { t.Fatal(tErr) } _ = f.Close() }) if err == nil || !strings.Contains(err.Error(), "per-image cap") { t.Fatalf("err = %v; want per-image cap rejection", err) } }) }