public void parse_error_message_is_null_if_a_document_is_successfully_parsed_after_one_fails_to_parse() { var badDocument = @"# First Program ## First Exercise whatever!"; var goodDocument = "# First Program"; var documents = new Subject <string>(); var exerciseDocumentService = new ExerciseDocumentServiceMock(); var scheduler = new TestScheduler(); exerciseDocumentService .When(x => x.ExerciseDocument) .Return(documents); var sut = new ExerciseProgramsViewModelBuilder() .WithExerciseDocumentService(exerciseDocumentService) .WithScheduler(scheduler) .Build(); documents.OnNext(badDocument); scheduler.AdvanceMinimal(); Assert.NotNull(sut.ParseErrorMessage); documents.OnNext(goodDocument); scheduler.AdvanceMinimal(); Assert.Null(sut.ParseErrorMessage); }
public void execution_context_is_cancelled_if_user_navigates_away() { var scheduler = new TestScheduler(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction( new WaitActionBuilder() .WithDelayService(new DelayServiceBuilder().Build()) .WithDelay(TimeSpan.FromMinutes(1)) .Build()))) .WithScheduler(scheduler) .Build(); sut .HostScreen .Router .NavigationStack .Add(sut); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.True(sut.IsStarted); sut .HostScreen .Router .NavigateBack .ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.False(sut.IsStarted); }
public void parse_error_message_is_null_if_a_document_is_successfully_parsed_after_one_fails_to_parse() { var badDocument = @"# First Program ## First Exercise whatever!"; var goodDocument = "# First Program"; var documents = new Subject<string>(); var exerciseDocumentService = new ExerciseDocumentServiceMock(); var scheduler = new TestScheduler(); exerciseDocumentService .When(x => x.ExerciseDocument) .Return(documents); var sut = new ExerciseProgramsViewModelBuilder() .WithExerciseDocumentService(exerciseDocumentService) .WithScheduler(scheduler) .Build(); documents.OnNext(badDocument); scheduler.AdvanceMinimal(); Assert.NotNull(sut.ParseErrorMessage); documents.OnNext(goodDocument); scheduler.AdvanceMinimal(); Assert.Null(sut.ParseErrorMessage); }
public void progress_time_span_is_not_reset_to_zero_if_another_exercise_is_started() { var scheduler = new TestScheduler(); var model1 = new ExerciseBuilder() .WithName("model 1") .Build(); var model2 = new ExerciseBuilder() .WithName("model 2") .Build(); var executionContext = new ExecutionContext(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .WithExecutionContext(executionContext) .WithModel(model1) .Build(); executionContext.SetCurrentExercise(model1); executionContext.AddProgress(TimeSpan.FromSeconds(3)); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.FromSeconds(3), sut.ProgressTimeSpan); executionContext.SetCurrentExercise(model2); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.FromSeconds(3), sut.ProgressTimeSpan); executionContext.AddProgress(TimeSpan.FromSeconds(3)); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.FromSeconds(3), sut.ProgressTimeSpan); }
public void is_resume_visible_cycles_correctly_if_start_command_is_executed_and_execution_is_paused() { var scheduler = new TestScheduler(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction( new WaitActionBuilder() .WithDelayService(new DelayServiceBuilder().Build()) .WithDelay(TimeSpan.FromMinutes(1)) .Build()))) .WithScheduler(scheduler) .Build(); var isResumeVisible = sut .WhenAnyValue(x => x.IsResumeVisible) .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); sut.PauseCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(2, isResumeVisible.Count); Assert.False(isResumeVisible[0]); Assert.True(isResumeVisible[1]); }
public void progress_time_span_reflects_any_progression_through_the_exercise() { var scheduler = new TestScheduler(); var model = new ExerciseBuilder() .Build(); var executionContext = new ExecutionContext(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .WithExecutionContext(executionContext) .WithModel(model) .Build(); executionContext.SetCurrentExercise(model); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.Zero, sut.ProgressTimeSpan); executionContext.AddProgress(TimeSpan.FromSeconds(3)); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.FromSeconds(3), sut.ProgressTimeSpan); executionContext.AddProgress(TimeSpan.FromSeconds(2)); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.FromSeconds(5), sut.ProgressTimeSpan); }
public void current_exercise_reflects_that_in_the_execution_context() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny <ExecutionContext>())) .Return <ExecutionContext>( ec => { ec.IsPaused = true; return(ec.WaitWhilePaused()); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var exercise3 = new ExerciseBuilder() .WithName("Exercise 3") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2) .WithExercise(exercise3)) .WithScheduler(scheduler) .Build(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 1", sut.CurrentExercise?.Name); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 2", sut.CurrentExercise?.Name); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 3", sut.CurrentExercise?.Name); sut.SkipBackwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 2", sut.CurrentExercise?.Name); }
public void skip_backwards_command_restarts_the_execution_context_from_the_start_of_the_previous_exercise_if_the_current_exercise_if_only_recently_started() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny <ExecutionContext>())) .Return <ExecutionContext>( ec => { ec.AddProgress(TimeSpan.FromSeconds(0.5)); ec.IsPaused = true; return(ec.WaitWhilePaused()); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2)) .WithScheduler(scheduler) .Build(); var progress = sut .WhenAnyValue(x => x.ProgressTimeSpan) .CreateCollection(); // start from the second exercise sut.StartCommand.ExecuteAsync(exercise1.Duration); scheduler.AdvanceMinimal(); sut.SkipBackwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(5, progress.Count); Assert.Equal(TimeSpan.Zero, progress[0]); Assert.Equal(TimeSpan.FromSeconds(10), progress[1]); Assert.Equal(TimeSpan.FromSeconds(10.5), progress[2]); Assert.Equal(TimeSpan.Zero, progress[3]); Assert.Equal(TimeSpan.FromSeconds(10), progress[4]); }
public void skip_forwards_command_is_disabled_if_on_last_exercise() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny <ExecutionContext>())) .Return <ExecutionContext>( ec => { ec.IsPaused = true; return(ec.WaitWhilePaused()); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2)) .WithScheduler(scheduler) .Build(); var canExecute = sut .SkipForwardsCommand .CanExecute .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(5, canExecute.Count); Assert.False(canExecute[0]); Assert.True(canExecute[1]); Assert.False(canExecute[2]); Assert.True(canExecute[3]); Assert.False(canExecute[4]); }
public void skip_forwards_command_skips_to_the_next_exercise() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny <ExecutionContext>())) .Return <ExecutionContext>( ec => { ec.IsPaused = true; return(ec.WaitWhilePaused()); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2)) .WithScheduler(scheduler) .Build(); var progress = sut .WhenAnyValue(x => x.ProgressTimeSpan) .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(2, progress.Count); Assert.Equal(TimeSpan.Zero, progress[0]); Assert.Equal(TimeSpan.FromSeconds(10), progress[1]); }
public void document_is_not_stored_in_cache_if_loaded_from_cache() { var document = "# First Program"; var scheduler = new TestScheduler(); var stateService = new StateServiceMock(); stateService .When(x => x.Get <string>(It.IsAny <string>())) .Return(Observable.Return(document)); stateService .When(x => x.Set <string>(It.IsAny <string>(), It.IsAny <string>())) .Return(Observable.Return(Unit.Default)); var sut = new ExerciseProgramsViewModelBuilder() .WithScheduler(scheduler) .WithStateService(stateService) .Build(); scheduler.AdvanceMinimal(); Assert.Equal(ExerciseProgramsViewModelStatus.LoadedFromCache, sut.Status); stateService .Verify(x => x.Set <string>("ExerciseProgramsDocument", document)) .WasNotCalled(); }
public void delete_all_deletes_all_entities_on_provided_scheduler() { var scheduler = new TestScheduler(); var repository = new RepositoryMock <int, TestEntity>(MockBehavior.Loose); repository .When(x => x.Get(42)) .Return(new TestEntity()); var sut = new AsyncRepositoryBuilder() .WithDataStoreScheduler(scheduler) .WithRepository(repository) .Build(); sut .DeleteAll() .Subscribe(); repository .Verify(x => x.DeleteAll()) .WasNotCalled(); scheduler.AdvanceMinimal(); repository .Verify(x => x.DeleteAll()) .WasCalledExactlyOnce(); }
public void items_retrieves_entities_on_provided_scheduler() { var scheduler = new TestScheduler(); var repository = new RepositoryMock <int, TestEntity>(MockBehavior.Loose); repository .When(x => x.GetAll()) .Return(ImmutableList <TestEntity> .Empty); var sut = new AsyncRepositoryBuilder() .WithDataStoreScheduler(scheduler) .WithRepository(repository) .Build(); sut .Items .Subscribe(); repository .Verify(x => x.GetAll()) .WasNotCalled(); scheduler.AdvanceMinimal(); repository .Verify(x => x.GetAll()) .WasCalledExactlyOnce(); }
public void programs_is_populated_from_cache_whilst_document_from_cloud_loads() { var cacheDocument = "# First Program"; var cloudDocument = @" # First Program # Second Program"; var scheduler = new TestScheduler(); var exerciseDocumentService = new ExerciseDocumentServiceMock(MockBehavior.Loose); exerciseDocumentService .When(x => x.ExerciseDocument) .Return( Observable .Return(cloudDocument) .Delay(TimeSpan.FromSeconds(3), scheduler)); var sut = new ExerciseProgramsViewModelBuilder() .WithExerciseDocumentService(exerciseDocumentService) .WithCachedDocument(cacheDocument) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.NotNull(sut.Programs); Assert.Equal(1, sut.Programs.Count); scheduler.AdvanceBy(TimeSpan.FromSeconds(2)); Assert.NotNull(sut.Programs); Assert.Equal(1, sut.Programs.Count); scheduler.AdvanceBy(TimeSpan.FromSeconds(2)); Assert.NotNull(sut.Programs); Assert.Equal(2, sut.Programs.Count); }
public void progress_is_calculated_based_on_duration_and_progress_time_span(int durationInMs, int progressInMs, double expectedProgress) { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Duration) .Return(TimeSpan.FromMilliseconds(durationInMs)); var model = new ExerciseBuilder() .WithBeforeExerciseAction(action) .Build(); var executionContext = new ExecutionContext(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .WithExecutionContext(executionContext) .WithModel(model) .Build(); executionContext.SetCurrentExercise(model); executionContext.AddProgress(TimeSpan.FromMilliseconds(progressInMs)); scheduler.AdvanceMinimal(); Assert.Equal(expectedProgress, sut.Progress); }
public void upgrade_records_versions() { var scheduler = new TestScheduler(); var dataStoreVersionRepository = new DataStoreVersionRepositoryMock(MockBehavior.Loose); var upgradeHandler1 = new UpgradeHandlerMock(MockBehavior.Loose); var upgradeHandler2 = new UpgradeHandlerMock(MockBehavior.Loose); upgradeHandler1 .When(x => x.Version) .Return(new Version(1, 0, 0)); upgradeHandler2 .When(x => x.Version) .Return(new Version(2, 0, 1)); var sut = new DataStoreServiceBuilder() .WithDataStoreScheduler(scheduler) .WithDataStoreVersionRepository(dataStoreVersionRepository) .WithUpgradeHandlers(upgradeHandler1, upgradeHandler2) .Build(); sut .Upgrade() .Subscribe(); scheduler.AdvanceMinimal(); dataStoreVersionRepository .Verify(x => x.Save(It.Matches <DataStoreVersionEntity>(y => y.Major == 1 && y.Minor == 0 && y.Build == 0))) .WasCalledExactlyOnce(); dataStoreVersionRepository .Verify(x => x.Save(It.Matches <DataStoreVersionEntity>(y => y.Major == 2 && y.Minor == 0 && y.Build == 1))) .WasCalledExactlyOnce(); }
public void skip_backwards_command_is_disabled_if_on_first_exercise() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Execute(It.IsAny <ExecutionContext>())) .Return <ExecutionContext>( ec => { ec.IsPaused = true; return(ec.WaitWhilePaused()); }); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.False(sut.SkipBackwardsCommand.CanExecute.FirstAsync().Wait()); }
public void is_pause_visible_cycles_correctly_if_start_command_is_executed() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Duration) .Return(TimeSpan.FromMinutes(1)); action .When(x => x.Execute(It.IsAny <ExecutionContext>())) .Return <ExecutionContext>( ec => Observable .Return(Unit.Default) .Do(_ => { }) .Delay(TimeSpan.FromMinutes(1), scheduler) .Do(_ => ec.AddProgress(TimeSpan.FromMinutes(1)))); var sut = new ExerciseProgramViewModelBuilder() .WithModel( new ExerciseProgramBuilder() .WithExercise( new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); Assert.False(sut.IsPauseVisible); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.True(sut.IsPauseVisible); scheduler.AdvanceBy(TimeSpan.FromMinutes(10)); Assert.False(sut.IsPauseVisible); }
public void upgrade_aborts_if_any_upgrade_fails() { var scheduler = new TestScheduler(); var upgradeHandler1 = new UpgradeHandlerMock(MockBehavior.Loose); var upgradeHandler2 = new UpgradeHandlerMock(MockBehavior.Loose); upgradeHandler1 .When(x => x.Version) .Return(new Version(1, 0, 0)); upgradeHandler1 .When(x => x.Apply(It.IsAny <IDatabaseConnection>())) .Throw(); upgradeHandler2 .When(x => x.Version) .Return(new Version(2, 0, 0)); var sut = new DataStoreServiceBuilder() .WithDataStoreScheduler(scheduler) .WithUpgradeHandlers(upgradeHandler1, upgradeHandler2) .Build(); sut .Upgrade() .Subscribe(); scheduler.AdvanceMinimal(); upgradeHandler1 .Verify(x => x.Apply(sut.Connection)) .WasCalledExactlyOnce(); upgradeHandler2 .Verify(x => x.Apply(It.IsAny <IDatabaseConnection>())) .WasNotCalled(); }
public void upgrade_applies_relevant_upgrades_only(string[] existingVersions, string[] availableVersions, bool[] applyExpected) { Assert.Equal(availableVersions.Length, applyExpected.Length); var scheduler = new TestScheduler(); var versions = existingVersions .Select( x => new DataStoreVersionEntityBuilder() .WithVersion(Version.Parse(x)) .Build()) .ToImmutableList(); var dataStoreVersionRepository = new DataStoreVersionRepositoryMock(MockBehavior.Loose); dataStoreVersionRepository .When(x => x.GetAll()) .Return(versions); dataStoreVersionRepository .When(x => x.GetLatest()) .Return(versions.Last()); var upgradeHandlers = availableVersions .Select( x => { var mock = new UpgradeHandlerMock(MockBehavior.Loose); mock .When(y => y.Version) .Return(Version.Parse(x)); return(mock); }) .ToArray(); var sut = new DataStoreServiceBuilder() .WithDataStoreScheduler(scheduler) .WithDataStoreVersionRepository(dataStoreVersionRepository) .WithUpgradeHandlers(upgradeHandlers) .Build(); sut .Upgrade() .Subscribe(); scheduler.AdvanceMinimal(); for (var i = 0; i < availableVersions.Length; ++i) { var upgradeHandler = upgradeHandlers[i]; if (applyExpected[i]) { upgradeHandler .Verify(x => x.Apply(sut.Connection)) .WasCalledExactlyOnce(); } else { upgradeHandler .Verify(x => x.Apply(sut.Connection)) .WasNotCalled(); } } }
public void is_active_is_false_if_there_is_no_execution_context() { var scheduler = new TestScheduler(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.False(sut.IsActive); }
public void is_active_is_true_if_this_exercise_is_the_current_exercise() { var scheduler = new TestScheduler(); var model = new ExerciseBuilder() .Build(); var executionContext = new ExecutionContext(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .WithExecutionContext(executionContext) .WithModel(model) .Build(); scheduler.AdvanceMinimal(); Assert.False(sut.IsActive); executionContext.SetCurrentExercise(model); scheduler.AdvanceMinimal(); Assert.True(sut.IsActive); }
public void programs_is_null_if_both_cache_and_cloud_are_empty() { var scheduler = new TestScheduler(); var sut = new ExerciseProgramsViewModelBuilder() .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.Null(sut.Programs); }
public void is_start_visible_is_true_by_default() { var scheduler = new TestScheduler(); var sut = new ExerciseProgramViewModelBuilder() .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.True(sut.IsStartVisible); }
public void is_started_cycles_correctly_if_start_command_is_executed() { var scheduler = new TestScheduler(); var sut = new ExerciseProgramViewModelBuilder() .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); var isStarted = sut .WhenAnyValue(x => x.IsStarted) .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(3, isStarted.Count); Assert.False(isStarted[0]); Assert.True(isStarted[1]); Assert.False(isStarted[2]); }
public void status_is_loaded_from_cloud_if_document_is_successfully_loaded_from_cloud() { var document = "# First Program"; var scheduler = new TestScheduler(); var sut = new ExerciseProgramsViewModelBuilder() .WithCloudDocument(document) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.Equal(ExerciseProgramsViewModelStatus.LoadedFromService, sut.Status); }
public void skip_backwards_command_restarts_the_execution_context_from_the_start_of_the_current_exercise_if_sufficient_progress_has_been_made() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Execute(It.IsAny <ExecutionContext>())) .Return <ExecutionContext>( ec => { ec.AddProgress(TimeSpan.FromSeconds(4)); ec.IsPaused = true; return(ec.WaitWhilePaused()); }); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); var progress = sut .WhenAnyValue(x => x.ProgressTimeSpan) .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); sut.SkipBackwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(3, progress.Count); Assert.Equal(TimeSpan.Zero, progress[0]); Assert.Equal(TimeSpan.FromSeconds(4), progress[1]); Assert.Equal(TimeSpan.Zero, progress[2]); }
public void programs_is_populated_from_cloud_if_cache_is_empty_and_cloud_is_populated() { var document = "# First Program"; var scheduler = new TestScheduler(); var sut = new ExerciseProgramsViewModelBuilder() .WithCloudDocument(document) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.NotNull(sut.Programs); Assert.Equal(1, sut.Programs.Count); }
public void progress_time_span_is_reset_to_zero_if_the_execution_context_changes_to_null() { var scheduler = new TestScheduler(); var model = new ExerciseBuilder() .Build(); var executionContext = new ExecutionContext(); var executionContextSubject = new Subject <ExecutionContext>(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .WithExecutionContext(executionContextSubject) .WithModel(model) .Build(); executionContextSubject.OnNext(executionContext); executionContext.SetCurrentExercise(model); executionContext.AddProgress(TimeSpan.FromSeconds(3)); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.FromSeconds(3), sut.ProgressTimeSpan); executionContextSubject.OnNext(null); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.Zero, sut.ProgressTimeSpan); }
public void programs_yields_any_successfully_parsed_programs() { var document = "# First Program"; var scheduler = new TestScheduler(); var sut = new ExerciseProgramsViewModelBuilder() .WithCloudDocument(document) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.NotNull(sut.Programs); Assert.Equal(1, sut.Programs.Count); Assert.Equal("First Program", sut.Programs.ElementAt(0).Name); }
public void is_paused_cycles_correctly_if_pause_command_is_executed() { var scheduler = new TestScheduler(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction( new WaitActionBuilder() .WithDelayService(new DelayServiceBuilder().Build()) .WithDelay(TimeSpan.FromMinutes(1)) .Build()))) .WithScheduler(scheduler) .Build(); Assert.False(sut.IsPaused); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.False(sut.IsPaused); sut.PauseCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.True(sut.IsPaused); }
public void parse_error_message_returns_appropriate_message_if_the_document_could_not_be_parsed() { var document = @"# First Program ## First Exercise whatever!"; var scheduler = new TestScheduler(); var sut = new ExerciseProgramsViewModelBuilder() .WithCloudDocument(document) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.NotNull(sut.ParseErrorMessage); Assert.Equal("Parsing failure: unexpected '#'; expected end of input (Line 3, Column 1); recently consumed: rogram\r\n\r\n", sut.ParseErrorMessage); }
public void skip_backwards_command_is_disabled_if_on_first_exercise() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.IsPaused = true; return ec.WaitWhilePaused(); }); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.False(sut.SkipBackwardsCommand.CanExecute.FirstAsync().Wait()); }
public void progress_is_updated_throughout_execution() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Duration) .Return(TimeSpan.FromMinutes(1)); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.AddProgress(TimeSpan.FromSeconds(15)); ec.AddProgress(TimeSpan.FromSeconds(30)); ec.IsPaused = true; return ec.WaitWhilePaused(); }); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); var progress = sut .WhenAnyValue(x => x.Progress) .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(3, progress.Count); Assert.Equal(0, progress[0]); Assert.Equal(0.25, progress[1]); Assert.Equal(0.75, progress[2]); }
public void status_is_load_failed_if_the_document_fails_to_load_altogether() { var exerciseDocumentService = new ExerciseDocumentServiceMock(); var scheduler = new TestScheduler(); exerciseDocumentService .When(x => x.ExerciseDocument) .Return(Observable.Throw<string>(new InvalidOperationException())); var sut = new ExerciseProgramsViewModelBuilder() .WithExerciseDocumentService(exerciseDocumentService) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.Equal(ExerciseProgramsViewModelStatus.LoadFailed, sut.Status); }
public void skip_forwards_command_skips_to_the_next_exercise() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.IsPaused = true; return ec.WaitWhilePaused(); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2)) .WithScheduler(scheduler) .Build(); var progress = sut .WhenAnyValue(x => x.ProgressTimeSpan) .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(2, progress.Count); Assert.Equal(TimeSpan.Zero, progress[0]); Assert.Equal(TimeSpan.FromSeconds(10), progress[1]); }
public void skip_backwards_command_restarts_the_execution_context_from_the_start_of_the_previous_exercise_if_the_current_exercise_if_only_recently_started() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.AddProgress(TimeSpan.FromSeconds(0.5)); ec.IsPaused = true; return ec.WaitWhilePaused(); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2)) .WithScheduler(scheduler) .Build(); var progress = sut .WhenAnyValue(x => x.ProgressTimeSpan) .CreateCollection(); // start from the second exercise sut.StartCommand.ExecuteAsync(exercise1.Duration); scheduler.AdvanceMinimal(); sut.SkipBackwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(5, progress.Count); Assert.Equal(TimeSpan.Zero, progress[0]); Assert.Equal(TimeSpan.FromSeconds(10), progress[1]); Assert.Equal(TimeSpan.FromSeconds(10.5), progress[2]); Assert.Equal(TimeSpan.Zero, progress[3]); Assert.Equal(TimeSpan.FromSeconds(10), progress[4]); }
public void document_is_not_stored_in_cache_if_loaded_from_cache() { var document = "# First Program"; var scheduler = new TestScheduler(); var stateService = new StateServiceMock(); stateService .When(x => x.Get<string>(It.IsAny<string>())) .Return(Observable.Return(document)); stateService .When(x => x.Set<string>(It.IsAny<string>(), It.IsAny<string>())) .Return(Observable.Return(Unit.Default)); var sut = new ExerciseProgramsViewModelBuilder() .WithScheduler(scheduler) .WithStateService(stateService) .Build(); scheduler.AdvanceMinimal(); Assert.Equal(ExerciseProgramsViewModelStatus.LoadedFromCache, sut.Status); stateService .Verify(x => x.Set<string>("ExerciseProgramsDocument", document)) .WasNotCalled(); }
public void skip_backwards_command_is_enabled_if_sufficient_progress_has_been_made_through_first_exercise() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.AddProgress(TimeSpan.FromSeconds(1)); ec.IsPaused = true; return ec.WaitWhilePaused(); }); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); // TODO: technically, I should just check CanExecute(null) at the end, but without this subscription the RxCommand does not update CanExecute correctly // try changing this once I'm using new RxCommand var canExecute = sut .SkipBackwardsCommand .CanExecute .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(2, canExecute.Count); Assert.False(canExecute[0]); Assert.True(canExecute[1]); }
public void skip_backwards_command_restarts_the_execution_context_from_the_start_of_the_current_exercise_if_sufficient_progress_has_been_made() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.AddProgress(TimeSpan.FromSeconds(4)); ec.IsPaused = true; return ec.WaitWhilePaused(); }); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); var progress = sut .WhenAnyValue(x => x.ProgressTimeSpan) .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); sut.SkipBackwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(3, progress.Count); Assert.Equal(TimeSpan.Zero, progress[0]); Assert.Equal(TimeSpan.FromSeconds(4), progress[1]); Assert.Equal(TimeSpan.Zero, progress[2]); }
public void status_is_parse_failed_if_the_document_could_not_be_parsed() { var document = @"# First Program ## First Exercise whatever!"; var scheduler = new TestScheduler(); var sut = new ExerciseProgramsViewModelBuilder() .WithCloudDocument(document) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.Equal(ExerciseProgramsViewModelStatus.ParseFailed, sut.Status); }
public void skip_forwards_command_is_disabled_if_on_last_exercise() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.IsPaused = true; return ec.WaitWhilePaused(); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2)) .WithScheduler(scheduler) .Build(); var canExecute = sut .SkipForwardsCommand .CanExecute .CreateCollection(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal(5, canExecute.Count); Assert.False(canExecute[0]); Assert.True(canExecute[1]); Assert.False(canExecute[2]); Assert.True(canExecute[3]); Assert.False(canExecute[4]); }
public void current_exercise_reflects_that_in_the_execution_context() { var scheduler = new TestScheduler(); var action = new ActionMock(); action .When(x => x.Duration) .Return(TimeSpan.FromSeconds(10)); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => { ec.IsPaused = true; return ec.WaitWhilePaused(); }); var exercise1 = new ExerciseBuilder() .WithName("Exercise 1") .WithBeforeExerciseAction(action) .Build(); var exercise2 = new ExerciseBuilder() .WithName("Exercise 2") .WithBeforeExerciseAction(action) .Build(); var exercise3 = new ExerciseBuilder() .WithName("Exercise 3") .WithBeforeExerciseAction(action) .Build(); var sut = new ExerciseProgramViewModelBuilder() .WithModel(new ExerciseProgramBuilder() .WithExercise(exercise1) .WithExercise(exercise2) .WithExercise(exercise3)) .WithScheduler(scheduler) .Build(); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 1", sut.CurrentExercise?.Name); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 2", sut.CurrentExercise?.Name); sut.SkipForwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 3", sut.CurrentExercise?.Name); sut.SkipBackwardsCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.Equal("Exercise 2", sut.CurrentExercise?.Name); }
public void programs_is_populated_from_cloud_if_cache_is_populated_and_cloud_is_populated() { var cacheDocument = "# First Program"; var cloudDocument = @" # First Program # Second Program"; var scheduler = new TestScheduler(); var sut = new ExerciseProgramsViewModelBuilder() .WithCloudDocument(cloudDocument) .WithCachedDocument(cacheDocument) .WithScheduler(scheduler) .Build(); scheduler.AdvanceMinimal(); Assert.NotNull(sut.Programs); Assert.Equal(2, sut.Programs.Count); }
public void programs_is_populated_from_cloud_if_cache_errors_and_cloud_is_populated() { var document = "# First Program"; var stateService = new StateServiceMock(); var scheduler = new TestScheduler(); stateService .When(x => x.Get<string>(It.IsAny<string>())) .Return(Observable.Throw<string>(new InvalidOperationException())); stateService .When(x => x.Set<string>(It.IsAny<string>(), It.IsAny<string>())) .Return(Observable.Return(Unit.Default)); var sut = new ExerciseProgramsViewModelBuilder() .WithCloudDocument(document) .WithScheduler(scheduler) .WithStateService(stateService) .Build(); scheduler.AdvanceMinimal(); Assert.NotNull(sut.Programs); Assert.Equal(1, sut.Programs.Count); }
public void progress_time_span_is_reset_to_zero_if_the_execution_context_changes_to_null() { var scheduler = new TestScheduler(); var model = new ExerciseBuilder() .Build(); var executionContext = new ExecutionContext(); var executionContextSubject = new Subject<ExecutionContext>(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .WithExecutionContext(executionContextSubject) .WithModel(model) .Build(); executionContextSubject.OnNext(executionContext); executionContext.SetCurrentExercise(model); executionContext.AddProgress(TimeSpan.FromSeconds(3)); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.FromSeconds(3), sut.ProgressTimeSpan); executionContextSubject.OnNext(null); scheduler.AdvanceMinimal(); Assert.Equal(TimeSpan.Zero, sut.ProgressTimeSpan); }
public void is_pause_visible_cycles_correctly_if_start_command_is_executed() { var scheduler = new TestScheduler(); var action = new ActionMock(MockBehavior.Loose); action .When(x => x.Duration) .Return(TimeSpan.FromMinutes(1)); action .When(x => x.Execute(It.IsAny<ExecutionContext>())) .Return<ExecutionContext>( ec => Observable .Return(Unit.Default) .Do(_ => { }) .Delay(TimeSpan.FromMinutes(1), scheduler) .Do(_ => ec.AddProgress(TimeSpan.FromMinutes(1)))); var sut = new ExerciseProgramViewModelBuilder() .WithModel( new ExerciseProgramBuilder() .WithExercise( new ExerciseBuilder() .WithBeforeExerciseAction(action))) .WithScheduler(scheduler) .Build(); Assert.False(sut.IsPauseVisible); sut.StartCommand.ExecuteAsync(); scheduler.AdvanceMinimal(); Assert.True(sut.IsPauseVisible); scheduler.AdvanceBy(TimeSpan.FromMinutes(10)); Assert.False(sut.IsPauseVisible); }
public void is_active_is_false_if_this_exercise_is_not_the_current_exercise() { var scheduler = new TestScheduler(); var model1 = new ExerciseBuilder() .Build(); var model2 = new ExerciseBuilder() .Build(); var executionContext = new ExecutionContext(); var sut = new ExerciseViewModelBuilder() .WithSchedulerService(scheduler) .WithExecutionContext(executionContext) .WithModel(model1) .Build(); scheduler.AdvanceMinimal(); Assert.False(sut.IsActive); executionContext.SetCurrentExercise(model2); scheduler.AdvanceMinimal(); Assert.False(sut.IsActive); }