private async Task TestTotalOvers(StatisticsFilter filter, string whereClause, Dictionary <string, object> parameters, IEnumerable <Stoolball.Matches.Match> matches)
        {
            var oversHelper = new OversHelper();

            foreach (var player in _databaseFixture.TestData.Players)
            {
                filter.Player = player;
                parameters.Remove("PlayerId");
                parameters.Add("PlayerId", player.PlayerId);
                var queryBuilder = new Mock <IStatisticsQueryBuilder>();
                queryBuilder.Setup(x => x.BuildWhereClause(filter)).Returns((" AND PlayerId = @PlayerId" + whereClause, parameters));
                var dataSource = new SqlServerPlayerSummaryStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object);

                var result = await dataSource.ReadBowlingStatistics(filter).ConfigureAwait(false);

                var ballsBowled = matches.SelectMany(x => x.MatchInnings)
                                  .SelectMany(x => x.BowlingFigures.Where(o => o.Bowler.Player.PlayerId == player.PlayerId && o.Overs.HasValue))
                                  .Sum(o => oversHelper.OversToBallsBowled(o.Overs.Value));

                Assert.NotNull(result);
                Assert.Equal(oversHelper.BallsBowledToOvers(ballsBowled), result.TotalOvers);
            }
        }
        private async Task ActAndAssertStatistics(StatisticsFilter filter, SqlServerBestPlayerAverageStatisticsDataSource dataSource, Func <Stoolball.Matches.Match, bool> matchFilter, Func <MatchInnings, bool> battingInningsFilter, Func <MatchInnings, bool> bowlingInningsFilter)
        {
            var oversHelper = new OversHelper();

            var results = await dataSource.ReadBestBowlingStrikeRate(filter).ConfigureAwait(false);

            var expected = _databaseFixture.TestData.Players.Select(p => new BestStatistic
            {
                Player       = p,
                TotalMatches = (int)_databaseFixture.TestData.Matches
                               .Where(matchFilter)
                               .Count(m => m.MatchInnings.Where(battingInningsFilter).Any(mi => mi.PlayerInnings.Any(pi => pi.Batter.Player.PlayerId == p.PlayerId)) ||
                                      m.MatchInnings.Where(bowlingInningsFilter).Any(mi =>
                                                                                     mi.PlayerInnings.Any(pi => pi.DismissedBy?.Player.PlayerId == p.PlayerId || pi.Bowler?.Player.PlayerId == p.PlayerId) ||
                                                                                     mi.OversBowled.Any(o => o.Bowler.Player.PlayerId == p.PlayerId) ||
                                                                                     mi.BowlingFigures.Any(bf => bf.Bowler.Player.PlayerId == p.PlayerId)
                                                                                     ) ||
                                      m.Awards.Any(aw => aw.PlayerIdentity.Player.PlayerId == p.PlayerId)),
                TotalInnings = (int)_databaseFixture.TestData.Matches
                               .Where(matchFilter)
                               .SelectMany(m => m.MatchInnings)
                               .Where(bowlingInningsFilter)
                               .SelectMany(mi => mi.BowlingFigures)
                               .Count(pi => pi.Bowler.Player.PlayerId == p.PlayerId && pi.Overs.HasValue),
                Average = (_databaseFixture.TestData.Matches
                           .Where(matchFilter)
                           .SelectMany(m => m.MatchInnings)
                           .Where(bowlingInningsFilter)
                           .SelectMany(mi => mi.BowlingFigures)
                           .Any(bf => bf.Bowler.Player.PlayerId == p.PlayerId && bf.Wickets > 0 && bf.Overs.HasValue) ?
                           ((decimal)_databaseFixture.TestData.Matches
                            .Where(matchFilter)
                            .SelectMany(m => m.MatchInnings)
                            .Where(bowlingInningsFilter)
                            .SelectMany(mi => mi.BowlingFigures)
                            .Where(bf => bf.Bowler.Player.PlayerId == p.PlayerId && bf.Overs.HasValue)
                            .Sum(bf => oversHelper.OversToBallsBowled(bf.Overs.Value)))
                           /
                           _databaseFixture.TestData.Matches
                           .Where(matchFilter)
                           .SelectMany(m => m.MatchInnings)
                           .Where(bowlingInningsFilter)
                           .SelectMany(mi => mi.BowlingFigures)
                           .Where(bf => bf.Bowler.Player.PlayerId == p.PlayerId && bf.Overs.HasValue)
                           .Sum(bf => bf.Wickets)
                            : (decimal?)null)
            }).Where(x => x.Average.HasValue);

            foreach (var player in expected)
            {
                var result = results.SingleOrDefault(x => x.Result.Player.PlayerId == player.Player.PlayerId);
                Assert.NotNull(result);

                Assert.Equal(player.TotalMatches, result.Result.TotalMatches);
                Assert.Equal(player.TotalInnings, result.Result.TotalInnings);
                if (player.Average.HasValue)
                {
                    Assert.Equal(player.Average.Value.AccurateToTwoDecimalPlaces(), result.Result.Average.Value.AccurateToTwoDecimalPlaces());
                }
                else
                {
                    Assert.Null(result.Result.Average);
                }
            }
        }
        private async Task TestStrikeRate(StatisticsFilter filter, string whereClause, Dictionary <string, object> parameters, IEnumerable <Stoolball.Matches.Match> matches)
        {
            var oversHelper = new OversHelper();

            foreach (var player in _databaseFixture.TestData.Players)
            {
                filter.Player = player;
                parameters.Remove("PlayerId");
                parameters.Add("PlayerId", player.PlayerId);
                var queryBuilder = new Mock <IStatisticsQueryBuilder>();
                queryBuilder.Setup(x => x.BuildWhereClause(filter)).Returns((" AND PlayerId = @PlayerId" + whereClause, parameters));
                var dataSource = new SqlServerPlayerSummaryStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object);

                var result = await dataSource.ReadBowlingStatistics(filter).ConfigureAwait(false);

                var dataForStrikeRate = matches.SelectMany(x => x.MatchInnings)
                                        .SelectMany(x => x.BowlingFigures.Where(o => o.Bowler.Player.PlayerId == player.PlayerId && o.Overs.HasValue));
                var expectedStrikeRate = dataForStrikeRate.Sum(x => x.Wickets) > 0 ? (decimal)dataForStrikeRate.Sum(x => oversHelper.OversToBallsBowled(x.Overs.Value)) / dataForStrikeRate.Sum(x => x.Wickets) : (decimal?)null;

                Assert.NotNull(result);
                if (expectedStrikeRate.HasValue)
                {
                    Assert.NotNull(result.StrikeRate);
                    Assert.Equal(expectedStrikeRate.Value.AccurateToTwoDecimalPlaces(), result.StrikeRate.Value.AccurateToTwoDecimalPlaces());
                }
                else
                {
                    Assert.Null(result.StrikeRate);
                }
            }
        }