Skip to content

Commit 0477b04

Browse files
Add last-lap exercise
1 parent e4dc3b4 commit 0477b04

File tree

3 files changed

+223
-13
lines changed

3 files changed

+223
-13
lines changed

exercises/practice/split-second-stopwatch/SplitSecondStopwatch.cs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,56 @@ public enum StopwatchState
66
Stopped
77
}
88

9-
public class SplitSecondStopwatch
9+
public class SplitSecondStopwatch(TimeProvider time)
1010
{
11+
private readonly List<TimeSpan> _previousLapSegments = new();
12+
private DateTimeOffset? _currentSegmentStart;
13+
1114
public StopwatchState State { get; private set; }
15+
16+
public List<TimeSpan> PreviousLaps { get; } = new();
17+
18+
public TimeSpan CurrentLap => PreviousLapSegments + CurrentSegment;
19+
20+
private TimeSpan PreviousLapSegments => _previousLapSegments.Aggregate(TimeSpan.Zero, (total, segment) => total + segment);
21+
22+
private TimeSpan CurrentSegment => _currentSegmentStart is {} start ? time.GetUtcNow() - start : TimeSpan.Zero;
23+
24+
public void Start()
25+
{
26+
if (State == StopwatchState.Paused)
27+
_currentSegmentStart = null;
28+
29+
_currentSegmentStart ??= time.GetUtcNow();
30+
31+
State = StopwatchState.Running;
32+
}
33+
34+
public void Stop()
35+
{
36+
if (State == StopwatchState.Ready)
37+
return;
38+
39+
PreviousLaps.Add(CurrentLap);
40+
_currentSegmentStart = null;
41+
State = StopwatchState.Stopped;
42+
}
43+
44+
public void Split()
45+
{
46+
State = StopwatchState.Running;
47+
}
48+
49+
public void Pause()
50+
{
51+
State = StopwatchState.Paused;
52+
_previousLapSegments.Add(CurrentSegment);
53+
_currentSegmentStart = null;
54+
}
55+
56+
public void Reset()
57+
{
58+
Stop();
59+
Start();
60+
}
1261
}

exercises/practice/split-second-stopwatch/SplitSecondStopwatch.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<Using Include="Xunit" />
1010
</ItemGroup>
1111
<ItemGroup>
12+
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" Version="9.2.0" />
1213
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
1314
<PackageReference Include="xunit.v3" Version="1.1.0" />
1415
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2" />
Lines changed: 172 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,204 @@
1+
using Microsoft.Extensions.Time.Testing;
2+
13
public class SplitSecondStopwatchTests
24
{
35
[Fact]
4-
public void InitalStateIsReady()
6+
public void NewStopwatchIsInReadyState()
57
{
6-
var stopwatch = new SplitSecondStopwatch();
8+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
79
Assert.Equal(StopwatchState.Ready, stopwatch.State);
810
}
11+
12+
[Fact]
13+
public void NewStopwatchHasNoPreviousLaps()
14+
{
15+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
16+
Assert.Empty(stopwatch.PreviousLaps);
17+
}
18+
19+
[Fact]
20+
public void NewStopwatchHasCurrentLapSetToZero()
21+
{
22+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
23+
Assert.Equal(TimeSpan.Zero, stopwatch.CurrentLap);
24+
}
925

1026
[Fact]
11-
public void StartChangesStateToRunning()
27+
public void StartWhenStateIsReadyChangesStateToRunning()
1228
{
13-
var stopwatch = new SplitSecondStopwatch();
29+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
1430
stopwatch.Start();
1531
Assert.Equal(StopwatchState.Running, stopwatch.State);
1632
}
1733

1834
[Fact]
19-
public void PauseChangesStateToPaused()
35+
public void StartWhenStateIsStoppedChangesStateToRunning()
2036
{
21-
var stopwatch = new SplitSecondStopwatch();
37+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
38+
stopwatch.Start();
39+
stopwatch.Stop();
40+
41+
stopwatch.Start();
42+
43+
Assert.Equal(StopwatchState.Running, stopwatch.State);
44+
}
45+
46+
[Fact]
47+
public void StartWhenStateIsPausedChangesStateToRunning()
48+
{
49+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
2250
stopwatch.Start();
2351
stopwatch.Pause();
24-
Assert.Equal(StopwatchState.Paused, stopwatch.State);
52+
53+
stopwatch.Start();
54+
55+
Assert.Equal(StopwatchState.Running, stopwatch.State);
2556
}
2657

2758
[Fact]
28-
public void SplitKeepsStateAsRunning()
59+
public void StartWhenStateIsRunningDoesNotChangeState()
2960
{
30-
var stopwatch = new SplitSecondStopwatch();
61+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
62+
stopwatch.Start();
63+
3164
stopwatch.Start();
32-
stopwatch.Split();
65+
3366
Assert.Equal(StopwatchState.Running, stopwatch.State);
3467
}
3568

3669
[Fact]
37-
public void StopChangesStateToStop()
70+
public void StopWhenStateIsReadyDoesNotChangeState()
71+
{
72+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
73+
stopwatch.Stop();
74+
Assert.Equal(StopwatchState.Ready, stopwatch.State);
75+
}
76+
77+
[Fact]
78+
public void StopWhenStateIsStoppedDoesNotChangeState()
79+
{
80+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
81+
stopwatch.Start();
82+
stopwatch.Stop();
83+
84+
stopwatch.Stop();
85+
86+
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
87+
}
88+
89+
[Fact]
90+
public void StopWhenStateIsPausedChangesStateToStopped()
91+
{
92+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
93+
stopwatch.Start();
94+
stopwatch.Pause();
95+
96+
stopwatch.Stop();
97+
98+
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
99+
}
100+
101+
[Fact]
102+
public void StopWhenStateIsRunningChangesStateToStopped()
38103
{
39-
var stopwatch = new SplitSecondStopwatch();
104+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
40105
stopwatch.Start();
106+
41107
stopwatch.Stop();
108+
42109
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
43110
}
111+
112+
[Fact]
113+
public void StopAddsLapToPreviousLaps()
114+
{
115+
var timeProvider = new FakeTimeProvider();
116+
var stopwatch = new SplitSecondStopwatch(timeProvider);
117+
stopwatch.Start();
118+
119+
stopwatch.Stop();
120+
121+
Assert.Single(stopwatch.PreviousLaps);
122+
}
123+
124+
[Fact]
125+
public void StopResetsCurrentLapToZero()
126+
{
127+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
128+
stopwatch.Start();
129+
130+
stopwatch.Stop();
131+
132+
Assert.Equal(TimeSpan.Zero, stopwatch.CurrentLap);
133+
}
134+
135+
[Fact]
136+
public void CurrentLapReturnsTimeElapsedSinceStart()
137+
{
138+
var timeProvider = new FakeTimeProvider();
139+
var stopwatch = new SplitSecondStopwatch(timeProvider);
140+
stopwatch.Start();
141+
142+
var elapsed = TimeSpan.FromSeconds(5);
143+
timeProvider.Advance(elapsed);
144+
145+
Assert.Equal(elapsed, stopwatch.CurrentLap);
146+
}
147+
148+
[Fact]
149+
public void PauseStopsTimeOfCurrentLap()
150+
{
151+
var timeProvider = new FakeTimeProvider();
152+
var stopwatch = new SplitSecondStopwatch(timeProvider);
153+
stopwatch.Start();
154+
155+
var elapsed = TimeSpan.FromSeconds(5);
156+
timeProvider.Advance(elapsed);
157+
158+
stopwatch.Pause();
159+
160+
timeProvider.Advance(TimeSpan.FromSeconds(10));
161+
162+
Assert.Equal(elapsed, stopwatch.CurrentLap);
163+
}
164+
165+
[Fact]
166+
public void StartAfterPauseResumesCurrentLap()
167+
{
168+
var timeProvider = new FakeTimeProvider();
169+
var stopwatch = new SplitSecondStopwatch(timeProvider);
170+
stopwatch.Start();
171+
172+
var elapsedBefore = TimeSpan.FromSeconds(5);
173+
timeProvider.Advance(elapsedBefore);
174+
175+
stopwatch.Pause();
176+
177+
timeProvider.Advance(TimeSpan.FromSeconds(10));
178+
179+
stopwatch.Start();
180+
181+
var elapsedAfter = TimeSpan.FromSeconds(3);
182+
timeProvider.Advance(elapsedAfter);
183+
184+
stopwatch.Stop();
185+
186+
var lap = Assert.Single(stopwatch.PreviousLaps);
187+
Assert.Equal(elapsedBefore + elapsedAfter, lap);
188+
}
189+
190+
[Fact]
191+
public void EachStartStopCallAddsLapToPreviousLaps()
192+
{
193+
var timeProvider = new FakeTimeProvider();
194+
var stopwatch = new SplitSecondStopwatch(timeProvider);
195+
196+
for (var i = 0; i < 10; i++)
197+
{
198+
stopwatch.Start();
199+
stopwatch.Stop();
200+
}
201+
202+
Assert.Equal(10, stopwatch.PreviousLaps.Count);
203+
}
44204
}

0 commit comments

Comments
 (0)