Skip to content

Commit a4eeb7f

Browse files
Add last-lap exercise
1 parent e4dc3b4 commit a4eeb7f

File tree

3 files changed

+165
-13
lines changed

3 files changed

+165
-13
lines changed

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

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

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

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: 119 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,151 @@
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()
36+
{
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()
2048
{
21-
var stopwatch = new SplitSecondStopwatch();
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());
3162
stopwatch.Start();
32-
stopwatch.Split();
63+
64+
stopwatch.Start();
65+
3366
Assert.Equal(StopwatchState.Running, stopwatch.State);
3467
}
68+
69+
[Fact]
70+
public void CurrentLapReturnsTimeElapsedSinceStart()
71+
{
72+
var timeProvider = new FakeTimeProvider();
73+
var stopwatch = new SplitSecondStopwatch(timeProvider);
74+
stopwatch.Start();
75+
76+
var elapsed = TimeSpan.FromSeconds(5);
77+
timeProvider.Advance(elapsed);
78+
79+
Assert.Equal(elapsed, stopwatch.CurrentLap);
80+
}
81+
82+
[Fact]
83+
public void StopWhenStateIsReadyDoesNotChangeState()
84+
{
85+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
86+
stopwatch.Stop();
87+
Assert.Equal(StopwatchState.Ready, stopwatch.State);
88+
}
3589

3690
[Fact]
37-
public void StopChangesStateToStop()
91+
public void StopWhenStateIsStoppedDoesNotChangeState()
3892
{
39-
var stopwatch = new SplitSecondStopwatch();
93+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
4094
stopwatch.Start();
4195
stopwatch.Stop();
96+
97+
stopwatch.Stop();
98+
99+
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
100+
}
101+
102+
[Fact]
103+
public void StopWhenStateIsPausedChangesStateToStopped()
104+
{
105+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
106+
stopwatch.Start();
107+
stopwatch.Pause();
108+
109+
stopwatch.Stop();
110+
42111
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
43112
}
113+
114+
[Fact]
115+
public void StopWhenStateIsRunningChangesStateToStopped()
116+
{
117+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
118+
stopwatch.Start();
119+
120+
stopwatch.Stop();
121+
122+
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
123+
}
124+
125+
[Fact]
126+
public void StopAddsCurrentLapToPreviousLaps()
127+
{
128+
var timeProvider = new FakeTimeProvider();
129+
var stopwatch = new SplitSecondStopwatch(timeProvider);
130+
stopwatch.Start();
131+
132+
var lapTime = TimeSpan.FromSeconds(56);
133+
timeProvider.Advance(lapTime);
134+
135+
stopwatch.Stop();
136+
137+
var lastLap = Assert.Single(stopwatch.PreviousLaps);
138+
Assert.Equal(lapTime, lastLap);
139+
}
140+
141+
[Fact]
142+
public void StopResetsCurrentLapToZero()
143+
{
144+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
145+
stopwatch.Start();
146+
147+
stopwatch.Stop();
148+
149+
Assert.Equal(TimeSpan.Zero, stopwatch.CurrentLap);
150+
}
44151
}

0 commit comments

Comments
 (0)