mirror of
https://github.com/Cysharp/R3.git
synced 2026-10-28 06:07:36 +08:00
419 lines
9.8 KiB
C#
419 lines
9.8 KiB
C#
using R3.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
|
|
namespace R3.Tests;
|
|
|
|
public class ReactivePropertyTest
|
|
{
|
|
[Fact]
|
|
public void Test()
|
|
{
|
|
var rp = new ReactiveProperty<int>(100);
|
|
rp.Value.ShouldBe(100);
|
|
|
|
var list = rp.ToLiveList();
|
|
list.AssertEqual([100]);
|
|
|
|
rp.Value = 9999;
|
|
|
|
var list2 = rp.ToLiveList();
|
|
list.AssertEqual([100, 9999]);
|
|
list2.AssertEqual([9999]);
|
|
|
|
rp.Value = 9999;
|
|
list.AssertEqual([100, 9999]);
|
|
list2.AssertEqual([9999]);
|
|
|
|
rp.Value = 100;
|
|
list.AssertEqual([100, 9999, 100]);
|
|
list2.AssertEqual([9999, 100]);
|
|
|
|
rp.Dispose();
|
|
|
|
list.AssertIsCompleted();
|
|
list2.AssertIsCompleted();
|
|
}
|
|
|
|
[Fact]
|
|
public void DefaultValueTest()
|
|
{
|
|
using var rp = new ReactiveProperty<int>();
|
|
rp.Value.ShouldBe(default);
|
|
}
|
|
|
|
[Fact]
|
|
public void SubscribeAfterCompleted()
|
|
{
|
|
var rp = new ReactiveProperty<string>("foo");
|
|
rp.OnCompleted();
|
|
|
|
using var list = rp.ToLiveList();
|
|
|
|
list.AssertIsCompleted();
|
|
list.AssertEqual(["foo"]);
|
|
}
|
|
|
|
// Node Check
|
|
[Fact]
|
|
public void CheckNode()
|
|
{
|
|
var rp = new ReactiveProperty<int>();
|
|
|
|
|
|
var list1 = rp.ToLiveList();
|
|
|
|
rp.Value = 1;
|
|
|
|
list1.AssertEqual([0, 1]);
|
|
|
|
list1.Dispose();
|
|
|
|
var list2 = rp.ToLiveList();
|
|
|
|
rp.Value = 2;
|
|
|
|
list2.AssertEqual([1, 2]);
|
|
|
|
var list3 = rp.ToLiveList();
|
|
var list4 = rp.ToLiveList();
|
|
|
|
// remove first
|
|
|
|
list2.Dispose();
|
|
rp.Value = 3;
|
|
|
|
list3.AssertEqual([2, 3]);
|
|
list4.AssertEqual([2, 3]);
|
|
|
|
var list5 = rp.ToLiveList();
|
|
|
|
// remove middle
|
|
list4.Dispose();
|
|
|
|
rp.Value = 4;
|
|
|
|
list3.AssertEqual([2, 3, 4]);
|
|
list5.AssertEqual([3, 4]);
|
|
|
|
// remove last
|
|
list5.Dispose();
|
|
|
|
rp.Value = 5;
|
|
list3.AssertEqual([2, 3, 4, 5]);
|
|
|
|
// remove single
|
|
list3.Dispose();
|
|
|
|
// subscribe once
|
|
var list6 = rp.ToLiveList();
|
|
rp.Value = 6;
|
|
list6.AssertEqual([5, 6]);
|
|
}
|
|
|
|
[Fact]
|
|
public void NodeDisposeCheck()
|
|
{
|
|
{
|
|
var rp = new ReactiveProperty<int>(1);
|
|
|
|
LiveList<int> list1;
|
|
LiveList<int> list2;
|
|
LiveList<int> list3 = null!;
|
|
LiveList<int> list4 = null!;
|
|
LiveList<int> list5;
|
|
|
|
list1 = rp.ToLiveList();
|
|
list2 = rp.Take(2).Do(_ => { list3?.Dispose(); list4?.Dispose(); }).ToLiveList();
|
|
list3 = rp.ToLiveList();
|
|
list4 = rp.ToLiveList();
|
|
list5 = rp.ToLiveList();
|
|
|
|
rp.Value = 10;
|
|
|
|
list1.AssertEqual([1, 10]);
|
|
list2.AssertEqual([1, 10]);
|
|
list3.AssertEqual([1]);
|
|
list4.AssertEqual([1]);
|
|
list5.AssertEqual([1, 10]);
|
|
}
|
|
{
|
|
// Dispose only self.
|
|
var rp = new ReactiveProperty<int>(1);
|
|
|
|
LiveList<int> list1;
|
|
LiveList<int> list2;
|
|
LiveList<int> list3 = null!;
|
|
LiveList<int> list4 = null!;
|
|
LiveList<int> list5;
|
|
|
|
list1 = rp.ToLiveList();
|
|
list2 = rp.Take(2).Do(_ => { /* list3?.Dispose(); list4?.Dispose(); */}).ToLiveList();
|
|
list3 = rp.ToLiveList();
|
|
list4 = rp.ToLiveList();
|
|
list5 = rp.ToLiveList();
|
|
|
|
rp.Value = 10;
|
|
|
|
list1.AssertEqual([1, 10]);
|
|
list2.AssertEqual([1, 10]);
|
|
list3.AssertEqual([1, 10]);
|
|
list4.AssertEqual([1, 10]);
|
|
list5.AssertEqual([1, 10]);
|
|
|
|
rp.Value = 20;
|
|
|
|
list1.AssertEqual([1, 10, 20]);
|
|
list2.AssertEqual([1, 10]);
|
|
list3.AssertEqual([1, 10, 20]);
|
|
list4.AssertEqual([1, 10, 20]);
|
|
list5.AssertEqual([1, 10, 20]);
|
|
}
|
|
{
|
|
// Dispose only next one.
|
|
var rp = new ReactiveProperty<int>(1);
|
|
|
|
LiveList<int> list1;
|
|
LiveList<int> list2;
|
|
LiveList<int> list3 = null!;
|
|
LiveList<int> list4 = null!;
|
|
LiveList<int> list5;
|
|
|
|
list1 = rp.ToLiveList();
|
|
list2 = rp.Do(_ => { list3?.Dispose(); /* list4?.Dispose(); */}).ToLiveList();
|
|
list3 = rp.ToLiveList();
|
|
list4 = rp.ToLiveList();
|
|
list5 = rp.ToLiveList();
|
|
|
|
rp.Value = 10;
|
|
|
|
list1.AssertEqual([1, 10]);
|
|
list2.AssertEqual([1, 10]);
|
|
list3.AssertEqual([1]);
|
|
list4.AssertEqual([1, 10]);
|
|
list5.AssertEqual([1, 10]);
|
|
|
|
rp.Value = 20;
|
|
|
|
list1.AssertEqual([1, 10, 20]);
|
|
list2.AssertEqual([1, 10, 20]);
|
|
list3.AssertEqual([1]);
|
|
list4.AssertEqual([1, 10, 20]);
|
|
list5.AssertEqual([1, 10, 20]);
|
|
}
|
|
{
|
|
// Dispose only next next one.
|
|
var rp = new ReactiveProperty<int>(1);
|
|
|
|
LiveList<int> list1;
|
|
LiveList<int> list2;
|
|
LiveList<int> list3 = null!;
|
|
LiveList<int> list4 = null!;
|
|
LiveList<int> list5;
|
|
|
|
list1 = rp.ToLiveList();
|
|
list2 = rp.Do(_ => { list4?.Dispose(); }).ToLiveList();
|
|
list3 = rp.ToLiveList();
|
|
list4 = rp.ToLiveList();
|
|
list5 = rp.ToLiveList();
|
|
|
|
rp.Value = 10;
|
|
|
|
list1.AssertEqual([1, 10]);
|
|
list2.AssertEqual([1, 10]);
|
|
list3.AssertEqual([1, 10]);
|
|
list4.AssertEqual([1]);
|
|
list5.AssertEqual([1, 10]);
|
|
|
|
rp.Value = 20;
|
|
|
|
list1.AssertEqual([1, 10, 20]);
|
|
list2.AssertEqual([1, 10, 20]);
|
|
list3.AssertEqual([1, 10, 20]);
|
|
list4.AssertEqual([1]);
|
|
list5.AssertEqual([1, 10, 20]);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void RecursiveSubscribe()
|
|
{
|
|
var rp = new ReactiveProperty<int>(0);
|
|
|
|
List<LiveList<int>> recList = new();
|
|
|
|
var list = rp.Do(x =>
|
|
{
|
|
recList.Add(rp.ToLiveList());
|
|
})
|
|
.ToLiveList();
|
|
|
|
list.AssertEqual([0]);
|
|
recList[0].AssertEqual([0]);
|
|
|
|
rp.Value = 99;
|
|
list.AssertEqual([0, 99]);
|
|
recList[0].AssertEqual([0, 99]);
|
|
recList[1].AssertEqual([99]);
|
|
|
|
|
|
}
|
|
|
|
[Fact]
|
|
public void RootChangedFromSecond()
|
|
{
|
|
|
|
var p1 = new ReactiveProperty<int>();
|
|
var p1List = p1.Skip(1).ToLiveList();
|
|
|
|
p1.Skip(1).Subscribe().Dispose(); // Subscribe and Dispose
|
|
|
|
var p3List = p1.Skip(1).ToLiveList();
|
|
|
|
p1.Value = 1;
|
|
p1.Value = 2;
|
|
|
|
p1List.AssertEqual([1, 2]);
|
|
p3List.AssertEqual([1, 2]);
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveLastNode()
|
|
{
|
|
var log = new List<string>();
|
|
|
|
var count = 0;
|
|
var r = new ReactiveProperty<int>(count);
|
|
var ctsA = new CancellationTokenSource();
|
|
var ctsB = new CancellationTokenSource();
|
|
var ctsC = new CancellationTokenSource();
|
|
r.Subscribe(x => log.Add($"A = {x}")).RegisterTo(ctsA.Token);
|
|
r.Subscribe(x => log.Add($"B = {x}")).RegisterTo(ctsB.Token);
|
|
r.Subscribe(x => log.Add($"C = {x}")).RegisterTo(ctsC.Token);
|
|
ctsA.Cancel();
|
|
ctsA.Dispose();
|
|
log.Add("A disposed");
|
|
|
|
ctsA = new CancellationTokenSource();
|
|
r.Subscribe(x => log.Add($"A = {x}")).RegisterTo(ctsA.Token);
|
|
log.Add("A re-registered");
|
|
ctsA.Cancel();
|
|
ctsA.Dispose();
|
|
log.Add("A disposed");
|
|
ctsA = new CancellationTokenSource();
|
|
r.Subscribe(x => log.Add($"A = {x}")).RegisterTo(ctsA.Token);
|
|
log.Add("A re-registered");
|
|
r.Value = ++count;
|
|
r.Value = ++count;
|
|
|
|
var actual = string.Join(Environment.NewLine, log);
|
|
|
|
actual.ShouldBe("""
|
|
A = 0
|
|
B = 0
|
|
C = 0
|
|
A disposed
|
|
A = 0
|
|
A re-registered
|
|
A disposed
|
|
A = 0
|
|
A re-registered
|
|
B = 1
|
|
C = 1
|
|
A = 1
|
|
B = 2
|
|
C = 2
|
|
A = 2
|
|
""");
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveMiddle()
|
|
{
|
|
var log = new List<string>();
|
|
|
|
var p1 = new ReactiveProperty<int>();
|
|
p1.Skip(1).Subscribe(x => log.Add("[P1]" + x)); // alive
|
|
|
|
var d1 = p1.Skip(1).Subscribe(x => log.Add("[P2]" + x));
|
|
var d2 = p1.Skip(1).Subscribe(x => log.Add("[P2]" + x));
|
|
d1.Dispose();
|
|
d2.Dispose();
|
|
|
|
p1.Skip(1).Subscribe(x => log.Add("[P3]" + x)); // alive
|
|
|
|
p1.Value = 1;
|
|
p1.Value = 2;
|
|
|
|
var actual = string.Join(Environment.NewLine, log);
|
|
|
|
actual.ShouldBe("""
|
|
[P1]1
|
|
[P3]1
|
|
[P1]2
|
|
[P3]2
|
|
""");
|
|
}
|
|
|
|
|
|
|
|
[Fact]
|
|
public void RemoveFirst()
|
|
{
|
|
var log = new List<string>();
|
|
|
|
var p1 = new ReactiveProperty<int>();
|
|
var d1 = p1.Skip(1).Subscribe(x => log.Add("[P1]" + x));
|
|
|
|
var d2 = p1.Skip(1).Subscribe(x => log.Add("[P2_1]" + x)); // alive
|
|
var d3 = p1.Skip(1).Subscribe(x => log.Add("[P2_2]" + x)); // alive
|
|
|
|
d1.Dispose();
|
|
|
|
p1.Skip(1).Subscribe(x => log.Add("[P3]" + x)); // alive
|
|
|
|
p1.Value = 1;
|
|
p1.Value = 2;
|
|
|
|
var actual = string.Join(Environment.NewLine, log);
|
|
|
|
actual.ShouldBe("""
|
|
[P2_1]1
|
|
[P2_2]1
|
|
[P3]1
|
|
[P2_1]2
|
|
[P2_2]2
|
|
[P3]2
|
|
""");
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveLast()
|
|
{
|
|
var log = new List<string>();
|
|
|
|
var p1 = new ReactiveProperty<int>();
|
|
p1.Skip(1).Subscribe(x => log.Add("[P1]" + x)); // alive
|
|
|
|
var d1 = p1.Skip(1).Subscribe(x => log.Add("[P2]" + x)); // alive
|
|
var d2 = p1.Skip(1).Subscribe(x => log.Add("[P2]" + x)); // alive
|
|
|
|
var d3 = p1.Skip(1).Subscribe(x => log.Add("[P3]" + x));
|
|
d3.Dispose();
|
|
|
|
p1.Value = 1;
|
|
p1.Value = 2;
|
|
|
|
var actual = string.Join(Environment.NewLine, log);
|
|
|
|
actual.ShouldBe("""
|
|
[P1]1
|
|
[P2]1
|
|
[P2]1
|
|
[P1]2
|
|
[P2]2
|
|
[P2]2
|
|
""");
|
|
}
|
|
}
|