Created
May 22, 2023 21:29
-
-
Save emanuelefirmani/bf9635f50f5c99b2bb20f2ce4adfe31c to your computer and use it in GitHub Desktop.
Simple linear skippable state maching
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Context = System.Collections.Generic.Dictionary<string, object>; | |
using ExecFunc = System.Func<System.Collections.Generic.Dictionary<string, object>, System.Collections.Generic.Dictionary<string, object>>; | |
namespace CeacEvaluationSelector.Web.Test; | |
internal enum WfSteps | |
{ | |
Initial, | |
Step1, | |
Step2, | |
Step3, | |
Final | |
} | |
internal record Step(WfSteps WfStep, Context Context, List<WfSteps> SkippedTests, ExecFunc Func); | |
internal static class Operations | |
{ | |
internal static Context ExecuteNullStep(Context context) => context; | |
internal static Context ExecuteStep1(Context context) | |
{ | |
context.Add("step1", true); | |
return context; | |
} | |
internal static Context ExecuteStep2(Context context) | |
{ | |
context.Add("step2", "ok"); | |
return context; | |
} | |
internal static Context ExecuteStep3(Context context) | |
{ | |
context.Add("step3", new List<string>()); | |
return context; | |
} | |
} | |
internal static class Factory | |
{ | |
internal static Step GetInitial(List<WfSteps> skippedTests) => | |
new(WfSteps.Initial, new Context(), skippedTests, Operations.ExecuteNullStep); | |
static Func<Context, Context> GetSkippableFunc(WfSteps wfStep, List<WfSteps> skippedTests) => | |
skippedTests.Contains(wfStep) | |
? Operations.ExecuteNullStep | |
: GetFunc(wfStep); | |
static Func<Context, Context> GetFunc(WfSteps wfStep) => | |
wfStep switch | |
{ | |
WfSteps.Step1 => Operations.ExecuteStep1, | |
WfSteps.Step2 => Operations.ExecuteStep2, | |
WfSteps.Step3 => Operations.ExecuteStep3, | |
WfSteps.Final => Operations.ExecuteNullStep, | |
_ => throw new ArgumentOutOfRangeException(nameof(wfStep), wfStep, null) | |
}; | |
internal static Step GetNextStep(this Step step) | |
{ | |
var newContext = step.Func(step.Context); | |
var nextStep = (WfSteps) (int)step.WfStep + 1; | |
return new Step(nextStep, newContext, step.SkippedTests, GetSkippableFunc(nextStep, step.SkippedTests)); | |
} | |
} | |
public class Tests | |
{ | |
[Fact] | |
void skips_first() | |
{ | |
var initial = Factory.GetInitial(new List<WfSteps> { WfSteps.Step1 }); | |
var first = initial.GetNextStep(); | |
var second = first.GetNextStep(); | |
var third = second.GetNextStep(); | |
var final = third.GetNextStep(); | |
Assert.Equal(WfSteps.Step1, first.WfStep); | |
Assert.Equal(WfSteps.Step2, second.WfStep); | |
Assert.Equal(WfSteps.Step3, third.WfStep); | |
Assert.Equal(WfSteps.Final, final.WfStep); | |
Assert.False(final.Context.ContainsKey("step1")); | |
Assert.Equal("ok", final.Context["step2"]); | |
Assert.True(final.Context["step3"] is List<string>); | |
} | |
[Fact] | |
void skips_second() | |
{ | |
var initial = Factory.GetInitial(new List<WfSteps> { WfSteps.Step2 }); | |
var first = initial.GetNextStep(); | |
var second = first.GetNextStep(); | |
var third = second.GetNextStep(); | |
var final = third.GetNextStep(); | |
Assert.Equal(WfSteps.Step1, first.WfStep); | |
Assert.Equal(WfSteps.Step2, second.WfStep); | |
Assert.Equal(WfSteps.Step3, third.WfStep); | |
Assert.Equal(WfSteps.Final, final.WfStep); | |
Assert.True((bool)final.Context["step1"]); | |
Assert.False(final.Context.ContainsKey("step2")); | |
Assert.True(final.Context["step3"] is List<string>); | |
} | |
[Fact] | |
void skips_first_and_third() | |
{ | |
var initial = Factory.GetInitial(new List<WfSteps> { WfSteps.Step1, WfSteps.Step3 }); | |
var first = initial.GetNextStep(); | |
var second = first.GetNextStep(); | |
var third = second.GetNextStep(); | |
var final = third.GetNextStep(); | |
Assert.Equal(WfSteps.Step1, first.WfStep); | |
Assert.Equal(WfSteps.Step2, second.WfStep); | |
Assert.Equal(WfSteps.Step3, third.WfStep); | |
Assert.Equal(WfSteps.Final, final.WfStep); | |
Assert.False(final.Context.ContainsKey("step1")); | |
Assert.Equal("ok", final.Context["step2"]); | |
Assert.False(final.Context.ContainsKey("step3")); | |
} | |
[Fact] | |
void skips_all() | |
{ | |
var initial = Factory.GetInitial(new List<WfSteps> { WfSteps.Step1, WfSteps.Step2, WfSteps.Step3 }); | |
var first = initial.GetNextStep(); | |
var second = first.GetNextStep(); | |
var third = second.GetNextStep(); | |
var final = third.GetNextStep(); | |
Assert.Equal(WfSteps.Step1, first.WfStep); | |
Assert.Equal(WfSteps.Step2, second.WfStep); | |
Assert.Equal(WfSteps.Step3, third.WfStep); | |
Assert.Equal(WfSteps.Final, final.WfStep); | |
Assert.False(final.Context.ContainsKey("step1")); | |
Assert.False(final.Context.ContainsKey("step2")); | |
Assert.False(final.Context.ContainsKey("step3")); | |
} | |
} |
arialdomartini
commented
May 22, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment