-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathObservableStoreSpec.cs
182 lines (152 loc) · 6.48 KB
/
ObservableStoreSpec.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
using AsyncRedux.Tests.Mock;
using AsyncRedux.Tests.Mock.Actions;
using Shouldly;
using Xunit;
// ReSharper disable MemberCanBePrivate.Global
namespace AsyncRedux.Tests
{
using ObservableSetup = Func<IObservable<object>, IObservable<object>>;
public class ObservableStoreSpec
{
private readonly IObservableStore<State> _store;
/// <inheritdoc />
public ObservableStoreSpec()
{
_store = StoreSetup.CreateStore<State>()
.FromReducer(Reducers.PassThrough)
.Build();
}
public static IEnumerable<object[]> ActionSequenceExamples
{
get
{
yield return new object[]
{
new object[] { new ChangeInt(3), new ChangeBool(true), new ChangeBool(true), new ChangeInt(3) },
new ObservableSetup(observable => observable),
new object[] { new ChangeInt(3), new ChangeBool(true), new ChangeBool(true), new ChangeInt(3) }
};
yield return new object[]
{
new object[] { new ChangeInt(3), new ChangeBool(true), new ChangeBool(true), new ChangeInt(3) },
new ObservableSetup(observable => observable.Distinct()),
new object[] { new ChangeInt(3), new ChangeBool(true) }
};
yield return new object[]
{
new object[] { new ChangeInt(3), new ChangeBool(true), new ChangeBool(true), new ChangeInt(3) },
new ObservableSetup(observable => observable.DistinctUntilChanged()),
new object[] { new ChangeInt(3), new ChangeBool(true), new ChangeInt(3) }
};
yield return new object[]
{
new[] { new ChangeInt(3), new ChangeBool(true), new object(), new ChangeInt(5) },
new ObservableSetup(observable => observable.Where(it => it is ChangeInt)),
new object[] { new ChangeInt(3), new ChangeInt(5) }
};
}
}
[Theory]
[MemberData(nameof(ActionSequenceExamples))]
internal async Task Observable_Store_Should_Allow_Observation(
object[] actionSequence,
ObservableSetup setup,
object[] expectedObservedActions)
{
var observedActions = new List<object>();
using (setup(_store.Observe()).Subscribe(observedActions.Add))
{
foreach (var action in actionSequence)
{
await _store.Dispatch(action);
}
}
observedActions.ShouldBe(expectedObservedActions);
}
[Fact]
internal async Task Observable_Store_Should_Support_Multiple_Observers()
{
var actions = new object[] { new ChangeInt(4), new ChangeBool(true) };
var observedActionsA = new List<object>();
var observedActionsB = new List<object>();
using (_store.Observe().Subscribe(observedActionsA.Add))
using (_store.Observe().Subscribe(observedActionsB.Add))
{
foreach (var action in actions)
{
await _store.Dispatch(action);
}
observedActionsA.ShouldBe(actions);
observedActionsB.ShouldBe(actions);
}
}
[Fact]
internal async Task Observers_Should_Not_Receive_Dispatched_Actions_After_Disposing_Subscription()
{
var changeInt = new ChangeInt(5);
var changeBool = new ChangeBool(true);
var observedActionsA = new List<object>();
var observedActionsB = new List<object>();
var subscriptionA = _store.Observe().Subscribe(observedActionsA.Add);
var subscriptionB = _store.Observe().Subscribe(observedActionsB.Add);
await _store.Dispatch(changeInt);
observedActionsA.ShouldBe(new object[] { changeInt });
observedActionsB.ShouldBe(new object[] { changeInt });
subscriptionA.Dispose();
await _store.Dispatch(changeBool);
observedActionsA.ShouldBe(new object[] { changeInt });
observedActionsB.ShouldBe(new object[] { changeInt, changeBool });
subscriptionB.Dispose();
await _store.Dispatch(new object());
observedActionsA.ShouldBe(new object[] { changeInt });
observedActionsB.ShouldBe(new object[] { changeInt, changeBool });
}
[Fact]
internal async Task Store_Should_Allow_Asynchronous_Handling_Of_Dispatched_Actions()
{
var tcs = new TaskCompletionSource<object>();
Task HandleDispatchedAction(object action)
{
tcs.SetResult(action);
return Task.CompletedTask;
}
_store.Subscribe<object>(HandleDispatchedAction);
var dispatchedAction = new ChangeInt(5);
await _store.Dispatch(dispatchedAction);
var receivedAction = await tcs.Task;
receivedAction.ShouldBe(dispatchedAction);
}
[Fact]
internal void Subscribers_Implementing_IStoreSubscriber_Should_Receive_Store_On_Subscription()
{
var store = StoreSetup.CreateStore<State>()
.FromReducer(Reducers.Replace)
.WithInitialState(new State(1, true))
.Build();
var subscriber = new Subscriber();
store.Subscribe(subscriber);
subscriber.Store.ShouldBe(store);
}
[Fact]
internal async Task Subscribers_Should_Only_Receive_Actions_Of_Type_They_Subscribe_To()
{
var tcs = new TaskCompletionSource<object>();
Task HandleDispatchedChangeBoolAction(ChangeBool changeBoolAction)
{
tcs.SetResult(changeBoolAction);
return Task.CompletedTask;
}
_store.Subscribe<ChangeBool>(HandleDispatchedChangeBoolAction);
var changeInt = new ChangeInt(5);
var changeBool = new ChangeBool(true);
await _store.Dispatch(changeInt);
await _store.Dispatch(changeBool);
var receivedAction = await tcs.Task;
receivedAction.ShouldBe(changeBool);
}
}
}