rastrillo / fiesta Public

Clone
git clone https://amadan.net/rastrillo/fiesta

Plain git — no account needed to clone.

Download

Download this file

1package fiesta
2
3import (
4 "os"
5 "strings"
6 "testing"
7 "time"
8)
9
10// This file is rastrillo's cssfloor_test.go aimed at Fiesta's two
11// documents, plus the two checks that hold the README and the
12// changelog to the release they describe.
13
14// cssFloor is the engine floor the stylesheets impose on every page
15// that links them. It is derived, not chosen: take the features
16// tokens.css and the three themes use, and keep the highest engine
17// version among them. light-dark() sets it everywhere except Firefox,
18// where :has() does. Both documents state the result, because a
19// reader who cannot find the floor invents one: an agent building on
20// rastrillo once refused oklch() as "a 2023-era browser feature" and
21// reached for hex twins, which protect nobody, since an engine too old
22// for oklch() dropped the whole light-dark() palette several
23// declarations earlier.
24//
25// Two files stating one fact can drift into two facts.
26// TestCSSFloorIsStatedTheSameInBothFiles holds them equal. Both
27// hard-wrap prose, so the comparison normalises whitespace: the string
28// may break across a line, it may not disagree.
29const cssFloor = "Chrome 123, Safari 17.5, Firefox 121"
30
31// The adoption policy is a rolling one: a feature is fair game once it
32// has been in all three engines about a year. A rolling policy with no
33// clock is a lapsed one nobody has noticed yet, and these two constants
34// are the clock.
35//
36// What does not move when the policy rolls is the floor. It rises only
37// when someone writes a newer feature into the CSS, so "anything a year
38// old may be used" and "today we bottom out at Chrome 123" stay true
39// together. That is also why the review is by hand: the computable
40// half, what is now a year old, was never the hard half. The judgement
41// is which of those to want, and every yes raises the floor for every
42// page that links the CSS.
43//
44// Nine months rather than twelve, so a review that slips a release
45// still lands inside the year the policy names.
46//
47// Answering the failure means re-deriving, not bumping the date: list
48// the features css/tokens.css and css/themes/*.css use, take the
49// highest engine version among them, and if it differs from cssFloor
50// change it here, in README.md and in DESIGN.md together. Then set
51// floorReviewed to the day you did it.
52const (
53 floorReviewed = "2026-09-01"
54 floorReviewMonths = 9
55)
56
57// floorFiles are the documents that state the floor: the README, for
58// someone deciding whether to link the CSS, and DESIGN.md, for someone
59// writing against it.
60var floorFiles = []string{"README.md", "DESIGN.md"}
61
62// TestCSSFloorIsStatedTheSameInBothFiles fails when the README and
63// DESIGN.md disagree about the floor, or either leaves it out. They
64// are written for different readers, and a reader who checks one
65// against the other and finds two numbers trusts neither.
66func TestCSSFloorIsStatedTheSameInBothFiles(t *testing.T) {
67 for _, path := range floorFiles {
68 b, err := os.ReadFile(path)
69 if err != nil {
70 t.Errorf("%s must exist and state the floor %q: %v", path, cssFloor, err)
71 continue
72 }
73 if !strings.Contains(strings.Join(strings.Fields(string(b)), " "), cssFloor) {
74 t.Errorf("%s does not state the floor %q.\n"+
75 "Either it drifted, or the floor moved and this file was not brought along: "+
76 "cssFloor, README.md and DESIGN.md change together or not at all.",
77 path, cssFloor)
78 }
79 }
80}
81
82// TestCSSFloorHasBeenReviewedRecently is the tripwire. It fails on a
83// date, which is unusual and intended: the alternative is a warning,
84// and a warning on a release evening is a thing you scroll past. A
85// build that stops for ten minutes while somebody re-reads a list of
86// CSS features is cheap; a floor that quietly describes 2024 while
87// the policy promises "about a year" is the silence the policy exists
88// to end.
89func TestCSSFloorHasBeenReviewedRecently(t *testing.T) {
90 reviewed, err := time.Parse(time.DateOnly, floorReviewed)
91 if err != nil {
92 t.Fatalf("floorReviewed must be a %s date: %v", time.DateOnly, err)
93 }
94 due := reviewed.AddDate(0, floorReviewMonths, 0)
95 if time.Now().After(due) {
96 t.Fatalf("the CSS floor was last reviewed %s and was due %s.\n"+
97 "Re-derive it, the features css/tokens.css and css/themes/*.css use and the highest engine "+
98 "version among them, then update cssFloor, README.md and DESIGN.md if it moved, and set "+
99 "floorReviewed to today. Do not bump the date alone; the date is the record that somebody looked.",
100 floorReviewed, due.Format(time.DateOnly))
101 }
102}
103
104// changelogName is the file whose newest release must be Version.
105const changelogName = "CHANGELOG.md"
106
107// TestVersionIsTheChangelogsNewestRelease holds the changelog and the
108// tree to one version: the first second-level heading is Unreleased,
109// and the one after it names Version, so a release is cut only once
110// its entry is written, and the tree is never a version the changelog
111// has not heard of. TestTheVersionIsSemver pins Version itself.
112func TestVersionIsTheChangelogsNewestRelease(t *testing.T) {
113 b, err := os.ReadFile(changelogName)
114 if err != nil {
115 t.Fatalf("%s must exist, with ## Unreleased and then ## %s: %v", changelogName, Version, err)
116 }
117 var headings []string
118 for _, line := range strings.Split(string(b), "\n") {
119 if strings.HasPrefix(line, "## ") {
120 headings = append(headings, strings.TrimSpace(line))
121 }
122 }
123 if len(headings) < 2 {
124 t.Fatalf("%s has %d second-level headings %q; want ## Unreleased and then ## %s", changelogName, len(headings), headings, Version)
125 }
126 if headings[0] != "## Unreleased" {
127 t.Errorf("%s's first heading is %q, want %q", changelogName, headings[0], "## Unreleased")
128 }
129 if want := "## " + Version; headings[1] != want {
130 t.Errorf("%s's newest release is %q, but the tree is %q: the changelog entry and fiesta.Version move together", changelogName, headings[1], want)
131 }
132}
133
134// oneLink is the tag the README exists to show: a page links this and
135// has the design system. /1/ is rewritten to the newest 1.y.z release.
136const oneLink = `<link rel="stylesheet" href="https://fiesta.rastrillo.org/1/fiesta.css">`
137
138// TestTheReadmeShowsTheOneLink: the README carries the link tag
139// exactly as a page should paste it.
140func TestTheReadmeShowsTheOneLink(t *testing.T) {
141 b, err := os.ReadFile("README.md")
142 if err != nil {
143 t.Fatalf("README.md must exist and show the one link: %v", err)
144 }
145 if !strings.Contains(string(b), oneLink) {
146 t.Errorf("README.md does not show the one link, verbatim: %s", oneLink)
147 }
148}
149