PageRenderTime 43ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/ReactiveUI.Tests/ReactiveCollectionTest.cs

https://github.com/bsiegel/ReactiveUI
C# | 524 lines | 422 code | 98 blank | 4 comment | 6 complexity | 5701300023850416c79d0fa764905163 MD5 | raw file
Possible License(s): Apache-2.0, CC-BY-SA-3.0, LGPL-2.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reactive.Linq;
  7. using System.Text;
  8. using ReactiveUI.Testing;
  9. using Xunit;
  10. using Microsoft.Reactive.Testing;
  11. namespace ReactiveUI.Tests
  12. {
  13. public class ReactiveCollectionTest
  14. {
  15. [Fact]
  16. public void CollectionCountChangedTest()
  17. {
  18. var fixture = new ReactiveCollection<int>();
  19. var before_output = new List<int>();
  20. var output = new List<int>();
  21. fixture.CollectionCountChanging.Subscribe(before_output.Add);
  22. fixture.CollectionCountChanged.Subscribe(output.Add);
  23. fixture.Add(10);
  24. fixture.Add(20);
  25. fixture.Add(30);
  26. fixture.RemoveAt(1);
  27. fixture.Clear();
  28. var before_results = new[] {0,1,2,3,2};
  29. Assert.Equal(before_results.Length, before_output.Count);
  30. before_results.AssertAreEqual(before_output);
  31. var results = new[]{1,2,3,2,0};
  32. Assert.Equal(results.Length, output.Count);
  33. results.AssertAreEqual(output);
  34. }
  35. [Fact]
  36. public void CollectionCountChangedFiresWhenClearing()
  37. {
  38. var items = new ReactiveCollection<object>(new []{new object()});
  39. bool countChanged = false;
  40. items.CollectionCountChanged.Subscribe(_ => {countChanged = true;});
  41. items.Clear();
  42. Assert.True(countChanged);
  43. }
  44. [Fact]
  45. public void ItemsAddedAndRemovedTest()
  46. {
  47. var fixture = new ReactiveCollection<int>();
  48. var before_added = new List<int>();
  49. var before_removed = new List<int>();
  50. var added = new List<int>();
  51. var removed = new List<int>();
  52. fixture.BeforeItemsAdded.Subscribe(before_added.Add);
  53. fixture.BeforeItemsRemoved.Subscribe(before_removed.Add);
  54. fixture.ItemsAdded.Subscribe(added.Add);
  55. fixture.ItemsRemoved.Subscribe(removed.Add);
  56. fixture.Add(10);
  57. fixture.Add(20);
  58. fixture.Add(30);
  59. fixture.RemoveAt(1);
  60. fixture.Clear();
  61. var added_results = new[]{10,20,30};
  62. Assert.Equal(added_results.Length, added.Count);
  63. added_results.AssertAreEqual(added);
  64. var removed_results = new[]{20};
  65. Assert.Equal(removed_results.Length, removed.Count);
  66. removed_results.AssertAreEqual(removed);
  67. Assert.Equal(before_added.Count, added.Count);
  68. added.AssertAreEqual(before_added);
  69. Assert.Equal(before_removed.Count, removed.Count);
  70. removed.AssertAreEqual(before_removed);
  71. }
  72. [Fact]
  73. public void ReactiveCollectionIsRoundTrippable()
  74. {
  75. var output = new[] {"Foo", "Bar", "Baz", "Bamf"};
  76. var fixture = new ReactiveCollection<string>(output);
  77. string json = JSONHelper.Serialize(fixture);
  78. var results = JSONHelper.Deserialize<ReactiveCollection<string>>(json);
  79. output.AssertAreEqual(results);
  80. bool should_die = true;
  81. results.ItemsAdded.Subscribe(_ => should_die = false);
  82. results.Add("Foobar");
  83. Assert.False(should_die);
  84. }
  85. [Fact]
  86. public void ChangeTrackingShouldFireNotifications()
  87. {
  88. var fixture = new ReactiveCollection<TestFixture>() { ChangeTrackingEnabled = true };
  89. var before_output = new List<Tuple<TestFixture, string>>();
  90. var output = new List<Tuple<TestFixture, string>>();
  91. var item1 = new TestFixture() { IsOnlyOneWord = "Foo" };
  92. var item2 = new TestFixture() { IsOnlyOneWord = "Bar" };
  93. fixture.ItemChanging.Subscribe(x => {
  94. before_output.Add(new Tuple<TestFixture,string>((TestFixture)x.Sender, x.PropertyName));
  95. });
  96. fixture.ItemChanged.Subscribe(x => {
  97. output.Add(new Tuple<TestFixture,string>((TestFixture)x.Sender, x.PropertyName));
  98. });
  99. fixture.Add(item1);
  100. fixture.Add(item2);
  101. item1.IsOnlyOneWord = "Baz";
  102. Assert.Equal(1, output.Count);
  103. item2.IsNotNullString = "FooBar";
  104. Assert.Equal(2, output.Count);
  105. fixture.Remove(item2);
  106. item2.IsNotNullString = "FooBarBaz";
  107. Assert.Equal(2, output.Count);
  108. fixture.ChangeTrackingEnabled = false;
  109. item1.IsNotNullString = "Bamf";
  110. Assert.Equal(2, output.Count);
  111. new[]{item1, item2}.AssertAreEqual(output.Select(x => x.Item1));
  112. new[]{item1, item2}.AssertAreEqual(before_output.Select(x => x.Item1));
  113. new[]{"IsOnlyOneWord", "IsNotNullString"}.AssertAreEqual(output.Select(x => x.Item2));
  114. }
  115. [Fact]
  116. public void ChangeTrackingShouldWorkWhenAddingTheSameThingMoreThanOnce()
  117. {
  118. var fixture = new ReactiveCollection<TestFixture>() { ChangeTrackingEnabled = true };
  119. var output = new List<Tuple<TestFixture, string>>();
  120. var item1 = new TestFixture() { IsOnlyOneWord = "Foo" };
  121. fixture.ItemChanged.Subscribe(x => {
  122. output.Add(new Tuple<TestFixture,string>((TestFixture)x.Sender, x.PropertyName));
  123. });
  124. fixture.Add(item1);
  125. fixture.Add(item1);
  126. fixture.Add(item1);
  127. item1.IsOnlyOneWord = "Bar";
  128. Assert.Equal(1, output.Count);
  129. fixture.RemoveAt(0);
  130. item1.IsOnlyOneWord = "Baz";
  131. Assert.Equal(2, output.Count);
  132. fixture.RemoveAt(0);
  133. fixture.RemoveAt(0);
  134. // We've completely removed item1, we shouldn't be seeing any
  135. // notifications from it
  136. item1.IsOnlyOneWord = "Bamf";
  137. Assert.Equal(2, output.Count);
  138. fixture.ChangeTrackingEnabled = false;
  139. fixture.Add(item1);
  140. fixture.Add(item1);
  141. fixture.Add(item1);
  142. fixture.ChangeTrackingEnabled = true;
  143. item1.IsOnlyOneWord = "Bonk";
  144. Assert.Equal(3, output.Count);
  145. }
  146. [Fact]
  147. public void CollectionsShouldntShareSubscriptions()
  148. {
  149. var fixture1 = new ReactiveCollection<TestFixture>() { ChangeTrackingEnabled = true };
  150. var fixture2 = new ReactiveCollection<TestFixture>() { ChangeTrackingEnabled = true };
  151. var item1 = new TestFixture() { IsOnlyOneWord = "Foo" };
  152. var output1 = new List<Tuple<TestFixture, string>>();
  153. var output2 = new List<Tuple<TestFixture, string>>();
  154. fixture1.ItemChanged.Subscribe(x => {
  155. output1.Add(new Tuple<TestFixture,string>((TestFixture)x.Sender, x.PropertyName));
  156. });
  157. fixture2.ItemChanged.Subscribe(x => {
  158. output2.Add(new Tuple<TestFixture,string>((TestFixture)x.Sender, x.PropertyName));
  159. });
  160. fixture1.Add(item1);
  161. fixture1.Add(item1);
  162. fixture2.Add(item1);
  163. fixture2.Add(item1);
  164. item1.IsOnlyOneWord = "Bar";
  165. Assert.Equal(1, output1.Count);
  166. Assert.Equal(1, output2.Count);
  167. fixture2.RemoveAt(0);
  168. item1.IsOnlyOneWord = "Baz";
  169. Assert.Equal(2, output1.Count);
  170. Assert.Equal(2, output2.Count);
  171. }
  172. [Fact]
  173. public void CreateCollectionWithoutTimer()
  174. {
  175. var input = new[] {"Foo", "Bar", "Baz", "Bamf"};
  176. var fixture = (new TestScheduler()).With(sched => {
  177. var f = input.ToObservable(sched).CreateCollection();
  178. sched.Start();
  179. return f;
  180. });
  181. input.AssertAreEqual(fixture);
  182. }
  183. [Fact]
  184. public void CreateCollectionWithTimer()
  185. {
  186. var input = new[] {"Foo", "Bar", "Baz", "Bamf"};
  187. var sched = new TestScheduler();
  188. using (TestUtils.WithScheduler(sched)) {
  189. ReactiveCollection<string> fixture;
  190. fixture = input.ToObservable(sched).CreateCollection(TimeSpan.FromSeconds(0.5));
  191. sched.AdvanceToMs(1005);
  192. fixture.AssertAreEqual(input.Take(2));
  193. sched.AdvanceToMs(1505);
  194. fixture.AssertAreEqual(input.Take(3));
  195. sched.AdvanceToMs(10000);
  196. fixture.AssertAreEqual(input);
  197. }
  198. }
  199. [Fact]
  200. public void DerivedCollectionsShouldFollowBaseCollection()
  201. {
  202. var input = new[] {"Foo", "Bar", "Baz", "Bamf"};
  203. var fixture = new ReactiveCollection<TestFixture>(
  204. input.Select(x => new TestFixture() { IsOnlyOneWord = x }));
  205. var output = fixture.CreateDerivedCollection(new Func<TestFixture, string>(x => x.IsOnlyOneWord));
  206. input.AssertAreEqual(output);
  207. fixture.Add(new TestFixture() { IsOnlyOneWord = "Hello" });
  208. Assert.Equal(5, output.Count);
  209. Assert.Equal("Hello", output[4]);
  210. fixture.RemoveAt(4);
  211. Assert.Equal(4, output.Count);
  212. fixture[1] = new TestFixture() { IsOnlyOneWord = "Goodbye" };
  213. Assert.Equal(4, output.Count);
  214. Assert.Equal("Goodbye", output[1]);
  215. fixture.Clear();
  216. Assert.Equal(0, output.Count);
  217. }
  218. [Fact]
  219. public void DerivedCollectionsShouldBeFiltered()
  220. {
  221. var input = new[] {"Foo", "Bar", "Baz", "Bamf"};
  222. var fixture = new ReactiveCollection<TestFixture>(
  223. input.Select(x => new TestFixture() { IsOnlyOneWord = x }));
  224. var itemsAdded = new List<TestFixture>();
  225. var itemsRemoved = new List<TestFixture>();
  226. var output = fixture.CreateDerivedCollection(x => x, x => x.IsOnlyOneWord[0] == 'F', (l,r) => l.IsOnlyOneWord.CompareTo(r.IsOnlyOneWord));
  227. output.ItemsAdded.Subscribe(itemsAdded.Add);
  228. output.ItemsRemoved.Subscribe(itemsRemoved.Add);
  229. Assert.Equal(1, output.Count);
  230. Assert.Equal(0, itemsAdded.Count);
  231. Assert.Equal(0, itemsRemoved.Count);
  232. fixture.Add(new TestFixture() {IsOnlyOneWord = "Boof"});
  233. Assert.Equal(1, output.Count);
  234. Assert.Equal(0, itemsAdded.Count);
  235. Assert.Equal(0, itemsRemoved.Count);
  236. fixture.Add(new TestFixture() {IsOnlyOneWord = "Far"});
  237. Assert.Equal(2, output.Count);
  238. Assert.Equal(1, itemsAdded.Count);
  239. Assert.Equal(0, itemsRemoved.Count);
  240. fixture.RemoveAt(1); // Remove "Bar"
  241. Assert.Equal(2, output.Count);
  242. Assert.Equal(1, itemsAdded.Count);
  243. Assert.Equal(0, itemsRemoved.Count);
  244. fixture.RemoveAt(0); // Remove "Foo"
  245. Assert.Equal(1, output.Count);
  246. Assert.Equal(1, itemsAdded.Count);
  247. Assert.Equal(1, itemsRemoved.Count);
  248. }
  249. [Fact]
  250. public void AddRangeSmokeTest()
  251. {
  252. var fixture = new ReactiveCollection<string>();
  253. var output = fixture.CreateDerivedCollection(x => "Prefix" + x);
  254. fixture.Add("Bamf");
  255. Assert.Equal(1, fixture.Count);
  256. Assert.Equal(1, output.Count);
  257. Assert.Equal("Bamf", fixture[0]);
  258. Assert.Equal("PrefixBamf", output[0]);
  259. fixture.AddRange(Enumerable.Repeat("Bar", 4));
  260. Assert.Equal(5, fixture.Count);
  261. Assert.Equal(5, output.Count);
  262. Assert.Equal("Bamf", fixture[0]);
  263. Assert.Equal("PrefixBamf", output[0]);
  264. Assert.True(fixture.Skip(1).All(x => x == "Bar"));
  265. Assert.True(output.Skip(1).All(x => x == "PrefixBar"));
  266. // Trigger the Reset by adding a ton of items
  267. fixture.AddRange(Enumerable.Repeat("Bar", 35));
  268. Assert.Equal(40, fixture.Count);
  269. Assert.Equal(40, output.Count);
  270. Assert.Equal("Bamf", fixture[0]);
  271. Assert.Equal("PrefixBamf", output[0]);
  272. }
  273. [Fact]
  274. public void InsertRangeSmokeTest()
  275. {
  276. var fixture = new ReactiveCollection<string>();
  277. var output = fixture.CreateDerivedCollection(x => "Prefix" + x);
  278. fixture.Add("Bamf");
  279. Assert.Equal(1, fixture.Count);
  280. Assert.Equal(1, output.Count);
  281. Assert.Equal("Bamf", fixture[0]);
  282. Assert.Equal("PrefixBamf", output[0]);
  283. fixture.InsertRange(0, Enumerable.Repeat("Bar", 4));
  284. Assert.Equal(5, fixture.Count);
  285. Assert.Equal(5, output.Count);
  286. Assert.Equal("Bamf", fixture[4]);
  287. Assert.Equal("PrefixBamf", output[4]);
  288. Assert.True(fixture.Take(4).All(x => x == "Bar"));
  289. Assert.True(output.Take(4).All(x => x == "PrefixBar"));
  290. // Trigger the Reset by adding a ton of items
  291. fixture.InsertRange(0, Enumerable.Repeat("Bar", 35));
  292. Assert.Equal(40, fixture.Count);
  293. Assert.Equal(40, output.Count);
  294. Assert.Equal("Bamf", fixture[39]);
  295. Assert.Equal("PrefixBamf", output[39]);
  296. }
  297. [Fact]
  298. public void SortShouldActuallySort()
  299. {
  300. var fixture = new ReactiveCollection<int>(new[] {5, 1, 3, 2, 4,});
  301. fixture.Sort();
  302. Assert.True(new[] {1, 2, 3, 4, 5,}.Zip(fixture, (expected, actual) => expected == actual).All(x => x));
  303. }
  304. [Fact]
  305. public void IListTSmokeTest() {
  306. var fixture = new ReactiveCollection<string>() as IList<string>;
  307. Assert.NotNull(fixture);
  308. fixture.Add("foo");
  309. Assert.Equal(1, fixture.Count);
  310. Assert.True(fixture.Contains("foo"));
  311. fixture.Insert(0, "bar");
  312. Assert.Equal(0, fixture.IndexOf("bar"));
  313. Assert.Equal(1, fixture.IndexOf("foo"));
  314. Assert.Equal("bar", fixture[0]);
  315. Assert.Equal("foo", fixture[1]);
  316. var genericEnum = ((IEnumerable<string>)fixture).GetEnumerator();
  317. Assert.NotNull(genericEnum);
  318. bool result = genericEnum.MoveNext();
  319. Assert.True(result);
  320. Assert.Equal("bar", genericEnum.Current);
  321. result = genericEnum.MoveNext();
  322. Assert.True(result);
  323. Assert.Equal("foo", genericEnum.Current);
  324. result = genericEnum.MoveNext();
  325. Assert.False(result);
  326. var plainEnum = ((IEnumerable)fixture).GetEnumerator();
  327. Assert.NotNull(plainEnum);
  328. result = plainEnum.MoveNext();
  329. Assert.True(result);
  330. Assert.Equal("bar", plainEnum.Current as string);
  331. result = plainEnum.MoveNext();
  332. Assert.True(result);
  333. Assert.Equal("foo", plainEnum.Current as string);
  334. result = plainEnum.MoveNext();
  335. Assert.False(result);
  336. var arr = new string[2];
  337. fixture.CopyTo(arr, 0);
  338. Assert.Equal(2, arr.Length);
  339. Assert.Equal("bar", arr[0]);
  340. Assert.Equal("foo", arr[1]);
  341. fixture[1] = "baz";
  342. Assert.Equal(1, fixture.IndexOf("baz"));
  343. Assert.Equal(-1, fixture.IndexOf("foo"));
  344. Assert.Equal("baz", fixture[1]);
  345. Assert.False(fixture.Contains("foo"));
  346. Assert.True(fixture.Contains("baz"));
  347. fixture.RemoveAt(1);
  348. Assert.False(fixture.Contains("baz"));
  349. fixture.Remove("bar");
  350. Assert.Equal(0, fixture.Count);
  351. Assert.False(fixture.Contains("bar"));
  352. }
  353. [Fact]
  354. public void IListSmokeTest()
  355. {
  356. var fixture = new ReactiveCollection<string>() as IList;
  357. Assert.NotNull(fixture);
  358. var pos = fixture.Add("foo");
  359. Assert.Equal(0, pos);
  360. Assert.Equal(1, fixture.Count);
  361. Assert.True(fixture.Contains("foo"));
  362. fixture.Insert(0, "bar");
  363. Assert.Equal(0, fixture.IndexOf("bar"));
  364. Assert.Equal(1, fixture.IndexOf("foo"));
  365. Assert.Equal("bar", fixture[0] as string);
  366. Assert.Equal("foo", fixture[1] as string);
  367. var arr = new string[2];
  368. fixture.CopyTo(arr, 0);
  369. Assert.Equal(2, arr.Length);
  370. Assert.Equal("bar", arr[0]);
  371. Assert.Equal("foo", arr[1]);
  372. fixture[1] = "baz";
  373. Assert.Equal(1, fixture.IndexOf("baz"));
  374. Assert.Equal(-1, fixture.IndexOf("foo"));
  375. Assert.Equal("baz", fixture[1] as string);
  376. Assert.False(fixture.Contains("foo"));
  377. Assert.True(fixture.Contains("baz"));
  378. fixture.Remove("bar");
  379. Assert.Equal(1, fixture.Count);
  380. Assert.False(fixture.Contains("bar"));
  381. }
  382. }
  383. #if SILVERLIGHT
  384. public class JSONHelper
  385. {
  386. public static string Serialize<T>(T obj)
  387. {
  388. using (var mstream = new MemoryStream()) {
  389. var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());
  390. serializer.WriteObject(mstream, obj);
  391. mstream.Position = 0;
  392. using (var sr = new StreamReader(mstream)) {
  393. return sr.ReadToEnd();
  394. }
  395. }
  396. }
  397. public static T Deserialize<T>(string json)
  398. {
  399. var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
  400. return (T)serializer.ReadObject(
  401. new MemoryStream(System.Text.Encoding.Unicode.GetBytes(json)));
  402. }
  403. }
  404. #else
  405. public class JSONHelper
  406. {
  407. public static string Serialize<T>(T obj)
  408. {
  409. var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());
  410. var ms = new MemoryStream();
  411. serializer.WriteObject(ms, obj);
  412. string retVal = Encoding.Default.GetString(ms.ToArray());
  413. return retVal;
  414. }
  415. public static T Deserialize<T>(string json)
  416. {
  417. var obj = Activator.CreateInstance<T>();
  418. var ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
  419. var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());
  420. obj = (T)serializer.ReadObject(ms);
  421. ms.Close();
  422. return obj;
  423. }
  424. }
  425. #endif
  426. }