From 7a68800f6faaea08caa1bbc16ab0ae7ff79d4ebf Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 30 Oct 2026 02:50:00 +0100 Subject: [PATCH] test: sample fixture course Co-Authored-By: Claude Opus 5.5 --- fixtures/courses/sample/MENTOR.md | 1 + .../sample/code/S01 - First steps/hello.sh | 1 + .../courses/sample/exercises/add/solution.js | 3 ++ .../courses/sample/exercises/add/starter.js | 3 ++ .../courses/sample/exercises/add/tests.js | 4 ++ fixtures/courses/sample/lessons/01-intro.md | 3 ++ fixtures/courses/sample/lessons/02-video.md | 3 ++ fixtures/courses/sample/lessons/03-code.md | 7 ++++ .../courses/sample/lessons/04-exercise.md | 23 ++++++++++++ fixtures/courses/sample/media/clip.mp4 | Bin 0 -> 3934 bytes fixtures/courses/sample/media/deck.pdf | Bin 0 -> 1454 bytes fixtures/courses/sample/stcourse.yaml | 35 ++++++++++++++++++ scripts/make-fixtures.sh | 14 +++++++ 13 files changed, 97 insertions(+) create mode 100644 fixtures/courses/sample/MENTOR.md create mode 100644 fixtures/courses/sample/code/S01 - First steps/hello.sh create mode 100644 fixtures/courses/sample/exercises/add/solution.js create mode 100644 fixtures/courses/sample/exercises/add/starter.js create mode 100644 fixtures/courses/sample/exercises/add/tests.js create mode 100644 fixtures/courses/sample/lessons/01-intro.md create mode 100644 fixtures/courses/sample/lessons/02-video.md create mode 100644 fixtures/courses/sample/lessons/03-code.md create mode 100644 fixtures/courses/sample/lessons/04-exercise.md create mode 100644 fixtures/courses/sample/media/clip.mp4 create mode 100644 fixtures/courses/sample/media/deck.pdf create mode 100644 fixtures/courses/sample/stcourse.yaml create mode 100755 scripts/make-fixtures.sh diff --git a/fixtures/courses/sample/MENTOR.md b/fixtures/courses/sample/MENTOR.md new file mode 100644 index 0000000..696e9f0 --- /dev/null +++ b/fixtures/courses/sample/MENTOR.md @@ -0,0 +1 @@ +You are the mentor for the sample course. Give hints, never full solutions. diff --git a/fixtures/courses/sample/code/S01 - First steps/hello.sh b/fixtures/courses/sample/code/S01 - First steps/hello.sh new file mode 100644 index 0000000..6c02b52 --- /dev/null +++ b/fixtures/courses/sample/code/S01 - First steps/hello.sh @@ -0,0 +1 @@ +echo "hello from the sample course" diff --git a/fixtures/courses/sample/exercises/add/solution.js b/fixtures/courses/sample/exercises/add/solution.js new file mode 100644 index 0000000..7d65831 --- /dev/null +++ b/fixtures/courses/sample/exercises/add/solution.js @@ -0,0 +1,3 @@ +export function add(a, b) { + return a + b; +} diff --git a/fixtures/courses/sample/exercises/add/starter.js b/fixtures/courses/sample/exercises/add/starter.js new file mode 100644 index 0000000..29b3851 --- /dev/null +++ b/fixtures/courses/sample/exercises/add/starter.js @@ -0,0 +1,3 @@ +export function add(a, b) { + return a - b; +} diff --git a/fixtures/courses/sample/exercises/add/tests.js b/fixtures/courses/sample/exercises/add/tests.js new file mode 100644 index 0000000..4d5843b --- /dev/null +++ b/fixtures/courses/sample/exercises/add/tests.js @@ -0,0 +1,4 @@ +export const tests = [ + { name: "adds 2 and 3", run: (mod, assert) => assert.equal(mod.add(2, 3), 5) }, + { name: "adds -1 and 1", run: (mod, assert) => assert.equal(mod.add(-1, 1), 0) }, +]; diff --git a/fixtures/courses/sample/lessons/01-intro.md b/fixtures/courses/sample/lessons/01-intro.md new file mode 100644 index 0000000..4e844ff --- /dev/null +++ b/fixtures/courses/sample/lessons/01-intro.md @@ -0,0 +1,3 @@ +# Introduction + +Welcome to the sample course. It exists so tests have something small to load. diff --git a/fixtures/courses/sample/lessons/02-video.md b/fixtures/courses/sample/lessons/02-video.md new file mode 100644 index 0000000..52c1d4b --- /dev/null +++ b/fixtures/courses/sample/lessons/02-video.md @@ -0,0 +1,3 @@ +# Transcript + +A two-second test pattern plays. Nothing is said. diff --git a/fixtures/courses/sample/lessons/03-code.md b/fixtures/courses/sample/lessons/03-code.md new file mode 100644 index 0000000..0a29890 --- /dev/null +++ b/fixtures/courses/sample/lessons/03-code.md @@ -0,0 +1,7 @@ +# Code along + +Run the script in the section files: + +```sh +sh hello.sh +``` diff --git a/fixtures/courses/sample/lessons/04-exercise.md b/fixtures/courses/sample/lessons/04-exercise.md new file mode 100644 index 0000000..4e78add --- /dev/null +++ b/fixtures/courses/sample/lessons/04-exercise.md @@ -0,0 +1,23 @@ +# Adding numbers + +Functions take values and return values. + +## Exercises + +### Exercise 2.1 — `add` + +Implement `add(a, b)` so that it returns the sum of its arguments. + +## Hints + +
Exercise 2.1 (add) — nudge + +Which operator combines two numbers? + +
+ +
Exercise 2.1 (add) — near-solution + +Return `a + b`. + +
diff --git a/fixtures/courses/sample/media/clip.mp4 b/fixtures/courses/sample/media/clip.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..2e316e002b531e9b380e2a857d7020918b66f570 GIT binary patch literal 3934 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 P@$mnLAnH_Es`>u_Pp5c< literal 0 HcmV?d00001 diff --git a/fixtures/courses/sample/media/deck.pdf b/fixtures/courses/sample/media/deck.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5f8fde26d5e3e7b37915f96ca69796302cd95561 GIT binary patch literal 1454 zcmcgs&ubGw6plin?mq+ z;L#q6)`B3kf(LI3;zf!*`3Kmm=s)1mn{Q%Ux7!}A13T=zH}Cu2`)1}97Hak#TGXY& z{=5D6QUNW+KIbe%opm%n1Sg_J*(hp~L=izzXCPH7cyWD|Vawr85cTka(_;ye!P~(1 zLN5aULL9lnE{kub5pK=EkXYyn5J~J$qm5Cp6%9j<6nx)zla?wVkv^WwVqQ+gD}Uqd zDC9ueXTc++iG8Pt1WJ|&&okF|%xKgi;8hKRWSuPIM#LS?5Wx+WM8miXWeJ)Flo&I} z>ragq(7`Hcm4q*ylORu1iNtVo*x^Dhp&7-dld!S*E@aEN-*s?3>_)C1_VAJ)R>Q?TEbQ?2at1(0S1GJgvZQTkw!b;Z~us;Z}K9^nbyQKa)LMc z%`dwzpKdqz+U~3T=3aiKI|#h~Rwrz41>V4IdmV4!1zYY;-))B-@5<-dwU38+T>P4U zJ6p_M{WSGc9NrPZ@iB_iNtY~+@!zOxWYrah|0lwv`}*0#%fD`*>nRb8x#=h8h#)TK z#fU(~{XBKY#+Hl>>c!oKN%zI}?)LM;gN@PJhmF;V_)_k`o4R(62&0&J5Xd4knqB}zWtFDYtFGxvNhM{aTGMAlQ%SfJ^RcLul%YKr>JMz`H|ayOfdBvi literal 0 HcmV?d00001 diff --git a/fixtures/courses/sample/stcourse.yaml b/fixtures/courses/sample/stcourse.yaml new file mode 100644 index 0000000..7d25ac2 --- /dev/null +++ b/fixtures/courses/sample/stcourse.yaml @@ -0,0 +1,35 @@ +schema: 1 +id: sample +title: Sample course +pitch: A tiny self-contained course used by the test suite. +visibility: public +tracks: + - { id: js, label: JavaScript } +mentor: MENTOR.md +source: { kind: authored } +decks: + - { id: d1, file: media/deck.pdf, attachTo: m1-video } +modules: + - id: m1 + title: First steps + code: { dir: "code/S01 - First steps", command: "sh hello.sh" } + lessons: + - { id: m1-intro, title: Introduction, type: text, file: lessons/01-intro.md } + - { id: m1-video, title: Watch the clip, type: video, file: media/clip.mp4, duration: 2, transcript: lessons/02-video.md } + - { id: m1-code, title: Code along, type: text, file: lessons/03-code.md } + - id: m2 + title: Exercises + lessons: + - { id: m2-text, title: Adding numbers, type: text, file: lessons/04-exercise.md } + - id: m2-ex-add + title: "Exercise 2.1: add" + type: exercise + file: lessons/04-exercise.md + anchor: exercise-21--add + hints: { file: lessons/04-exercise.md, match: "Exercise 2.1 (add)" } + browser: + language: js + starter: exercises/add/starter.js + tests: exercises/add/tests.js + solution: exercises/add/solution.js + localCommand: "node --test" diff --git a/scripts/make-fixtures.sh b/scripts/make-fixtures.sh new file mode 100755 index 0000000..a9112ef --- /dev/null +++ b/scripts/make-fixtures.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Regenerates the binary fixtures under fixtures/courses/sample/media. +set -eu +cd "$(dirname "$0")/../fixtures/courses/sample/media" +/usr/bin/ffmpeg -y -loglevel error -f lavfi -i "testsrc=duration=2:size=160x90:rate=10" \ + -pix_fmt yuv420p -c:v libx264 -crf 35 -preset veryslow -movflags +faststart clip.mp4 +/home/user/.venvs/pdf/bin/python -I - <<'PY' +import pymupdf +doc = pymupdf.open() +for i, text in enumerate(["Sample deck: title", "Sample deck: middle", "Sample deck: end"], 1): + page = doc.new_page(width=480, height=270) + page.insert_text((40, 135), text, fontsize=24) +doc.save("deck.pdf", garbage=4, deflate=True) +PY