public void YEdGraphMl(string dummyName, Func <string, StateMachineDefinition <States, Events>, IAsyncStateMachine <States, Events> > createStateMachine) { var builder = new StateMachineDefinitionBuilder <States, Events>(); builder .DefineHierarchyOn(States.Healthy) .WithHistoryType(HistoryType.Deep) .WithInitialSubState(States.OnFloor) .WithSubState(States.Moving); builder .DefineHierarchyOn(States.Moving) .WithHistoryType(HistoryType.Shallow) .WithInitialSubState(States.MovingUp) .WithSubState(States.MovingDown); builder .DefineHierarchyOn(States.OnFloor) .WithHistoryType(HistoryType.None) .WithInitialSubState(States.DoorClosed) .WithSubState(States.DoorOpen); builder .In(States.Healthy) .On(Events.ErrorOccured).Goto(States.Error); builder .In(States.Error) .On(Events.Reset).Goto(States.Healthy) .On(Events.ErrorOccured); builder .In(States.OnFloor) .ExecuteOnEntry(AnnounceFloor) .ExecuteOnExit(Beep) .ExecuteOnExit(Beep) .On(Events.CloseDoor).Goto(States.DoorClosed) .On(Events.OpenDoor).Goto(States.DoorOpen) .On(Events.GoUp) .If(CheckOverload).Goto(States.MovingUp) .Otherwise() .Execute(AnnounceOverload) .Execute(Beep) .On(Events.GoDown) .If(CheckOverload).Goto(States.MovingDown) .Otherwise().Execute(AnnounceOverload); builder .In(States.Moving) .On(Events.Stop).Goto(States.OnFloor); var stateMachineDefinition = builder .WithInitialState(States.OnFloor) .Build(); var elevator = createStateMachine("Elevator", stateMachineDefinition); var stream = new MemoryStream(); var textWriter = new StreamWriter(stream); var testee = new YEdStateMachineReportGenerator <States, Events>(textWriter); elevator.Report(testee); stream.Position = 0; var reader = new StreamReader(stream); var report = reader.ReadToEnd(); const string ExpectedReport = "<?xml version=\"1.0\" encoding=\"utf-8\"?><graphml xmlns:y=\"http://www.yworks.com/xml/graphml\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:yed=\"http://www.yworks.com/xml/yed/3\" xmlns:schemaLocation=\"http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd\" xmlns=\"http://graphml.graphdrawing.org/xmlns\"> <!--Created by Appccelerate.StateMachine.YEdStateMachineReportGenerator--> <key for=\"graphml\" id=\"d0\" yfiles.type=\"resources\" /> <key for=\"port\" id=\"d1\" yfiles.type=\"portgraphics\" /> <key for=\"port\" id=\"d2\" yfiles.type=\"portgeometry\" /> <key for=\"port\" id=\"d3\" yfiles.type=\"portuserdata\" /> <key attr.name=\"url\" attr.type=\"string\" for=\"node\" id=\"d4\" /> <key attr.name=\"description\" attr.type=\"string\" for=\"node\" id=\"d5\" /> <key for=\"node\" id=\"d6\" yfiles.type=\"nodegraphics\" /> <key attr.name=\"Beschreibung\" attr.type=\"string\" for=\"graph\" id=\"d7\"> <default /> </key> <key attr.name=\"url\" attr.type=\"string\" for=\"edge\" id=\"d8\" /> <key attr.name=\"description\" attr.type=\"string\" for=\"edge\" id=\"d9\" /> <key for=\"edge\" id=\"d10\" yfiles.type=\"edgegraphics\" /> <graph edgedefault=\"directed\" id=\"G\"> <node id=\"Healthy\"> <data key=\"d6\"> <y:ProxyAutoBoundsNode> <y:Realizers active=\"0\"> <y:GroupNode> <y:NodeLabel alignment=\"right\" autoSizePolicy=\"node_width\" backgroundColor=\"#EBEBEB\" modelName=\"internal\" modelPosition=\"t\">Healthy</y:NodeLabel> <y:State closed=\"false\" innerGraphDisplayEnabled=\"true\" /> </y:GroupNode> </y:Realizers> </y:ProxyAutoBoundsNode> </data> <graph edgedefault=\"directed\" id=\"Healthy:\"> <node id=\"OnFloor\"> <data key=\"d6\"> <y:ProxyAutoBoundsNode> <y:Realizers active=\"0\"> <y:GroupNode> <y:NodeLabel alignment=\"right\" autoSizePolicy=\"node_width\" backgroundColor=\"#EBEBEB\" modelName=\"internal\" modelPosition=\"t\">(AnnounceFloor)OnFloor(Beep, Beep)</y:NodeLabel> <y:State closed=\"false\" innerGraphDisplayEnabled=\"true\" /> <y:BorderStyle width=\"2.0\" /> </y:GroupNode> </y:Realizers> </y:ProxyAutoBoundsNode> </data> <graph edgedefault=\"directed\" id=\"OnFloor:\"> <node id=\"DoorClosed\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>DoorClosed</y:NodeLabel> <y:Shape type=\"ellipse\" /> <y:BorderStyle width=\"2.0\" /> </y:ShapeNode> </data> </node> <node id=\"DoorOpen\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>DoorOpen</y:NodeLabel> <y:Shape type=\"ellipse\" /> </y:ShapeNode> </data> </node> </graph> </node> <node id=\"Moving\"> <data key=\"d6\"> <y:ProxyAutoBoundsNode> <y:Realizers active=\"0\"> <y:GroupNode> <y:NodeLabel alignment=\"right\" autoSizePolicy=\"node_width\" backgroundColor=\"#EBEBEB\" modelName=\"internal\" modelPosition=\"t\">Moving</y:NodeLabel> <y:State closed=\"false\" innerGraphDisplayEnabled=\"true\" /> </y:GroupNode> </y:Realizers> </y:ProxyAutoBoundsNode> </data> <graph edgedefault=\"directed\" id=\"Moving:\"> <node id=\"MovingUp\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>MovingUp</y:NodeLabel> <y:Shape type=\"ellipse\" /> <y:BorderStyle width=\"2.0\" /> </y:ShapeNode> </data> </node> <node id=\"MovingDown\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>MovingDown</y:NodeLabel> <y:Shape type=\"ellipse\" /> </y:ShapeNode> </data> </node> </graph> </node> </graph> </node> <node id=\"Error\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>Error</y:NodeLabel> <y:Shape type=\"ellipse\" /> </y:ShapeNode> </data> </node> <edge id=\"ErrorOccured0\" source=\"Healthy\" target=\"Error\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>ErrorOccured</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"CloseDoor1\" source=\"OnFloor\" target=\"DoorClosed\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>CloseDoor</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"OpenDoor2\" source=\"OnFloor\" target=\"DoorOpen\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>OpenDoor</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoUp3\" source=\"OnFloor\" target=\"MovingUp\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>[CheckOverload]GoUp</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoUp4\" source=\"OnFloor\" target=\"OnFloor\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"dashed\" /> <y:Arrows source=\"none\" target=\"plain\" /> <y:EdgeLabel>GoUp(AnnounceOverload, Beep)</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoDown5\" source=\"OnFloor\" target=\"MovingDown\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>[CheckOverload]GoDown</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoDown6\" source=\"OnFloor\" target=\"OnFloor\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"dashed\" /> <y:Arrows source=\"none\" target=\"plain\" /> <y:EdgeLabel>GoDown(AnnounceOverload)</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"Stop7\" source=\"Moving\" target=\"OnFloor\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>Stop</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"Reset8\" source=\"Error\" target=\"Healthy\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>Reset</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"ErrorOccured9\" source=\"Error\" target=\"Error\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"dashed\" /> <y:Arrows source=\"none\" target=\"plain\" /> <y:EdgeLabel>ErrorOccured</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> </graph> <data key=\"d0\"> <y:Resources /> </data></graphml>"; var cleanedReport = report.Replace("\n", string.Empty).Replace("\r", string.Empty); cleanedReport .Should() .Be( ExpectedReport .IgnoringNewlines()); }
public void YEdGraphML() { var elevator = new PassiveStateMachine<States, Events>("Elevator"); elevator.DefineHierarchyOn(States.Healthy) .WithHistoryType(HistoryType.Deep) .WithInitialSubState(States.OnFloor) .WithSubState(States.Moving); elevator.DefineHierarchyOn(States.Moving) .WithHistoryType(HistoryType.Shallow) .WithInitialSubState(States.MovingUp) .WithSubState(States.MovingDown); elevator.DefineHierarchyOn(States.OnFloor) .WithHistoryType(HistoryType.None) .WithInitialSubState(States.DoorClosed) .WithSubState(States.DoorOpen); elevator.In(States.Healthy) .On(Events.ErrorOccured).Goto(States.Error); elevator.In(States.Error) .On(Events.Reset).Goto(States.Healthy) .On(Events.ErrorOccured); elevator.In(States.OnFloor) .ExecuteOnEntry(AnnounceFloor) .ExecuteOnExit(Beep) .ExecuteOnExit(Beep) .On(Events.CloseDoor).Goto(States.DoorClosed) .On(Events.OpenDoor).Goto(States.DoorOpen) .On(Events.GoUp) .If(CheckOverload).Goto(States.MovingUp) .Otherwise() .Execute(AnnounceOverload) .Execute(Beep) .On(Events.GoDown) .If(CheckOverload).Goto(States.MovingDown) .Otherwise().Execute(AnnounceOverload); elevator.In(States.Moving) .On(Events.Stop).Goto(States.OnFloor); elevator.Initialize(States.OnFloor); var stream = new MemoryStream(); var textWriter = new StreamWriter(stream); var testee = new YEdStateMachineReportGenerator<States, Events>(textWriter); elevator.Report(testee); stream.Position = 0; var reader = new StreamReader(stream); var report = reader.ReadToEnd(); const string ExpectedReport = "<?xml version=\"1.0\" encoding=\"utf-8\"?><graphml xmlns:y=\"http://www.yworks.com/xml/graphml\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:yed=\"http://www.yworks.com/xml/yed/3\" xmlns:schemaLocation=\"http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd\" xmlns=\"http://graphml.graphdrawing.org/xmlns\"> <!--Created by Appccelerate.StateMachine.YEdStateMachineReportGenerator--> <key for=\"graphml\" id=\"d0\" yfiles.type=\"resources\" /> <key for=\"port\" id=\"d1\" yfiles.type=\"portgraphics\" /> <key for=\"port\" id=\"d2\" yfiles.type=\"portgeometry\" /> <key for=\"port\" id=\"d3\" yfiles.type=\"portuserdata\" /> <key attr.name=\"url\" attr.type=\"string\" for=\"node\" id=\"d4\" /> <key attr.name=\"description\" attr.type=\"string\" for=\"node\" id=\"d5\" /> <key for=\"node\" id=\"d6\" yfiles.type=\"nodegraphics\" /> <key attr.name=\"Beschreibung\" attr.type=\"string\" for=\"graph\" id=\"d7\"> <default /> </key> <key attr.name=\"url\" attr.type=\"string\" for=\"edge\" id=\"d8\" /> <key attr.name=\"description\" attr.type=\"string\" for=\"edge\" id=\"d9\" /> <key for=\"edge\" id=\"d10\" yfiles.type=\"edgegraphics\" /> <graph edgedefault=\"directed\" id=\"G\"> <node id=\"Healthy\"> <data key=\"d6\"> <y:ProxyAutoBoundsNode> <y:Realizers active=\"0\"> <y:GroupNode> <y:NodeLabel alignment=\"right\" autoSizePolicy=\"node_width\" backgroundColor=\"#EBEBEB\" modelName=\"internal\" modelPosition=\"t\">Healthy</y:NodeLabel> <y:State closed=\"false\" innerGraphDisplayEnabled=\"true\" /> </y:GroupNode> </y:Realizers> </y:ProxyAutoBoundsNode> </data> <graph edgedefault=\"directed\" id=\"Healthy:\"> <node id=\"OnFloor\"> <data key=\"d6\"> <y:ProxyAutoBoundsNode> <y:Realizers active=\"0\"> <y:GroupNode> <y:NodeLabel alignment=\"right\" autoSizePolicy=\"node_width\" backgroundColor=\"#EBEBEB\" modelName=\"internal\" modelPosition=\"t\">(AnnounceFloor)OnFloor(Beep, Beep)</y:NodeLabel> <y:State closed=\"false\" innerGraphDisplayEnabled=\"true\" /> <y:BorderStyle width=\"2.0\" /> </y:GroupNode> </y:Realizers> </y:ProxyAutoBoundsNode> </data> <graph edgedefault=\"directed\" id=\"OnFloor:\"> <node id=\"DoorClosed\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>DoorClosed</y:NodeLabel> <y:Shape type=\"ellipse\" /> <y:BorderStyle width=\"2.0\" /> </y:ShapeNode> </data> </node> <node id=\"DoorOpen\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>DoorOpen</y:NodeLabel> <y:Shape type=\"ellipse\" /> </y:ShapeNode> </data> </node> </graph> </node> <node id=\"Moving\"> <data key=\"d6\"> <y:ProxyAutoBoundsNode> <y:Realizers active=\"0\"> <y:GroupNode> <y:NodeLabel alignment=\"right\" autoSizePolicy=\"node_width\" backgroundColor=\"#EBEBEB\" modelName=\"internal\" modelPosition=\"t\">Moving</y:NodeLabel> <y:State closed=\"false\" innerGraphDisplayEnabled=\"true\" /> </y:GroupNode> </y:Realizers> </y:ProxyAutoBoundsNode> </data> <graph edgedefault=\"directed\" id=\"Moving:\"> <node id=\"MovingUp\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>MovingUp</y:NodeLabel> <y:Shape type=\"ellipse\" /> <y:BorderStyle width=\"2.0\" /> </y:ShapeNode> </data> </node> <node id=\"MovingDown\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>MovingDown</y:NodeLabel> <y:Shape type=\"ellipse\" /> </y:ShapeNode> </data> </node> </graph> </node> </graph> </node> <node id=\"Error\"> <data key=\"d6\"> <y:ShapeNode> <y:NodeLabel>Error</y:NodeLabel> <y:Shape type=\"ellipse\" /> </y:ShapeNode> </data> </node> <edge id=\"ErrorOccured0\" source=\"Healthy\" target=\"Error\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>ErrorOccured</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"CloseDoor1\" source=\"OnFloor\" target=\"DoorClosed\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>CloseDoor</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"OpenDoor2\" source=\"OnFloor\" target=\"DoorOpen\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>OpenDoor</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoUp3\" source=\"OnFloor\" target=\"MovingUp\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>[CheckOverload]GoUp</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoUp4\" source=\"OnFloor\" target=\"OnFloor\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"dashed\" /> <y:Arrows source=\"none\" target=\"plain\" /> <y:EdgeLabel>GoUp(AnnounceOverload, Beep)</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoDown5\" source=\"OnFloor\" target=\"MovingDown\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>[CheckOverload]GoDown</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"GoDown6\" source=\"OnFloor\" target=\"OnFloor\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"dashed\" /> <y:Arrows source=\"none\" target=\"plain\" /> <y:EdgeLabel>GoDown(AnnounceOverload)</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"Stop7\" source=\"Moving\" target=\"OnFloor\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>Stop</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"Reset8\" source=\"Error\" target=\"Healthy\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"line\" /> <y:Arrows source=\"none\" target=\"standard\" /> <y:EdgeLabel>Reset</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> <edge id=\"ErrorOccured9\" source=\"Error\" target=\"Error\"> <data key=\"d10\"> <y:PolyLineEdge> <y:LineStyle type=\"dashed\" /> <y:Arrows source=\"none\" target=\"plain\" /> <y:EdgeLabel>ErrorOccured</y:EdgeLabel> </y:PolyLineEdge> </data> </edge> </graph> <data key=\"d0\"> <y:Resources /> </data></graphml>"; var cleanedReport = report.Replace("\n", string.Empty).Replace("\r", string.Empty); cleanedReport.Should().Be(ExpectedReport.Replace("\n", string.Empty).Replace("\r", string.Empty)); }
public Robot() { #region State machine definition StateMachine.In(State.NotInitialized) .On(Triggers.InitializationStarts).Goto(State.Initializing); StateMachine.In(State.Initializing) .On(Triggers.InitializationEnds).Goto(State.PowerOn); StateMachine.In(State.PowerOn) .On(Triggers.ExecutionStarts).Goto(State.Processing); StateMachine.In(State.Processing) .On(Triggers.ExecutionEnds).Goto(State.PowerOn); StateMachine.In(State.AxesIdle) .On(Triggers.AxesBusy).Goto(State.AxesMoving); StateMachine.In(State.AxesMoving) .On(Triggers.AxesStop).Goto(State.AxesIdle); StateMachine.In(State.PowerOn) .On(Triggers.PowerOff).Goto(State.PoweringOff); StateMachine.In(State.PowerOff) .On(Triggers.PowerOn).Goto(State.PoweringOn); StateMachine.In(State.PoweringOff) .On(Triggers.PowerOffReady).Goto(State.PowerOff); StateMachine.In(State.PoweringOn) .On(Triggers.PowerOnReady).Goto(State.PowerOn); StateMachine.In(State.Error) .On(Triggers.InitializationStarts).Goto(State.Initializing); StateMachine.In(State.Ready) .On(Triggers.Error).Goto(State.Error); StateMachine.In(State.Down) .On(Triggers.Error).Goto(State.Error); StateMachine.In(State.Idle) .On(Triggers.Deinitialize).Goto(State.NotInitialized); StateMachine.DefineHierarchyOn(State.Processing) .WithHistoryType(HistoryType.None) .WithInitialSubState(State.AxesMoving) .WithSubState(State.AxesIdle); StateMachine.DefineHierarchyOn(State.Idle) .WithHistoryType(HistoryType.None) .WithInitialSubState(State.PowerOn) .WithSubState(State.PowerOff) .WithSubState(State.PoweringOff) .WithSubState(State.PoweringOn); StateMachine.DefineHierarchyOn(State.Ready) .WithHistoryType(HistoryType.Deep) .WithInitialSubState(State.Idle) .WithSubState(State.Processing); StateMachine.DefineHierarchyOn(State.Down) .WithHistoryType(HistoryType.None) .WithInitialSubState(State.NotInitialized) .WithSubState(State.Initializing) .WithSubState(State.Error); StateMachine.Initialize(State.NotInitialized); StateMachine.Start(); StateMachine.TransitionCompleted += MyStateMachine_TransitionCompleted; using (Stream stream = File.Open("StateDiagram.graphml", FileMode.Create, FileAccess.Write, FileShare.Read)) using (TextWriter writer = new StreamWriter(stream)) { var generator = new YEdStateMachineReportGenerator <State, Triggers>(writer); StateMachine.Report(generator); } StateMachine.Report(customReporter); }