Skip to content

Commit 85f7d9c

Browse files
authored
✨ feature: Create State Machine Base Class (#1)
* ✨ feature: Create State Machine Base Class * Update CHANGELOG.md * Update README.md
1 parent afde634 commit 85f7d9c

File tree

11 files changed

+163
-24
lines changed

11 files changed

+163
-24
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9+
10+
### Added
11+
12+
- Created state machine base class

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![License](https://img.shields.io/github/license/TJC-Tools/TJC.StateMachine.svg)](LICENSE)
88

99
[![tests](https://github.com/TJC-Tools/TJC.StateMachine/actions/workflows/ct-matrix.yml/badge.svg)](https://github.com/TJC-Tools/TJC.StateMachine/actions/workflows/ct-matrix.yml)
10-
[![codecov](https://codecov.io/gh/TJC-Tools/TJC.StateMachine/graph/badge.svg?token=StateMachine_CODECOV_TOKEN)](https://codecov.io/gh/TJC-Tools/TJC.StateMachine)
10+
[![codecov](https://codecov.io/gh/TJC-Tools/TJC.StateMachine/graph/badge.svg?token=ZwhQB7Ku8u)](https://codecov.io/gh/TJC-Tools/TJC.StateMachine)
1111

1212
## Documentation
1313
- [Changelog](CHANGELOG.md)
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+
}

0 commit comments

Comments
 (0)