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.
Files changed (117) hide show
  1. package/README.md +2 -0
  2. package/README.md.meta +7 -0
  3. package/Runtime/CollectionIdProvider.cs +72 -0
  4. package/Runtime/CollectionIdProvider.cs.meta +2 -0
  5. package/Runtime/IObservable.cs +66 -0
  6. package/Runtime/IObservable.cs.meta +2 -0
  7. package/Runtime/Implementations/Observable.cs +30 -0
  8. package/Runtime/Implementations/Observable.cs.meta +2 -0
  9. package/Runtime/Implementations/ObservableBase.cs +173 -0
  10. package/Runtime/Implementations/ObservableBase.cs.meta +2 -0
  11. package/Runtime/Implementations/ObservableCollection.cs +141 -0
  12. package/Runtime/Implementations/ObservableCollection.cs.meta +2 -0
  13. package/Runtime/Implementations/ObservableDictionary.cs +166 -0
  14. package/Runtime/Implementations/ObservableDictionary.cs.meta +2 -0
  15. package/Runtime/Implementations/ObservableList.cs +163 -0
  16. package/Runtime/Implementations/ObservableList.cs.meta +2 -0
  17. package/Runtime/Implementations/ObservableSet.cs +137 -0
  18. package/Runtime/Implementations/ObservableSet.cs.meta +2 -0
  19. package/Runtime/Implementations/ObservableValue.cs +59 -0
  20. package/Runtime/Implementations/ObservableValue.cs.meta +2 -0
  21. package/Runtime/Implementations.meta +8 -0
  22. package/Runtime/Observables/BatchObservable.cs +72 -0
  23. package/Runtime/Observables/BatchObservable.cs.meta +2 -0
  24. package/Runtime/Observables/CastObservable.cs +128 -0
  25. package/Runtime/Observables/CastObservable.cs.meta +2 -0
  26. package/Runtime/Observables/CombineObservable.cs +96 -0
  27. package/Runtime/Observables/CombineObservable.cs.meta +2 -0
  28. package/Runtime/Observables/CombineValueObservable.cs +319 -0
  29. package/Runtime/Observables/CombineValueObservable.cs.meta +2 -0
  30. package/Runtime/Observables/ConcatObservable.cs +75 -0
  31. package/Runtime/Observables/ConcatObservable.cs.meta +2 -0
  32. package/Runtime/Observables/ContainsObservable.cs +71 -0
  33. package/Runtime/Observables/ContainsObservable.cs.meta +2 -0
  34. package/Runtime/Observables/CountObservable.cs +29 -0
  35. package/Runtime/Observables/CountObservable.cs.meta +2 -0
  36. package/Runtime/Observables/DistinctObservable.cs +55 -0
  37. package/Runtime/Observables/DistinctObservable.cs.meta +2 -0
  38. package/Runtime/Observables/FirstObservable.cs +53 -0
  39. package/Runtime/Observables/FirstObservable.cs.meta +2 -0
  40. package/Runtime/Observables/IndexOfObservable.cs +83 -0
  41. package/Runtime/Observables/IndexOfObservable.cs.meta +2 -0
  42. package/Runtime/Observables/OperationStreamObservable.cs +194 -0
  43. package/Runtime/Observables/OperationStreamObservable.cs.meta +2 -0
  44. package/Runtime/Observables/OrderByObservable.cs +116 -0
  45. package/Runtime/Observables/OrderByObservable.cs.meta +2 -0
  46. package/Runtime/Observables/SelectCollectionObservable.cs +29 -0
  47. package/Runtime/Observables/SelectCollectionObservable.cs.meta +2 -0
  48. package/Runtime/Observables/SelectListObservable.cs +29 -0
  49. package/Runtime/Observables/SelectListObservable.cs.meta +2 -0
  50. package/Runtime/Observables/SelectManyObservable.cs +78 -0
  51. package/Runtime/Observables/SelectManyObservable.cs.meta +2 -0
  52. package/Runtime/Observables/SelectValueObservable.cs +28 -0
  53. package/Runtime/Observables/SelectValueObservable.cs.meta +2 -0
  54. package/Runtime/Observables/SkipWhileObservable.cs +32 -0
  55. package/Runtime/Observables/SkipWhileObservable.cs.meta +2 -0
  56. package/Runtime/Observables/ThenObservable.cs +209 -0
  57. package/Runtime/Observables/ThenObservable.cs.meta +2 -0
  58. package/Runtime/Observables/ToDictionaryObservable.cs +35 -0
  59. package/Runtime/Observables/ToDictionaryObservable.cs.meta +2 -0
  60. package/Runtime/Observables/TrackObservable.cs +74 -0
  61. package/Runtime/Observables/TrackObservable.cs.meta +2 -0
  62. package/Runtime/Observables/UnwrapCollectionObservable.cs +64 -0
  63. package/Runtime/Observables/UnwrapCollectionObservable.cs.meta +2 -0
  64. package/Runtime/Observables/UnwrapListObservable.cs +69 -0
  65. package/Runtime/Observables/UnwrapListObservable.cs.meta +2 -0
  66. package/Runtime/Observables/UnwrapValueObservable.cs +56 -0
  67. package/Runtime/Observables/UnwrapValueObservable.cs.meta +2 -0
  68. package/Runtime/Observables/WhereObservable.cs +85 -0
  69. package/Runtime/Observables/WhereObservable.cs.meta +2 -0
  70. package/Runtime/Observables/WithPreviousObservable.cs +36 -0
  71. package/Runtime/Observables/WithPreviousObservable.cs.meta +2 -0
  72. package/Runtime/Observables.cs +467 -0
  73. package/Runtime/Observables.cs.meta +2 -0
  74. package/Runtime/Observables.meta +8 -0
  75. package/Runtime/ObservationContext.cs +126 -0
  76. package/Runtime/ObservationContext.cs.meta +2 -0
  77. package/Runtime/Observers.cs +403 -0
  78. package/Runtime/Observers.cs.meta +2 -0
  79. package/Runtime/Operators/BatchOperator.cs +71 -0
  80. package/Runtime/Operators/BatchOperator.cs.meta +2 -0
  81. package/Runtime/Operators/CollectionOperator.cs +30 -0
  82. package/Runtime/Operators/CollectionOperator.cs.meta +2 -0
  83. package/Runtime/Operators/DictionaryOperator.cs +45 -0
  84. package/Runtime/Operators/DictionaryOperator.cs.meta +2 -0
  85. package/Runtime/Operators/IInitializationOperationsProvider.cs +10 -0
  86. package/Runtime/Operators/IInitializationOperationsProvider.cs.meta +2 -0
  87. package/Runtime/Operators/ListOperator.cs +44 -0
  88. package/Runtime/Operators/ListOperator.cs.meta +2 -0
  89. package/Runtime/Operators/ObservableOperator.cs +75 -0
  90. package/Runtime/Operators/ObservableOperator.cs.meta +2 -0
  91. package/Runtime/Operators/Operator.cs +65 -0
  92. package/Runtime/Operators/Operator.cs.meta +2 -0
  93. package/Runtime/Operators/SetOperator.cs +44 -0
  94. package/Runtime/Operators/SetOperator.cs.meta +2 -0
  95. package/Runtime/Operators/ValueOperator.cs +30 -0
  96. package/Runtime/Operators/ValueOperator.cs.meta +2 -0
  97. package/Runtime/Operators.meta +8 -0
  98. package/Runtime/PriorityQueue.cs +1096 -0
  99. package/Runtime/PriorityQueue.cs.meta +2 -0
  100. package/Runtime/com.fofx.observething.asmdef +14 -0
  101. package/Runtime/com.fofx.observething.asmdef.meta +7 -0
  102. package/Runtime.meta +8 -0
  103. package/Tests/CollectionObservableTests.cs +739 -0
  104. package/Tests/CollectionObservableTests.cs.meta +2 -0
  105. package/Tests/DictionaryObservableTests.cs +85 -0
  106. package/Tests/DictionaryObservableTests.cs.meta +2 -0
  107. package/Tests/ListObservableTests.cs +148 -0
  108. package/Tests/ListObservableTests.cs.meta +2 -0
  109. package/Tests/ObservationContextTests.cs +359 -0
  110. package/Tests/ObservationContextTests.cs.meta +2 -0
  111. package/Tests/ValueObservableTests.cs +322 -0
  112. package/Tests/ValueObservableTests.cs.meta +2 -0
  113. package/Tests/com.fofx.observething.tests.asmdef +24 -0
  114. package/Tests/com.fofx.observething.tests.asmdef.meta +7 -0
  115. package/Tests.meta +8 -0
  116. package/package.json +24 -0
  117. package/package.json.meta +7 -0
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 62a831dcf935dd84f897290af875a1db
@@ -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,2 @@
1
+ fileFormatVersion: 2
2
+ guid: a94e77255360f7147bf014722956e332
@@ -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,2 @@
1
+ fileFormatVersion: 2
2
+ guid: f882eb52ecddecd4e9796cdd37447b08
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 4da78d805d539ea4db48bc0b719908d5