Files
workouts/WorkoutsTests/ExerciseInfoTests.swift
T
rzen 669ecf1259 Surface machine settings in the exercise library and refine machine rigs
Library detail screens now lead with the user's recorded machine settings
(per-split when they disagree, empty-state card for machine-based entries)
and append the weight progression chart. Starter seeds mark machine
exercises with an empty machineSettings list so the settings UI lights up
before first use. The figure rig gains a frontal body profile for face-on
machines, props that can ride mid joints (knees/elbows), and an
alternating four-frame Bird Dog loop.

Claude-Session: https://claude.ai/code/session_01LEoff8bXGBS83tK1c55Mf7
2026-07-06 18:35:15 -04:00

47 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.isMachineBased)
#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")
}
}
}