public async Task Read_most_runs_scored_pages_results()
        {
            const int pageSize   = 10;
            var       pageNumber = 1;

            var remaining = _databaseFixture.TestData.Matches
                            .SelectMany(x => x.MatchInnings)
                            .SelectMany(x => x.PlayerInnings)
                            .Where(x => x.RunsScored.HasValue)
                            .Select(x => x.Batter.Player.PlayerId)
                            .Distinct()
                            .Count();

            while (remaining > 0)
            {
                var filter = new StatisticsFilter {
                    Paging = new Paging {
                        PageNumber = pageNumber, PageSize = pageSize
                    }
                };
                var queryBuilder = new Mock <IStatisticsQueryBuilder>();
                queryBuilder.Setup(x => x.BuildWhereClause(It.IsAny <StatisticsFilter>())).Returns((string.Empty, new Dictionary <string, object>()));
                var playerDataSource = new Mock <IPlayerDataSource>();
                playerDataSource.Setup(x => x.ReadPlayers(It.IsAny <PlayerFilter>())).Returns(Task.FromResult(_databaseFixture.TestData.Players));
                var dataSource = new SqlServerBestPlayerTotalStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object, playerDataSource.Object);
                var results    = await dataSource.ReadMostRunsScored(filter).ConfigureAwait(false);

                var expected = pageSize > remaining ? remaining : pageSize;
                Assert.Equal(expected, results.Count());

                pageNumber++;
                remaining -= pageSize;
            }
        }
        public async Task Read_most_runs_returns_results_equal_to_max_with_max_results_filter()
        {
            var filter = new StatisticsFilter {
                Paging = new Paging {
                    PageSize = int.MaxValue
                }, MaxResultsAllowingExtraResultsIfValuesAreEqual = 5
            };
            var queryBuilder = new Mock <IStatisticsQueryBuilder>();

            queryBuilder.Setup(x => x.BuildWhereClause(It.IsAny <StatisticsFilter>())).Returns((string.Empty, new Dictionary <string, object>()));
            var playerDataSource = new Mock <IPlayerDataSource>();

            playerDataSource.Setup(x => x.ReadPlayers(It.IsAny <PlayerFilter>())).Returns(Task.FromResult(_databaseFixture.TestData.Players));
            var dataSource = new SqlServerBestPlayerTotalStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object, playerDataSource.Object);

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

            // The test data is altered to ensure the 5th and 6th results are the same
            Assert.True(results.Count > 5);

            var fifthValue = results[4].Result.Total;

            for (var i = 4; i < results.Count; i++)
            {
                Assert.Equal(fifthValue, results[i].Result.Total);
            }
        }
        public async Task Read_most_runs_sorts_by_highest_total_first()
        {
            var filter = new StatisticsFilter {
                Paging = new Paging {
                    PageSize = int.MaxValue
                }
            };
            var queryBuilder = new Mock <IStatisticsQueryBuilder>();

            queryBuilder.Setup(x => x.BuildWhereClause(It.IsAny <StatisticsFilter>())).Returns((string.Empty, new Dictionary <string, object>()));
            var playerDataSource = new Mock <IPlayerDataSource>();

            playerDataSource.Setup(x => x.ReadPlayers(It.IsAny <PlayerFilter>())).Returns(Task.FromResult(_databaseFixture.TestData.Players));
            var dataSource = new SqlServerBestPlayerTotalStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object, playerDataSource.Object);

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

            var previousTotal = int.MaxValue;

            foreach (var result in results)
            {
                Assert.True(result.Result.Total <= previousTotal);
                previousTotal = result.Result.Total.Value;
            }
        }
        public async Task Read_most_runs_scored_supports_filter_by_season_id()
        {
            var filter = new StatisticsFilter
            {
                Paging = new Paging
                {
                    PageSize = int.MaxValue
                },
                Season = _databaseFixture.TestData.Competitions.First().Seasons.First()
            };
            var queryBuilder = new Mock <IStatisticsQueryBuilder>();

            queryBuilder.Setup(x => x.BuildWhereClause(It.IsAny <StatisticsFilter>())).Returns((" AND SeasonId = @SeasonId", new Dictionary <string, object> {
                { "SeasonId", _databaseFixture.TestData.Competitions.First().Seasons.First().SeasonId }
            }));
            var playerDataSource = new Mock <IPlayerDataSource>();

            playerDataSource.Setup(x => x.ReadPlayers(It.IsAny <PlayerFilter>())).Returns(Task.FromResult(_databaseFixture.TestData.Players));
            var dataSource = new SqlServerBestPlayerTotalStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object, playerDataSource.Object);

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

            var expected = _databaseFixture.TestData.Players.Where(x => _databaseFixture.TestData.Matches
                                                                   .Where(x => x.Season?.SeasonId == _databaseFixture.TestData.Competitions.First().Seasons.First().SeasonId)
                                                                   .SelectMany(m => m.MatchInnings)
                                                                   .SelectMany(mi => mi.PlayerInnings)
                                                                   .Any(pi => pi.Batter.Player.PlayerId == x.PlayerId && pi.RunsScored.HasValue));

            Assert.Equal(expected.Count(), results.Count());
            foreach (var player in expected)
            {
                Assert.NotNull(results.SingleOrDefault(x => x.Result.Player.PlayerId == player.PlayerId));
            }
        }
        public async Task Read_most_runs_scored_returns_teams()
        {
            var filter = new StatisticsFilter {
                Paging = new Paging {
                    PageSize = int.MaxValue
                }
            };
            var queryBuilder = new Mock <IStatisticsQueryBuilder>();

            queryBuilder.Setup(x => x.BuildWhereClause(It.IsAny <StatisticsFilter>())).Returns((string.Empty, new Dictionary <string, object>()));
            var playerDataSource = new Mock <IPlayerDataSource>();

            playerDataSource.Setup(x => x.ReadPlayers(It.IsAny <PlayerFilter>())).Returns(Task.FromResult(_databaseFixture.TestData.Players));
            var dataSource = new SqlServerBestPlayerTotalStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object, playerDataSource.Object);

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

            var expected = _databaseFixture.TestData.Players.Where(x => _databaseFixture.TestData.Matches
                                                                   .SelectMany(m => m.MatchInnings)
                                                                   .SelectMany(mi => mi.PlayerInnings)
                                                                   .Any(pi => pi.Batter.Player.PlayerId == x.PlayerId && pi.RunsScored.HasValue));

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

                foreach (var identity in player.PlayerIdentities)
                {
                    var resultIdentity = result.Result.Player.PlayerIdentities.SingleOrDefault(x => x.PlayerIdentityId == identity.PlayerIdentityId);
                    Assert.NotNull(resultIdentity);
                    Assert.Equal(identity.Team.TeamName, resultIdentity.Team.TeamName);
                }
            }
        }
        public async Task Read_most_runs_scored_supports_no_filter()
        {
            var queryBuilder = new Mock <IStatisticsQueryBuilder>();

            queryBuilder.Setup(x => x.BuildWhereClause(It.IsAny <StatisticsFilter>())).Returns((string.Empty, new Dictionary <string, object>()));
            var playerDataSource = new Mock <IPlayerDataSource>();

            playerDataSource.Setup(x => x.ReadPlayers(It.IsAny <PlayerFilter>())).Returns(Task.FromResult(_databaseFixture.TestData.Players));
            var dataSource = new SqlServerBestPlayerTotalStatisticsDataSource(_databaseFixture.ConnectionFactory, queryBuilder.Object, playerDataSource.Object);

            var results = await dataSource.ReadMostRunsScored(null).ConfigureAwait(false);

            var expected = _databaseFixture.TestData.Players.Where(x => _databaseFixture.TestData.Matches
                                                                   .SelectMany(m => m.MatchInnings)
                                                                   .SelectMany(mi => mi.PlayerInnings)
                                                                   .Any(pi => pi.Batter.Player.PlayerId == x.PlayerId && pi.RunsScored.HasValue));

            Assert.Equal(expected.Count(), results.Count());
            foreach (var player in expected)
            {
                Assert.NotNull(results.SingleOrDefault(x => x.Result.Player.PlayerId == player.PlayerId));
            }
        }
        private async Task ActAndAssertStatistics(StatisticsFilter filter, SqlServerBestPlayerTotalStatisticsDataSource dataSource, Func <Stoolball.Matches.Match, bool> matchFilter, Func <MatchInnings, bool> matchInningsFilter)
        {
            var results = await dataSource.ReadMostRunsScored(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(matchInningsFilter).Any(mi =>
                                                                                        mi.PlayerInnings.Any(pi => pi.Batter.Player.PlayerId == p.PlayerId || 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(matchInningsFilter)
                               .SelectMany(mi => mi.PlayerInnings)
                               .Count(pi => pi.Batter.Player.PlayerId == p.PlayerId && pi.RunsScored.HasValue),
                Total = (int)_databaseFixture.TestData.Matches
                        .Where(matchFilter)
                        .SelectMany(m => m.MatchInnings)
                        .Where(matchInningsFilter)
                        .SelectMany(mi => mi.PlayerInnings)
                        .Where(pi => pi.Batter.Player.PlayerId == p.PlayerId && pi.RunsScored.HasValue)
                        .Sum(pi => pi.RunsScored),
                Average = (_databaseFixture.TestData.Matches
                           .Where(matchFilter)
                           .SelectMany(m => m.MatchInnings)
                           .Where(matchInningsFilter)
                           .SelectMany(mi => mi.PlayerInnings)
                           .Any(pi => pi.Batter.Player.PlayerId == p.PlayerId && StatisticsConstants.DISMISSALS_THAT_ARE_OUT.Contains(pi.DismissalType) && pi.RunsScored.HasValue) ?
                           ((decimal)_databaseFixture.TestData.Matches
                            .Where(matchFilter)
                            .SelectMany(m => m.MatchInnings)
                            .Where(matchInningsFilter)
                            .SelectMany(mi => mi.PlayerInnings)
                            .Where(pi => pi.Batter.Player.PlayerId == p.PlayerId && pi.RunsScored.HasValue)
                            .Sum(pi => pi.RunsScored))
                           /
                           _databaseFixture.TestData.Matches
                           .Where(matchFilter)
                           .SelectMany(m => m.MatchInnings)
                           .Where(matchInningsFilter)
                           .SelectMany(mi => mi.PlayerInnings)
                           .Count(pi => pi.Batter.Player.PlayerId == p.PlayerId && StatisticsConstants.DISMISSALS_THAT_ARE_OUT.Contains(pi.DismissalType) && pi.RunsScored.HasValue)
                            : (decimal?)null)
            }).Where(x => x.Total > 0);

            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);
                Assert.Equal(player.Total, result.Result.Total);
                if (player.Average.HasValue)
                {
                    Assert.Equal(player.Average.Value.AccurateToTwoDecimalPlaces(), result.Result.Average.Value.AccurateToTwoDecimalPlaces());
                }
                else
                {
                    Assert.Null(result.Result.Average);
                }
            }
        }