Browse files

Add lots of tests for bugs reported on the mailing list

  • Loading branch information...
1 parent bebc4a1 commit fbf83be1dc235d8e8d9544cd0b5f106ff472d319 @paulcbetts committed Feb 19, 2011
View
63 ReactiveUI.Tests/MakeObjectReactiveHelperTest.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace ReactiveUI.Tests
+{
+ public class NonReactiveINPCObjectMadeReactive : IReactiveNotifyPropertyChanged
+ {
+ public event PropertyChangingEventHandler PropertyChanging;
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ TestFixture _InpcProperty;
+ public TestFixture InpcProperty {
+ get { return _InpcProperty; }
+ set {
+ if (_InpcProperty == value) {
+ return;
+ }
+ _InpcProperty = value;
+
+ PropertyChanged(this, new PropertyChangedEventArgs("InpcProperty"));
+ }
+ }
+
+ MakeObjectReactiveHelper _reactiveHelper;
+ public NonReactiveINPCObjectMadeReactive()
+ {
+ _reactiveHelper = new MakeObjectReactiveHelper(this);
+ }
+
+ public IObservable<IObservedChange<object, object>> Changing {
+ get { return _reactiveHelper.Changing; }
+ }
+ public IObservable<IObservedChange<object, object>> Changed {
+ get { return _reactiveHelper.Changed; }
+ }
+ public IDisposable SuppressChangeNotifications() {
+ return _reactiveHelper.SuppressChangeNotifications();
+ }
+ }
+
+ public class MakeObjectReactiveHelperTest
+ {
+ [Fact]
+ public void MakeObjectReactiveHelperSmokeTest()
+ {
+ var fixture = new NonReactiveINPCObjectMadeReactive();
+ var output = fixture.Changed.CreateCollection();
+
+ Assert.Equal(0, output.Count);
+
+ var input = new TestFixture();
+ fixture.InpcProperty = input;
+
+ Assert.Equal(1, output.Count);
+ Assert.Equal(fixture, output[0].Sender);
+ Assert.Equal("InpcProperty", output[0].PropertyName);
+ }
+ }
+}
View
26 ReactiveUI.Tests/ObservableAsPropertyHelperTest.cs
@@ -5,6 +5,7 @@
using System.Linq;
using System.Concurrency;
using System.Collections.Generic;
+using System.Reactive.Testing;
namespace ReactiveUI.Tests
{
@@ -75,5 +76,28 @@ public void OAPHShouldRethrowErrors()
}
Assert.True(false, "We should've threw there");
}
+
+ [Fact]
+ public void OAPHShouldBeObservable()
+ {
+ (new TestScheduler()).With(sched => {
+ var input = sched.CreateHotObservable(
+ sched.OnNextAt(100, 5),
+ sched.OnNextAt(200, 10),
+ sched.OnNextAt(300, 15),
+ sched.OnNextAt(400, 20)
+ );
+
+ var result = new List<string>();
+
+ var inputOaph = new ObservableAsPropertyHelper<int>(input, x => { }, 0);
+ var fixture = new ObservableAsPropertyHelper<string>(inputOaph.Select(x => x.ToString()),
+ result.Add, "0");
+
+ sched.RunToMilliseconds(500);
+
+ new[] {"0", "5", "10", "15", "20"}.AssertAreEqual(result);
+ });
+ }
}
-}
+}
View
114 ReactiveUI.Tests/ReactiveCommandTest.cs
@@ -5,6 +5,7 @@
using System.Concurrency;
using System.Collections.Generic;
using System.Threading;
+using System.Reactive.Testing;
using ReactiveUI.Xaml;
using ReactiveUI.Testing;
@@ -350,5 +351,116 @@ public void MultipleResultsFromObservableShouldntDecrementRefcountBelowZero()
Assert.Equal(0, latestInFlight);
});
}
+
+ [Fact]
+ public void RAFShouldActuallyRunOnTheTaskpool()
+ {
+ var deferred = RxApp.DeferredScheduler;
+ var taskpool = RxApp.TaskpoolScheduler;
+
+ try {
+ var testDeferred = new CountingTestScheduler(Scheduler.Immediate);
+ var testTaskpool = new CountingTestScheduler(Scheduler.NewThread);
+ RxApp.DeferredScheduler = testDeferred; RxApp.DeferredScheduler = testTaskpool;
+
+ var fixture = new ReactiveAsyncCommand();
+ var result = fixture.RegisterAsyncFunction(x => { Thread.Sleep(1000); return (int)x * 5; });
+
+ fixture.Execute(1);
+ result.First();
+
+ Assert.Equal(1, testDeferred.ScheduledItems.Count);
+ Assert.Equal(1, testTaskpool.ScheduledItems.Count);
+ } finally {
+ RxApp.DeferredScheduler = deferred;
+ RxApp.TaskpoolScheduler = taskpool;
+ }
+ }
+
+ [Fact]
+ public void RAOShouldActuallyRunOnTheTaskpool()
+ {
+ var deferred = RxApp.DeferredScheduler;
+ var taskpool = RxApp.TaskpoolScheduler;
+
+ try {
+ var testDeferred = new CountingTestScheduler(Scheduler.Immediate);
+ var testTaskpool = new CountingTestScheduler(Scheduler.NewThread);
+ RxApp.DeferredScheduler = testDeferred; RxApp.DeferredScheduler = testTaskpool;
+
+ var fixture = new ReactiveAsyncCommand();
+ var result = fixture.RegisterAsyncObservable(x =>
+ Observable.Return((int)x * 5).Delay(TimeSpan.FromSeconds(1), RxApp.TaskpoolScheduler));
+
+ fixture.Execute(1);
+ result.First();
+
+ Assert.Equal(1, testDeferred.ScheduledItems.Count);
+ Assert.Equal(1, testTaskpool.ScheduledItems.Count);
+ } finally {
+ RxApp.DeferredScheduler = deferred;
+ RxApp.TaskpoolScheduler = taskpool;
+ }
+ }
+
+ [Fact]
+ public void CanExecuteShouldChangeOnInflightOp()
+ {
+ (new TestScheduler()).With(sched => {
+ var canExecute = sched.CreateHotObservable(
+ sched.OnNextAt(0, true),
+ sched.OnNextAt(250, false),
+ sched.OnNextAt(500, true),
+ sched.OnNextAt(750, false),
+ sched.OnNextAt(1000, true),
+ sched.OnNextAt(1100, false)
+ );
+
+ var fixture = new ReactiveAsyncCommand(canExecute);
+ int calculatedResult = -1;
+ bool latestCanExecute = false;
+
+ fixture.RegisterAsyncObservable(x =>
+ Observable.Return((int)x * 5).Delay(TimeSpan.FromMilliseconds(900), RxApp.DeferredScheduler))
+ .Subscribe(x => calculatedResult = x);
+
+ fixture.CanExecuteObservable.Subscribe(x => latestCanExecute = x);
+
+ // CanExecute should be true, both input observable is true
+ // and we don't have anything inflight
+ sched.RunToMilliseconds(10);
+ Assert.True(fixture.CanExecute(1));
+ Assert.True(latestCanExecute);
+
+ // Invoke a command 10ms in
+ fixture.Execute(1);
+
+ // At 300ms, input is false
+ sched.RunToMilliseconds(300);
+ Assert.False(fixture.CanExecute(1));
+ Assert.False(latestCanExecute);
+
+ // At 600ms, input is true, but the command is still running
+ sched.RunToMilliseconds(600);
+ Assert.False(fixture.CanExecute(1));
+ Assert.False(latestCanExecute);
+
+ // After we've completed, we should still be false, since from
+ // 750ms-1000ms the input observable is false
+ sched.RunToMilliseconds(900);
+ Assert.False(fixture.CanExecute(1));
+ Assert.False(latestCanExecute);
+ Assert.Equal(-1, calculatedResult);
+
+ sched.RunToMilliseconds(1010);
+ Assert.True(fixture.CanExecute(1));
+ Assert.True(latestCanExecute);
+ Assert.Equal(calculatedResult, 5);
+
+ sched.RunToMilliseconds(1200);
+ Assert.False(fixture.CanExecute(1));
+ Assert.False(latestCanExecute);
+ });
+ }
}
-}
+}
View
60 ReactiveUI.Tests/ReactiveNotifyPropertyChangedMixinTest.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Concurrency;
using System.Linq;
using System.Linq.Expressions;
@@ -35,6 +36,25 @@ public class NonObservableTestFixture
public TestFixture Child {get; set;}
}
+ public class NonReactiveINPCObject : INotifyPropertyChanged
+ {
+ public event PropertyChangingEventHandler PropertyChanging;
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ TestFixture _InpcProperty;
+ public TestFixture InpcProperty {
+ get { return _InpcProperty; }
+ set {
+ if (_InpcProperty == value) {
+ return;
+ }
+ _InpcProperty = value;
+
+ PropertyChanged(this, new PropertyChangedEventArgs("InpcProperty"));
+ }
+ }
+ }
+
public class ReactiveNotifyPropertyChangedMixinTest : IEnableLogger
{
[Fact]
@@ -190,6 +210,32 @@ public void OFPChangingTheHostPropertyShouldFireAChildChangeNotificationOnlyIfTh
}
[Fact]
+ public void OFPShouldWorkWithINPCObjectsToo()
+ {
+ (new TestScheduler()).With(sched => {
+ var fixture = new NonReactiveINPCObject() { InpcProperty = null };
+
+ var changes = fixture.ObservableForProperty(x => x.InpcProperty.IsOnlyOneWord).CreateCollection();
+
+ fixture.InpcProperty = new TestFixture();
+ sched.Run();
+ Assert.Equal(1, changes.Count);
+
+ fixture.InpcProperty.IsOnlyOneWord = "Foo";
+ sched.Run();
+ Assert.Equal(2, changes.Count);
+
+ fixture.InpcProperty.IsOnlyOneWord = "Bar";
+ sched.Run();
+ Assert.Equal(3, changes.Count);
+
+ fixture.InpcProperty = new TestFixture() {IsOnlyOneWord = "Bar"};
+ sched.Run();
+ Assert.Equal(3, changes.Count);
+ });
+ }
+
+ [Fact]
public void MultiPropertyExpressionsShouldBeProperlyResolved()
{
var data = new Dictionary<Expression<Func<HostTestFixture, object>>, string[]>() {
@@ -248,5 +294,19 @@ public void WhenAnySmokeTest()
Assert.Equal("Bar", output2[2].Value);
});
}
+
+ [Fact]
+ public void WhenAnyShouldWorkEvenWithNormalProperties()
+ {
+ var fixture = new TestFixture() { IsNotNullString = "Foo", IsOnlyOneWord = "Baz", PocoProperty = "Bamf" };
+
+ var output = new List<IObservedChange<TestFixture, string>>();
+ fixture.WhenAny(x => x.PocoProperty, x => x).Subscribe(output.Add);
+
+ Assert.Equal(1, output.Count);
+ Assert.Equal(fixture, output[0].Sender);
+ Assert.Equal("PocoProperty", output[0].PropertyName);
+ Assert.Equal("Bamf", output[0].Value);
+ }
}
}
View
30 ReactiveUI.Tests/ReactiveObjectTest.cs
@@ -1,39 +1,47 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
-using System.Concurrency;
using Xunit;
-using ReactiveUI;
namespace ReactiveUI.Tests
{
public class TestFixture : ReactiveObject
{
[DataMember]
- public string _IsNotNullString;
+ string _IsNotNullString;
[IgnoreDataMember]
public string IsNotNullString {
get { return _IsNotNullString; }
- set { this.RaiseAndSetIfChanged(x => x.IsNotNullString, value); }
+ set { this.RaiseAndSetIfChanged(x => x.IsNotNullString, ref _IsNotNullString, value); }
}
[DataMember]
- public string _IsOnlyOneWord;
+ string _IsOnlyOneWord;
[IgnoreDataMember]
public string IsOnlyOneWord {
get { return _IsOnlyOneWord; }
- set { this.RaiseAndSetIfChanged(x => x.IsOnlyOneWord, value); }
+ set { this.RaiseAndSetIfChanged(x => x.IsOnlyOneWord, ref _IsOnlyOneWord, value); }
}
[DataMember]
- public string _UsesExprRaiseSet;
+ string _UsesExprRaiseSet;
[IgnoreDataMember]
public string UsesExprRaiseSet {
get { return _UsesExprRaiseSet; }
- set { this.RaiseAndSetIfChanged(x => x.UsesExprRaiseSet, value); }
+ set { this.RaiseAndSetIfChanged(x => x.UsesExprRaiseSet, ref _UsesExprRaiseSet, value); }
}
+ [DataMember]
+ string _PocoProperty;
+ [IgnoreDataMember]
+ public string PocoProperty {
+ get { return _PocoProperty; }
+ set { _PocoProperty = value; }
+ }
+
+ [DataMember]
public ReactiveCollection<int> TestCollection { get; protected set; }
public TestFixture()
@@ -105,9 +113,9 @@ public void ReactiveObjectShouldntSerializeAnythingExtra()
// Should look something like:
// {"IsNotNullString":"Foo","IsOnlyOneWord":"Baz", "UserExprRaiseSet":null}
- Assert.True(json.Count(x => x == ',') == 2);
- Assert.True(json.Count(x => x == ':') == 3);
- Assert.True(json.Count(x => x == '"') == 10);
+ Assert.True(json.Count(x => x == ',') == 3);
+ Assert.True(json.Count(x => x == ':') == 4);
+ Assert.True(json.Count(x => x == '"') == 12);
}
[Fact]
View
1 ReactiveUI.Tests/ReactiveUI.Tests.csproj
@@ -81,6 +81,7 @@
</CodeAnalysisDependentAssemblyPaths>
</ItemGroup>
<ItemGroup>
+ <Compile Include="MakeObjectReactiveHelperTest.cs" />
<Compile Include="ObservableAsyncMRUCacheTest.cs" />
<Compile Include="MessageBusTest.cs" />
<Compile Include="DependencyObjectMixinTest.cs" />
View
31 ReactiveUI.Tests/Utility.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Concurrency;
using System.Linq;
using Xunit;
@@ -26,4 +27,32 @@ public static void AssertAreEqual<T>(this IEnumerable<T> lhs, IEnumerable<T> rhs
}
}
}
-}
+
+ public class CountingTestScheduler : IScheduler
+ {
+ public CountingTestScheduler(IScheduler innerScheduler)
+ {
+ InnerScheduler = innerScheduler;
+ ScheduledItems = new List<Tuple<Action, TimeSpan?>>();
+ }
+
+ public IScheduler InnerScheduler { get; private set; }
+ public List<Tuple<Action, TimeSpan?>> ScheduledItems { get; private set; }
+
+ public IDisposable Schedule(Action action)
+ {
+ ScheduledItems.Add(new Tuple<Action, TimeSpan?>(action, null));
+ return InnerScheduler.Schedule(action);
+ }
+
+ public IDisposable Schedule(Action action, TimeSpan dueTime)
+ {
+ ScheduledItems.Add(new Tuple<Action, TimeSpan?>(action, dueTime));
+ return InnerScheduler.Schedule(action, dueTime);
+ }
+
+ public DateTimeOffset Now {
+ get { return InnerScheduler.Now; }
+ }
+ }
+}

0 comments on commit fbf83be

Please sign in to comment.