def test_add_workout(self): ws1 = [0, 2, 5] rt1 = FirstRaceType(name='Marathon', distance=FirstDistance.from_string('42.195 km')) rd1 = date(year=2017, month=7, day=29) r1 = FirstRace(name='SFM', race_type=rt1, race_date=rd1) rn1 = FirstRunner(name='DBD') p1 = FirstPlan(name='My first marathon training plan', weekly_schedule=ws1, race=r1, runner=rn1) t_warmup = FirstTime.from_string('0:15:00') p_warmup = FirstPace.from_string('0:10:00 min per mile') s_warmup = FirstStepBody(name='Warm up', pace=p_warmup, time=t_warmup) s_repeat = FirstStepRepeat(name='repeat X 8', repeat=8) d_interval = FirstDistance.from_string('400 m') p_fast = FirstPace.from_string('0:08:00 min per mile') s_fast = FirstStepBody(name='Fast', pace=p_fast, distance=d_interval) s_repeat.add_step(s_fast) s_slow = FirstStepBody(name='Rest', pace=p_warmup, distance=d_interval) s_repeat.add_step(s_slow) t_cooldown = FirstTime.from_string('0:10:00') s_cooldown = FirstStepBody(name='Cool down', pace=p_warmup, time=t_cooldown) wo = FirstWorkout(name='Week 1 Key-run 1', workout_date=date(year=2017, month=6, day=24)) wo.add_step(step=s_warmup) wo.add_step(step=s_repeat) wo.add_step(step=s_cooldown) try: # first workout p1.add_workout(workout=wo) cmp_string = ('Training Plan:\nName - "My first marathon training plan"\n' + 'Workout days: Mon, Wed, Sat\nRace:\n' + ' Name - "SFM" of type Marathon - 42.195 km\nRunner:\n Name - "DBD"\nWorkouts:\n' + ' "Week 1 Key-run 1"\n Sat 2017-06-24\n scheduled\n' + 'Total 1 workouts\n') self.assertEqual(cmp_string, str(p1)) file_name = 'cmp_plan2.tcx' with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file: cmp_string = from_file.read() self.assertEqual(cmp_string, p1.tcx()) file_name = 'cmp_plan2.json' with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file: cmp_json = json.load(from_file) self.assertEqual(cmp_json, p1.to_json()) file_name = 'cmp_plan2_km.json' with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file: cmp_json = json.load(from_file) self.assertEqual(cmp_json, p1.to_json(output_unit='km')) file_name = 'cmp_plan2.html' with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file: cmp_html = from_file.read() self.assertEqual(cmp_html, p1.to_html()) file_name = 'cmp_plan2_km.html' with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file: cmp_html = from_file.read() self.assertEqual(cmp_html, p1.to_html(output_unit='km')) except TypeError as ex: self.fail(str(ex))
def __parse_simple_steps(data: FirstData, instructions: str, time_index: int, race_pace: FirstPace): steps = [] last = instructions.split('#')[-1] result = parse('{:d}x', last) if result is not None: simple_instructions = '#'.join(instructions.split('#')[:-1]) repeat = result.fixed[0] else: simple_instructions = instructions repeat = -1 if simple_instructions != '': for item in simple_instructions.split('#'): steps.append(FirstStepBody.from_instructions(instructions=item, data=data, time_index=time_index, rp=race_pace)) return steps, repeat
def test_repeat(self): FirstStepBase.reset_global_id() p1 = FirstPace.from_string('0:10:00 min per mile') d1 = FirstDistance.from_string('3 mile') t1 = FirstTime.from_string('0:15:00') try: name = '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)' s1 = FirstStepRepeat(name=name, repeat=3) self.assertEqual( 'Step: "' + name + '" id = 0\ntype - repeat repeat - 3\n', str(s1)) self.assertAlmostEquals(0.0, s1.total(unit='mile'), 5) self.assertAlmostEquals(0.0, s1.total(what='time', unit='minute')) tcx_string = ( '<Step xsi:type="Repeat_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n' + ' <Repetitions>3</Repetitions>\n' + '</Step>\n') self.assertEqual(tcx_string, s1.tcx()) except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: s2 = FirstStepBody(name='3 mile @ 10 min per mile', pace=p1, distance=d1) s3 = FirstStepBody(name='15 minutes @ 19 min per mile', pace=p1, time=t1) s1.add_step(s2) s1.add_step(s3) short = 'Step: "' + name + '" id = 0\ntype - repeat repeat - 3\n' self.assertEqual(short, str(s1)) detail = 'Step: "3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)"\n' +\ ' Step: "3 mile @ 10 min per mile"\n' +\ ' 3.0 mile at 0:10:00 min per mile\n' +\ ' Step: "15 minutes @ 19 min per mile"\n' +\ ' 0:15:00 at 0:10:00 min per mile\n' self.assertEqual(detail, s1.details()) self.assertAlmostEquals(13.5, s1.total(unit='mile'), 5) self.assertAlmostEquals(135.0, s1.total(what='time', unit='minute')) tcx_string = ( ' <Step xsi:type="Repeat_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n' + ' <Repetitions>3</Repetitions>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>1</StepId>\n' + ' <Name>3 mile @ 10 min per mile</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>4828</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>2</StepId>\n' + ' <Name>15 minutes @ 19 min per mile</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>900</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' ' </Step>\n') self.assertEqual(tcx_string, s1.tcx(indent=' ', delta_seconds=10)) except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: # bad repeat type dummy = FirstStepRepeat(name='bla', repeat='3') self.fail('Should not get here with bad repeat type') except TypeError as ex: self.assertEqual( 'FirstStepRepeat.__init__ - repeat must be an integer', str(ex)) try: # negative repeat dummy = FirstStepRepeat(name='bla', repeat=-3) self.fail('Should not get here with negative repeat value') except ValueError as ex: self.assertEqual( 'FirstStepRepeat.__init__ - repeat must be greater than 0', str(ex)) try: # bad child step type s1.add_step('bad step') self.fail('Should not get here with bad step type') except TypeError as ex: self.assertEqual( 'FirstStepRepeat.add_step - step must be an instance of FirstStepBase', str(ex))
def test_body(self): FirstStepBase.reset_global_id() p1 = FirstPace.from_string('0:10:00 min per mile') d1 = FirstDistance.from_string('3 mile') t1 = FirstTime.from_string('0:15:00') try: # distance step s1 = FirstStepBody(name='3 miles @ 10 minutes per mile', pace=p1, distance=d1) cmp_string = 'Step: "3 miles @ 10 minutes per mile" id = 0\n' + \ 'type - body pace - 0:10:00 min per mile\nDistance - 3.0 mile\n' self.assertEqual(cmp_string, str(s1)) self.assertAlmostEquals(3.0, s1.total(unit='mile'), 5) self.assertAlmostEquals(4.828032, s1.total(unit='km'), 5) self.assertAlmostEquals(30.0, s1.total(what='time', unit='minute'), 5) self.assertAlmostEquals(0.5, s1.total(what='time', unit='hour'), 5) tcx_string = ( '<Step xsi:type="Step_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 miles @ 10 minutes per mile</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>4828</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + '</Step>\n') self.assertEqual(tcx_string, s1.tcx()) # no indent tcx_string = ( ' <Step xsi:type="Step_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 miles @ 10 minutes per mile</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>4828</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6688955</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.6957186</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Step>\n') self.assertEqual(tcx_string, s1.tcx(indent=' ', delta_seconds=3)) # with indent except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: # time step s1 = FirstStepBody(name='15 minutes @ 10 minutes per mile', pace=p1, time=t1) cmp_string = 'Step: "15 minutes @ 10 minutes per mile" id = 1\n' + \ 'type - body pace - 0:10:00 min per mile\nTime - 0:15:00\n' self.assertEqual(cmp_string, str(s1)) self.assertAlmostEquals(15.0, s1.total(what='time', unit='minute'), 5) self.assertAlmostEquals(7920.0, s1.total(unit='ft')) tcx_string = ( '<Step xsi:type="Step_t">\n' + ' <StepId>1</StepId>\n' + ' <Name>15 minutes @ 10 minutes per mile</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>900</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + '</Step>\n') self.assertEqual(tcx_string, s1.tcx()) except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: # bad name type dummy = FirstStepBody(name=123, pace=p1, time=t1) self.fail('Should not get here with bad name') except TypeError as ex: self.assertEqual('FirstStepBase.__init__ - name must be a string', str(ex)) try: # bad pace dummy = FirstStepBody(name='dummy', pace='bad pace type', time=t1) self.fail('Should not get here with bad pace') except TypeError as ex: self.assertEqual( 'FirstStepBody.__init__ - pace must be an instance of FirstPace', str(ex)) try: # no distance and no time dummy = FirstStepBody(name='dummy', pace=p1) self.fail('Should not get here with neither distance nor duration') except ValueError as ex: self.assertEqual( 'FirstStepBody.__init__ - Either distance or time must have a value', str(ex)) try: # bad distance dummy = FirstStepBody(name='dummy', pace=p1, distance=123.45) self.fail('Should not get here with bad distance') except TypeError as ex: self.assertEqual( 'FirstStepBody.__init__ - distance must be an instance of FirstDistance', str(ex)) try: # bad time dummy = FirstStepBody(name='dummy', pace=p1, time=987.65) self.fail('Should not get here with bad time') except TypeError as ex: self.assertEqual( 'FirstStepBody.__init__ - time must be an instance of FirstTime', str(ex)) try: # both distance and time dummy = FirstStepBody(name='dummy', pace=p1, distance=d1, time=t1) self.fail('Should not get here with both distance and time') except ValueError as ex: self.assertEqual( 'FirstStepBody.__init__ - cannot set both distance and duration in the same step', str(ex))
def test_repeat(self): FirstStepBase.reset_global_id() pace = FirstPace.from_string(str_input='0:10:00 min per mile') distance = FirstDistance.from_string(string='3 mile') time = FirstTime.from_string(string='0:15:00') try: name = '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)' step_r = FirstStepRepeat(name=name, repeat=3) self.assertEqual( 'Step: "' + name + '" id = 0\ntype - repeat repeat - 3\n', str(step_r)) self.assertAlmostEqual(0.0, step_r.total(unit='mile'), 5) self.assertAlmostEqual(0.0, step_r.total(what='time', unit='minute')) tcx_string = ( '<Step xsi:type="Repeat_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n' + ' <Repetitions>3</Repetitions>\n' + '</Step>') self.assertEqual(tcx_string, step_r.tcx().indented_str()) except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: step_b1 = FirstStepBody(name='3 mile @ 10 min per mile', pace=pace, distance=distance) step_b2 = FirstStepBody(name='15 minutes @ 19 min per mile', pace=pace, time=time) step_r.add_step(step_b1) step_r.add_step(step_b2) short = 'Step: "' + name + '" id = 0\ntype - repeat repeat - 3\n' self.assertEqual(short, str(step_r)) detail = 'Step: "3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)"\n' + \ ' Step: "3 mile @ 10 min per mile"\n' + \ ' 3.0 mile at 0:10:00 min per mile\n' + \ ' Step: "15 minutes @ 19 min per mile"\n' + \ ' 0:15:00 at 0:10:00 min per mile\n' self.assertEqual(detail, step_r.details()) self.assertAlmostEqual(13.5, step_r.total(unit='mile'), 5) self.assertAlmostEqual(135.0, step_r.total(what='time', unit='minute')) tcx_string = ( '<Step xsi:type="Repeat_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n' + ' <Repetitions>3</Repetitions>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>1</StepId>\n' + ' <Name>3 mile @ 10 min per mile</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>4828</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>2</StepId>\n' + ' <Name>15 minutes @ 19 min per mile</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>900</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' '</Step>') self.assertEqual(tcx_string, step_r.tcx(delta_seconds=10).indented_str()) cmp_json = { 'name': '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)', 'repeat': 3, 'steps': [{ 'distance': { 'distance': 3.0, 'unit': 'mile' }, 'name': '3 mile @ 10 min per mile', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } } }, { 'name': '15 minutes @ 19 min per mile', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } }] } self.assertEqual(cmp_json, step_r.to_json()) cmp_json = { 'name': '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)', 'repeat': 3, 'steps': [{ 'distance': { 'distance': 4.828032, 'unit': 'km' }, 'name': '3 mile @ 10 min per mile', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } } }, { 'name': '15 minutes @ 19 min per mile', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } }] } self.assertEqual(cmp_json, step_r.to_json(output_unit='km')) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <p>\n' + ' Repeat 3 times:\n' + ' </p>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' 3 mile @ 10 min per mile - 3.000 mile at 0:10:00 min per mile\n' + ' </p>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' 15 minutes @ 19 min per mile - 0:15:00 at 0:10:00 min per mile\n' + ' </p>\n' + ' </div>\n' + '</div>') self.assertEqual(cmp_html, step_r.to_html().indented_str()) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <p>\n' + ' Repeat 3 times:\n' + ' </p>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' 3 mile @ 10 min per mile - 4.828 km at 0:06:13 min per km\n' + ' </p>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' 15 minutes @ 19 min per mile - 0:15:00 at 0:06:13 min per km\n' + ' </p>\n' + ' </div>\n' + '</div>') self.assertEqual(cmp_html, step_r.to_html(output_unit='km').indented_str()) except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: # negative repeat _ = FirstStepRepeat(name='bla', repeat=-3) self.fail('Should not get here with negative repeat value') except ValueError as ex: self.assertEqual('repeat must be greater than 0', str(ex))
def test_body(self): FirstStepBase.reset_global_id() pace = FirstPace.from_string(str_input='0:10:00 min per mile') distance = FirstDistance.from_string(string='3 mile') time = FirstTime.from_string(string='0:15:00') try: # distance step step_b = FirstStepBody(name='3 miles @ 10 minutes per mile', pace=pace, distance=distance) cmp_string = 'Step: "3 miles @ 10 minutes per mile" id = 0\n' + \ 'type - body pace - 0:10:00 min per mile\nDistance - 3.0 mile\n' self.assertEqual(cmp_string, str(step_b)) self.assertAlmostEqual(3.0, step_b.total(unit='mile'), 5) self.assertAlmostEqual(4.828032, step_b.total(unit='km'), 5) self.assertAlmostEqual(30.0, step_b.total(what='time', unit='minute'), 5) self.assertAlmostEqual(0.5, step_b.total(what='time', unit='hour'), 5) tcx_string = ( '<Step xsi:type="Step_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 miles @ 10 minutes per mile</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>4828</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + '</Step>') self.assertEqual(tcx_string, step_b.tcx().indented_str()) # no indent tcx_string = ( '<Step xsi:type="Step_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>3 miles @ 10 minutes per mile</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>4828</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6688955</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.6957186</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + '</Step>') self.assertEqual(tcx_string, step_b.tcx(delta_seconds=3).indented_str()) cmp_json = { 'distance': { 'distance': 3.0, 'unit': 'mile' }, 'name': '3 miles @ 10 minutes per mile', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } } } self.assertEqual(cmp_json, step_b.to_json()) cmp_json = { 'distance': { 'distance': 4.828032, 'unit': 'km' }, 'name': '3 miles @ 10 minutes per mile', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } } } self.assertEqual(cmp_json, step_b.to_json(output_unit='km')) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <p>\n' + ' 3 miles @ 10 minutes per mile - 3.000 mile at 0:10:00 min per mile\n' + ' </p>\n' + '</div>') self.assertEqual(cmp_html, step_b.to_html().indented_str()) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <p>\n' + ' 3 miles @ 10 minutes per mile - 4.828 km at 0:06:13 min per km\n' + ' </p>\n' + '</div>') self.assertEqual(cmp_html, step_b.to_html(output_unit='km').indented_str()) except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: # time step step_b = FirstStepBody(name='15 minutes @ 10 minutes per mile', pace=pace, time=time) cmp_string = 'Step: "15 minutes @ 10 minutes per mile" id = 1\n' + \ 'type - body pace - 0:10:00 min per mile\nTime - 0:15:00\n' self.assertEqual(cmp_string, str(step_b)) self.assertAlmostEqual(15.0, step_b.total(what='time', unit='minute'), 5) self.assertAlmostEqual(7920.0, step_b.total(unit='ft')) tcx_string = ( '<Step xsi:type="Step_t">\n' + ' <StepId>1</StepId>\n' + ' <Name>15 minutes @ 10 minutes per mile</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>900</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + '</Step>') self.assertEqual(tcx_string, step_b.tcx().indented_str()) cmp_json = { 'name': '15 minutes @ 10 minutes per mile', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } } self.assertEqual(cmp_json, step_b.to_json()) cmp_json = { 'name': '15 minutes @ 10 minutes per mile', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } } self.assertEqual(cmp_json, step_b.to_json(output_unit='km')) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <p>\n' + ' 15 minutes @ 10 minutes per mile - 0:15:00 at 0:10:00 min per mile\n' + ' </p>\n' + '</div>') self.assertEqual(cmp_html, step_b.to_html().indented_str()) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <p>\n' + ' 15 minutes @ 10 minutes per mile - 0:15:00 at 0:06:13 min per km\n' + ' </p>\n' + '</div>') self.assertEqual(cmp_html, step_b.to_html(output_unit='km').indented_str()) except TypeError as tex: self.fail(str(tex)) except ValueError as vex: self.fail(str(vex)) try: # no distance and no time _ = FirstStepBody(name='dummy', pace=pace) self.fail('Should not get here with neither distance nor duration') except ValueError as ex: self.assertEqual('Either distance or time must have a value', str(ex)) try: # both distance and time _ = FirstStepBody(name='dummy', pace=pace, distance=distance, time=time) self.fail('Should not get here with both distance and time') except ValueError as ex: self.assertEqual( 'Cannot set both distance and duration in the same step', str(ex))
def test_add_workout(self): ws1 = [0, 2, 5] rt1 = FirstRaceType(name='Marathon', distance=42.195, unit='km') rd1 = date(year=2017, month=7, day=29) r1 = FirstRace(name='SFM', race_type=rt1, race_date=rd1) rn1 = FirstRunner(name='DBD') p1 = FirstPlan(name='My first marathon training plan', weekly_schedule=ws1, race=r1, runner=rn1) t_warmup = FirstTime.from_string('0:15:00') p_warmup = FirstPace.from_string('0:10:00 min per mile') s_warmup = FirstStepBody(name='Warm up', pace=p_warmup, time=t_warmup) s_repeat = FirstStepRepeat(name='repeat X 8', repeat=8) d_interval = FirstDistance.from_string('400 m') p_fast = FirstPace.from_string('0:08:00 min per mile') s_fast = FirstStepBody(name='Fast', pace=p_fast, distance=d_interval) s_repeat.add_step(s_fast) s_slow = FirstStepBody(name='Rest', pace=p_warmup, distance=d_interval) s_repeat.add_step(s_slow) t_cooldown = FirstTime.from_string('0:10:00') s_cooldown = FirstStepBody(name='Cool down', pace=p_warmup, time=t_cooldown) wo = FirstWorkout(name='Week 1 Key-run 1', workout_date=date(year=2017, month=6, day=24)) wo.add_step(step=s_warmup) wo.add_step(step=s_repeat) wo.add_step(step=s_cooldown) try: # first workout p1.add_workout(workout=wo) cmp_string = ( 'Training Plan:\nName - "My first marathon training plan"\n' + 'Workout days: Mon, Wed, Sat\nRace:\n' + ' Name - "SFM" of type Marathon - 42.195 km\nRunner:\n Name - "DBD"\nWorkouts:\n' + ' "Week 1 Key-run 1"\n Sat 2017-06-24\n scheduled\n' + 'Total 1 workouts\n') self.assertEqual(cmp_string, str(p1)) file_name = expanduser( '~/PycharmProjects/first/database/cmp_plan2.tcx') # to_file = open(file_name, 'w') # to_file.write(p1.tcx()) # to_file.close() from_file = open(file_name) cmp_string = from_file.read() from_file.close() self.assertEqual(cmp_string, p1.tcx()) except TypeError as ex: self.fail(str(ex)) try: # bad workout p1.add_workout(workout='workout') self.fail('Should not get here with bad workout') except TypeError as ex: self.assertEqual( 'FirstPlan.add_workout - workout must be an instance of FirstWorkout', str(ex))
def test_steps(self): FirstStepBase.reset_global_id() t_warmup = FirstTime.from_string(string='0:15:00') p_warmup = FirstPace.from_string(str_input='0:10:00 min per mile') s_warmup = FirstStepBody(name='Warm up', pace=p_warmup, time=t_warmup) s_intervals = FirstStepRepeat(name='Intervals', repeat=8) d_interval = FirstDistance.from_string(string='400 m') p_fast = FirstPace.from_string(str_input='0:08:00 min per mile') s_fast = FirstStepBody(name='Fast', pace=p_fast, distance=d_interval) s_slow = FirstStepBody(name='Rest', pace=p_warmup, distance=d_interval) s_intervals.add_step(step=s_fast) s_intervals.add_step(step=s_slow) t_cooldown = FirstTime.from_string(string='0:10:00') s_cooldown = FirstStepBody(name='Cool down', pace=p_warmup, time=t_cooldown) try: # positive wo = FirstWorkout(name='Week 1 Key-run 1', workout_date=date(2017, 6, 24)) wo.add_step(step=s_warmup) wo.add_step(step=s_intervals) wo.add_step(step=s_cooldown) cmp_string = ('Week 1 Key-run 1\n' + '2017-06-24\n' + 'scheduled\n' + '\tStep: "Warm up" id = 0\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:15:00\n' + '\tStep: "Intervals" id = 1\n' + 'type - repeat repeat - 8\n' + '\tStep: "Cool down" id = 4\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:10:00\n') self.assertEqual(cmp_string, str(wo)) cmp_string = '"Week 1 Key-run 1"\n' + \ ' Sat 2017-06-24\n' + \ ' scheduled\n' + \ ' Step: "Warm up"\n' + \ ' 0:15:00 at 0:10:00 min per mile\n' + \ ' Step: "Intervals"\n' + \ ' Step: "Fast"\n' + \ ' 400.0 m at 0:08:00 min per mile\n' + \ ' Step: "Rest"\n' + \ ' 400.0 m at 0:10:00 min per mile\n' + \ ' Step: "Cool down"\n' + \ ' 0:10:00 at 0:10:00 min per mile\n' + \ ' Totals: distance = 6.48 miles duration = 60.73 minutes\n' self.assertEqual(cmp_string, wo.details(level=2)) total_distance_miles = 15.0 / 10 + 8 * (800 / 1609.344) + 10.0 / 10 self.assertAlmostEqual(total_distance_miles, wo.total(), 5) total_distance_km = total_distance_miles * 1.609344 self.assertAlmostEqual(total_distance_km, wo.total(unit='km'), 5) total_time_minutes = 15.0 + 8 * ( round(400 / 1609.344 * 8 * 60) / 60 + round(400 / 1609.344 * 10 * 60) / 60) + 10.0 self.assertAlmostEqual(total_time_minutes, wo.total(what='time', unit='minute'), 5) total_time_hours = total_time_minutes / 60.0 self.assertAlmostEqual(total_time_hours, wo.total(what='time', unit='hour')) tcx_string = ( '<Workout Sport="Running">\n' + ' <Name>Week 1 Key-run 1</Name>\n' + ' <Step xsi:type="Step_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>Warm up</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>900</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Step>\n' + ' <Step xsi:type="Repeat_t">\n' + ' <StepId>1</StepId>\n' + ' <Name>Intervals</Name>\n' + ' <Repetitions>8</Repetitions>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>2</StepId>\n' + ' <Name>Fast</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>400</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>3.3182351</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>3.3880926</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>3</StepId>\n' + ' <Name>Rest</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>400</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' + ' </Step>\n' + ' <Step xsi:type="Step_t">\n' + ' <StepId>4</StepId>\n' + ' <Name>Cool down</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>600</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Step>\n') tcx_string_end = (' <ScheduledOn>2017-06-24</ScheduledOn>\n' + '</Workout>') cmp_string = tcx_string + tcx_string_end self.assertEqual(cmp_string, wo.tcx().indented_str()) steps = [{ 'name': 'Warm up', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } }, { 'name': 'Intervals', 'repeat': 8, 'steps': [{ 'distance': { 'distance': 400.0, 'unit': 'm' }, 'name': 'Fast', 'pace': { 'length_unit': 'mile', 'pace': '0:08:00 min per mile', 'time': { 'seconds': 480, 'time': '0:08:00' } } }, { 'distance': { 'distance': 400.0, 'unit': 'm' }, 'name': 'Rest', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } } }] }, { 'name': 'Cool down', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } }, 'time': { 'seconds': 600, 'time': '0:10:00' } }] cmp_json = { 'date': '2017-06-24', 'name': 'Week 1 Key-run 1', 'note': None, 'status': 'scheduled', 'steps': steps, 'total_distance': { 'distance': 6.47678, 'unit': 'mile' }, 'total_time': { 'time': 60.73333, 'unit': 'minute' } } FirstUtils.assert_deep_almost_equal(self, cmp_json, wo.to_json(), 5) km_steps = [{ 'name': 'Warm up', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } }, { 'name': 'Intervals', 'repeat': 8, 'steps': [{ 'distance': { 'distance': 0.4, 'unit': 'km' }, 'name': 'Fast', 'pace': { 'length_unit': 'km', 'pace': '0:04:58 min per km', 'time': { 'seconds': 298, 'time': '0:04:58' } } }, { 'distance': { 'distance': 0.4, 'unit': 'km' }, 'name': 'Rest', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } } }] }, { 'name': 'Cool down', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } }, 'time': { 'seconds': 600, 'time': '0:10:00' } }] cmp_json['steps'] = km_steps cmp_json['total_distance'] = {'distance': 10.42336, 'unit': 'km'} FirstUtils.assert_deep_almost_equal(self, cmp_json, wo.to_json(output_unit='km'), 5) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <h3>Week 1 Key-run 1 - Sat, Jun 24 2017</h3>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Warm up - 0:15:00 at 0:10:00 min per mile\n' + ' </p>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Repeat 8 times:\n' + ' </p>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Fast - 400.000 m at 0:08:00 min per mile\n' + ' </p>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Rest - 400.000 m at 0:10:00 min per mile\n' + ' </p>\n' + ' </div>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Cool down - 0:10:00 at 0:10:00 min per mile\n' + ' </p>\n' + ' </div>\n' + ' <table style="border-spacing: 15px 0">\n' + ' <tbody>\n' + ' <tr>\n' + ' <td>Total Distance:</td>\n' + ' <td><b>6.48 mile</b></td>\n' + ' </tr>\n' + ' <tr>\n' + ' <td>Total Time:</td>\n' + ' <td><b>61 minutes</b></td>\n' + ' </tr>\n' + ' </tbody>\n' + ' </table>\n' + '</div>') self.assertEqual(cmp_html, wo.to_html().indented_str()) cmp_html = ( '<div style="margin-left: 20px">\n' + ' <h3>Week 1 Key-run 1 - Sat, Jun 24 2017</h3>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Warm up - 0:15:00 at 0:06:13 min per km\n' + ' </p>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Repeat 8 times:\n' + ' </p>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Fast - 0.400 km at 0:04:58 min per km\n' + ' </p>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Rest - 0.400 km at 0:06:13 min per km\n' + ' </p>\n' + ' </div>\n' + ' </div>\n' + ' <div style="margin-left: 20px">\n' + ' <p>\n' + ' Cool down - 0:10:00 at 0:06:13 min per km\n' + ' </p>\n' + ' </div>\n' + ' <table style="border-spacing: 15px 0">\n' + ' <tbody>\n' + ' <tr>\n' + ' <td>Total Distance:</td>\n' + ' <td><b>10.42 km</b></td>\n' + ' </tr>\n' + ' <tr>\n' + ' <td>Total Time:</td>\n' + ' <td><b>61 minutes</b></td>\n' + ' </tr>\n' + ' </tbody>\n' + ' </table>\n' + '</div>') self.assertEqual(cmp_html, wo.to_html(output_unit='km').indented_str()) wo.add_step(step=s_warmup) cmp_string = ('Week 1 Key-run 1\n' + '2017-06-24\n' + 'scheduled\n' + '\tStep: "Warm up" id = 0\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:15:00\n' + '\tStep: "Intervals" id = 1\n' + 'type - repeat repeat - 8\n' + '\tStep: "Cool down" id = 4\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:10:00\n' + '\tStep: "Warm up" id = 0\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:15:00\n') self.assertEqual(cmp_string, str(wo)) steps.append({ 'name': 'Warm up', 'pace': { 'length_unit': 'mile', 'pace': '0:10:00 min per mile', 'time': { 'seconds': 600, 'time': '0:10:00' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } }) cmp_json['steps'] = steps cmp_json['total_distance'] = {'distance': 7.97678, 'unit': 'mile'} cmp_json['total_time'] = {'time': 75.73333, 'unit': 'minute'} FirstUtils.assert_deep_almost_equal(self, cmp_json, wo.to_json(), 5) km_steps.append({ 'name': 'Warm up', 'pace': { 'length_unit': 'km', 'pace': '0:06:13 min per km', 'time': { 'seconds': 373, 'time': '0:06:13' } }, 'time': { 'seconds': 900, 'time': '0:15:00' } }) cmp_json['steps'] = km_steps cmp_json['total_distance'] = {'distance': 12.83738, 'unit': 'km'} FirstUtils.assert_deep_almost_equal(self, cmp_json, wo.to_json(output_unit='km'), 5) except ValueError as vex: self.fail(str(vex)) except TypeError as tex: self.fail(str(tex)) wo1 = FirstWorkout(name='Week 1 Key-run 1', workout_date=date(2017, 4, 1)) try: # change status wo1.set_status('skipped') self.assertEqual( 'Week 1 Key-run 1\n2017-04-01\nskipped\n\tEmpty workout\n', str(wo1)) except ValueError as ex: self.fail(str(ex)) try: # bad status wo1.set_status('lulu') self.fail('Should not get here with bad status') except ValueError as ex: self.assertEqual("Status not in ['scheduled', 'done', 'skipped']", str(ex))
def test_steps_new(self): FirstStepBase.reset_global_id() t_warmup = FirstTime.from_string('0:15:00') p_warmup = FirstPace.from_string('0:10:00 min per mile') s_warmup = FirstStepBody(name='Warm up', pace=p_warmup, time=t_warmup) s_intervals = FirstStepRepeat(name='Intervals', repeat=8) d_interval = FirstDistance.from_string('400 m') p_fast = FirstPace.from_string('0:08:00 min per mile') s_fast = FirstStepBody(name='Fast', pace=p_fast, distance=d_interval) s_slow = FirstStepBody(name='Rest', pace=p_warmup, distance=d_interval) s_intervals.add_step(s_fast) s_intervals.add_step(s_slow) t_cooldown = FirstTime.from_string('0:10:00') s_cooldown = FirstStepBody(name='Cool down', pace=p_warmup, time=t_cooldown) try: # positive wo = FirstWorkout(name='Week 1 Key-run 1', workout_date=date(2017, 6, 24)) wo.add_step(s_warmup) wo.add_step(s_intervals) wo.add_step(s_cooldown) cmp_string = ('Week 1 Key-run 1\n' + '2017-06-24\n' + 'scheduled\n' + '\tStep: "Warm up" id = 0\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:15:00\n' + '\tStep: "Intervals" id = 1\n' + 'type - repeat repeat - 8\n' + '\tStep: "Cool down" id = 4\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:10:00\n') self.assertEqual(cmp_string, str(wo)) cmp_string = '"Week 1 Key-run 1"\n' +\ ' Sat 2017-06-24\n' +\ ' scheduled\n' +\ ' Step: "Warm up"\n' +\ ' 0:15:00 at 0:10:00 min per mile\n' +\ ' Step: "Intervals"\n' +\ ' Step: "Fast"\n' +\ ' 400.0 m at 0:08:00 min per mile\n' +\ ' Step: "Rest"\n' +\ ' 400.0 m at 0:10:00 min per mile\n' +\ ' Step: "Cool down"\n' +\ ' 0:10:00 at 0:10:00 min per mile\n' +\ ' Totals: distance = 6.48 miles duration = 60.79 minutes\n' self.assertEqual(cmp_string, wo.details(level=2)) total_distance_miles = 15.0 / 10 + 8 * (800 / 1609.344) + 10.0 / 10 self.assertAlmostEqual(total_distance_miles, wo.total(), 5) total_distance_km = total_distance_miles * 1.609344 self.assertAlmostEqual(total_distance_km, wo.total(unit='km'), 5) total_time_minutes = 15.0 + 8 * (400 / 1609.344 * 8 + 400 / 1609.344 * 10) + 10.0 self.assertAlmostEqual(total_time_minutes, wo.total(what='time', unit='minute')) total_time_hours = total_time_minutes / 60.0 self.assertAlmostEqual(total_time_hours, wo.total(what='time', unit='hour')) tcx_string = ( '<Workout Sport="Running">\n' + ' <Name>Week 1 Key-run 1</Name>\n' + ' <Step xsi:type="Step_t">\n' + ' <StepId>0</StepId>\n' + ' <Name>Warm up</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>900</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Step>\n' + ' <Step xsi:type="Repeat_t">\n' + ' <StepId>1</StepId>\n' + ' <Name>Intervals</Name>\n' + ' <Repetitions>8</Repetitions>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>2</StepId>\n' + ' <Name>Fast</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>400</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>3.3182351</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>3.3880926</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' + ' <Child xsi:type="Step_t">\n' + ' <StepId>3</StepId>\n' + ' <Name>Rest</Name>\n' + ' <Duration xsi:type="Distance_t">\n' + ' <Meters>400</Meters>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Child>\n' + ' </Step>\n' + ' <Step xsi:type="Step_t">\n' + ' <StepId>4</StepId>\n' + ' <Name>Cool down</Name>\n' + ' <Duration xsi:type="Time_t">\n' + ' <Seconds>600</Seconds>\n' + ' </Duration>\n' + ' <Intensity>Active</Intensity>\n' + ' <Target xsi:type="Speed_t">\n' + ' <SpeedZone xsi:type="CustomSpeedZone_t">\n' + ' <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n' + ' <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n' + ' </SpeedZone>\n' + ' </Target>\n' + ' </Step>\n') tcx_string_end = (' <ScheduledOn>2017-06-24</ScheduledOn>\n' + '</Workout>\n') cmp_string = tcx_string + tcx_string_end self.assertEqual(cmp_string, wo.tcx()) wo.add_step(step=s_warmup) cmp_string = ('Week 1 Key-run 1\n' + '2017-06-24\n' + 'scheduled\n' + '\tStep: "Warm up" id = 0\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:15:00\n' + '\tStep: "Intervals" id = 1\n' + 'type - repeat repeat - 8\n' + '\tStep: "Cool down" id = 4\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:10:00\n' + '\tStep: "Warm up" id = 0\n' + 'type - body pace - 0:10:00 min per mile\n' + 'Time - 0:15:00\n') self.assertEqual(cmp_string, str(wo)) except ValueError as vex: self.fail(str(vex)) except TypeError as tex: self.fail(str(tex)) try: # wrong type dummy = FirstWorkout(name='Week 1 Key-run 1', workout_date=123) self.fail('Should not get here with a wrong type for date') except TypeError as ex: self.assertEqual('FirstWorkout.__init__ - date must be a datetime', str(ex)) wo1 = FirstWorkout(name='Week 1 Key-run 1', workout_date=date(2017, 4, 1)) try: # change status wo1.set_status('skipped') self.assertEqual( 'Week 1 Key-run 1\n2017-04-01\nskipped\n\tEmpty workout\n', str(wo1)) except ValueError as ex: self.fail(str(ex)) try: # bad status wo1.set_status('lulu') self.fail('Should not get here with bad status') except ValueError as ex: self.assertEqual( "FirstWorkout.set_status - Status not in ['scheduled', 'done', 'skipped']", str(ex))