Пример #1
0
        public TogglDataSource(
            ITogglApi api,
            ITogglDatabase database,
            ITimeService timeService,
            Func <ITogglDataSource, ISyncManager> createSyncManager,
            IAnalyticsService analyticsService)
        {
            Ensure.Argument.IsNotNull(api, nameof(api));
            Ensure.Argument.IsNotNull(database, nameof(database));
            Ensure.Argument.IsNotNull(timeService, nameof(timeService));
            Ensure.Argument.IsNotNull(createSyncManager, nameof(createSyncManager));
            Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService));

            this.database = database;

            User              = new UserDataSource(database.User);
            Tags              = new TagsDataSource(database.Tags);
            Tasks             = new TasksDataSource(database.Tasks);
            Clients           = new ClientsDataSource(database.Clients);
            Projects          = new ProjectsDataSource(database.Projects);
            Workspaces        = new WorkspacesDataSource(database.Workspaces);
            Preferences       = new PreferencesDataSource(database.Preferences);
            WorkspaceFeatures = new WorkspaceFeaturesDataSource(database.WorkspaceFeatures);
            TimeEntries       = new TimeEntriesDataSource(database.TimeEntries, timeService, analyticsService);

            SyncManager = createSyncManager(this);

            ReportsProvider = new ReportsProvider(api, database);

            FeedbackApi = api.Feedback;
        }
Пример #2
0
            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);
            }
Пример #4
0
        public IActionResult Uber()
        {
            var dates = GetDates();

            ReportsProvider.StartReport(Reports.Uber, _amo, _processQueue, _gSheets, dates.Item1, dates.Item2);

            return(Ok("Requested."));
        }
Пример #5
0
        public static void RegisterAllServices(this SimpleServiceContainer store)
        {
            var repoFactory = new GenericRepositoryFactory(store, store);

            store.RegisterSingleton <IRepositoryFactory>(c => repoFactory);
            var reports = new ReportsProvider();

            store.RegisterSingleton <IReportsProvider>(reports);
            store.RegisterSingleton <IReportsStore>(reports);
            RegisterRepositories(repoFactory);
        }
Пример #6
0
            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();

                ViewModel.IsLoading.Should().BeTrue();
            }
Пример #8
0
            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();
            }
Пример #9
0
        [HttpGet("{from},{to}")]                                                                                                                //Запрашиваем отчёт для диапазона дат
        public IActionResult CorporateSales(string from, string to)
        {
            if (!long.TryParse(from, out long dateFrom) &
                !long.TryParse(to, out long dateTo))
            {
                return(BadRequest("Incorrect dates"));
            }

            ReportsProvider.StartReport(Reports.CorporateSales, _amo, _processQueue, _gSheets, dateFrom, dateTo);

            return(Ok("Requested."));
        }
Пример #10
0
            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();
            }
Пример #11
0
        public IActionResult Calls()
        {
            var  now      = DateTime.UtcNow.AddHours(3);
            var  to       = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0, DateTimeKind.Utc).AddHours(-3).AddSeconds(-1);
            var  from     = to.AddSeconds(1).AddDays(-1);
            long dateFrom = ((DateTimeOffset)from).ToUnixTimeSeconds();
            long dateTo   = ((DateTimeOffset)to).ToUnixTimeSeconds();

            ReportsProvider.StartReport(Reports.SuccessCalls, _amo, _processQueue, _gSheets, dateFrom, dateTo);

            return(Ok("Requested."));
        }
Пример #12
0
        [HttpGet("{to}")]                                                                                                                //Запрашиваем отчёт для диапазона дат
        public IActionResult CorporateSales(string to)
        {
            if (!long.TryParse(to, out long dateTo))
            {
                return(BadRequest("Incorrect dates"));
            }

            var dates = GetDates(dateTo);

            ReportsProvider.StartReport(Reports.CorporateSales, _amo, _processQueue, _gSheets, dates.Item1, dates.Item2);

            return(Ok("Requested."));
        }
            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();
            }
Пример #14
0
            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 ShouldNotTriggerAReportReloadWhenSelectionIsCancelled()
            {
                TimeService.CurrentDateTime.Returns(DateTimeOffset.Now);
                await ViewModel.Initialize();

                DialogService.Select(Arg.Any <string>(), Arg.Any <IEnumerable <(string, IThreadSafeWorkspace)> >(), Arg.Any <int>())
                .Returns(Observable.Return <IThreadSafeWorkspace>(null));

                ViewModel.SelectWorkspace.Execute();
                TestScheduler.Start();

                await ReportsProvider.DidNotReceive().GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(),
                                                                        Arg.Any <DateTimeOffset>());
            }
            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();
            }
Пример #17
0
            public void FiresACallToLoadReports(DateTimeOffset now)
            {
                var date = now.Date;

                TimeService.CurrentDateTime.Returns(now);
                var expectedStartDate = date.AddDays(1 - (int)date.DayOfWeek);

                ViewModel.Prepare(WorkspaceId);

                ViewModel.Initialize().Wait();

                ReportsProvider.Received().GetProjectSummary(
                    WorkspaceId, expectedStartDate, expectedStartDate.AddDays(6));
            }
Пример #18
0
        public TogglDataSource(
            ITogglApi api,
            ITogglDatabase database,
            ITimeService timeService,
            IErrorHandlingService errorHandlingService,
            IBackgroundService backgroundService,
            Func <ITogglDataSource, ISyncManager> createSyncManager,
            TimeSpan minimumTimeInBackgroundForFullSync,
            INotificationService notificationService,
            IApplicationShortcutCreator shortcutCreator,
            IAnalyticsService analyticsService)
        {
            Ensure.Argument.IsNotNull(api, nameof(api));
            Ensure.Argument.IsNotNull(database, nameof(database));
            Ensure.Argument.IsNotNull(timeService, nameof(timeService));
            Ensure.Argument.IsNotNull(notificationService, nameof(notificationService));
            Ensure.Argument.IsNotNull(errorHandlingService, nameof(errorHandlingService));
            Ensure.Argument.IsNotNull(backgroundService, nameof(backgroundService));
            Ensure.Argument.IsNotNull(createSyncManager, nameof(createSyncManager));
            Ensure.Argument.IsNotNull(shortcutCreator, nameof(shortcutCreator));
            Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService));

            this.database             = database;
            this.timeService          = timeService;
            this.shortcutCreator      = shortcutCreator;
            this.backgroundService    = backgroundService;
            this.notificationService  = notificationService;
            this.errorHandlingService = errorHandlingService;
            this.minimumTimeInBackgroundForFullSync = minimumTimeInBackgroundForFullSync;

            User              = new UserDataSource(database.User);
            Tags              = new TagsDataSource(database.Tags);
            Tasks             = new TasksDataSource(database.Tasks);
            Clients           = new ClientsDataSource(database.Clients);
            Projects          = new ProjectsDataSource(database.Projects);
            Workspaces        = new WorkspacesDataSource(database.Workspaces);
            Preferences       = new PreferencesDataSource(database.Preferences);
            WorkspaceFeatures = new WorkspaceFeaturesDataSource(database.WorkspaceFeatures);
            TimeEntries       = new TimeEntriesDataSource(database.TimeEntries, timeService, analyticsService);

            this.createSyncManager = createSyncManager;
            CreateNewSyncManager();

            ReportsProvider = new ReportsProvider(api, database);

            FeedbackApi = api.Feedback;

            isLoggedIn = true;
        }
Пример #19
0
            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);
            }
Пример #20
0
            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>());
            }
Пример #23
0
        public TogglDataSource(
            ITogglApi api,
            ITogglDatabase database,
            ITimeService timeService,
            IApiErrorHandlingService apiErrorHandlingService,
            IBackgroundService backgroundService,
            Func <ITogglDataSource, ISyncManager> createSyncManager,
            TimeSpan minimumTimeInBackgroundForFullSync,
            IApplicationShortcutCreator shortcutCreator)
        {
            Ensure.Argument.IsNotNull(api, nameof(api));
            Ensure.Argument.IsNotNull(database, nameof(database));
            Ensure.Argument.IsNotNull(timeService, nameof(timeService));
            Ensure.Argument.IsNotNull(apiErrorHandlingService, nameof(apiErrorHandlingService));
            Ensure.Argument.IsNotNull(backgroundService, nameof(backgroundService));
            Ensure.Argument.IsNotNull(createSyncManager, nameof(createSyncManager));
            Ensure.Argument.IsNotNull(shortcutCreator, nameof(shortcutCreator));

            this.database = database;
            this.apiErrorHandlingService = apiErrorHandlingService;
            this.backgroundService       = backgroundService;
            this.shortcutCreator         = shortcutCreator;

            this.minimumTimeInBackgroundForFullSync = minimumTimeInBackgroundForFullSync;

            User              = new UserDataSource(database.User, timeService);
            Tags              = new TagsDataSource(database.IdProvider, database.Tags, timeService);
            Tasks             = new TasksDataSource(database.Tasks);
            Clients           = new ClientsDataSource(database.IdProvider, database.Clients, timeService);
            Preferences       = new PreferencesDataSource(database.Preferences);
            Projects          = new ProjectsDataSource(database.IdProvider, database.Projects, timeService);
            TimeEntries       = new TimeEntriesDataSource(database.TimeEntries, timeService);
            Workspaces        = new WorkspacesDataSource(database.Workspaces);
            WorkspaceFeatures = new WorkspaceFeaturesDataSource(database.WorkspaceFeatures);

            SyncManager = createSyncManager(this);

            ReportsProvider = new ReportsProvider(api, database);

            errorHandlingDisposable = SyncManager.ProgressObservable.Subscribe(onSyncError);
            isLoggedIn = true;
        }
            public async Task ShouldTriggerAReportReload()
            {
                TimeService.CurrentDateTime.Returns(DateTimeOffset.Now);
                await ViewModel.Initialize();

                TestScheduler.Start();

                var mockWorkspace = new MockWorkspace {
                    Id = WorkspaceId + 1
                };

                DialogService.Select(Arg.Any <string>(), Arg.Any <IEnumerable <(string, IThreadSafeWorkspace)> >(), Arg.Any <int>())
                .Returns(Observable.Return(mockWorkspace));

                ViewModel.SelectWorkspace.Execute();
                TestScheduler.Start();

                await ReportsProvider.Received().GetProjectSummary(Arg.Is(mockWorkspace.Id), 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();
            }
Пример #26
0
            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);
            }
Пример #27
0
            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);
            }
Пример #28
0
            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 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 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));
            }