diff --git a/BugPro/BugPro.csproj b/BugPro/BugPro.csproj new file mode 100644 index 0000000..7fc7560 --- /dev/null +++ b/BugPro/BugPro.csproj @@ -0,0 +1,11 @@ + + + Exe + net9.0 + enable + enable + + + + + diff --git a/BugPro/Program.cs b/BugPro/Program.cs new file mode 100644 index 0000000..9a5cde6 --- /dev/null +++ b/BugPro/Program.cs @@ -0,0 +1,82 @@ +// Copyright 2026 NNTU-CS +using Stateless; +using System; + +namespace BugPro { + public class Bug { + public enum State { + Open, Assigned, InProgress, Resolved, Closed, Reopened + } + + public enum Trigger { + Assign, Start, Resolve, Close, Reopen, Reset + } + + private readonly StateMachine _machine; + private string _title; + + public State CurrentState => _machine.State; + + public Bug(string title) { + _title = title; + _machine = new StateMachine(State.Open); + + _machine.Configure(State.Open) + .Permit(Trigger.Assign, State.Assigned); + + _machine.Configure(State.Assigned) + .Permit(Trigger.Start, State.InProgress) + .Permit(Trigger.Reset, State.Open); + + _machine.Configure(State.InProgress) + .Permit(Trigger.Resolve, State.Resolved) + .Permit(Trigger.Reset, State.Open); + + _machine.Configure(State.Resolved) + .Permit(Trigger.Close, State.Closed) + .Permit(Trigger.Reopen, State.Reopened); + + _machine.Configure(State.Closed) + .Permit(Trigger.Reopen, State.Reopened); + + _machine.Configure(State.Reopened) + .Permit(Trigger.Assign, State.Assigned) + .Permit(Trigger.Resolve, State.Resolved); + } + + public void Assign() => _machine.Fire(Trigger.Assign); + public void Start() => _machine.Fire(Trigger.Start); + public void Resolve() => _machine.Fire(Trigger.Resolve); + public void Close() => _machine.Fire(Trigger.Close); + public void Reopen() => _machine.Fire(Trigger.Reopen); + public void Reset() => _machine.Fire(Trigger.Reset); + + public bool CanAssign() => _machine.CanFire(Trigger.Assign); + public bool CanStart() => _machine.CanFire(Trigger.Start); + public bool CanResolve() => _machine.CanFire(Trigger.Resolve); + public bool CanClose() => _machine.CanFire(Trigger.Close); + public bool CanReopen() => _machine.CanFire(Trigger.Reopen); + } + + class Program { + static void Main(string[] args) { + var bug = new Bug("Sample Bug"); + Console.WriteLine($"Initial state: {bug.CurrentState}"); + + bug.Assign(); + Console.WriteLine($"After Assign: {bug.CurrentState}"); + + bug.Start(); + Console.WriteLine($"After Start: {bug.CurrentState}"); + + bug.Resolve(); + Console.WriteLine($"After Resolve: {bug.CurrentState}"); + + bug.Close(); + Console.WriteLine($"After Close: {bug.CurrentState}"); + + bug.Reopen(); + Console.WriteLine($"After Reopen: {bug.CurrentState}"); + } + } +} diff --git a/BugTests/BugTests.csproj b/BugTests/BugTests.csproj new file mode 100644 index 0000000..9ee27db --- /dev/null +++ b/BugTests/BugTests.csproj @@ -0,0 +1,17 @@ + + + net9.0 + enable + enable + false + + + + + + + + + + + diff --git a/BugTests/UnitTest1.cs b/BugTests/UnitTest1.cs new file mode 100644 index 0000000..7f641eb --- /dev/null +++ b/BugTests/UnitTest1.cs @@ -0,0 +1,179 @@ +// Copyright 2026 NNTU-CS +using Microsoft.VisualStudio.TestTools.UnitTesting; +using BugPro; +using Stateless; +using System; + +namespace BugTests { + [TestClass] + public class UnitTest1 { + [TestMethod] + public void Bug_InitialState_IsOpen() { + var bug = new Bug("Test"); + Assert.AreEqual(Bug.State.Open, bug.CurrentState); + } + + [TestMethod] + public void Bug_Assign_MovesToAssigned() { + var bug = new Bug("Test"); + bug.Assign(); + Assert.AreEqual(Bug.State.Assigned, bug.CurrentState); + } + + [TestMethod] + public void Bug_Start_MovesToInProgress() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + Assert.AreEqual(Bug.State.InProgress, bug.CurrentState); + } + + [TestMethod] + public void Bug_Resolve_MovesToResolved() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + bug.Resolve(); + Assert.AreEqual(Bug.State.Resolved, bug.CurrentState); + } + + [TestMethod] + public void Bug_Close_MovesToClosed() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + bug.Resolve(); + bug.Close(); + Assert.AreEqual(Bug.State.Closed, bug.CurrentState); + } + + [TestMethod] + public void Bug_Reopen_FromClosed_MovesToReopened() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + bug.Resolve(); + bug.Close(); + bug.Reopen(); + Assert.AreEqual(Bug.State.Reopened, bug.CurrentState); + } + + [TestMethod] + public void Bug_Reopen_FromResolved_MovesToReopened() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + bug.Resolve(); + bug.Reopen(); + Assert.AreEqual(Bug.State.Reopened, bug.CurrentState); + } + + [TestMethod] + public void Bug_Reset_FromAssigned_MovesToOpen() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Reset(); + Assert.AreEqual(Bug.State.Open, bug.CurrentState); + } + + [TestMethod] + public void Bug_Reset_FromInProgress_MovesToOpen() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + bug.Reset(); + Assert.AreEqual(Bug.State.Open, bug.CurrentState); + } + + [TestMethod] + public void Bug_ReopenedCanAssign() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + bug.Resolve(); + bug.Reopen(); + Assert.IsTrue(bug.CanAssign()); + } + + [TestMethod] + public void Bug_CanAssign_WhenOpen() { + var bug = new Bug("Test"); + Assert.IsTrue(bug.CanAssign()); + } + + [TestMethod] + public void Bug_CannotStart_WhenOpen() { + var bug = new Bug("Test"); + Assert.IsFalse(bug.CanStart()); + } + + [TestMethod] + public void Bug_CannotClose_WhenOpen() { + var bug = new Bug("Test"); + Assert.IsFalse(bug.CanClose()); + } + + [TestMethod] + public void Bug_CannotReopen_WhenOpen() { + var bug = new Bug("Test"); + Assert.IsFalse(bug.CanReopen()); + } + + [TestMethod] + public void Bug_CannotResolve_WhenOpen() { + var bug = new Bug("Test"); + Assert.IsFalse(bug.CanResolve()); + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void Bug_Start_WhenOpen_ThrowsException() { + var bug = new Bug("Test"); + bug.Start(); + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void Bug_Resolve_WhenOpen_ThrowsException() { + var bug = new Bug("Test"); + bug.Resolve(); + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void Bug_Close_WhenOpen_ThrowsException() { + var bug = new Bug("Test"); + bug.Close(); + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void Bug_Reopen_WhenOpen_ThrowsException() { + var bug = new Bug("Test"); + bug.Reopen(); + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void Bug_Assign_WhenInProgress_ThrowsException() { + var bug = new Bug("Test"); + bug.Assign(); + bug.Start(); + bug.Assign(); + } + + [TestMethod] + public void Bug_FullCycle_WorksCorrectly() { + var bug = new Bug("Test"); + Assert.AreEqual(Bug.State.Open, bug.CurrentState); + bug.Assign(); + Assert.AreEqual(Bug.State.Assigned, bug.CurrentState); + bug.Start(); + Assert.AreEqual(Bug.State.InProgress, bug.CurrentState); + bug.Resolve(); + Assert.AreEqual(Bug.State.Resolved, bug.CurrentState); + bug.Close(); + Assert.AreEqual(Bug.State.Closed, bug.CurrentState); + } + } +} diff --git a/ST-4.sln b/ST-4.sln index 58ea566..06cf042 100644 --- a/ST-4.sln +++ b/ST-4.sln @@ -1,14 +1,22 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugPro", "BugPro\BugPro.csproj", "{11111111-1111-1111-1111-111111111111}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BugTests", "BugTests\BugTests.csproj", "{22222222-2222-2222-2222-222222222222}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {11111111-1111-1111-1111-111111111111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11111111-1111-1111-1111-111111111111}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11111111-1111-1111-1111-111111111111}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11111111-1111-1111-1111-111111111111}.Release|Any CPU.Build.0 = Release|Any CPU + {22222222-2222-2222-2222-222222222222}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22222222-2222-2222-2222-222222222222}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22222222-2222-2222-2222-222222222222}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22222222-2222-2222-2222-222222222222}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal