public void Test()
        {
            var a1 = Helpers.BuildActivity();
            var a2 = Helpers.BuildActivity();
            var a3 = Helpers.BuildActivity();
            var a4 = Helpers.BuildActivity();
            var a5 = Helpers.BuildActivity();
            var c1 = new SequenceBlock(new[] {a1});
            var f = new ForkBlock(a2, 1);
            var p = new ParallelBlock(new[] {a4, a5}, 1);
            var c2 = new SequenceBlock(new WorkflowBlock[] {f, c1, a3, p});

            var navigator = new WorkflowPathNavigator(c2);

            Assert.Equal("Sequence[0].Sequence[1].Activity[0]", navigator.Path(a1));
            Assert.Equal("Sequence[0].Fork[0].Activity[0]", navigator.Path(a2));
            Assert.Equal("Sequence[0].Activity[2]", navigator.Path(a3));
            Assert.Equal("Sequence[0].Sequence[1]", navigator.Path(c1));
            Assert.Equal("Sequence[0].Fork[0]", navigator.Path(f));
            Assert.Equal("Sequence[0]", navigator.Path(c2));
            Assert.Equal("Sequence[0].Parallel[3]", navigator.Path(p));
            Assert.Equal("Sequence[0].Parallel[3].Activity[0]", navigator.Path(a4));
            Assert.Equal("Sequence[0].Parallel[3].Activity[1]", navigator.Path(a5));

            Assert.Equal(a1, navigator.Find("Sequence[0].Sequence[1].Activity[0]"));
            Assert.Equal(a2, navigator.Find("Sequence[0].Fork[0].Activity[0]"));
            Assert.Equal(a3, navigator.Find("Sequence[0].Activity[2]"));
            Assert.Equal(c1, navigator.Find("Sequence[0].Sequence[1]"));
            Assert.Equal(f, navigator.Find("Sequence[0].Fork[0]"));
            Assert.Equal(c2, navigator.Find("Sequence[0]"));

            Assert.Equal(p, navigator.Find("Sequence[0].Parallel[3]"));
            Assert.Equal(a4, navigator.Find("Sequence[0].Parallel[3].Activity[0]"));
            Assert.Equal(a5, navigator.Find("Sequence[0].Parallel[3].Activity[1]"));
        }
        public async Task TestSequence()
        {
            Func<int, int> increment = x => x + 1;

            var a1 = new ActivityBlock(increment);
            var a2 = new ActivityBlock(increment);

            var seq = new SequenceBlock(new[] {a1, a2});

            var workflow = new Workflow<int, int>("test", seq);

            var output = await WorkflowRunner.Run(workflow, 0);

            Assert.Equal(2, output);
        }
        public void SequenceConstruction()
        {
            Func<string, int> parse = int.Parse;
            Func<int, string> stringify = x => x.ToString();

            var seq = new SequenceBlock(new[] {new ActivityBlock(parse), new ActivityBlock(stringify)});

            Assert.Equal(WorkflowType.Sequence, seq.Type);
            Assert.Equal(new[] {typeof (string)}, seq.InputTypes);
            Assert.Equal(typeof (string), seq.OutputType);

            // test method with signature void(void)
            seq = new SequenceBlock(new[] {new ActivityBlock(new Action(delegate { }))});
            Assert.Equal(new Type[0], seq.InputTypes);
            Assert.Equal(typeof (void), seq.OutputType);
        }
        public async Task TestVeryLongSequence()
        {
            Func<int, int> increment = x => x + 1;

            var steps = new List<ActivityBlock>();
            var count = 1000;
            for (var i = 0; i < count; i++)
            {
                steps.Add(new ActivityBlock(increment));
            }

            var seq = new SequenceBlock(steps);

            var workflow = new Workflow<int, int>("test", seq);

            var output = await WorkflowRunner.Run(workflow, 0);

            Assert.Equal(count, output);
        }
        public async Task TestExceptionPropagation()
        {
            Func<int, int> increment = x => x + 1;
            Func<int, int> divide = x => 1/x;

            var a1 = new ActivityBlock(increment);
            var a2 = new ActivityBlock(divide);

            var seq = new SequenceBlock(new[] {new SequenceBlock(new[] {a1, a2})})
            {
                ExceptionHandler = (Func<Exception, int>) (_ => -1)
            };

            var workflow = new Workflow<int, int>("test", seq);

            var output = await WorkflowRunner.Run(workflow, -1);

            Assert.Equal(-1, output);
        }
        public async Task TestIntegration4()
        {
            Func<string, Task<string[]>> split = str => Task.FromResult(str.Split(','));
            Func<string, Task<int>> parse = i => Task.FromResult(int.Parse(i));
            Func<int, Task<User>> load = id => Task.FromResult(new User {Id = id});
            Func<int, Task<string>> name = id => Task.FromResult("n" + id);
            Func<User, string, Task<User>> projection = async (user, s) =>
            {
                await Task.Delay(100);
                user.Name = s;
                return user;
            };

            var root = new SequenceBlock(new WorkflowBlock[]
            {
                new ActivityBlock(split),
                new ForkBlock(
                    new SequenceBlock(
                        new WorkflowBlock[]
                        {
                            new ActivityBlock(parse),
                            new ParallelBlock(new[]
                            {
                                new ActivityBlock(load),
                                new ActivityBlock(name)
                            }, 1),
                            new ActivityBlock(projection)
                        }), 1)
            });

            var workflow = new Workflow<string, IEnumerable<User>>("test", root);
            var output = await WorkflowRunner.Run(workflow, "1,2,3");

            Assert.Equal(
                new[] {new User {Id = 1, Name = "n1"}, new User {Id = 2, Name = "n2"}, new User {Id = 3, Name = "n3"}},
                output);
        }
        public async Task TestIntegration3()
        {
            Func<string, int> parse = int.Parse;
            Func<int, int, int> add = (x, y) => x + y;

            var root = new SequenceBlock(new WorkflowBlock[]
            {
                new ParallelBlock(new[] {new ActivityBlock(parse), new ActivityBlock(parse)}, 2),
                new ActivityBlock(add)
            });

            var workflow = new Workflow<string, int>("test", root);

            var output = await WorkflowRunner.Run(workflow, "1");

            Assert.Equal(2, output);
        }
        public async Task TestIntegration2()
        {
            Func<string, Task<string[]>> split = s => Task.FromResult(s.Split(','));
            Func<string, Task<int>> convert = s => Task.FromResult(int.Parse(s));
            Func<int[], Task<int>> sum = nums => Task.FromResult(nums.Sum());

            var root = new SequenceBlock(new WorkflowBlock[]
            {
                new ActivityBlock(split),
                new ForkBlock(new ActivityBlock(convert), 2),
                new ActivityBlock(sum)
            });

            var workflow = new Workflow<string, int>("test", root);
            var output = await WorkflowRunner.Run(workflow, "1,2,3,4,5,6,7,8,9,10");

            Assert.Equal(55, output);
        }
        public async Task TestIntegration1()
        {
            Func<string, string[]> split = s => s.Split(',');
            Func<string, int> parse = int.Parse;
            Func<int[], int> sum = nums => nums.Sum();

            var root = new SequenceBlock(new WorkflowBlock[]
            {
                new ActivityBlock(split),
                new ForkBlock(new ActivityBlock(parse), 2),
                new ActivityBlock(sum)
            });

            var workflow = new Workflow<string, int>("test", root);
            var output = await WorkflowRunner.Run(workflow, "1,2,3,4,5,6,7,8,9,10");

            Assert.Equal(55, output);
        }
        public void SequenceChildren()
        {
            var a1 = Helpers.BuildActivity();
            var a2 = Helpers.BuildActivity();
            var c = new SequenceBlock(new[] {a1, a2});

            var wi = new WorkItem(Helpers.Integer(), Helpers.Integer(), 0, WorkflowType.Sequence, Helpers.String());
            wi.Id = Helpers.Integer();
            wi.InputId = Helpers.Integer();

            _navigator.Find(wi.WorkflowPath).Returns(c);

            var items = _workItemBuilder.BuildChildren(wi).ToArray();
            var item1 = items.First();
            var item2 = items.Last();

            Assert.Equal(2, items.Count());

            Assert.Equal(wi.JobId, item1.JobId);
            Assert.Equal(wi.Id, item1.ParentId);
            Assert.Equal(0, item1.Order);
            Assert.Equal(wi.InputId, item1.InputId);
            Assert.Equal(WorkflowType.Activity, item1.Type);

            Assert.Equal(wi.JobId, item2.JobId);
            Assert.Equal(wi.Id, item2.ParentId);
            Assert.Equal(1, item2.Order);
            Assert.Null(item2.InputId);
            Assert.Equal(WorkflowType.Activity, item2.Type);
        }