A game framework written with osu! in mind.
at master 289 lines 10 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 System; 5using System.Threading; 6using NUnit.Framework; 7using osu.Framework.Allocation; 8using osu.Framework.Graphics; 9using osu.Framework.Graphics.Containers; 10using osu.Framework.Graphics.Shapes; 11using osu.Framework.Graphics.Sprites; 12using osuTK; 13using osuTK.Graphics; 14 15namespace osu.Framework.Tests.Visual.Drawables 16{ 17 public class TestSceneModelBackedDrawable : FrameworkTestScene 18 { 19 private TestModelBackedDrawable backedDrawable; 20 21 private void createModelBackedDrawable(bool hasIntermediate, bool showNullModel = false) => 22 Child = backedDrawable = new TestModelBackedDrawable 23 { 24 Anchor = Anchor.Centre, 25 Origin = Anchor.Centre, 26 Size = new Vector2(200), 27 HasIntermediate = hasIntermediate, 28 ShowNullModel = showNullModel 29 }; 30 31 [Test] 32 public void TestEmptyDefaultState() 33 { 34 AddStep("setup", () => createModelBackedDrawable(false)); 35 AddAssert("nothing shown", () => backedDrawable.DisplayedDrawable == null); 36 } 37 38 [Test] 39 public void TestModelDefaultState() 40 { 41 TestDrawableModel drawableModel = null; 42 43 AddStep("setup", () => 44 { 45 createModelBackedDrawable(false); 46 backedDrawable.Model = new TestModel(drawableModel = new TestDrawableModel(1).With(d => d.AllowLoad.Set())); 47 }); 48 49 assertDrawableVisibility(1, () => drawableModel); 50 } 51 52 [TestCase(false)] 53 [TestCase(true)] 54 public void TestChangeModel(bool hasIntermediate) 55 { 56 TestDrawableModel firstModel = null; 57 TestDrawableModel secondModel = null; 58 59 AddStep("setup", () => 60 { 61 createModelBackedDrawable(hasIntermediate); 62 backedDrawable.Model = new TestModel(firstModel = new TestDrawableModel(1).With(d => d.AllowLoad.Set())); 63 }); 64 65 assertDrawableVisibility(1, () => firstModel); 66 67 AddStep("set second model", () => backedDrawable.Model = new TestModel(secondModel = new TestDrawableModel(2))); 68 assertIntermediateVisibility(hasIntermediate, () => firstModel); 69 70 AddStep("allow second model to load", () => secondModel.AllowLoad.Set()); 71 assertDrawableVisibility(2, () => secondModel); 72 } 73 74 [TestCase(false)] 75 [TestCase(true)] 76 public void TestChangeModelDuringLoad(bool hasIntermediate) 77 { 78 TestDrawableModel firstModel = null; 79 TestDrawableModel secondModel = null; 80 TestDrawableModel thirdModel = null; 81 82 AddStep("setup", () => 83 { 84 createModelBackedDrawable(hasIntermediate); 85 backedDrawable.Model = new TestModel(firstModel = new TestDrawableModel(1).With(d => d.AllowLoad.Set())); 86 }); 87 88 assertDrawableVisibility(1, () => firstModel); 89 90 AddStep("set second model", () => backedDrawable.Model = new TestModel(secondModel = new TestDrawableModel(2))); 91 assertIntermediateVisibility(hasIntermediate, () => firstModel); 92 93 AddStep("set third model", () => backedDrawable.Model = new TestModel(thirdModel = new TestDrawableModel(3))); 94 assertIntermediateVisibility(hasIntermediate, () => firstModel); 95 96 AddStep("allow second model to load", () => secondModel.AllowLoad.Set()); 97 assertIntermediateVisibility(hasIntermediate, () => firstModel); 98 99 AddStep("allow third model to load", () => thirdModel.AllowLoad.Set()); 100 assertDrawableVisibility(3, () => thirdModel); 101 } 102 103 [TestCase(false)] 104 [TestCase(true)] 105 public void TestOutOfOrderLoad(bool hasIntermediate) 106 { 107 TestDrawableModel firstModel = null; 108 TestDrawableModel secondModel = null; 109 110 AddStep("setup", () => 111 { 112 createModelBackedDrawable(hasIntermediate); 113 backedDrawable.Model = new TestModel(firstModel = new TestDrawableModel(1).With(d => d.AllowLoad.Set())); 114 }); 115 116 assertDrawableVisibility(1, () => firstModel); 117 118 AddStep("set second model", () => backedDrawable.Model = new TestModel(secondModel = new TestDrawableModel(2))); 119 assertIntermediateVisibility(hasIntermediate, () => firstModel); 120 121 AddStep("allow second model to load", () => secondModel.AllowLoad.Set()); 122 assertDrawableVisibility(2, () => secondModel); 123 124 AddStep("allow first model to load", () => firstModel.AllowLoad.Set()); 125 assertDrawableVisibility(2, () => secondModel); 126 } 127 128 [Test] 129 public void TestSetNullModel() 130 { 131 TestDrawableModel drawableModel = null; 132 133 AddStep("setup", () => 134 { 135 createModelBackedDrawable(false, true); 136 backedDrawable.Model = new TestModel(drawableModel = new TestDrawableModel(1).With(d => d.AllowLoad.Set())); 137 }); 138 139 assertDrawableVisibility(1, () => drawableModel); 140 141 AddStep("set null model", () => backedDrawable.Model = null); 142 AddUntilStep("null model shown", () => backedDrawable.DisplayedDrawable is TestNullDrawableModel); 143 } 144 145 [Test] 146 public void TestInsideBufferedContainer() 147 { 148 TestDrawableModel drawableModel = null; 149 150 AddStep("setup", () => 151 { 152 Child = new BufferedContainer 153 { 154 Anchor = Anchor.Centre, 155 Origin = Anchor.Centre, 156 Size = new Vector2(200), 157 Child = backedDrawable = new TestModelBackedDrawable 158 { 159 RelativeSizeAxes = Axes.Both, 160 HasIntermediate = false, 161 ShowNullModel = false, 162 Model = new TestModel(drawableModel = new TestDrawableModel(1).With(d => d.AllowLoad.Set())) 163 } 164 }; 165 }); 166 167 assertDrawableVisibility(1, () => drawableModel); 168 } 169 170 private void assertIntermediateVisibility(bool hasIntermediate, Func<Drawable> getLastFunc) 171 { 172 if (hasIntermediate) 173 AddAssert("no drawable visible", () => backedDrawable.DisplayedDrawable == null); 174 else 175 AddUntilStep("last drawable visible", () => backedDrawable.DisplayedDrawable == getLastFunc()); 176 } 177 178 private void assertDrawableVisibility(int id, Func<Drawable> getFunc) 179 { 180 AddUntilStep($"model {id} visible", () => backedDrawable.DisplayedDrawable == getFunc()); 181 } 182 183 private class TestModel 184 { 185 public readonly TestDrawableModel DrawableModel; 186 187 public TestModel(TestDrawableModel drawableModel) 188 { 189 DrawableModel = drawableModel; 190 } 191 } 192 193 private class TestDrawableModel : CompositeDrawable 194 { 195 private readonly int id; 196 197 public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(false); 198 199 protected virtual Color4 BackgroundColour 200 { 201 get 202 { 203 switch (id % 5) 204 { 205 default: 206 return Color4.SkyBlue; 207 208 case 1: 209 return Color4.Tomato; 210 211 case 2: 212 return Color4.DarkGreen; 213 214 case 3: 215 return Color4.MediumPurple; 216 217 case 4: 218 return Color4.DarkOrchid; 219 } 220 } 221 } 222 223 public TestDrawableModel(int id) 224 { 225 this.id = id; 226 227 RelativeSizeAxes = Axes.Both; 228 229 InternalChildren = new Drawable[] 230 { 231 new Box 232 { 233 RelativeSizeAxes = Axes.Both, 234 Colour = BackgroundColour 235 }, 236 new SpriteText 237 { 238 Anchor = Anchor.Centre, 239 Origin = Anchor.Centre, 240 Text = id > 0 ? $"model {id}" : "null" 241 } 242 }; 243 } 244 245 [BackgroundDependencyLoader] 246 private void load() 247 { 248 if (!AllowLoad.Wait(TimeSpan.FromSeconds(10))) 249 { 250 } 251 } 252 } 253 254 private class TestNullDrawableModel : TestDrawableModel 255 { 256 protected override Color4 BackgroundColour => Color4.SlateGray; 257 258 public TestNullDrawableModel() 259 : base(0) 260 { 261 AllowLoad.Set(); 262 } 263 } 264 265 private class TestModelBackedDrawable : ModelBackedDrawable<TestModel> 266 { 267 public bool ShowNullModel; 268 269 public bool HasIntermediate; 270 271 protected override Drawable CreateDrawable(TestModel model) 272 { 273 if (model == null && ShowNullModel) 274 return new TestNullDrawableModel(); 275 276 return model?.DrawableModel; 277 } 278 279 public new Drawable DisplayedDrawable => base.DisplayedDrawable; 280 281 public new TestModel Model 282 { 283 set => base.Model = value; 284 } 285 286 protected override bool TransformImmediately => HasIntermediate; 287 } 288 } 289}