Files
workouts/WorkoutsTests/ExerciseInfoTests.swift
T
rzen fce8fa4c17 Author the machine exercise circuit with props and corrected hip machine motions
Fourteen Planet Fitness machine exercises join the rig library, each with
authored motion, info page, and schematic equipment via the new props layer
(scene shapes, cables, bars, pads) rendered in lockstep by render.py and the
in-app figure renderer. Abductor and Adductor are authored face-on with the
real seated machine motion — knees-bent legs swinging apart/together against
knee pads — replacing the earlier middle-split depiction. The watch target
now bundles the figure renderer and motion rigs too.

Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
2026-07-06 16:29:31 -04:00

46 lines
2.1 KiB
Swift

import Foundation
import Testing
@testable import Workouts
/// Locks the `info.md` parsing contract: the bundled reference pages must parse into
/// the summary / metadata / sections shape the library detail screen renders, and
/// every shipped motion rig must come with one (the authoring convention).
struct ExerciseInfoTests {
@Test func bundledChestPressInfoParses() throws {
let info = try #require(ExerciseInfoLibrary.info(for: "Chest Press"))
#expect(info.summary.contains("machine bench press"))
#expect(info.category == "Main circuit")
#expect(info.type == "Machine-based horizontal press")
#expect(info.targets == ["Pectorals", "anterior deltoids", "triceps"])
#expect(info.sections.map(\.title) == ["Setup", "Execution", "Cues", "Common Mistakes", "Progression"])
let execution = try #require(info.sections.first { $0.title == "Execution" })
#expect(execution.items.count == 3)
guard case .step(let firstStep) = execution.items[0] else {
Issue.record("expected Execution to start with a numbered step")
return
}
// Hard-wrapped source lines must rejoin into one step.
#expect(firstStep.contains("stop short of locking the elbows"))
let cues = try #require(info.sections.first { $0.title == "Cues" })
guard case .bullet = cues.items[0] else {
Issue.record("expected Cues to be bullets")
return
}
}
/// Every bundled motion rig ships a parseable info page — the exporter copies
/// `info.md` per entry, and the detail screen counts on the shape.
@Test func everyBundledExerciseHasParseableInfo() throws {
#expect(!ExerciseMotionLibrary.exerciseNames.isEmpty)
for name in ExerciseMotionLibrary.exerciseNames {
let info = try #require(ExerciseInfoLibrary.info(for: name), "\(name) has no bundled info.md")
#expect(!info.summary.isEmpty, "\(name): empty summary")
#expect(!info.targets.isEmpty, "\(name): no targets")
#expect(!info.sections.isEmpty, "\(name): no sections")
}
}
}