A game framework written with osu! in mind.
at master 166 lines 7.0 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using NUnit.Framework; 5using osu.Framework.Allocation; 6using osu.Framework.Bindables; 7using osu.Framework.Graphics; 8using osu.Framework.Graphics.Containers; 9using osu.Framework.Graphics.Shapes; 10using osu.Framework.Graphics.Sprites; 11using osuTK; 12using osuTK.Graphics; 13 14namespace osu.Framework.Tests.Visual.Bindables 15{ 16 public class TestSceneBindableAutoUnbinding : FrameworkTestScene 17 { 18 [Test] 19 public void TestBindableAutoUnbindingAssign() 20 { 21 TestExposedBindableDrawable drawable1 = null, drawable2 = null, drawable3 = null, drawable4 = null; 22 23 AddStep("add drawables", () => 24 { 25 Child = new FillFlowContainer 26 { 27 RelativeSizeAxes = Axes.Both, 28 Direction = FillDirection.Vertical, 29 Spacing = new Vector2(5), 30 Children = new Drawable[] 31 { 32 drawable1 = new TestExposedBindableDrawable { Bindable = new Bindable<int>() }, 33 drawable2 = new TestExposedBindableDrawable { Bindable = drawable1.Bindable.GetBoundCopy() }, 34 drawable3 = new TestExposedBindableDrawable(true) { Bindable = drawable1.Bindable }, // an example of a bad usage of bindables 35 drawable4 = new TestExposedBindableDrawable { Bindable = drawable1.Bindable.GetBoundCopy() }, 36 } 37 }; 38 }); 39 40 AddStep("attempt value transfer", () => drawable1.Bindable.Value = 10); 41 42 AddAssert("transfer 1-2 completed", () => drawable1.Bindable.Value == drawable2.Bindable.Value); 43 AddAssert("transfer 1-3 completed", () => drawable1.Bindable.Value == drawable3.Bindable.Value); 44 AddAssert("transfer 1-4 completed", () => drawable1.Bindable.Value == drawable4.Bindable.Value); 45 46 AddStep("expire child 4", () => drawable4.Expire()); 47 48 AddStep("attempt value transfer", () => drawable1.Bindable.Value = 20); 49 50 AddAssert("transfer 1-2 completed", () => drawable1.Bindable.Value == drawable2.Bindable.Value); 51 AddAssert("transfer 1-3 completed", () => drawable1.Bindable.Value == drawable3.Bindable.Value); 52 AddAssert("transfer 1-4 skipped", () => drawable1.Bindable.Value != drawable4.Bindable.Value); 53 54 AddStep("expire child 3", () => drawable3.Expire()); 55 56 AddStep("attempt value transfer", () => drawable1.Bindable.Value = 10); 57 58 // fails due to drawable3 being expired/disposed with a direct reference to drawable1's bindable. 59 AddAssert("transfer 1-2 fails", () => drawable1.Bindable.Value != drawable2.Bindable.Value); 60 } 61 62 [Test] 63 public void TestBindableAutoUnbindingResolution() 64 { 65 TestResolvedBindableDrawable drawable1 = null, drawable2 = null, drawable3 = null, drawable4 = null; 66 67 AddStep("add drawables", () => 68 { 69 Child = new BindableExposingFillFlowContainer 70 { 71 RelativeSizeAxes = Axes.Both, 72 Direction = FillDirection.Vertical, 73 Spacing = new Vector2(5), 74 Children = new Drawable[] 75 { 76 drawable1 = new TestResolvedBindableDrawable(), 77 drawable2 = new TestResolvedBindableDrawable(), 78 drawable3 = new TestResolvedBindableDrawable(true), // an example of a bad usage of bindables 79 drawable4 = new TestResolvedBindableDrawable(), 80 } 81 }; 82 }); 83 84 AddStep("attempt value transfer", () => drawable1.Bindable.Value = 10); 85 86 AddAssert("transfer 1-2 completed", () => drawable1.Bindable.Value == drawable2.Bindable.Value); 87 AddAssert("transfer 1-3 completed", () => drawable1.Bindable.Value == drawable3.Bindable.Value); 88 AddAssert("transfer 1-4 completed", () => drawable1.Bindable.Value == drawable4.Bindable.Value); 89 90 AddStep("expire child 4", () => drawable4.Expire()); 91 92 AddStep("attempt value transfer", () => drawable1.Bindable.Value = 20); 93 94 AddAssert("transfer 1-2 completed", () => drawable1.Bindable.Value == drawable2.Bindable.Value); 95 AddAssert("transfer 1-3 completed", () => drawable1.Bindable.Value == drawable3.Bindable.Value); 96 AddAssert("transfer 1-4 skipped", () => drawable1.Bindable.Value != drawable4.Bindable.Value); 97 98 AddStep("expire child 3", () => drawable3.Expire()); 99 100 AddStep("attempt value transfer", () => drawable1.Bindable.Value = 10); 101 102 // fails due to drawable3 being expired/disposed with a direct reference to drawable1's bindable. 103 AddAssert("transfer 1-2 fails", () => drawable1.Bindable.Value != drawable2.Bindable.Value); 104 } 105 106 public class BindableExposingFillFlowContainer : FillFlowContainer 107 { 108 [Cached] 109 private Bindable<int> bindable = new Bindable<int>(); 110 } 111 112 public class TestResolvedBindableDrawable : TestExposedBindableDrawable 113 { 114 private readonly bool badActor; 115 116 public TestResolvedBindableDrawable(bool badActor = false) 117 : base(badActor) 118 { 119 this.badActor = badActor; 120 } 121 122 [BackgroundDependencyLoader] 123 private void load(Bindable<int> parentBindable) 124 { 125 if (badActor) 126 Bindable = parentBindable; 127 else 128 { 129 Bindable = new Bindable<int>(); 130 Bindable.BindTo(parentBindable); 131 } 132 } 133 } 134 135 public class TestExposedBindableDrawable : CompositeDrawable 136 { 137 public Bindable<int> Bindable; 138 139 private readonly SpriteText spriteText; 140 141 public TestExposedBindableDrawable(bool badActor = false) 142 { 143 Size = new Vector2(50); 144 InternalChildren = new Drawable[] 145 { 146 new Box 147 { 148 Colour = badActor ? Color4.Red : Color4.Green, 149 RelativeSizeAxes = Axes.Both, 150 }, 151 spriteText = new SpriteText 152 { 153 Anchor = Anchor.Centre, 154 Origin = Anchor.Centre, 155 } 156 }; 157 } 158 159 protected override void LoadComplete() 160 { 161 base.LoadComplete(); 162 Bindable.BindValueChanged(val => spriteText.Text = val.NewValue.ToString(), true); 163 } 164 } 165 } 166}