from django.test import SimpleTestCase from generator.services.workout_generation.entry_rules import ( apply_rep_volume_floor, pick_reps_for_exercise, working_rest_seconds, ) from generator.services.workout_generation.focus import ( focus_key_for_exercise, has_duplicate_focus, ) from generator.services.workout_generation.modality import ( clamp_duration_bias, plan_superset_modalities, ) from generator.services.workout_generation.pattern_planning import ( merge_pattern_preferences, rotated_muscle_subset, working_position_label, ) from generator.services.workout_generation.recovery import is_recovery_exercise from generator.services.workout_generation.scaling import apply_fitness_scaling from generator.services.workout_generation.section_builders import ( build_duration_entries, build_section_superset, section_exercise_count, ) class _Rng: def __init__(self, randint_values=None): self._randint_values = list(randint_values or []) def randint(self, low, high): if self._randint_values: return self._randint_values.pop(0) return low def shuffle(self, arr): # Deterministic for tests. return None class _Ex: def __init__(self, **kwargs): self.__dict__.update(kwargs) class TestWorkoutGenerationModules(SimpleTestCase): def test_section_count_and_duration_entries(self): rng = _Rng([6, 27, 31]) self.assertEqual(section_exercise_count('warmup', 1, rng=rng), 6) exercises = [_Ex(name='A'), _Ex(name='B')] entries = build_duration_entries( exercises, duration_min=20, duration_max=40, min_duration=20, duration_multiple=5, rng=rng, ) self.assertEqual(entries[0]['duration'], 25) self.assertEqual(entries[1]['duration'], 30) section = build_section_superset('Warm Up', entries) self.assertEqual(section['name'], 'Warm Up') self.assertEqual(section['rounds'], 1) def test_scaling_and_rest_floor(self): params = { 'rep_min': 4, 'rep_max': 10, 'rounds': (3, 4), 'rest_between_rounds': 60, } scaling = { 1: {'rep_min_mult': 1.1, 'rep_max_mult': 1.2, 'rounds_adj': -1, 'rest_adj': 15}, 2: {'rep_min_mult': 1.0, 'rep_max_mult': 1.0, 'rounds_adj': 0, 'rest_adj': 0}, } out = apply_fitness_scaling( params, fitness_level=1, scaling_config=scaling, min_reps=6, min_reps_strength=1, is_strength=True, ) self.assertGreaterEqual(out['rep_min'], 5) self.assertEqual(working_rest_seconds(-5, 0), 15) def test_modality_helpers(self): self.assertEqual(clamp_duration_bias(0.9, (0.2, 0.6)), 0.6) modalities = plan_superset_modalities( num_supersets=4, duration_bias=0.5, duration_bias_range=(0.25, 0.5), is_strength_workout=False, rng=_Rng(), ) self.assertEqual(len(modalities), 4) self.assertTrue(any(modalities)) def test_pattern_and_focus_helpers(self): self.assertEqual(working_position_label(0, 3), 'early') self.assertEqual(working_position_label(1, 3), 'middle') self.assertEqual(working_position_label(2, 3), 'late') self.assertEqual( merge_pattern_preferences(['upper pull', 'core'], ['core', 'lunge']), ['core'], ) self.assertEqual( rotated_muscle_subset(['a', 'b', 'c'], 1), ['b', 'c', 'a'], ) curl_a = _Ex(name='Alternating Bicep Curls', movement_patterns='upper pull') curl_b = _Ex(name='Bicep Curls', movement_patterns='upper pull') self.assertEqual(focus_key_for_exercise(curl_a), 'bicep_curl') self.assertTrue(has_duplicate_focus([curl_a, curl_b])) def test_recovery_and_rep_selection(self): stretch = _Ex(name='Supine Pec Stretch - T', movement_patterns='mobility - static') self.assertTrue(is_recovery_exercise(stretch)) ex = _Ex(exercise_tier='primary') reps = pick_reps_for_exercise( ex, {'rep_min': 8, 'rep_max': 12}, {'primary': (3, 6)}, rng=_Rng([5]), ) self.assertEqual(reps, 5) entries = [{'reps': 3}, {'duration': 30}] apply_rep_volume_floor(entries, rounds=3, min_volume=12) self.assertEqual(entries[0]['reps'], 4)