public void CachesTheApiResultsInMemorySoTheApiIsNotCalledTwiceForTheSameProjects( NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); var idCount = actualProjectIds.Length; if (idCount < 2) { return; } var dbProjectCount = (int)Math.Floor((float)idCount / 2); var apiProjectCount = idCount - dbProjectCount; var projectsInDb = actualProjectIds.Take(dbProjectCount).ToArray(); var projectsInApi = actualProjectIds.TakeLast(apiProjectCount).ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(projectsInDb, projectsInApi); configureApiToReturn(projectsInApi); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ProjectsApi.Received(1) .Search(workspaceId, Arg.Is <long[]>( calledIds => ensureExpectedIdsAreReturned(calledIds, projectsInApi))); }
public async Task ReturnsSegmentsJustOnceWhenChangingDateRange() { var segments = new ChartSegment[2] { new ChartSegment("Project 1", "Client 1", 50f, 10, 0, "ff0000"), new ChartSegment("Project 2", "Client 2", 50f, 10, 0, "00ff00") }; var projectsNotSyncedCount = 0; var currentDate = new DateTimeOffset(2018, 5, 23, 0, 0, 0, TimeSpan.Zero); var start = new DateTimeOffset(2018, 5, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2018, 5, 7, 0, 0, 0, TimeSpan.Zero); TimeService.CurrentDateTime.Returns(currentDate); var delayed = Observable .Return(new ProjectSummaryReport(segments, projectsNotSyncedCount)) .Delay(TimeSpan.FromMilliseconds(100)); var instant = Observable .Return(new ProjectSummaryReport(segments, projectsNotSyncedCount)); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(delayed, instant); await Initialize(); ViewModel.ChangeDateRangeCommand.Execute( ReportsDateRangeParameter.WithDates(start, end)); await delayed; ViewModel.Segments.Count.Should().Be(segments.Length); }
public async Task IsSetToTrueWhenAReportIsLoading() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Never <ProjectSummaryReport>()); await Initialize(); ViewModel.IsLoading.Should().BeTrue(); }
public async Task IsSetToFalseWhenLoadingIsCompleted() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0]))); ViewModel.Prepare(WorkspaceId); await ViewModel.Initialize(); ViewModel.IsLoading.Should().BeFalse(); }
public async Task IsSetToFalseWhenLoadingOverBecauseOfAnError() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Throw <ProjectSummaryReport>(new Exception())); ViewModel.Prepare(WorkspaceId); await ViewModel.Initialize(); ViewModel.IsLoading.Should().BeFalse(); }
public void DoesNotCallTheApiIfAllProjectsAreInTheDatabase(NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ProjectsApi.DidNotReceive().Search(Arg.Any <long>(), Arg.Any <long[]>()); }
public async Task IsSetToTrueWhenAReportIsLoading() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Never <ProjectSummaryReport>()); await Initialize(); TestScheduler.Start(); isLoadingObserver.Messages.Last().Value.Value.Should().BeTrue(); }
public void QueriesTheDatabaseForFindingProjects(NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ProjectsRepository.Received() .GetById(Arg.Is <long>(id => Array.IndexOf(actualProjectIds, id) >= 0)); }
public async Task IsSetToFalseWhenLoadingIsCompleted() { var now = DateTimeOffset.Now; var projectsNotSyncedCount = 0; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0], projectsNotSyncedCount))); await Initialize(); TestScheduler.Start(); isLoadingObserver.Messages.Last().Value.Value.Should().BeFalse(); }
public void CreatesAChartSegmentWithNoProjectIfThereAreNullProjectIdsAmongTheApiResults( NonNegativeInt[] projectIds) { var actualProjectIds = projectIds.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); summaries.Add(new ProjectSummary()); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); var report = ReportsProvider .GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); report.Segments.Single(s => s.Color == Color.NoProject).ProjectName.Should().Be(Resources.NoProject); }
public void IsSetToNullIfTheTotalTimeOfAReportIsZero(DateTimeOffset now) { var date = now.Date; var projectsNotSyncedCount = 0; TimeService.CurrentDateTime.Returns(now); var expectedStartDate = date.AddDays(1 - (int)date.DayOfWeek); ReportsProvider.GetProjectSummary( WorkspaceId, expectedStartDate, expectedStartDate.AddDays(6)) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0], projectsNotSyncedCount))); ViewModel.Initialize().Wait(); ViewModel.BillablePercentage.Should().BeNull(); }
public async Task IsSetToTrueWhenAReportIsLoading() { var loadingObserver = TestScheduler.CreateObserver <bool>(); var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Never <ProjectSummaryReport>()); ViewModel.IsLoadingObservable.Subscribe(loadingObserver); await Initialize(); TestScheduler.Start(); var isLoading = loadingObserver.Values().Last(); isLoading.Should().BeTrue(); }
public async Task ShouldTriggerReloadForEveryAppearance(int numberOfAppearances) { TimeService.CurrentDateTime.Returns(DateTimeOffset.Now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .ReturnsForAnyArgs(Observable.Empty <ProjectSummaryReport>(SchedulerProvider.TestScheduler)); await ViewModel.Initialize(); ViewModel.ViewAppeared(); // First call is skipped for (int i = 0; i < numberOfAppearances; ++i) { ViewModel.ViewAppeared(); } TestScheduler.Start(); ReportsProvider.Received(numberOfAppearances).GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()); }
public void IsSetToNullIfTheTotalTimeOfAReportIsZero() { var billableObserver = TestScheduler.CreateObserver <float?>(); var projectsNotSyncedCount = 0; TimeService.CurrentDateTime.Returns(DateTime.Now); TimeService.MidnightObservable.Returns(Observable.Never <DateTimeOffset>()); ReportsProvider .GetProjectSummary(WorkspaceId, Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0], projectsNotSyncedCount))); ViewModel.BillablePercentageObservable.Subscribe(billableObserver); Initialize().Wait(); TestScheduler.Start(); var billablePercentage = billableObserver.Values().Last(); billablePercentage.Should().BeNull(); }
public void ReturnsTheProjectOrderedByTotalTimeTracked(NonNegativeInt[] projectIds) { var actualProjectIds = projectIds.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); summaries.Add(new ProjectSummary()); var summaryCount = summaries.Count; for (int i = 0; i < summaryCount; i++) { var summary = (ProjectSummary)summaries[i]; summary.TrackedSeconds = i; } apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); var report = ReportsProvider .GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); report.Segments.Should().BeInDescendingOrder(s => s.Percentage); }
public void ReturnsOnlyOneListIfItQueriesTheApi(NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); if (actualProjectIds.Length < 2) { return; } var projectsInDb = actualProjectIds.Where((i, id) => i % 2 == 0).ToArray(); var projectsInApi = actualProjectIds.Where((i, id) => i % 2 != 0).ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(projectsInDb, projectsInApi); configureApiToReturn(projectsInApi); var lists = ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).ToList().Wait(); lists.Should().HaveCount(1); }
public async Task SetsOtherProjectWithOneSegmentToThatSegmentButWithOnePercentIfLessThanOnePercent() { ChartSegment[] segments = { new ChartSegment("Project 1", "Client 1", 0.2f, 2, 0, "#666666"), new ChartSegment("Project 2", "Client 2", 8.8f, 4, 0, "#ffffff"), new ChartSegment("Project 3", "Client 3", 12, 12, 0, "#ffffff"), new ChartSegment("Project 4", "Client 4", 23, 23, 0, "#ffffff"), new ChartSegment("Project 5", "Client 5", 56, 56, 0, "#ffffff") }; TimeService.CurrentDateTime.Returns(new DateTimeOffset(2018, 05, 15, 12, 00, 00, TimeSpan.Zero)); ReportsProvider.GetProjectSummary(WorkspaceId, Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(segments, projectsNotSyncedCount))); var segmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); var groupedSegmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); ViewModel.SegmentsObservable.Subscribe(segmentsObservable); ViewModel.GroupedSegmentsObservable.Subscribe(groupedSegmentsObservable); TestScheduler.Start(); await Initialize(); var actualSegments = segmentsObservable.Values().Last(); var actualGroupedSegments = groupedSegmentsObservable.Values().Last(); actualSegments.Should().HaveCount(5); actualGroupedSegments.Should().HaveCount(5); actualGroupedSegments.Should().Contain(segment => segment.ProjectName == "Project 1" && segment.Percentage == 1f && segment.Color == "#666666"); actualGroupedSegments .Where(project => project.ProjectName != "Project 1") .Select(segment => segment.Percentage) .ForEach(percentage => percentage.Should().BeGreaterOrEqualTo(5)); }
public async Task GroupsProjectSegmentsWithPercentageBetweenOneAndFiveIntoOtherIfTotalOfOtherLessThanFivePercent() { ChartSegment[] segments = { new ChartSegment("Project 1", "Client 1", 0.9f, 2, 0, "#ffffff"), new ChartSegment("Project 2", "Client 2", 0.9f, 3, 0, "#ffffff"), new ChartSegment("Project 3", "Client 3", 2.5f, 4, 0, "#ffffff"), new ChartSegment("Project 4", "Client 4", 4, 12, 0, "#ffffff"), new ChartSegment("Project 5", "Client 5", 31.7f, 23, 0, "#ffffff"), new ChartSegment("Project 6", "Client 6", 60, 56, 0, "#ffffff") }; TimeService.CurrentDateTime.Returns(new DateTimeOffset(2018, 05, 15, 12, 00, 00, TimeSpan.Zero)); ReportsProvider.GetProjectSummary(WorkspaceId, Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(segments, projectsNotSyncedCount))); var segmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); var groupedSegmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); ViewModel.SegmentsObservable.Subscribe(segmentsObservable); ViewModel.GroupedSegmentsObservable.Subscribe(groupedSegmentsObservable); TestScheduler.Start(); await Initialize(); var actualSegments = segmentsObservable.Values().Last(); var actualGroupedSegments = groupedSegmentsObservable.Values().Last(); actualSegments.Should().HaveCount(6); actualGroupedSegments.Should().HaveCount(4); actualGroupedSegments.Should().Contain(segment => segment.ProjectName == Resources.Other && segment.Percentage == segments[0].Percentage + segments[1].Percentage + segments[2].Percentage); actualGroupedSegments .Where(project => project.ProjectName != Resources.Other) .Select(segment => segment.Percentage) .ForEach(percentage => percentage.Should().BeGreaterOrEqualTo(4)); }
public async Task TracksAnEventWhenReportFailsToLoad() { var startDateRange = new DateTimeOffset(2018, 05, 05, 0, 0, 0, TimeSpan.Zero); var endDateRange = startDateRange.AddDays(7); var totalDays = (int)(endDateRange - startDateRange).TotalDays; var loadingDuration = TimeSpan.FromSeconds(5); var now = new DateTimeOffset(2018, 01, 01, 0, 0, 0, TimeSpan.Zero); TimeService.CurrentDateTime.Returns(_ => { now = now + loadingDuration; return(now); }); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Throw <ProjectSummaryReport>(new Exception())); await Initialize(); AnalyticsService.Received().ReportsFailure.Track(ReportsSource.Initial, totalDays, loadingDuration.TotalMilliseconds); }
public async Task TracksAnEventWhenReportLoadsSuccessfully() { var startDateRange = new DateTimeOffset(2018, 05, 05, 0, 0, 0, TimeSpan.Zero); var endDateRange = startDateRange.AddDays(7); var totalDays = (int)(endDateRange - startDateRange).TotalDays; var projectsNotSyncedCount = 0; var loadingDuration = TimeSpan.FromSeconds(5); var now = new DateTimeOffset(2018, 01, 01, 0, 0, 0, TimeSpan.Zero); TimeService.CurrentDateTime.Returns(_ => { now = now + loadingDuration; return(now); }); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0], projectsNotSyncedCount))); await Initialize(); AnalyticsService.Received().ReportsSuccess.Track(ReportsSource.Initial, totalDays, projectsNotSyncedCount, loadingDuration.TotalMilliseconds); }
public void QueriesTheApiIfAnyProjectIsNotFoundInTheDatabase(NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); if (actualProjectIds.Length < 2) { return; } var projectsInDb = actualProjectIds.Where((id, i) => i % 2 == 0).ToArray(); var projectsInApi = actualProjectIds.Where((id, i) => i % 2 != 0).ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(projectsInDb, projectsInApi); configureApiToReturn(projectsInApi); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ProjectsApi.Received() .Search(workspaceId, Arg.Is <long[]>( calledIds => ensureExpectedIdsAreReturned(calledIds, projectsInApi))); }