oficina / slides Public

Clone
git clone https://amadan.net/oficina/slides

Plain git — no account needed to clone.

Download

Download this file

1package render
2
3import (
4 "strings"
5 "testing"
6
7 "amadan.net/oficina/slides/internal/slides/deck"
8)
9
10// imageDeck is one slide with one image block and an image background,
11// both naming the same registered asset.
12func imageDeck(assets map[string]deck.Asset) *deck.Deck {
13 return &deck.Deck{
14 Meta: deck.Meta{Theme: "paper"},
15 Assets: assets,
16 Slides: []deck.Slide{{
17 ID: "slide001aaaa", Layout: "flow", Template: "image-full",
18 Background: deck.Background{Kind: "image", Value: "asset0001aaa"},
19 Blocks: []deck.Block{{
20 ID: "b001aaaaaaaa", Type: "image", Region: "media",
21 Props: map[string]any{"asset": "asset0001aaa", "alt": "A chart"},
22 }},
23 }},
24 }
25}
26
27// The renderer writes the deck's own REF into the src, under whichever
28// surface's base the caller passed — a slide is drawn for four
29// audiences authenticated four different ways, and the picture has to
30// be fetchable by whoever is looking at it (§2.7).
31func TestImageSrcIsTheRefUnderTheSurfacesOwnBase(t *testing.T) {
32 d := imageDeck(map[string]deck.Asset{
33 "asset0001aaa": {Ref: "aa01bb02cc03dd04", Name: "chart.png", Width: 800, Height: 600, Alt: "A chart"},
34 })
35
36 for _, base := range []string{"/d/k7m3/assets", "/s/tok3n/assets", "/p/sess1/assets"} {
37 html, err := SlideWith(d, 0, Desktop, Options{AssetBase: base})
38 if err != nil {
39 t.Fatalf("SlideWith(%q): %v", base, err)
40 }
41 body := string(html)
42 want := `src="` + base + `/aa01bb02cc03dd04"`
43 if !strings.Contains(body, want) {
44 t.Errorf("base %q: no %s in\n%s", base, want, body)
45 }
46 if !strings.Contains(body, "url("+base+"/aa01bb02cc03dd04)") {
47 t.Errorf("base %q: the background image does not follow the same base:\n%s", base, body)
48 }
49 // The deck's own id for the asset never appears in a URL: it
50 // means something inside this document and nothing at all to
51 // the route that serves the bytes.
52 if strings.Contains(body, base+"/asset0001aaa") {
53 t.Errorf("base %q: the asset ID leaked into a URL:\n%s", base, body)
54 }
55 }
56
57 // A trailing slash on the base is not two slashes in the src.
58 html, _ := SlideWith(d, 0, Desktop, Options{AssetBase: "/d/k7m3/assets/"})
59 if strings.Contains(string(html), "//aa01bb02") {
60 t.Errorf("a trailing slash doubled up:\n%s", html)
61 }
62
63 // No options at all still renders something, rather than an <img>
64 // with no src.
65 plain, err := Slide(d, 0, Desktop)
66 if err != nil {
67 t.Fatalf("Slide: %v", err)
68 }
69 if !strings.Contains(string(plain), `src="`+DefaultAssetBase+`/aa01bb02cc03dd04"`) {
70 t.Errorf("Slide without Options did not fall back to %s:\n%s", DefaultAssetBase, plain)
71 }
72}
73
74// An asset id nothing registered — a block whose asset was removed, a
75// document a peer left half-written, a ref that could not survive a URL
76// — is an empty frame, never an <img> pointing somewhere that cannot
77// resolve.
78func TestAnUnregisteredAssetIsAnEmptyFrame(t *testing.T) {
79 for name, assets := range map[string]map[string]deck.Asset{
80 "no assets at all": {},
81 "a different asset": {"asset0002bbb": {Ref: "ee05ff06"}},
82 "a ref that is empty": {"asset0001aaa": {Ref: ""}},
83 "a ref with a slash": {"asset0001aaa": {Ref: "decks/k7m/x.png"}},
84 "a ref with a scheme": {"asset0001aaa": {Ref: "https://elsewhere.test/x.png"}},
85 } {
86 html, err := SlideWith(imageDeck(assets), 0, Desktop, Options{AssetBase: "/d/k7m3/assets"})
87 if err != nil {
88 t.Fatalf("%s: %v", name, err)
89 }
90 body := string(html)
91 if !strings.Contains(body, `data-missing-asset="true"`) {
92 t.Errorf("%s: the image block is not marked missing:\n%s", name, body)
93 }
94 if strings.Contains(body, "<img") {
95 t.Errorf("%s: an <img> was drawn anyway:\n%s", name, body)
96 }
97 if strings.Contains(body, "--slides-bg-image") {
98 t.Errorf("%s: the background still points at something:\n%s", name, body)
99 }
100 }
101}
102