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(); }
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)))); }
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); }
public void ShouldHaveADefaultValue() { var timeEntry = new MockTimeEntry(); var calendarItem = CalendarItem.From(timeEntry); calendarItem.Color.Should().Be(Colors.NoProject); }
public void SetsTheAppropriateCalendarIconKind(SyncStatus syncStatus, CalendarIconKind expectedCalendarIcon) { var timeEntry = new MockTimeEntry { SyncStatus = syncStatus }; var calendarItem = CalendarItem.From(timeEntry); calendarItem.IconKind.Should().Be(expectedCalendarIcon); }
public void ShouldBeTakenFromTimeEntry(long duration) { var timeEntry = new MockTimeEntry { Duration = duration }; var calendarItem = CalendarItem.From(timeEntry); calendarItem.Duration.Should().Be(TimeSpan.FromSeconds(duration)); }
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); }
public void ShouldUseDefaultValueIfPassedAnInvalidColor() { var timeEntry = new MockTimeEntry { Project = new MockProject { Color = "#fa" } }; var calendarItem = CalendarItem.From(timeEntry); calendarItem.Color.Should().Be(Colors.NoProject); }
public void ShouldInheritFromTimeEntryProjectColor() { var timeEntry = new MockTimeEntry { Project = new MockProject { Color = "#666666" } }; var calendarItem = CalendarItem.From(timeEntry); calendarItem.Color.Should().Be("#666666"); }
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>())); }
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); }
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)); }
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>()); }
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); }
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)); }
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); }
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); }
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)); }
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)); }
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>()); }