Skip to content

Commit 3e22157

Browse files
committed
Tests and big fix
1 parent 09b99c2 commit 3e22157

16 files changed

+1288
-114
lines changed

SimpleStateMachineLibrary/Helpers/Check.cs

+64-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Microsoft.Extensions.Logging;
22
using System;
33
using System.Collections.Generic;
4+
using System.Linq;
45

56
namespace SimpleStateMachineLibrary.Helpers
67
{
@@ -41,81 +42,99 @@ public static TObject NamedObject<TObject>(TObject objectRequested, ILogger logg
4142
return objectRequested;
4243
}
4344

44-
45+
4546
public static bool Contains<TObject>(Dictionary<string, TObject> dictionary, string nameObject, ILogger logger, bool exception = true) where TObject : NamedObject
47+
{
48+
nameObject = Contains(dictionary, nameObject, logger, out bool result, exception);
49+
return result;
50+
}
51+
public static bool Contains<TObject>(Dictionary<string, TObject> dictionary, TObject objectRequested, ILogger logger, bool exception = true) where TObject : NamedObject
52+
{
53+
objectRequested = Contains(dictionary, objectRequested, logger, out bool result, exception);
54+
return result;
55+
}
56+
public static string Contains<TObject>(Dictionary<string, TObject> dictionary, string nameObject, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
4657
{
4758
dictionary = Check.Object(dictionary, logger);
4859
nameObject = Check.Name(nameObject, logger);
49-
bool contains = dictionary.ContainsKey(nameObject);
60+
result = dictionary.ContainsKey(nameObject);
5061

51-
if ((exception)&&(!contains))
62+
if ((exception) && (!result))
5263
{
5364
object[] args = { nameObject };
5465
string message = "Element with name \"{0}\" is not found";
5566
var ex = new KeyNotFoundException(message: String.Format(message, args));
56-
logger?.LogError(ex, message, args);
67+
logger?.LogError(ex, message, args);
5768
throw ex;
5869
}
5970

60-
return contains;
71+
return nameObject;
6172
}
62-
63-
public static bool Contains<TObject>(Dictionary<string, TObject> dictionary, TObject objectRequested, ILogger logger, bool exception = true) where TObject : NamedObject
73+
public static TObject Contains<TObject>(Dictionary<string, TObject> dictionary, TObject objectRequested, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
6474
{
6575
dictionary = Check.Object(dictionary, logger);
6676
objectRequested = Check.Object(objectRequested, logger);
6777

68-
bool contains = dictionary.ContainsValue(objectRequested);
78+
result = dictionary.ContainsValue(objectRequested);
6979

70-
if ((exception) && (!contains))
80+
if ((exception) && (!result))
7181
{
7282
object[] args = { objectRequested.Name };
7383
string message = "Element with name \"{0}\" is not found";
7484
var ex = new KeyNotFoundException(message: String.Format(message, args));
75-
logger?.LogError(ex, message, args);
85+
logger?.LogError(ex, message, args);
7686
throw ex;
7787
}
7888

79-
return contains;
89+
return objectRequested;
8090
}
8191

92+
8293
public static bool NotContains<TObject>(Dictionary<string, TObject> dictionary, string nameObject, ILogger logger, bool exception = true) where TObject : NamedObject
94+
{
95+
nameObject = NotContains(dictionary, nameObject, logger, out bool result, exception);
96+
return result;
97+
}
98+
public static bool NotContains<TObject>(Dictionary<string, TObject> dictionary, TObject objectRequested, ILogger logger, bool exception = true) where TObject : NamedObject
99+
{
100+
objectRequested = NotContains(dictionary, objectRequested, logger, out bool result, exception);
101+
return result;
102+
}
103+
public static string NotContains<TObject>(Dictionary<string, TObject> dictionary, string nameObject, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
83104
{
84105
dictionary = Check.Object(dictionary, logger);
85106
nameObject = Check.Name(nameObject, logger);
86-
bool notContains = !dictionary.ContainsKey(nameObject);
107+
result = !dictionary.ContainsKey(nameObject);
87108

88-
if ((exception) && (!notContains))
109+
if ((exception) && (!result))
89110
{
90111
object[] args = { nameObject };
91-
string message = "Element of type \"{0}\" already exists";
92-
var ex = new KeyNotFoundException(message: String.Format(message, args));
93-
logger?.LogError(ex, message, args);
112+
string message = "Element with name \"{0}\" already exists";
113+
var ex = new ArgumentException(message: String.Format(message, args));
114+
logger?.LogError(ex, message, args);
94115
throw ex;
95116
}
96117

97-
return notContains;
118+
return nameObject;
98119
}
99-
100-
public static bool NotContains<TObject>(Dictionary<string, TObject> dictionary, TObject objectRequested, ILogger logger, bool exception = true) where TObject : NamedObject
120+
public static TObject NotContains<TObject>(Dictionary<string, TObject> dictionary, TObject objectRequested, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
101121
{
102122
dictionary = Check.Object(dictionary, logger);
103123
objectRequested = Check.Object(objectRequested, logger);
124+
result = !dictionary.ContainsValue(objectRequested);
104125

105-
bool notContains = !dictionary.ContainsValue(objectRequested);
106-
107-
if ((exception) && (!notContains))
126+
if ((exception) && (!result))
108127
{
109128
object[] args = { objectRequested.Name };
110-
string message = "Element of type \"{0}\" already exists";
111-
var ex = new KeyNotFoundException(message: String.Format(message, args));
112-
logger?.LogError(ex, message, args);
129+
string message = "Element with name \"{0}\" already exists";
130+
var ex = new ArgumentException(message: String.Format(message, args));
131+
logger?.LogError(ex, message, args);
113132
throw ex;
114133
}
115134

116-
return notContains;
135+
return objectRequested;
117136
}
118-
137+
119138

120139
public static TObject Remove<TObject>(Dictionary<string, TObject> dictionary, string nameObject, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
121140
{
@@ -145,7 +164,6 @@ public static TObject Remove<TObject>(Dictionary<string, TObject> dictionary, st
145164
result = true;
146165
return removedObj;
147166
}
148-
149167
public static TObject Remove<TObject>(Dictionary<string, TObject> dictionary, TObject obj, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
150168
{
151169
result = false;
@@ -181,12 +199,29 @@ public static TObject GetElement<TObject>(Dictionary<string, TObject> dictionary
181199
result = Contains(dictionary, nameObject, logger, exception);
182200
return result ? dictionary[nameObject] : default(TObject);
183201
}
184-
185202
public static TObject GetElement<TObject>(Dictionary<string, TObject> dictionary, TObject obj, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
186203
{
187204
result = Contains(dictionary, obj, logger, exception);
188205
return result ? obj : default(TObject);
189206
}
190207

208+
209+
public static Dictionary<string, TObject> GetValuesWhere<TObject>(Dictionary<string, TObject> dictionary, Func<TObject, bool> action, ILogger logger, out bool result, bool exception = true) where TObject : NamedObject
210+
{
211+
dictionary = Check.Object(dictionary, logger);
212+
Dictionary<string, TObject> foundElements = dictionary.Values.Where(action).ToDictionary(x => x.Name, x => x);
213+
result = foundElements.Count > 1;
214+
if ((exception) && (!result))
215+
{
216+
object[] args = { };
217+
string message = "Elements aren't found";
218+
var ex = new KeyNotFoundException(message: String.Format(message, args));
219+
logger?.LogError(ex, message, args);
220+
throw ex;
221+
}
222+
223+
return foundElements;
224+
}
225+
191226
}
192227
}

SimpleStateMachineLibrary/StateMachines/InvokeParameters.cs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public static class InvokeParametersExtension
1818
{
1919
public static InvokeParameters AddParameter(this InvokeParameters invokeParameters, string nameParameter, object valueParameter)
2020
{
21+
2122
if(invokeParameters.StateMachine._nextParameters ==null)
2223
{
2324
invokeParameters.StateMachine._nextParameters = new Dictionary<string, object>();
@@ -29,6 +30,7 @@ public static InvokeParameters AddParameter(this InvokeParameters invokeParamete
2930

3031
public static InvokeParameters AddParameters(this InvokeParameters invokeParameters, Dictionary<string, object> parameters)
3132
{
33+
3234
if (invokeParameters.StateMachine._nextParameters == null)
3335
{
3436
invokeParameters.StateMachine._nextParameters = new Dictionary<string, object>();

SimpleStateMachineLibrary/StateMachines/StateMachine.cs

+62-48
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,27 @@ public partial class StateMachine
1919

2020
private Dictionary<string, Data> _data = new Dictionary<string, Data>();
2121

22-
public State CurrentState { get; private set; }
22+
internal string _currentState;
23+
24+
internal string _previousState;
25+
internal string _currentTransition { get; private set; }
26+
27+
internal string _nextTransition;
28+
internal string _startState { get; private set; }
29+
30+
internal Dictionary<string, object> _currentParameters;
31+
32+
internal Dictionary<string, object> _nextParameters;
33+
34+
internal Action<State, State> _onChangeState;
35+
36+
public State CurrentState { get { return GetState(_currentState); } }
37+
public Transition CurrentTransition { get { return GetTransition(_currentTransition); } }
38+
39+
2340

24-
public State PreviousState { get; private set; }
2541

26-
public Transition CurrentTransition{ get; private set; }
2742

28-
public State StartState { get; private set; }
2943

3044
internal ILogger _logger;
3145

@@ -53,15 +67,6 @@ public StateMachine(string xDocumentPath, ILogger logger = null): this(logger)
5367
FromXDocument(this, xDocumentPath);
5468
}
5569

56-
internal Transition _nextTransition;
57-
58-
internal Dictionary<string, object> _currentParameters;
59-
60-
internal Dictionary<string, object> _nextParameters;
61-
62-
internal Action<State, State> _onChangeState;
63-
64-
6570
public StateMachine OnChangeState(Action<State, State> actionOnChangeState)
6671
{
6772
_onChangeState += actionOnChangeState;
@@ -71,7 +76,7 @@ public StateMachine OnChangeState(Action<State, State> actionOnChangeState)
7176

7277
public State SetStartState(State state)
7378
{
74-
StartState = state;
79+
_startState = _StateExists(state.Name, out _, true);
7580

7681
_logger?.LogDebug("State \"{NameState}\" set as start", state.Name);
7782

@@ -80,43 +85,44 @@ public State SetStartState(State state)
8085

8186
public State SetStartState(string stateName)
8287
{
83-
StartState = GetState(stateName);
88+
State state = GetState(stateName);
89+
_startState = state.Name;
8490

8591
_logger?.LogDebug("State \"{NameState}\" set as start", stateName);
8692

87-
return StartState;
93+
return state;
8894
}
8995

9096
public InvokeParameters InvokeTransition(string nameTransition, Dictionary<string, object> parameters=null)
9197
{
92-
_nextTransition = Check.GetElement(_transitions, nameTransition, this._logger, out bool result, true);
98+
_nextTransition = TransitionExists(nameTransition, out _);
9399

94100
CheckBeforeInvoke(this._logger);
95101

96-
return new InvokeParameters(this);
102+
InvokeParameters invokeParameters = new InvokeParameters(this);
103+
if(parameters!=null)
104+
invokeParameters.AddParameters(parameters);
105+
return invokeParameters;
97106
}
98107

99108
private void CheckBeforeInvoke(ILogger logger)
100109
{
101-
if (_nextTransition.StateFrom != CurrentState)
110+
Transition transition = GetTransition(_nextTransition);
111+
if (transition.StateFrom!= _currentState)
102112
{
103-
object[] args = { _nextTransition.Name, CurrentState?.Name };
113+
object[] args = { _nextTransition, _currentState };
104114
string message = "Transition \"{0}\" not available from state \"{0}\"";
105115
var exception = new ArgumentException(message: String.Format(message, args));
106116
_logger?.LogError(exception, message, args);
107117

108118
throw exception;
109119
}
110-
_logger?.LogDebug("Transition \"{NameTransition}\" set as next", _nextTransition.Name);
120+
_logger?.LogDebug("Transition \"{NameTransition}\" set as next", _nextTransition);
111121
}
112122

113123
public InvokeParameters InvokeTransition(Transition transition, Dictionary<string, object> parameters = null)
114124
{
115-
_nextTransition = Check.NamedObject(transition, this._logger);
116-
117-
CheckBeforeInvoke(this._logger);
118-
119-
return new InvokeParameters(this);
125+
return InvokeTransition(transition?.Name, parameters);
120126
}
121127

122128

@@ -128,55 +134,63 @@ private StateMachine InvokeTransition()
128134
_nextParameters = null;
129135

130136
//Mark nextTransition as current
131-
CurrentTransition = _nextTransition;
137+
_currentTransition = _nextTransition;
132138
_nextTransition = null;
133139

134140
//Mark currentState as previous
135-
PreviousState = CurrentState;
136-
CurrentState = null;
141+
_previousState = _currentState;
142+
_currentState = null;
137143

138-
139-
CurrentTransition.Invoking(_currentParameters);
140-
CurrentState = CurrentTransition.StateTo;
141-
CurrentTransition = null;
144+
Transition currentTransition = GetTransition(_currentTransition);
145+
currentTransition.Invoking(_currentParameters);
146+
_currentState = currentTransition.StateTo;
147+
_currentTransition = null;
142148

143149
return this;
144150
}
145151

146152
private StateMachine ChangeState()
147153
{
148-
CurrentState.Entry(_currentParameters);
149-
150-
_onChangeState?.Invoke(PreviousState, CurrentState);
151-
152-
object[] obj = { PreviousState?.Name, CurrentState?.Name };
153-
154-
_logger?.LogDebug("State \"{StateOld}\" change on \"{StateNew}\"", obj);
155-
156-
CurrentState.Exit(_currentParameters);
154+
State currentState = GetState(_currentState);
155+
currentState.Entry(_currentParameters);
156+
State previousState = null;
157+
object[] obj = { _previousState, _currentState };
158+
string message;
159+
if (string.IsNullOrEmpty(_previousState))
160+
{
161+
message = "State \"{StateNew}\" was set";
162+
}
163+
else
164+
{
165+
message = "State \"{StateOld}\" change on \"{StateNew}\"";
166+
previousState = GetState(_previousState);
167+
}
168+
_onChangeState?.Invoke(previousState, currentState);
169+
_logger?.LogDebug(message, obj);
170+
currentState.Exit(_currentParameters);
157171

158172
return this;
159173
}
160174

161175
private void CheckStartState()
162176
{
163-
if (StartState == null)
177+
string message;
178+
if (string.IsNullOrEmpty(_startState))
164179
{
165-
string message = "Start state not set";
180+
message = "Start state not set";
166181
var exception = new NullReferenceException(message: message);
167182
_logger?.LogError(exception, message);
168183
throw exception;
169-
170184
}
185+
_startState = _StateExists(_startState, out _, true);
186+
_currentState = _startState;
171187
}
172188

173189
public void Start(Dictionary<string, object> startParameters = null)
174190
{
175191
CheckStartState();
176-
192+
177193
_logger?.LogDebugAndInformation("Start work state machine");
178-
179-
CurrentState = StartState;
180194
_currentParameters = startParameters;
181195

182196
ChangeState();

0 commit comments

Comments
 (0)