com.fofx.observething 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/README.md.meta +7 -0
- package/Runtime/CollectionIdProvider.cs +72 -0
- package/Runtime/CollectionIdProvider.cs.meta +2 -0
- package/Runtime/IObservable.cs +66 -0
- package/Runtime/IObservable.cs.meta +2 -0
- package/Runtime/Implementations/Observable.cs +30 -0
- package/Runtime/Implementations/Observable.cs.meta +2 -0
- package/Runtime/Implementations/ObservableBase.cs +173 -0
- package/Runtime/Implementations/ObservableBase.cs.meta +2 -0
- package/Runtime/Implementations/ObservableCollection.cs +141 -0
- package/Runtime/Implementations/ObservableCollection.cs.meta +2 -0
- package/Runtime/Implementations/ObservableDictionary.cs +166 -0
- package/Runtime/Implementations/ObservableDictionary.cs.meta +2 -0
- package/Runtime/Implementations/ObservableList.cs +163 -0
- package/Runtime/Implementations/ObservableList.cs.meta +2 -0
- package/Runtime/Implementations/ObservableSet.cs +137 -0
- package/Runtime/Implementations/ObservableSet.cs.meta +2 -0
- package/Runtime/Implementations/ObservableValue.cs +59 -0
- package/Runtime/Implementations/ObservableValue.cs.meta +2 -0
- package/Runtime/Implementations.meta +8 -0
- package/Runtime/Observables/BatchObservable.cs +72 -0
- package/Runtime/Observables/BatchObservable.cs.meta +2 -0
- package/Runtime/Observables/CastObservable.cs +128 -0
- package/Runtime/Observables/CastObservable.cs.meta +2 -0
- package/Runtime/Observables/CombineObservable.cs +96 -0
- package/Runtime/Observables/CombineObservable.cs.meta +2 -0
- package/Runtime/Observables/CombineValueObservable.cs +319 -0
- package/Runtime/Observables/CombineValueObservable.cs.meta +2 -0
- package/Runtime/Observables/ConcatObservable.cs +75 -0
- package/Runtime/Observables/ConcatObservable.cs.meta +2 -0
- package/Runtime/Observables/ContainsObservable.cs +71 -0
- package/Runtime/Observables/ContainsObservable.cs.meta +2 -0
- package/Runtime/Observables/CountObservable.cs +29 -0
- package/Runtime/Observables/CountObservable.cs.meta +2 -0
- package/Runtime/Observables/DistinctObservable.cs +55 -0
- package/Runtime/Observables/DistinctObservable.cs.meta +2 -0
- package/Runtime/Observables/FirstObservable.cs +53 -0
- package/Runtime/Observables/FirstObservable.cs.meta +2 -0
- package/Runtime/Observables/IndexOfObservable.cs +83 -0
- package/Runtime/Observables/IndexOfObservable.cs.meta +2 -0
- package/Runtime/Observables/OperationStreamObservable.cs +194 -0
- package/Runtime/Observables/OperationStreamObservable.cs.meta +2 -0
- package/Runtime/Observables/OrderByObservable.cs +116 -0
- package/Runtime/Observables/OrderByObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectCollectionObservable.cs +29 -0
- package/Runtime/Observables/SelectCollectionObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectListObservable.cs +29 -0
- package/Runtime/Observables/SelectListObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectManyObservable.cs +78 -0
- package/Runtime/Observables/SelectManyObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectValueObservable.cs +28 -0
- package/Runtime/Observables/SelectValueObservable.cs.meta +2 -0
- package/Runtime/Observables/SkipWhileObservable.cs +32 -0
- package/Runtime/Observables/SkipWhileObservable.cs.meta +2 -0
- package/Runtime/Observables/ThenObservable.cs +209 -0
- package/Runtime/Observables/ThenObservable.cs.meta +2 -0
- package/Runtime/Observables/ToDictionaryObservable.cs +35 -0
- package/Runtime/Observables/ToDictionaryObservable.cs.meta +2 -0
- package/Runtime/Observables/TrackObservable.cs +74 -0
- package/Runtime/Observables/TrackObservable.cs.meta +2 -0
- package/Runtime/Observables/UnwrapCollectionObservable.cs +64 -0
- package/Runtime/Observables/UnwrapCollectionObservable.cs.meta +2 -0
- package/Runtime/Observables/UnwrapListObservable.cs +69 -0
- package/Runtime/Observables/UnwrapListObservable.cs.meta +2 -0
- package/Runtime/Observables/UnwrapValueObservable.cs +56 -0
- package/Runtime/Observables/UnwrapValueObservable.cs.meta +2 -0
- package/Runtime/Observables/WhereObservable.cs +85 -0
- package/Runtime/Observables/WhereObservable.cs.meta +2 -0
- package/Runtime/Observables/WithPreviousObservable.cs +36 -0
- package/Runtime/Observables/WithPreviousObservable.cs.meta +2 -0
- package/Runtime/Observables.cs +467 -0
- package/Runtime/Observables.cs.meta +2 -0
- package/Runtime/Observables.meta +8 -0
- package/Runtime/ObservationContext.cs +126 -0
- package/Runtime/ObservationContext.cs.meta +2 -0
- package/Runtime/Observers.cs +403 -0
- package/Runtime/Observers.cs.meta +2 -0
- package/Runtime/Operators/BatchOperator.cs +71 -0
- package/Runtime/Operators/BatchOperator.cs.meta +2 -0
- package/Runtime/Operators/CollectionOperator.cs +30 -0
- package/Runtime/Operators/CollectionOperator.cs.meta +2 -0
- package/Runtime/Operators/DictionaryOperator.cs +45 -0
- package/Runtime/Operators/DictionaryOperator.cs.meta +2 -0
- package/Runtime/Operators/IInitializationOperationsProvider.cs +10 -0
- package/Runtime/Operators/IInitializationOperationsProvider.cs.meta +2 -0
- package/Runtime/Operators/ListOperator.cs +44 -0
- package/Runtime/Operators/ListOperator.cs.meta +2 -0
- package/Runtime/Operators/ObservableOperator.cs +75 -0
- package/Runtime/Operators/ObservableOperator.cs.meta +2 -0
- package/Runtime/Operators/Operator.cs +65 -0
- package/Runtime/Operators/Operator.cs.meta +2 -0
- package/Runtime/Operators/SetOperator.cs +44 -0
- package/Runtime/Operators/SetOperator.cs.meta +2 -0
- package/Runtime/Operators/ValueOperator.cs +30 -0
- package/Runtime/Operators/ValueOperator.cs.meta +2 -0
- package/Runtime/Operators.meta +8 -0
- package/Runtime/PriorityQueue.cs +1096 -0
- package/Runtime/PriorityQueue.cs.meta +2 -0
- package/Runtime/com.fofx.observething.asmdef +14 -0
- package/Runtime/com.fofx.observething.asmdef.meta +7 -0
- package/Runtime.meta +8 -0
- package/Tests/CollectionObservableTests.cs +739 -0
- package/Tests/CollectionObservableTests.cs.meta +2 -0
- package/Tests/DictionaryObservableTests.cs +85 -0
- package/Tests/DictionaryObservableTests.cs.meta +2 -0
- package/Tests/ListObservableTests.cs +148 -0
- package/Tests/ListObservableTests.cs.meta +2 -0
- package/Tests/ObservationContextTests.cs +359 -0
- package/Tests/ObservationContextTests.cs.meta +2 -0
- package/Tests/ValueObservableTests.cs +322 -0
- package/Tests/ValueObservableTests.cs.meta +2 -0
- package/Tests/com.fofx.observething.tests.asmdef +24 -0
- package/Tests/com.fofx.observething.tests.asmdef.meta +7 -0
- package/Tests.meta +8 -0
- package/package.json +24 -0
- package/package.json.meta +7 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using NUnit.Framework;
|
|
4
|
+
using UnityEngine.TestTools;
|
|
5
|
+
|
|
6
|
+
namespace ObserveThing.Tests
|
|
7
|
+
{
|
|
8
|
+
public class DictionaryObservableTests
|
|
9
|
+
{
|
|
10
|
+
[SetUp]
|
|
11
|
+
public void SetUp()
|
|
12
|
+
{
|
|
13
|
+
Settings.DefaultExceptionHandler = UnityEngine.Debug.LogException;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[Test]
|
|
17
|
+
public void TestTrack()
|
|
18
|
+
{
|
|
19
|
+
int callCount = 0;
|
|
20
|
+
(bool keyPresent, string value) value = default;
|
|
21
|
+
Exception exception = default;
|
|
22
|
+
bool disposed = false;
|
|
23
|
+
|
|
24
|
+
ObservableDictionary<int, string> dict = new ObservableDictionary<int, string>();
|
|
25
|
+
ObservableValue<int> key = new ObservableValue<int>();
|
|
26
|
+
|
|
27
|
+
dict.ObservableTrack(key).Subscribe(
|
|
28
|
+
x =>
|
|
29
|
+
{
|
|
30
|
+
callCount++;
|
|
31
|
+
value = x;
|
|
32
|
+
},
|
|
33
|
+
exc => exception = exc,
|
|
34
|
+
() => disposed = true
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
Assert.AreEqual(1, callCount);
|
|
38
|
+
Assert.AreEqual(false, value.keyPresent);
|
|
39
|
+
Assert.AreEqual(default, value.value);
|
|
40
|
+
|
|
41
|
+
dict.Add(2, "cat");
|
|
42
|
+
|
|
43
|
+
Assert.AreEqual(1, callCount);
|
|
44
|
+
Assert.AreEqual(false, value.keyPresent);
|
|
45
|
+
Assert.AreEqual(default, value.value);
|
|
46
|
+
|
|
47
|
+
key.value = 2;
|
|
48
|
+
|
|
49
|
+
Assert.AreEqual(2, callCount);
|
|
50
|
+
Assert.AreEqual(true, value.keyPresent);
|
|
51
|
+
Assert.AreEqual("cat", value.value);
|
|
52
|
+
|
|
53
|
+
dict.Remove(2);
|
|
54
|
+
|
|
55
|
+
Assert.AreEqual(3, callCount);
|
|
56
|
+
Assert.AreEqual(false, value.keyPresent);
|
|
57
|
+
Assert.AreEqual(default, value.value);
|
|
58
|
+
|
|
59
|
+
dict.Remove(40);
|
|
60
|
+
|
|
61
|
+
Assert.AreEqual(3, callCount);
|
|
62
|
+
Assert.AreEqual(false, value.keyPresent);
|
|
63
|
+
Assert.AreEqual(default, value.value);
|
|
64
|
+
|
|
65
|
+
dict.Add(2, "dog");
|
|
66
|
+
|
|
67
|
+
Assert.AreEqual(4, callCount);
|
|
68
|
+
Assert.AreEqual(true, value.keyPresent);
|
|
69
|
+
Assert.AreEqual("dog", value.value);
|
|
70
|
+
|
|
71
|
+
// var exc = new Exception();
|
|
72
|
+
// dict.OnError(exc);
|
|
73
|
+
// Assert.AreEqual(exc, exception);
|
|
74
|
+
|
|
75
|
+
// var keyProviderExc = new Exception();
|
|
76
|
+
// dict.OnError(keyProviderExc);
|
|
77
|
+
// Assert.AreEqual(keyProviderExc, exception);
|
|
78
|
+
|
|
79
|
+
dict.Dispose();
|
|
80
|
+
Assert.IsTrue(disposed);
|
|
81
|
+
Assert.Throws(typeof(ObjectDisposedException), () => dict.Add(100, "me"));
|
|
82
|
+
Assert.AreEqual(4, callCount);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Linq;
|
|
4
|
+
using NUnit.Framework;
|
|
5
|
+
|
|
6
|
+
namespace ObserveThing.Tests
|
|
7
|
+
{
|
|
8
|
+
public class ListObservableTests
|
|
9
|
+
{
|
|
10
|
+
[SetUp]
|
|
11
|
+
public void SetUp()
|
|
12
|
+
{
|
|
13
|
+
Settings.DefaultExceptionHandler = UnityEngine.Debug.LogException;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[Test]
|
|
17
|
+
public void TestSelect()
|
|
18
|
+
{
|
|
19
|
+
var result = new List<string>();
|
|
20
|
+
var list = new ObservableList<int>();
|
|
21
|
+
bool disposed = false;
|
|
22
|
+
bool receivedCall = false;
|
|
23
|
+
var select = list.ObservableSelect(x => x.ToString()).Subscribe(
|
|
24
|
+
onAdd: (index, value) =>
|
|
25
|
+
{
|
|
26
|
+
result.Insert(index, value);
|
|
27
|
+
receivedCall = true;
|
|
28
|
+
},
|
|
29
|
+
onRemove: (index, value) =>
|
|
30
|
+
{
|
|
31
|
+
result.RemoveAt(index);
|
|
32
|
+
receivedCall = true;
|
|
33
|
+
},
|
|
34
|
+
onDispose: () => disposed = true
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
list.Add(1);
|
|
38
|
+
list.Add(1);
|
|
39
|
+
list.Add(2);
|
|
40
|
+
list.Add(3);
|
|
41
|
+
list.Add(4);
|
|
42
|
+
list.Add(45);
|
|
43
|
+
|
|
44
|
+
Assert.AreEqual(
|
|
45
|
+
Enumerable.Select(list, x => x.ToString()),
|
|
46
|
+
result
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
list.Remove(3);
|
|
50
|
+
list.Remove(3);
|
|
51
|
+
list.Add(1);
|
|
52
|
+
list.Add(45);
|
|
53
|
+
list.Remove(45);
|
|
54
|
+
|
|
55
|
+
Assert.AreEqual(
|
|
56
|
+
Enumerable.Select(list, x => x.ToString()),
|
|
57
|
+
result
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
list.Clear();
|
|
61
|
+
|
|
62
|
+
Assert.AreEqual(
|
|
63
|
+
Enumerable.Select(list, x => x.ToString()),
|
|
64
|
+
result
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
receivedCall = false;
|
|
68
|
+
select.Dispose();
|
|
69
|
+
Assert.IsTrue(disposed);
|
|
70
|
+
list.Add(100);
|
|
71
|
+
Assert.IsFalse(receivedCall);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
[Test]
|
|
75
|
+
public void TestShallowCopy()
|
|
76
|
+
{
|
|
77
|
+
var list = new ObservableList<ObservableValue<int>>();
|
|
78
|
+
var result = new List<string>();
|
|
79
|
+
bool disposed = false;
|
|
80
|
+
bool receivedCall = false;
|
|
81
|
+
var stream = list.ObservableSelect(x => x.ObservableSelect(x => x.ToString())).Subscribe(
|
|
82
|
+
onAdd: (index, x) =>
|
|
83
|
+
{
|
|
84
|
+
result.Insert(index, x);
|
|
85
|
+
receivedCall = true;
|
|
86
|
+
},
|
|
87
|
+
onRemove: (index, x) =>
|
|
88
|
+
{
|
|
89
|
+
result.RemoveAt(index);
|
|
90
|
+
receivedCall = true;
|
|
91
|
+
},
|
|
92
|
+
onDispose: () => disposed = true
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
var element1 = new ObservableValue<int>(2);
|
|
96
|
+
var element2 = new ObservableValue<int>(3);
|
|
97
|
+
var element3 = new ObservableValue<int>(45);
|
|
98
|
+
var element4 = new ObservableValue<int>(11);
|
|
99
|
+
|
|
100
|
+
list.Add(element1);
|
|
101
|
+
list.Add(element2);
|
|
102
|
+
list.Add(element3);
|
|
103
|
+
list.Add(element4);
|
|
104
|
+
|
|
105
|
+
Assert.AreEqual(
|
|
106
|
+
Enumerable.Select(list, x => x.value.ToString()),
|
|
107
|
+
result
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
element1.value = 3;
|
|
111
|
+
element1.value = 100;
|
|
112
|
+
element1.value = 22;
|
|
113
|
+
element1.value = 6;
|
|
114
|
+
|
|
115
|
+
Assert.AreEqual(
|
|
116
|
+
Enumerable.Select(list, x => x.value.ToString()),
|
|
117
|
+
result
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
element2.value = 3;
|
|
121
|
+
element3.value = 3;
|
|
122
|
+
element4.value = 3;
|
|
123
|
+
|
|
124
|
+
Assert.AreEqual(
|
|
125
|
+
Enumerable.Select(list, x => x.value.ToString()),
|
|
126
|
+
result
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
list.Remove(element2);
|
|
130
|
+
list.Add(element3);
|
|
131
|
+
|
|
132
|
+
element2.value = 5;
|
|
133
|
+
element3.value = 100;
|
|
134
|
+
element3.value = 50;
|
|
135
|
+
|
|
136
|
+
Assert.AreEqual(
|
|
137
|
+
Enumerable.Select(list, x => x.value.ToString()),
|
|
138
|
+
result
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
receivedCall = false;
|
|
142
|
+
stream.Dispose();
|
|
143
|
+
Assert.IsTrue(disposed);
|
|
144
|
+
list.Add(new ObservableValue<int>(150));
|
|
145
|
+
Assert.IsFalse(receivedCall);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Linq;
|
|
4
|
+
using System.Runtime.InteropServices;
|
|
5
|
+
using NUnit.Framework;
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
using UnityEngine.TestTools;
|
|
8
|
+
|
|
9
|
+
namespace ObserveThing.Tests
|
|
10
|
+
{
|
|
11
|
+
public class ObservationContextTests
|
|
12
|
+
{
|
|
13
|
+
[Test]
|
|
14
|
+
public void TestOperationOrder()
|
|
15
|
+
{
|
|
16
|
+
var context = new ObservationContext();
|
|
17
|
+
|
|
18
|
+
ObservableValue<int> intObservable = new ObservableValue<int>(context, 100);
|
|
19
|
+
ObservableValue<string> stringObservable = new ObservableValue<string>(context, "200");
|
|
20
|
+
List<(object source, object value)> operations = new List<(object source, object value)>();
|
|
21
|
+
|
|
22
|
+
int callCount = 0;
|
|
23
|
+
|
|
24
|
+
var stream = Observables.ObservableCombine(intObservable, stringObservable).Subscribe(
|
|
25
|
+
onNext: op =>
|
|
26
|
+
{
|
|
27
|
+
callCount++;
|
|
28
|
+
operations.Add(new(op.source, ((IValueOp)op).value));
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
Assert.AreEqual(2, callCount);
|
|
33
|
+
Assert.AreEqual(
|
|
34
|
+
new List<(object, object)>
|
|
35
|
+
{
|
|
36
|
+
new(intObservable, 100),
|
|
37
|
+
new(stringObservable, "200")
|
|
38
|
+
},
|
|
39
|
+
operations
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
callCount = 0;
|
|
43
|
+
operations.Clear();
|
|
44
|
+
|
|
45
|
+
context.ExecuteBatchOperation(() =>
|
|
46
|
+
{
|
|
47
|
+
intObservable.value = 1;
|
|
48
|
+
stringObservable.value = "2";
|
|
49
|
+
intObservable.value = 3;
|
|
50
|
+
intObservable.value = 4;
|
|
51
|
+
stringObservable.value = "5";
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
Assert.AreEqual(5, callCount);
|
|
55
|
+
Assert.AreEqual(
|
|
56
|
+
new List<(object, object)>
|
|
57
|
+
{
|
|
58
|
+
new(intObservable, 1),
|
|
59
|
+
new(stringObservable, "2"),
|
|
60
|
+
new(intObservable, 3),
|
|
61
|
+
new(intObservable, 4),
|
|
62
|
+
new(stringObservable, "5"),
|
|
63
|
+
},
|
|
64
|
+
operations
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
[Test]
|
|
69
|
+
public void TestRollingObserverOrder()
|
|
70
|
+
{
|
|
71
|
+
var context = new ObservationContext();
|
|
72
|
+
|
|
73
|
+
ObservableValue<int> intObservable = new ObservableValue<int>(context);
|
|
74
|
+
|
|
75
|
+
List<(int observer, int value)> observerCallOrder = new List<(int observer, int value)>();
|
|
76
|
+
|
|
77
|
+
IDisposable subscription1 = default;
|
|
78
|
+
IDisposable subscription2 = default;
|
|
79
|
+
IDisposable subscription3 = default;
|
|
80
|
+
IDisposable subscription4 = default;
|
|
81
|
+
IDisposable subscription5 = default;
|
|
82
|
+
|
|
83
|
+
subscription1 = intObservable.Subscribe(
|
|
84
|
+
onNext: value => observerCallOrder.Add(new(1, value))
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
subscription2 = intObservable.Subscribe(
|
|
88
|
+
onNext: value =>
|
|
89
|
+
{
|
|
90
|
+
observerCallOrder.Add(new(2, value));
|
|
91
|
+
|
|
92
|
+
if (value == 1)
|
|
93
|
+
intObservable.value = 2;
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
subscription3 = intObservable.Subscribe(
|
|
98
|
+
onNext: value =>
|
|
99
|
+
{
|
|
100
|
+
observerCallOrder.Add(new(3, value));
|
|
101
|
+
|
|
102
|
+
if (value == 2)
|
|
103
|
+
{
|
|
104
|
+
intObservable.value = 3;
|
|
105
|
+
subscription4.Dispose();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
subscription4 = intObservable.Subscribe(
|
|
111
|
+
onNext: value => observerCallOrder.Add(new(4, value))
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
subscription5 = intObservable.Subscribe(
|
|
115
|
+
onNext: value => observerCallOrder.Add(new(5, value))
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
intObservable.value = 1;
|
|
119
|
+
|
|
120
|
+
Assert.AreEqual(3, intObservable.value);
|
|
121
|
+
|
|
122
|
+
Assert.AreEqual(
|
|
123
|
+
new List<(int observer, int value)>()
|
|
124
|
+
{
|
|
125
|
+
new (1, 0), //init observer1
|
|
126
|
+
new (2, 0), //init observer2
|
|
127
|
+
new (3, 0), //init observer3
|
|
128
|
+
new (4, 0), //init observer4
|
|
129
|
+
new (5, 0), //init observer5
|
|
130
|
+
new (1, 1), //observer1 observes external setting intObservable to 1
|
|
131
|
+
new (2, 1), //observer2 observes external setting intObservable to 1
|
|
132
|
+
new (1, 2), //observer1 observes observer2 setting intObservable to 2
|
|
133
|
+
new (2, 2), //observer2 observes observer2 setting intObservable to 2
|
|
134
|
+
new (3, 1), //observer3 observes external setting intObservable to 1
|
|
135
|
+
new (3, 2), //observer3 observes observer2 setting intObservable to 2
|
|
136
|
+
//4, //observer4 is never called past the init because it gets unsubscribed by observer3
|
|
137
|
+
new (1, 3), //observer1 observes observer3 setting intObservable to 3
|
|
138
|
+
new (2, 3), //observer2 observes observer3 setting intObservable to 3
|
|
139
|
+
new (3, 3), //observer3 observes observer3 setting intObservable to 3
|
|
140
|
+
new (5, 1), //observer5 observes external setting intObservable to 1
|
|
141
|
+
new (5, 2), //observer5 observes observer2 setting intObservable to 2
|
|
142
|
+
new (5, 3) //observer5 observes observer3 setting intObservable to 3
|
|
143
|
+
},
|
|
144
|
+
observerCallOrder
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
[Test]
|
|
149
|
+
public void TestCombineObservable()
|
|
150
|
+
{
|
|
151
|
+
var context = new ObservationContext();
|
|
152
|
+
|
|
153
|
+
ObservableValue<int> intObservable = new ObservableValue<int>(context);
|
|
154
|
+
ObservableValue<string> stringObservable = new ObservableValue<string>(context);
|
|
155
|
+
|
|
156
|
+
var query = Observables.ObservableCombine(intObservable, stringObservable);
|
|
157
|
+
|
|
158
|
+
List<(object source, object value)> observerCallOrder = new List<(object source, object value)>();
|
|
159
|
+
|
|
160
|
+
IDisposable subscription = query.Subscribe(
|
|
161
|
+
onNext: op =>
|
|
162
|
+
{
|
|
163
|
+
observerCallOrder.Add(new(op.source, ((IValueOp)op).value));
|
|
164
|
+
|
|
165
|
+
if (intObservable.value == 2)
|
|
166
|
+
{
|
|
167
|
+
intObservable.value = 6;
|
|
168
|
+
intObservable.value = 7;
|
|
169
|
+
intObservable.value = 8;
|
|
170
|
+
stringObservable.value = "mouse";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
intObservable.value = 1;
|
|
176
|
+
stringObservable.value = "cat";
|
|
177
|
+
stringObservable.value = "dog";
|
|
178
|
+
intObservable.value = 2;
|
|
179
|
+
stringObservable.value = "frog";
|
|
180
|
+
intObservable.value = 3;
|
|
181
|
+
intObservable.value = 4;
|
|
182
|
+
|
|
183
|
+
Assert.AreEqual(
|
|
184
|
+
new List<(object source, object value)>()
|
|
185
|
+
{
|
|
186
|
+
new(intObservable, 0),
|
|
187
|
+
new(stringObservable, null),
|
|
188
|
+
new(intObservable, 1),
|
|
189
|
+
new(stringObservable, "cat"),
|
|
190
|
+
new(stringObservable, "dog"),
|
|
191
|
+
new(intObservable, 2),
|
|
192
|
+
new(intObservable, 6),
|
|
193
|
+
new(intObservable, 7),
|
|
194
|
+
new(intObservable, 8),
|
|
195
|
+
new(stringObservable, "mouse"),
|
|
196
|
+
new(stringObservable, "frog"),
|
|
197
|
+
new(intObservable, 3),
|
|
198
|
+
new(intObservable, 4),
|
|
199
|
+
},
|
|
200
|
+
observerCallOrder
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
[Test]
|
|
205
|
+
public void TestAllObservablesDispose()
|
|
206
|
+
{
|
|
207
|
+
var context = new ObservationContext();
|
|
208
|
+
var observable1 = new ObservableValue<int>(context);
|
|
209
|
+
var observable2 = new ObservableValue<int>(context);
|
|
210
|
+
var disposeCallCount = 0;
|
|
211
|
+
var disposed = false;
|
|
212
|
+
|
|
213
|
+
var query = Observables.ObservableCombine(observable1, observable2);
|
|
214
|
+
|
|
215
|
+
var stream = query.Subscribe(
|
|
216
|
+
onDispose: () =>
|
|
217
|
+
{
|
|
218
|
+
disposeCallCount++;
|
|
219
|
+
disposed = true;
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
observable1.Dispose();
|
|
224
|
+
|
|
225
|
+
Assert.IsFalse(disposed);
|
|
226
|
+
Assert.AreEqual(0, disposeCallCount);
|
|
227
|
+
|
|
228
|
+
observable2.Dispose();
|
|
229
|
+
|
|
230
|
+
Assert.IsTrue(disposed);
|
|
231
|
+
Assert.AreEqual(1, disposeCallCount);
|
|
232
|
+
|
|
233
|
+
disposeCallCount = 0;
|
|
234
|
+
disposed = false;
|
|
235
|
+
|
|
236
|
+
Assert.Throws(
|
|
237
|
+
typeof(ObjectDisposedException),
|
|
238
|
+
() => query.Subscribe(
|
|
239
|
+
onDispose: () =>
|
|
240
|
+
{
|
|
241
|
+
disposeCallCount++;
|
|
242
|
+
disposed = true;
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
[Test]
|
|
249
|
+
public void TestBatchObservable()
|
|
250
|
+
{
|
|
251
|
+
var context = new ObservationContext();
|
|
252
|
+
var value = new ObservableValue<int>(context, 2);
|
|
253
|
+
|
|
254
|
+
var init = false;
|
|
255
|
+
var lastValue = 0;
|
|
256
|
+
var callCount = 0;
|
|
257
|
+
|
|
258
|
+
value.ObservableBatch().Subscribe(
|
|
259
|
+
onNext: ops =>
|
|
260
|
+
{
|
|
261
|
+
callCount++;
|
|
262
|
+
lastValue = ops.Last().value;
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
Assert.AreEqual(1, callCount);
|
|
267
|
+
Assert.AreEqual(value.value, lastValue);
|
|
268
|
+
|
|
269
|
+
init = false;
|
|
270
|
+
value.value = 4;
|
|
271
|
+
|
|
272
|
+
Assert.AreEqual(2, callCount);
|
|
273
|
+
Assert.IsFalse(init);
|
|
274
|
+
Assert.AreEqual(value.value, lastValue);
|
|
275
|
+
|
|
276
|
+
context.ExecuteBatchOperation(() =>
|
|
277
|
+
{
|
|
278
|
+
value.value = 5;
|
|
279
|
+
value.value = 6;
|
|
280
|
+
value.value = 7;
|
|
281
|
+
value.value = 8;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
Assert.AreEqual(3, callCount);
|
|
285
|
+
Assert.IsFalse(init);
|
|
286
|
+
Assert.AreEqual(value.value, lastValue);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
[Test]
|
|
290
|
+
public void TestCollectionInitialization()
|
|
291
|
+
{
|
|
292
|
+
ObservationContext context = new ObservationContext();
|
|
293
|
+
var dictionary = new ObservableDictionary<string, int>(context);
|
|
294
|
+
|
|
295
|
+
dictionary.Add("cat", 1);
|
|
296
|
+
dictionary.Add("dog", 2);
|
|
297
|
+
dictionary.Add("frog", 3);
|
|
298
|
+
|
|
299
|
+
var initOps = new List<(object source, object value, bool isRemove)>();
|
|
300
|
+
|
|
301
|
+
Observables.ObservableCombine(dictionary).Subscribe(onNext: op =>
|
|
302
|
+
{
|
|
303
|
+
var args = (DictionaryOp<string, int>)op;
|
|
304
|
+
initOps.Add(new(op.source, new KeyValuePair<string, int>(args.key, args.value), args.isRemove));
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
Assert.That(
|
|
308
|
+
initOps,
|
|
309
|
+
Is.EqualTo(
|
|
310
|
+
new List<(object source, object value, bool isRemove)>()
|
|
311
|
+
{
|
|
312
|
+
new(dictionary, KeyValuePair.Create("cat", 1), false),
|
|
313
|
+
new(dictionary, KeyValuePair.Create("dog", 2), false),
|
|
314
|
+
new(dictionary, KeyValuePair.Create("frog", 3), false)
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
initOps.Clear();
|
|
320
|
+
|
|
321
|
+
var list = new ObservableList<float>(context);
|
|
322
|
+
|
|
323
|
+
list.Add(0.22f);
|
|
324
|
+
list.Add(0.11f);
|
|
325
|
+
list.Add(-1000f);
|
|
326
|
+
list.Insert(1, 50f);
|
|
327
|
+
|
|
328
|
+
var subscription = Observables.ObservableCombine(dictionary, list).Subscribe(onNext: op =>
|
|
329
|
+
{
|
|
330
|
+
if (op.source == dictionary)
|
|
331
|
+
{
|
|
332
|
+
var args = (DictionaryOp<string, int>)op;
|
|
333
|
+
initOps.Add(new(op.source, new KeyValuePair<string, int>(args.key, args.value), args.isRemove));
|
|
334
|
+
}
|
|
335
|
+
else
|
|
336
|
+
{
|
|
337
|
+
var args = (ListOp<float>)op;
|
|
338
|
+
initOps.Add(new(op.source, args.element, args.isRemove));
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
Assert.That(
|
|
343
|
+
initOps,
|
|
344
|
+
Is.EqualTo(
|
|
345
|
+
new List<(object source, object value, bool isRemove)>()
|
|
346
|
+
{
|
|
347
|
+
new(dictionary, KeyValuePair.Create("cat", 1), false),
|
|
348
|
+
new(dictionary, KeyValuePair.Create("dog", 2), false),
|
|
349
|
+
new(dictionary, KeyValuePair.Create("frog", 3), false),
|
|
350
|
+
new(list, 0.22f, false),
|
|
351
|
+
new(list, 50f, false),
|
|
352
|
+
new(list, 0.11f, false),
|
|
353
|
+
new(list, -1000f, false)
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|