Skip to content

Commit 4a7e943

Browse files
Add last-lap exercise
1 parent 9210b05 commit 4a7e943

File tree

2 files changed

+234
-20
lines changed

2 files changed

+234
-20
lines changed

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

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,65 @@ public enum StopwatchState
22
{
33
Ready,
44
Running,
5-
Paused,
6-
Stopped
5+
Paused
76
}
87

98
public class SplitSecondStopwatch(TimeProvider time)
109
{
10+
private readonly List<TimeSpan> _previousLapSegments = new();
11+
private DateTimeOffset? _currentSegmentStart;
12+
1113
public StopwatchState State { get; private set; }
1214

15+
public List<TimeSpan> PreviousLaps { get; } = new();
16+
17+
public TimeSpan CurrentLap => PreviousLapSegments + CurrentSegment;
18+
19+
private TimeSpan PreviousLapSegments => _previousLapSegments.Aggregate(TimeSpan.Zero, (total, segment) => total + segment);
20+
21+
private TimeSpan CurrentSegment => _currentSegmentStart is {} start ? time.GetUtcNow() - start : TimeSpan.Zero;
22+
1323
public void Start()
1424
{
15-
throw new NotImplementedException();
25+
if (State == StopwatchState.Paused)
26+
_currentSegmentStart = null;
27+
28+
_currentSegmentStart ??= time.GetUtcNow();
29+
30+
State = StopwatchState.Running;
1631
}
1732

1833
public void Stop()
1934
{
20-
throw new NotImplementedException();
35+
if (State == StopwatchState.Ready)
36+
return;
37+
38+
PreviousLaps.Add(CurrentLap);
39+
_currentSegmentStart = null;
40+
State = StopwatchState.Ready;
2141
}
2242

2343
public void Split()
2444
{
25-
throw new NotImplementedException();
45+
AddSegment();
2646
}
2747

2848
public void Pause()
2949
{
30-
throw new NotImplementedException();
50+
State = StopwatchState.Paused;
51+
AddSegment();
52+
}
53+
54+
public void Reset()
55+
{
56+
Stop();
57+
_previousLapSegments.Clear();
58+
Start();
59+
}
60+
61+
private void AddSegment()
62+
{
63+
_previousLapSegments.Add(CurrentSegment);
64+
_currentSegmentStart = null;
3165
}
3266
}

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

Lines changed: 194 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,233 @@
33
public class SplitSecondStopwatchTests
44
{
55
[Fact]
6-
public void InitalStateIsReady()
6+
public void NewStopwatchIsInReadyState()
77
{
88
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
99
Assert.Equal(StopwatchState.Ready, stopwatch.State);
1010
}
11-
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+
}
25+
1226
[Fact]
13-
public void StartChangesStateToRunning()
27+
public void StartFromReadyStateChangesStateToRunning()
1428
{
1529
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
1630
stopwatch.Start();
1731
Assert.Equal(StopwatchState.Running, stopwatch.State);
1832
}
19-
33+
2034
[Fact]
21-
public void PauseChangesStateToPaused()
35+
public void StartFromPausedStateChangesStateToRunning()
2236
{
2337
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
2438
stopwatch.Start();
2539
stopwatch.Pause();
26-
Assert.Equal(StopwatchState.Paused, stopwatch.State);
40+
41+
stopwatch.Start();
42+
43+
Assert.Equal(StopwatchState.Running, stopwatch.State);
2744
}
28-
45+
2946
[Fact]
30-
public void SplitKeepsStateAsRunning()
47+
public void StartFromStartStateIsInvalid()
3148
{
3249
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
3350
stopwatch.Start();
34-
stopwatch.Split();
35-
Assert.Equal(StopwatchState.Running, stopwatch.State);
51+
52+
Assert.Throws<InvalidOperationException>(() => stopwatch.Start());
53+
}
54+
55+
56+
57+
58+
[Fact]
59+
public void StartFromReadyStateDoesNotChangePreviousLaps()
60+
{
61+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
62+
stopwatch.Start();
63+
Assert.Empty(stopwatch.PreviousLaps);
64+
}
65+
66+
[Fact]
67+
public void StartFromPausedStateDoesNotChangePreviousLaps()
68+
{
69+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
70+
stopwatch.Start();
71+
stopwatch.Pause();
72+
73+
stopwatch.Start();
74+
75+
Assert.Empty(stopwatch.PreviousLaps);
76+
}
77+
78+
79+
public void StopFromReadyStateIsInvalid()
80+
{
81+
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
82+
Assert.Throws<InvalidOperationException>(() => stopwatch.Stop());
3683
}
3784

3885
[Fact]
39-
public void StopChangesStateToStop()
86+
public void StopFromRunningStateChangesStateToReady()
4087
{
4188
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
4289
stopwatch.Start();
90+
4391
stopwatch.Stop();
44-
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
92+
93+
Assert.Equal(StopwatchState.Ready, stopwatch.State);
4594
}
4695

4796
[Fact]
48-
public void StopAddsLapTime()
97+
public void StopFromRunningStateResetsCurrentLap()
98+
{
99+
var timeProvider = new FakeTimeProvider();
100+
var stopwatch = new SplitSecondStopwatch(timeProvider);
101+
stopwatch.Start();
102+
103+
stopwatch.Stop();
104+
105+
Assert.Equal(TimeSpan.Zero, stopwatch.CurrentLap);
106+
}
107+
108+
[Fact]
109+
public void StopFromPausedStateChangesStateToReady()
49110
{
50111
var stopwatch = new SplitSecondStopwatch(new FakeTimeProvider());
51112
stopwatch.Start();
113+
stopwatch.Pause();
114+
115+
stopwatch.Stop();
116+
117+
Assert.Equal(StopwatchState.Ready, stopwatch.State);
118+
}
119+
120+
[Fact]
121+
public void StopFromPausedStateResetsCurrentLap()
122+
{
123+
var timeProvider = new FakeTimeProvider();
124+
var stopwatch = new SplitSecondStopwatch(timeProvider);
125+
stopwatch.Start();
126+
stopwatch.Pause();
127+
128+
stopwatch.Stop();
129+
130+
Assert.Equal(TimeSpan.Zero, stopwatch.CurrentLap);
131+
}
132+
133+
[Fact]
134+
public void StopFromPausedStateAddsCurrentLapToPreviousLaps()
135+
{
136+
var timeProvider = new FakeTimeProvider();
137+
var stopwatch = new SplitSecondStopwatch(timeProvider);
138+
stopwatch.Start();
139+
140+
var elapsed1 = TimeSpan.FromSeconds(33.6);
141+
timeProvider.Advance(elapsed1);
142+
stopwatch.Pause();
143+
144+
var elapsed2 = TimeSpan.FromSeconds(44.4);
145+
timeProvider.Advance(elapsed2);
52146
stopwatch.Stop();
53-
Assert.Equal(StopwatchState.Stopped, stopwatch.State);
147+
148+
var recordedLap = Assert.Single(stopwatch.PreviousLaps);
149+
Assert.Equal(elapsed1 + elapsed2, recordedLap);
150+
}
151+
152+
153+
154+
155+
156+
157+
158+
[Fact]
159+
public void CurrentLapDoesNotTrackTimeElapsedInReadyState()
160+
{
161+
var timeProvider = new FakeTimeProvider();
162+
var stopwatch = new SplitSecondStopwatch(timeProvider);
163+
164+
timeProvider.Advance(TimeSpan.FromSeconds(55.5));
165+
166+
Assert.Equal(TimeSpan.Zero, stopwatch.CurrentLap);
167+
}
168+
169+
[Fact]
170+
public void CurrentLapTracksTimeElapsedInRunningState()
171+
{
172+
var timeProvider = new FakeTimeProvider();
173+
var stopwatch = new SplitSecondStopwatch(timeProvider);
174+
stopwatch.Start();
175+
176+
var elapsed1 = TimeSpan.FromSeconds(5.2);
177+
timeProvider.Advance(elapsed1);
178+
179+
Assert.Equal(elapsed1, stopwatch.CurrentLap);
180+
181+
var elapsed2 = TimeSpan.FromSeconds(3.4);
182+
timeProvider.Advance(elapsed2);
183+
184+
Assert.Equal(elapsed1 + elapsed2, stopwatch.CurrentLap);
185+
}
186+
187+
[Fact]
188+
public void CurrentLapDoesNotTrackTimeElapsedInPausedState()
189+
{
190+
var timeProvider = new FakeTimeProvider();
191+
var stopwatch = new SplitSecondStopwatch(timeProvider);
192+
stopwatch.Start();
193+
194+
stopwatch.Pause();
195+
timeProvider.Advance(TimeSpan.FromSeconds(55.5));
196+
197+
Assert.Equal(TimeSpan.Zero, stopwatch.CurrentLap);
54198
}
199+
200+
201+
202+
203+
204+
205+
206+
207+
208+
209+
// [Fact]
210+
// public void EachStartStopCycleAddsToPreviousLaps()
211+
// {
212+
// var timeProvider = new FakeTimeProvider();
213+
// var stopwatch = new SplitSecondStopwatch(timeProvider);
214+
//
215+
// List<TimeSpan> expectedLapTimes = [];
216+
// const int numberOfLaps = 8;
217+
//
218+
// for (var i = 0; i < numberOfLaps; i++)
219+
// {
220+
// stopwatch.Start();
221+
//
222+
// var elapsed = TimeSpan.FromSeconds(i * 1.1);
223+
// timeProvider.Advance(elapsed);
224+
//
225+
// stopwatch.Stop();
226+
//
227+
// expectedLapTimes.Add(elapsed);
228+
// }
229+
//
230+
// for (var i = 0; i < numberOfLaps; i++)
231+
// {
232+
// Assert.Equal(expectedLapTimes[i], stopwatch.PreviousLaps[i]);
233+
// }
234+
// }
55235
}

0 commit comments

Comments
 (0)