Skip to content

Commit d8c0e60

Browse files
committed
✨ feature: Create State Machine Base Class
1 parent afde634 commit d8c0e60

9 files changed

Lines changed: 158 additions & 23 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace TJC.StateMachine.Tests.Mocks
2+
{
3+
internal class RevolverMock()
4+
: StateMachineBase<RevolverStates>(RevolverStates.Loaded)
5+
{
6+
public int BulletsLoaded { get; private set; } = 6;
7+
8+
public bool TryShoot()
9+
{
10+
switch (State)
11+
{
12+
case RevolverStates.Empty:
13+
return false;
14+
case RevolverStates.Loaded:
15+
BulletsLoaded--;
16+
if (BulletsLoaded == 0)
17+
State = RevolverStates.Empty;
18+
return true;
19+
default:
20+
throw new InvalidOperationException($"Unknown State [{State}] for method {nameof(TryShoot)}");
21+
}
22+
}
23+
24+
public void Reload()
25+
{
26+
BulletsLoaded = 6;
27+
State = RevolverStates.Loaded;
28+
}
29+
}
30+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace TJC.StateMachine.Tests.Mocks
2+
{
3+
internal enum RevolverStates
4+
{
5+
Loaded,
6+
Empty
7+
}
8+
}

TJC.StateMachine.Tests/TJC.StateMachine.Tests.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<Nullable>enable</Nullable>
77
<IsPackable>false</IsPackable>
88
<IsTestProject>true</IsTestProject>
9+
<AppDesignerFolder>Tests</AppDesignerFolder>
910
</PropertyGroup>
1011

1112
<ItemGroup>
@@ -15,6 +16,10 @@
1516
<PackageReference Include="MSTest.TestFramework" Version="3.6.1" />
1617
</ItemGroup>
1718

19+
<ItemGroup>
20+
<ProjectReference Include="..\TJC.StateMachine\TJC.StateMachine.csproj" />
21+
</ItemGroup>
22+
1823
<ItemGroup>
1924
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
2025
</ItemGroup>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using TJC.StateMachine.Tests.Mocks;
2+
3+
namespace TJC.StateMachine.Tests.Tests
4+
{
5+
[TestClass]
6+
public class RevolverMockTests
7+
{
8+
[TestMethod]
9+
public void EnsureRevolverStartsFull()
10+
{
11+
var revolver = new RevolverMock();
12+
Assert.AreEqual(6, revolver.BulletsLoaded);
13+
}
14+
15+
[TestMethod]
16+
public void EnsureRevolverShootingLowersBulletsToZeroThenRequiresReloading()
17+
{
18+
var revolver = new RevolverMock();
19+
20+
var result = revolver.TryShoot();
21+
Assert.IsTrue(result);
22+
Assert.AreEqual(5, revolver.BulletsLoaded);
23+
24+
result = revolver.TryShoot();
25+
Assert.IsTrue(result);
26+
Assert.AreEqual(4, revolver.BulletsLoaded);
27+
28+
result = revolver.TryShoot();
29+
Assert.IsTrue(result);
30+
Assert.AreEqual(3, revolver.BulletsLoaded);
31+
32+
result = revolver.TryShoot();
33+
Assert.IsTrue(result);
34+
Assert.AreEqual(2, revolver.BulletsLoaded);
35+
36+
result = revolver.TryShoot();
37+
Assert.IsTrue(result);
38+
Assert.AreEqual(1, revolver.BulletsLoaded);
39+
40+
result = revolver.TryShoot();
41+
Assert.IsTrue(result);
42+
Assert.AreEqual(0, revolver.BulletsLoaded);
43+
44+
result = revolver.TryShoot();
45+
Assert.IsFalse(result);
46+
Assert.AreEqual(0, revolver.BulletsLoaded);
47+
}
48+
49+
[TestMethod]
50+
public void EnsureReloadingResetsBulletsTo6()
51+
{
52+
var revolver = new RevolverMock();
53+
54+
Assert.AreEqual(6, revolver.BulletsLoaded);
55+
revolver.TryShoot();
56+
Assert.AreEqual(5, revolver.BulletsLoaded);
57+
revolver.Reload();
58+
Assert.AreEqual(6, revolver.BulletsLoaded);
59+
}
60+
}
61+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Reflection;
2+
using TJC.StateMachine.Tests.Mocks;
3+
4+
namespace TJC.StateMachine.Tests.Tests
5+
{
6+
[TestClass]
7+
public class StatePropertyAccessibility
8+
{
9+
[TestMethod]
10+
public void EnsurePropertyStateIsNotPubliclyAccessible()
11+
{
12+
var prop = typeof(StateMachineBase<RevolverStates>).GetProperty("State", BindingFlags.Instance | BindingFlags.Public);
13+
Assert.IsNull(prop);
14+
}
15+
16+
[TestMethod]
17+
public void EnsurePropertyStateIsProtectedAccessible()
18+
{
19+
var prop = typeof(StateMachineBase<RevolverStates>).GetProperty("State", BindingFlags.Instance | BindingFlags.NonPublic);
20+
Assert.IsNotNull(prop);
21+
var getter = prop.GetMethod;
22+
Assert.IsNotNull(getter);
23+
Assert.IsTrue(getter.IsFamily);
24+
}
25+
}
26+
}

TJC.StateMachine.Tests/UnitTest1.cs

Lines changed: 0 additions & 9 deletions
This file was deleted.

TJC.StateMachine/Class1.cs

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace TJC.StateMachine
2+
{
3+
/// <summary>
4+
/// State machine pattern base class.
5+
/// </summary>
6+
/// <typeparam name="T">State Type.</typeparam>
7+
/// <param name="initialState">Initial State of the State Machine.</param>
8+
public class StateMachineBase<T>(T initialState)
9+
{
10+
/// <summary>
11+
/// State of the state machine.
12+
/// </summary>
13+
protected T State { get; set; } = initialState;
14+
}
15+
}

Testing.sln

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,29 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.8.34316.72
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TJC.Rename", "TJC.Rename\TJC.Rename.csproj", "{73B82231-E966-42EC-8635-5B98C99D8B4C}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TJC.StateMachine", "TJC.StateMachine\TJC.StateMachine.csproj", "{0759E8E9-2315-4AC0-898A-A0896F4CB2A3}"
77
EndProject
8-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TJC.Rename.Tests", "TJC.Rename.Tests\TJC.Rename.Tests.csproj", "{D10EE1DD-1F71-4828-908D-1DEAA0285E71}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TJC.StateMachine.Tests", "TJC.StateMachine.Tests\TJC.StateMachine.Tests.csproj", "{2F309AA3-B442-467B-8B73-7AA31F5840F2}"
99
EndProject
1010
Global
1111
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1212
Debug|Any CPU = Debug|Any CPU
1313
Release|Any CPU = Release|Any CPU
1414
EndGlobalSection
1515
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16-
{73B82231-E966-42EC-8635-5B98C99D8B4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17-
{73B82231-E966-42EC-8635-5B98C99D8B4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
18-
{73B82231-E966-42EC-8635-5B98C99D8B4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
19-
{73B82231-E966-42EC-8635-5B98C99D8B4C}.Release|Any CPU.Build.0 = Release|Any CPU
20-
{D10EE1DD-1F71-4828-908D-1DEAA0285E71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21-
{D10EE1DD-1F71-4828-908D-1DEAA0285E71}.Debug|Any CPU.Build.0 = Debug|Any CPU
22-
{D10EE1DD-1F71-4828-908D-1DEAA0285E71}.Release|Any CPU.ActiveCfg = Release|Any CPU
23-
{D10EE1DD-1F71-4828-908D-1DEAA0285E71}.Release|Any CPU.Build.0 = Release|Any CPU
16+
{0759E8E9-2315-4AC0-898A-A0896F4CB2A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{0759E8E9-2315-4AC0-898A-A0896F4CB2A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{0759E8E9-2315-4AC0-898A-A0896F4CB2A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{0759E8E9-2315-4AC0-898A-A0896F4CB2A3}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{2F309AA3-B442-467B-8B73-7AA31F5840F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{2F309AA3-B442-467B-8B73-7AA31F5840F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{2F309AA3-B442-467B-8B73-7AA31F5840F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{2F309AA3-B442-467B-8B73-7AA31F5840F2}.Release|Any CPU.Build.0 = Release|Any CPU
2424
EndGlobalSection
2525
GlobalSection(SolutionProperties) = preSolution
2626
HideSolutionNode = FALSE
2727
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {55B3F5F4-C774-4815-8438-CD3E90055A85}
30+
EndGlobalSection
2831
EndGlobal

0 commit comments

Comments
 (0)