|
7 | 7 | commercialLabel, |
8 | 8 | entryPageUrl, |
9 | 9 | esc, |
| 10 | + isRealDate, |
10 | 11 | STATUS_NOTES, |
11 | 12 | verifiedAge, |
12 | 13 | } from "./shared.mjs"; |
@@ -37,12 +38,21 @@ function throws(label, fn, needle) { |
37 | 38 | } |
38 | 39 |
|
39 | 40 | /* shared ----------------------------------------------------------------- */ |
| 41 | +for (const date of ["2026-01-01", "2026-12-31", "2026-04-30", "2024-02-29", "2000-02-29", "0000-02-29", "0099-12-31"]) { |
| 42 | + eq(`isRealDate accepts ${date}`, isRealDate(date), true); |
| 43 | +} |
| 44 | +for (const date of ["2025-13-01", "2026-02-30", "2025-02-29", "1900-02-29", "2100-02-29", "2026-04-31", "2026-00-01", "2026-01-00", "2026-01-32", "0099-02-29", "2026-1-01", "2026-01-1", "2026-01-01\n", " 2026-01-01", "2026-01-01T00:00:00Z", "", null, undefined, 20260101]) { |
| 45 | + eq(`isRealDate rejects ${JSON.stringify(date)}`, isRealDate(date), false); |
| 46 | +} |
40 | 47 | eq("esc escapes all five characters", esc(`<a href="x">'&'</a>`), "<a href="x">'&'</a>"); |
41 | 48 | eq("commercialLabel true", commercialLabel(true), "commercial OK"); |
42 | 49 | eq("commercialLabel varies", commercialLabel("varies"), "per-file review"); |
43 | 50 | eq("commercialLabel unknown", commercialLabel("unknown"), "commercial ?"); |
44 | 51 | eq("verifiedAge fresh", verifiedAge("2026-09-01", Date.parse("2026-09-24T00:00:00Z")).bucket, "fresh"); |
45 | 52 | eq("verifiedAge missing", verifiedAge(null, Date.now()).bucket, "unknown"); |
| 53 | +for (const date of ["2025-13-01", "2026-02-30", "2025-02-29", "1900-02-29", "2026-04-31"]) { |
| 54 | + eq(`verifiedAge rejects ${date}`, verifiedAge(date, Date.parse("2026-09-24T00:00:00Z")).bucket, "unknown"); |
| 55 | +} |
46 | 56 | eq("entryPageUrl trims the site slash", entryPageUrl({ siteUrl: "https://x.test/site/" }, "a-b"), "https://x.test/site/entry/a-b/"); |
47 | 57 | has("STATUS_NOTES covers needs-review", STATUS_NOTES["needs-review"], "open"); |
48 | 58 |
|
@@ -241,6 +251,10 @@ throws("licence in a why sentence", badStack((m) => m.replace("Five loops.", "Fi |
241 | 251 | throws("licence phrase in a why sentence", badStack((m) => m.replace("Five loops.", "Five public domain loops.")), '("public domain")'); |
242 | 252 | throws("missing walked", badStack((m) => m.replace("walked: 2026-09-20\n", "")), "frontmatter is missing walked"); |
243 | 253 | throws("bad walked date", badStack((m) => m.replace("2026-09-20", "20 Sept")), "walked is not YYYY-MM-DD"); |
| 254 | +for (const date of ["2025-13-01", "2026-02-30", "2025-02-29", "1900-02-29", "2026-04-31"]) { |
| 255 | + throws(`impossible walked date ${date}`, badStack((m) => m.replace("2026-09-20", date)), "walked is not YYYY-MM-DD"); |
| 256 | +} |
| 257 | +eq("leap-day walked date", parseStack(stackMd.replace("2026-09-20", "2000-02-29"), { file: "stacks/s1.md" }).meta.walked, "2000-02-29"); |
244 | 258 | throws("empty pick section", badStack((m) => m.replace("- **Music, no credit:** [Chips](../catalog/audio/subspaceaudio-5-chiptunes.md). Five loops.", "")), 'section "Audio" has no picks'); |
245 | 259 | throws("gaps line not a bullet", badStack((m) => m.replace("- No parallax layers yet.", "No parallax layers yet.")), "stacks/s1.md:24: a Gaps line is a bullet"); |
246 | 260 | eq("licence terms skip plain words", licenceTerms({ licenses: { custom: {}, MIT: { spdx: "MIT" }, CC0: { spdx: "CC0-1.0" } } }, ["OFL-1.1"]).sort().join(","), "CC0,CC0-1.0,MIT,OFL-1.1"); |
|
0 commit comments