Exemplo n.º 1
0
            protected CalendarViewModelTest()
            {
                CalendarInteractor = Substitute.For <IInteractor <IObservable <IEnumerable <CalendarItem> > > >();

                var workspace = new MockWorkspace {
                    Id = DefaultWorkspaceId
                };
                var timeEntry = new MockTimeEntry {
                    Id = TimeEntryId
                };

                TimeService.CurrentDateTime.Returns(Now);

                InteractorFactory
                .GetCalendarItemsForDate(Arg.Any <DateTime>())
                .Returns(CalendarInteractor);

                InteractorFactory
                .GetDefaultWorkspace()
                .Execute()
                .Returns(Observable.Return(workspace));

                InteractorFactory
                .CreateTimeEntry(Arg.Any <ITimeEntryPrototype>())
                .Execute()
                .Returns(Observable.Return(timeEntry));

                InteractorFactory
                .UpdateTimeEntry(Arg.Any <EditTimeEntryDto>())
                .Execute()
                .Returns(Observable.Return(timeEntry));
            }
            protected override IDatabaseTimeEntry CreateCleanWithPositiveIdFrom(IDatabaseTimeEntry entity)
            {
                var te = new MockTimeEntry(entity);

                te.Id = 1;
                return(TimeEntry.Clean(te));
            }
            public async ThreadingTask EmitsObservableEventsForTheNewRunningTimeEntryAndTheStoppedTimeEntry()
            {
                var durationAfterStopping = 100;
                var updatedObserver       = TestScheduler.CreateObserver <EntityUpdate <IThreadSafeTimeEntry> >();
                var createdObserver       = TestScheduler.CreateObserver <IThreadSafeTimeEntry>();
                var runningTimeEntry      = new MockTimeEntry {
                    Id = 1, Duration = null
                };
                var newTimeEntry = new MockTimeEntry {
                    Id = -2, Duration = null
                };

                Repository.GetAll(Arg.Any <Func <IDatabaseTimeEntry, bool> >())
                .Returns(Observable.Return(new IDatabaseTimeEntry[] { runningTimeEntry }));
                Repository.BatchUpdate(
                    Arg.Any <IEnumerable <(long, IDatabaseTimeEntry)> >(),
                    Arg.Any <Func <IDatabaseTimeEntry, IDatabaseTimeEntry, ConflictResolutionMode> >(),
                    Arg.Any <IRivalsResolver <IDatabaseTimeEntry> >())
                .Returns(Observable.Return(new IConflictResolutionResult <IDatabaseTimeEntry>[]
                {
                    new UpdateResult <IDatabaseTimeEntry>(runningTimeEntry.Id, runningTimeEntry.With(durationAfterStopping)),
                    new CreateResult <IDatabaseTimeEntry>(newTimeEntry)
                }));

                var timeEntriesSource = new TimeEntriesDataSource(Repository, TimeService);

                timeEntriesSource.Updated.Subscribe(updatedObserver);
                timeEntriesSource.Created.Subscribe(createdObserver);
                await timeEntriesSource.Create(newTimeEntry);

                updatedObserver.Messages.Single().Value.Value.Entity.Duration.Should().Be(durationAfterStopping);
                createdObserver.Messages.Single().Value.Value.Id.Should().Be(newTimeEntry.Id);
                createdObserver.Messages.Single().Value.Value.Duration.Should().BeNull();
            }
Exemplo n.º 4
0
        public async Task DeleteProjectsUnreferencedByTimeEntriesInInaccessibleWorkspace()
        {
            var accessibleWorkspace   = new MockWorkspace(1000, isInaccessible: false);
            var inaccessibleWorkspace = new MockWorkspace(2000, isInaccessible: true);

            var project1 = new MockProject(101, accessibleWorkspace, syncStatus: SyncStatus.InSync);
            var project2 = new MockProject(102, accessibleWorkspace, syncStatus: SyncStatus.RefetchingNeeded);
            var project3 = new MockProject(201, inaccessibleWorkspace, syncStatus: SyncStatus.InSync);
            var project4 = new MockProject(202, inaccessibleWorkspace, syncStatus: SyncStatus.SyncNeeded);
            var project5 = new MockProject(203, inaccessibleWorkspace, syncStatus: SyncStatus.SyncNeeded);
            var project6 = new MockProject(204, inaccessibleWorkspace, syncStatus: SyncStatus.InSync);
            var project7 = new MockProject(205, inaccessibleWorkspace, syncStatus: SyncStatus.InSync);

            var te1 = new MockTimeEntry(10001, accessibleWorkspace, project: project1, syncStatus: SyncStatus.InSync);
            var te2 = new MockTimeEntry(10002, accessibleWorkspace, project: project2, syncStatus: SyncStatus.SyncNeeded);
            var te3 = new MockTimeEntry(20001, inaccessibleWorkspace, project: project3, syncStatus: SyncStatus.InSync);
            var te4 = new MockTimeEntry(20002, inaccessibleWorkspace, project: project4, syncStatus: SyncStatus.SyncNeeded);
            var te5 = new MockTimeEntry(20003, inaccessibleWorkspace, project: project4, syncStatus: SyncStatus.SyncFailed);
            var te6 = new MockTimeEntry(20004, inaccessibleWorkspace, project: project4, syncStatus: SyncStatus.InSync);

            var projects    = new[] { project1, project2, project3, project4, project5, project6, project7 };
            var tasks       = new IThreadSafeTask[] { };
            var timeEntries = new[] { te1, te2, te3, te4, te5, te6 };

            var unreferencedProjects = new[] { project6, project7 };
            var neededProjects       = projects.Where(project => !unreferencedProjects.Contains(project));

            configureDataSource(projects, tasks, timeEntries);

            await state.Start().SingleAsync();

            projectsDataSource.Received().DeleteAll(Arg.Is <IEnumerable <IThreadSafeProject> >(arg =>
                                                                                               arg.All(project => unreferencedProjects.Contains(project)) &&
                                                                                               arg.None(project => neededProjects.Contains(project))));
        }
        public async Task DeleteUnreferencedTagsInInaccessibleWorkspace()
        {
            var accessibleWorkspace   = new MockWorkspace(1000);
            var inaccessibleWorkspace = new MockWorkspace(2000, isInaccessible: true);

            var tag1 = new MockTag(1001, accessibleWorkspace);
            var tag2 = new MockTag(1002, accessibleWorkspace, SyncStatus.SyncFailed);
            var tag3 = new MockTag(1003, accessibleWorkspace, SyncStatus.RefetchingNeeded);
            var tag4 = new MockTag(2001, inaccessibleWorkspace);
            var tag5 = new MockTag(2002, inaccessibleWorkspace, SyncStatus.SyncNeeded);
            var tag6 = new MockTag(2003, inaccessibleWorkspace, SyncStatus.RefetchingNeeded);
            var tag7 = new MockTag(2004, inaccessibleWorkspace);
            var tag8 = new MockTag(2005, inaccessibleWorkspace);

            var te1 = new MockTimeEntry(10001, accessibleWorkspace, tags: new[] { tag1 });
            var te2 = new MockTimeEntry(10002, accessibleWorkspace, tags: new[] { tag2 });
            var te3 = new MockTimeEntry(20001, inaccessibleWorkspace, tags: new[] { tag4 });
            var te4 = new MockTimeEntry(20002, inaccessibleWorkspace, tags: new[] { tag5 });

            var tags        = new[] { tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8 };
            var timeEntries = new[] { te1, te2, te3, te4 };

            var unreferencedTags = new[] { tag7, tag8 };
            var neededTags       = tags.Where(tag => !unreferencedTags.Contains(tag));

            configureDataSource(tags, timeEntries);

            await state.Start().SingleAsync();

            tagsDataSource.Received().DeleteAll(Arg.Is <IEnumerable <IThreadSafeTag> >(arg =>
                                                                                       arg.All(tag => unreferencedTags.Contains(tag)) &&
                                                                                       arg.None(tag => neededTags.Contains(tag))));
        }
Exemplo n.º 6
0
        public async Task TracksTheNumberOfActuallyCreatedPlaceholders()
        {
            var timeEntryA = new MockTimeEntry {
                ProjectId = 123, WorkspaceId = 456
            };
            var timeEntryB = new MockTimeEntry {
                ProjectId = 456, WorkspaceId = 456
            };
            var timeEntryC = new MockTimeEntry {
                ProjectId = 789, WorkspaceId = 456
            };
            var timeEntryD = new MockTimeEntry {
                ProjectId = null, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntryA, timeEntryB, timeEntryC, timeEntryD);

            dataSource.GetByIds(Arg.Is <long[]>(ids => ids.Length == 1 && (ids[0] == 123 || ids[0] == 456)))
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(
                         new IThreadSafeTestModel[0]));
            dataSource.GetByIds(Arg.Is <long[]>(ids => ids.Length == 0 || (ids[0] != 123 && ids[0] != 456)))
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(
                         new[] { new TestModel(), new TestModel() }));

            await state.Start(fetchObservables);

            analyticsService.ProjectPlaceholdersCreated.Received().Track(2);
        }
Exemplo n.º 7
0
            public void ShouldHaveADefaultValue()
            {
                var timeEntry = new MockTimeEntry();

                var calendarItem = CalendarItem.From(timeEntry);

                calendarItem.Color.Should().Be(Colors.NoProject);
            }
Exemplo n.º 8
0
            public void SetsTheAppropriateCalendarIconKind(SyncStatus syncStatus, CalendarIconKind expectedCalendarIcon)
            {
                var timeEntry = new MockTimeEntry {
                    SyncStatus = syncStatus
                };

                var calendarItem = CalendarItem.From(timeEntry);

                calendarItem.IconKind.Should().Be(expectedCalendarIcon);
            }
Exemplo n.º 9
0
            public void ShouldBeTakenFromTimeEntry(long duration)
            {
                var timeEntry = new MockTimeEntry {
                    Duration = duration
                };

                var calendarItem = CalendarItem.From(timeEntry);

                calendarItem.Duration.Should().Be(TimeSpan.FromSeconds(duration));
            }
Exemplo n.º 10
0
            public async Task ReturnsTheEntityWithTheGivenId()
            {
                const long id     = 42;
                var        entity = new MockTimeEntry();

                DataSource.TimeEntries.GetById(id).Returns(Observable.Return(entity));

                var result = await InteractorFactory.GetTimeEntryById(id).Execute();

                result.Should().BeSameAs(entity);
            }
Exemplo n.º 11
0
            public void ShouldUseDefaultValueIfPassedAnInvalidColor()
            {
                var timeEntry = new MockTimeEntry {
                    Project = new MockProject {
                        Color = "#fa"
                    }
                };

                var calendarItem = CalendarItem.From(timeEntry);

                calendarItem.Color.Should().Be(Colors.NoProject);
            }
Exemplo n.º 12
0
            public void ShouldInheritFromTimeEntryProjectColor()
            {
                var timeEntry = new MockTimeEntry {
                    Project = new MockProject {
                        Color = "#666666"
                    }
                };

                var calendarItem = CalendarItem.From(timeEntry);

                calendarItem.Color.Should().Be("#666666");
            }
Exemplo n.º 13
0
        public DeleteTimeEntryInteractorTests()
        {
            timeEntry = new MockTimeEntry
            {
                Id = 12
            };

            DataSource.TimeEntries.GetById(timeEntry.Id)
            .Returns(Observable.Return(timeEntry));
            DataSource.TimeEntries.Update(Arg.Any <IThreadSafeTimeEntry>())
            .Returns(callInfo => Observable.Return(callInfo.Arg <IThreadSafeTimeEntry>()));
        }
Exemplo n.º 14
0
            public void ShouldReturnTheExpectedForegroundColor(string color, string expectedColor)
            {
                var timeEntry = new MockTimeEntry {
                    Project = new MockProject {
                        Color = color
                    }
                };

                var calendarItem    = CalendarItem.From(timeEntry);
                var foregroundColor = calendarItem.ForegroundColor();

                foregroundColor.Should().BeEquivalentTo(new Color(expectedColor));
            }
        public async Task TracksThatNoGhostProjectsWereCreatedWhenTheResponseFromTheServerIsAnEmptyList()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetAll(Arg.Any <Func <IDatabaseProject, bool> >())
            .Returns(Observable.Return <IEnumerable <IThreadSafeProject> >(new IThreadSafeProject[] { new MockProject() }));

            await state.Start(fetchObservables);

            analyticsService.ProjectGhostsCreated.Received().Track(0);
        }
Exemplo n.º 16
0
        public async Task CreatesAProjectPlaceholderIfThereIsNoProjectWithGivenIdInTheDatabase()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetAll(Arg.Any <Func <IDatabaseTestModel, bool> >())
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(new IThreadSafeTestModel[0]));

            await state.Start(fetchObservables);

            await dataSource.Received().Create(Arg.Is <IThreadSafeTestModel>(dto => dto.Id == timeEntry.ProjectId.Value));
        }
Exemplo n.º 17
0
        public async Task DoesNotMarkPlaceholderCreationWhenNoPlaceholdersWereCreated()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetByIds(Arg.Any <long[]>())
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(new[] { new TestModel() }));

            var transition = await state.Start(fetchObservables);

            lastTimeUsageStorage.DidNotReceive().SetPlaceholdersWereCreated(Arg.Any <DateTimeOffset>());
        }
        public async Task DoesNotCreateAGhostWhenTheProjectIsInTheDatabase()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetAll(Arg.Any <Func <IDatabaseProject, bool> >())
            .Returns(Observable.Return <IEnumerable <IThreadSafeProject> >(new[] { new MockProject() }));

            await state.Start(fetchObservables);

            await dataSource.DidNotReceive().Create(Arg.Any <IThreadSafeProject>());
        }
Exemplo n.º 19
0
        public async Task TracksThatNoPlaceholdersWereCreatedWhenTheResponseFromTheServerIsAnEmptyList()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetByIds(Arg.Any <long[]>())
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(new IThreadSafeTestModel[] { new TestModel() }));

            await state.Start(fetchObservables);

            analyticsService.ProjectPlaceholdersCreated.Received().Track(0);
        }
Exemplo n.º 20
0
        public async Task DoesNotCreateAPlaceholderWhenTheDependencyIsInTheDatabase()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetByIds(Arg.Any <long[]>())
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(new[] { new TestModel() }));

            await state.Start(fetchObservables);

            await dataSource.DidNotReceive().Create(Arg.Any <IThreadSafeTestModel>());
        }
            public async ThreadingTask CallsRepositoryWithConflictResolvers()
            {
                var timeEntry = new MockTimeEntry();

                Repository.BatchUpdate(null, null, null)
                .ReturnsForAnyArgs(Observable.Return(new[] { new CreateResult <IDatabaseTimeEntry>(timeEntry) }));

                await TimeEntriesSource.Create(timeEntry);

                Repository.Received().BatchUpdate(
                    Arg.Any <IEnumerable <(long, IDatabaseTimeEntry)> >(),
                    Arg.Is <Func <IDatabaseTimeEntry, IDatabaseTimeEntry, ConflictResolutionMode> >(conflictResolution => conflictResolution != null),
                    Arg.Is <IRivalsResolver <IDatabaseTimeEntry> >(resolver => resolver != null));
            }
        public async Task TheCreatedGhostProjectIsNotActive()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetAll(Arg.Any <Func <IDatabaseProject, bool> >())
            .Returns(Observable.Return <IEnumerable <IThreadSafeProject> >(new IThreadSafeProject[0]));

            await state.Start(fetchObservables);

            await dataSource.Received().Create(
                Arg.Is <IThreadSafeProject>(project => project.Active == false));
        }
Exemplo n.º 23
0
        public DeleteTimeEntryInteractorTests()
        {
            timeEntry = new MockTimeEntry
            {
                Id = 12
            };

            InteractorFactory.GetTimeEntryById(timeEntry.Id)
            .Execute()
            .Returns(Observable.Return(timeEntry));
            DataSource.TimeEntries.Update(Arg.Any <IThreadSafeTimeEntry>())
            .Returns(callInfo => Observable.Return(callInfo.Arg <IThreadSafeTimeEntry>()));

            interactor = new DeleteTimeEntryInteractor(TimeService, DataSource.TimeEntries, InteractorFactory, timeEntry.Id);
        }
Exemplo n.º 24
0
            public async Task TracksTheTimeEntryEditedFromCalendarEventWhenStartTimeChanges()
            {
                var timeEntry = new MockTimeEntry
                {
                    Start    = calendarItem.StartTime.Add(TimeSpan.FromHours(1)),
                    Duration = (long)calendarItem.Duration.Value.TotalSeconds
                };

                InteractorFactory.GetTimeEntryById(Arg.Any <long>())
                .Execute()
                .Returns(Observable.Return(timeEntry));

                ViewModel.OnUpdateTimeEntry.Execute(calendarItem);

                AnalyticsService.TimeEntryChangedFromCalendar.Received().Track(CalendarChangeEvent.StartTime);
            }
            public async Task TracksTheTimeEntryEditedFromCalendarEventWhenDurationChanges()
            {
                var timeEntry = new MockTimeEntry
                {
                    Start    = calendarItem.StartTime,
                    Duration = (long)calendarItem.Duration.TotalSeconds + 10
                };

                DataSource.TimeEntries
                .GetById(Arg.Any <long>())
                .Returns(Observable.Return(timeEntry));

                await ViewModel.OnUpdateTimeEntry.Execute(calendarItem);

                AnalyticsService.TimeEntryChangedFromCalendar.Received().Track(CalendarChangeEvent.Duration);
            }
Exemplo n.º 26
0
            public void CannotBeExecutedWhenThereIsARunningTimeEntry(bool useDefaultMode)
            {
                var timeEntry = new MockTimeEntry();

                subject.OnNext(timeEntry);
                TestScheduler.AdvanceBy(TimeSpan.FromMilliseconds(50).Ticks);

                var observer = TestScheduler.CreateObserver <Unit>();

                ViewModel.StartTimeEntry.Execute(useDefaultMode)
                .Subscribe(observer);
                TestScheduler.Start();

                observer.Messages.Count.Should().Be(1);
                observer.Messages.Last().Value.Exception.Should().BeEquivalentTo(new RxActionNotEnabledException());
            }
        public async Task CreatesAGhostProjectIfThereIsNoProjectWithGivenIdInTheDatabase()
        {
            var timeEntry = new MockTimeEntry {
                ProjectId = 123, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetAll(Arg.Any <Func <IDatabaseProject, bool> >())
            .Returns(Observable.Return <IEnumerable <IThreadSafeProject> >(new IThreadSafeProject[0]));

            await state.Start(fetchObservables);

            await dataSource.Received().Create(Arg.Is <IThreadSafeProject>(dto =>
                                                                           dto.Id == timeEntry.ProjectId.Value &&
                                                                           dto.WorkspaceId == timeEntry.WorkspaceId &&
                                                                           dto.SyncStatus == SyncStatus.RefetchingNeeded));
        }
Exemplo n.º 28
0
        public async Task CreatesOnlyOnePlaceholderWhenMultipleTimeEntriesRequireSameUnknownDependency()
        {
            var projectId  = 123;
            var timeEntryA = new MockTimeEntry {
                ProjectId = projectId, WorkspaceId = 456
            };
            var timeEntryB = new MockTimeEntry {
                ProjectId = projectId, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntryA, timeEntryB);

            dataSource.GetByIds(Arg.Any <long[]>())
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(new IThreadSafeTestModel[0]));

            await state.Start(fetchObservables);

            await dataSource.Received(1).Create(Arg.Is <IThreadSafeTestModel>(dto => dto.Id == projectId));
        }
Exemplo n.º 29
0
        public async Task MarksPlaceholderCreationWhenNoPlaceholdersWereCreated()
        {
            var now = new DateTimeOffset(2019, 5, 21, 19, 20, 00, TimeSpan.Zero);

            timeService.CurrentDateTime.Returns(now);
            var timeEntry = new MockTimeEntry {
                ProjectId = 123, WorkspaceId = 456
            };
            var fetchObservables = fetch(timeEntry);

            dataSource.GetAll(Arg.Any <Func <IDatabaseTestModel, bool> >())
            .Returns(Observable.Return <IEnumerable <IThreadSafeTestModel> >(new IThreadSafeTestModel[0]));

            var transition = await state.Start(fetchObservables);

            transition.Result.Should().Be(state.Done);
            lastTimeUsageStorage.Received().SetPlaceholdersWereCreated(now);
        }
        public async Task DoesNotDeleteAnyRunningTimeEntryInAccessibleWorkspaces(SyncStatus syncStatus)
        {
            var fetch = Substitute.For <IFetchObservables>();

            var start    = new DateTimeOffset(2018, 10, 23, 15, 42, 00, TimeSpan.Zero);
            var duration = (long)TimeSpan.FromMinutes(15).TotalSeconds;

            var workspace        = new MockWorkspace(1, isInaccessible: false);
            var runningTimeEntry = new MockTimeEntry(11, workspace, start: start, syncStatus: syncStatus);
            var timeEntry1       = new MockTimeEntry(11, workspace, start: start, duration: duration);
            var timeEntry2       = new MockTimeEntry(11, workspace, start: start, duration: duration);

            configureDataSource(new[] { runningTimeEntry, timeEntry1, timeEntry2 });

            await state.Start(fetch).SingleAsync();

            dataSource.DidNotReceive().Delete(Arg.Any <long>());
        }