AnimationIterationTests.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. using System;
  2. using System.Threading.Tasks;
  3. using Avalonia.Animation;
  4. using Avalonia.Controls;
  5. using Avalonia.Styling;
  6. using Xunit;
  7. using Avalonia.Animation.Easings;
  8. using System.Threading;
  9. using System.Reactive.Linq;
  10. using Avalonia.Layout;
  11. namespace Avalonia.Base.UnitTests.Animation
  12. {
  13. using Animation = Avalonia.Animation.Animation;
  14. public class AnimationIterationTests
  15. {
  16. [Fact]
  17. public void Check_KeyTime_Correctly_Converted_To_Cue()
  18. {
  19. var keyframe1 = new KeyFrame()
  20. {
  21. Setters = { new Setter(Layoutable.WidthProperty, 100d), }, KeyTime = TimeSpan.FromSeconds(0.5)
  22. };
  23. var keyframe2 = new KeyFrame()
  24. {
  25. Setters = { new Setter(Layoutable.WidthProperty, 0d), }, KeyTime = TimeSpan.FromSeconds(0)
  26. };
  27. var animation = new Animation() { Duration = TimeSpan.FromSeconds(1), Children = { keyframe2, keyframe1 } };
  28. var border = new Border() { Height = 100d, Width = 100d };
  29. var clock = new TestClock();
  30. animation.RunAsync(border, clock);
  31. clock.Step(TimeSpan.Zero);
  32. Assert.Equal(border.Width, 0d);
  33. clock.Step(TimeSpan.FromSeconds(1));
  34. Assert.Equal(border.Width, 100d);
  35. }
  36. [Fact]
  37. public void Check_Initial_Inter_and_Trailing_Delay_Values()
  38. {
  39. var keyframe1 = new KeyFrame()
  40. {
  41. Setters = { new Setter(Layoutable.WidthProperty, 200d), }, Cue = new Cue(1d)
  42. };
  43. var keyframe2 = new KeyFrame()
  44. {
  45. Setters = { new Setter(Layoutable.WidthProperty, 100d), }, Cue = new Cue(0d)
  46. };
  47. var animation = new Animation()
  48. {
  49. Duration = TimeSpan.FromSeconds(3),
  50. Delay = TimeSpan.FromSeconds(3),
  51. DelayBetweenIterations = TimeSpan.FromSeconds(3),
  52. IterationCount = new IterationCount(2),
  53. Children = { keyframe2, keyframe1 }
  54. };
  55. var border = new Border() { Height = 100d, Width = 100d };
  56. var clock = new TestClock();
  57. var animationRun = animation.RunAsync(border, clock);
  58. clock.Step(TimeSpan.Zero);
  59. // Initial Delay.
  60. clock.Step(TimeSpan.FromSeconds(1));
  61. Assert.Equal(border.Width, 0d);
  62. clock.Step(TimeSpan.FromSeconds(6));
  63. // First Inter-Iteration delay.
  64. clock.Step(TimeSpan.FromSeconds(8));
  65. Assert.Equal(border.Width, 200d);
  66. // Trailing Delay should be non-existent.
  67. clock.Step(TimeSpan.FromSeconds(14));
  68. Assert.True(animationRun.Status == TaskStatus.RanToCompletion);
  69. Assert.Equal(border.Width, 100d);
  70. }
  71. [Fact]
  72. public void Check_FillModes_Start_and_End_Values_if_Retained()
  73. {
  74. var keyframe1 = new KeyFrame()
  75. {
  76. Setters = { new Setter(Layoutable.WidthProperty, 0d), }, Cue = new Cue(0.0d)
  77. };
  78. var keyframe2 = new KeyFrame()
  79. {
  80. Setters = { new Setter(Layoutable.WidthProperty, 300d), }, Cue = new Cue(1.0d)
  81. };
  82. var animation = new Animation()
  83. {
  84. Duration = TimeSpan.FromSeconds(0.05d),
  85. Delay = TimeSpan.FromSeconds(0.05d),
  86. Easing = new SineEaseInOut(),
  87. FillMode = FillMode.Both,
  88. Children = { keyframe1, keyframe2 }
  89. };
  90. var border = new Border() { Height = 100d, Width = 100d, };
  91. var clock = new TestClock();
  92. animation.RunAsync(border, clock);
  93. clock.Step(TimeSpan.FromSeconds(0d));
  94. Assert.Equal(border.Width, 0d);
  95. clock.Step(TimeSpan.FromSeconds(0.050d));
  96. Assert.Equal(border.Width, 0d);
  97. clock.Step(TimeSpan.FromSeconds(0.100d));
  98. Assert.Equal(border.Width, 300d);
  99. }
  100. [Fact]
  101. public void Dispose_Subscription_Should_Stop_Animation()
  102. {
  103. var keyframe1 = new KeyFrame()
  104. {
  105. Setters = { new Setter(Layoutable.WidthProperty, 200d), }, Cue = new Cue(1d)
  106. };
  107. var keyframe2 = new KeyFrame()
  108. {
  109. Setters = { new Setter(Layoutable.WidthProperty, 100d), }, Cue = new Cue(0d)
  110. };
  111. var animation = new Animation()
  112. {
  113. Duration = TimeSpan.FromSeconds(10),
  114. Delay = TimeSpan.FromSeconds(0),
  115. DelayBetweenIterations = TimeSpan.FromSeconds(0),
  116. IterationCount = new IterationCount(1),
  117. Children = { keyframe2, keyframe1 }
  118. };
  119. var border = new Border() { Height = 100d, Width = 50d };
  120. var propertyChangedCount = 0;
  121. var animationCompletedCount = 0;
  122. border.PropertyChanged += (_, e) =>
  123. {
  124. if (e.Property == Layoutable.WidthProperty)
  125. {
  126. propertyChangedCount++;
  127. }
  128. };
  129. var clock = new TestClock();
  130. var disposable = animation.Apply(border, clock, Observable.Return(true), () => animationCompletedCount++);
  131. Assert.Equal(0, propertyChangedCount);
  132. clock.Step(TimeSpan.FromSeconds(0));
  133. Assert.Equal(0, animationCompletedCount);
  134. Assert.Equal(1, propertyChangedCount);
  135. disposable.Dispose();
  136. // Clock ticks should be ignored after Dispose
  137. clock.Step(TimeSpan.FromSeconds(5));
  138. clock.Step(TimeSpan.FromSeconds(6));
  139. clock.Step(TimeSpan.FromSeconds(7));
  140. // On animation disposing (cancellation) on completed is not invoked (is it expected?)
  141. Assert.Equal(0, animationCompletedCount);
  142. // Initial property changed before cancellation + animation value removal.
  143. Assert.Equal(2, propertyChangedCount);
  144. }
  145. [Fact]
  146. public void Do_Not_Run_Cancelled_Animation()
  147. {
  148. var keyframe1 = new KeyFrame()
  149. {
  150. Setters = { new Setter(Layoutable.WidthProperty, 200d), }, Cue = new Cue(1d)
  151. };
  152. var keyframe2 = new KeyFrame()
  153. {
  154. Setters = { new Setter(Layoutable.WidthProperty, 100d), }, Cue = new Cue(0d)
  155. };
  156. var animation = new Animation()
  157. {
  158. Duration = TimeSpan.FromSeconds(10),
  159. Delay = TimeSpan.FromSeconds(0),
  160. DelayBetweenIterations = TimeSpan.FromSeconds(0),
  161. IterationCount = new IterationCount(1),
  162. Children = { keyframe2, keyframe1 }
  163. };
  164. var border = new Border() { Height = 100d, Width = 100d };
  165. var propertyChangedCount = 0;
  166. border.PropertyChanged += (_, e) =>
  167. {
  168. if (e.Property == Layoutable.WidthProperty)
  169. {
  170. propertyChangedCount++;
  171. }
  172. };
  173. var clock = new TestClock();
  174. var cancellationTokenSource = new CancellationTokenSource();
  175. cancellationTokenSource.Cancel();
  176. var animationRun = animation.RunAsync(border, clock, cancellationTokenSource.Token);
  177. clock.Step(TimeSpan.FromSeconds(10));
  178. Assert.Equal(0, propertyChangedCount);
  179. Assert.True(animationRun.IsCompleted);
  180. }
  181. [Fact]
  182. public void Cancellation_Should_Stop_Animation()
  183. {
  184. var keyframe1 = new KeyFrame()
  185. {
  186. Setters = { new Setter(Layoutable.WidthProperty, 200d), }, Cue = new Cue(1d)
  187. };
  188. var keyframe2 = new KeyFrame()
  189. {
  190. Setters = { new Setter(Layoutable.WidthProperty, 100d), }, Cue = new Cue(0d)
  191. };
  192. var animation = new Animation()
  193. {
  194. Duration = TimeSpan.FromSeconds(10),
  195. Delay = TimeSpan.FromSeconds(0),
  196. DelayBetweenIterations = TimeSpan.FromSeconds(0),
  197. IterationCount = new IterationCount(1),
  198. Children = { keyframe2, keyframe1 }
  199. };
  200. var border = new Border() { Height = 100d, Width = 50d };
  201. var propertyChangedCount = 0;
  202. border.PropertyChanged += (_, e) =>
  203. {
  204. if (e.Property == Layoutable.WidthProperty)
  205. {
  206. propertyChangedCount++;
  207. }
  208. };
  209. var clock = new TestClock();
  210. var cancellationTokenSource = new CancellationTokenSource();
  211. var animationRun = animation.RunAsync(border, clock, cancellationTokenSource.Token);
  212. Assert.False(animationRun.IsCompleted);
  213. Assert.Equal(0, propertyChangedCount);
  214. clock.Step(TimeSpan.FromSeconds(0));
  215. Assert.False(animationRun.IsCompleted);
  216. Assert.Equal(1, propertyChangedCount);
  217. cancellationTokenSource.Cancel();
  218. clock.Step(TimeSpan.FromSeconds(1));
  219. clock.Step(TimeSpan.FromSeconds(2));
  220. clock.Step(TimeSpan.FromSeconds(3));
  221. animationRun.Wait();
  222. clock.Step(TimeSpan.FromSeconds(6));
  223. Assert.True(animationRun.IsCompleted);
  224. Assert.Equal(2, propertyChangedCount);
  225. }
  226. [Fact]
  227. public void Dont_Run_Infinite_Iteration_Animation_On_RunAsync_Method()
  228. {
  229. var keyframe1 = new KeyFrame()
  230. {
  231. Setters = { new Setter(Layoutable.WidthProperty, 200d), }, Cue = new Cue(1d)
  232. };
  233. var keyframe2 = new KeyFrame()
  234. {
  235. Setters = { new Setter(Layoutable.WidthProperty, 100d), }, Cue = new Cue(0d)
  236. };
  237. var animation = new Animation()
  238. {
  239. Duration = TimeSpan.FromSeconds(10),
  240. Delay = TimeSpan.FromSeconds(0),
  241. DelayBetweenIterations = TimeSpan.FromSeconds(0),
  242. IterationCount = IterationCount.Infinite,
  243. Children = { keyframe2, keyframe1 }
  244. };
  245. var border = new Border() { Height = 100d, Width = 50d };
  246. var clock = new TestClock();
  247. var cancellationTokenSource = new CancellationTokenSource();
  248. var animationRun = animation.RunAsync(border, clock, cancellationTokenSource.Token);
  249. Assert.True(animationRun.IsCompleted);
  250. Assert.NotNull(animationRun.Exception);
  251. }
  252. [Fact]
  253. public void Cancellation_Of_Completed_Animation_Does_Not_Fail()
  254. {
  255. var keyframe1 = new KeyFrame()
  256. {
  257. Setters = { new Setter(Layoutable.WidthProperty, 200d), }, Cue = new Cue(1d)
  258. };
  259. var keyframe2 = new KeyFrame()
  260. {
  261. Setters = { new Setter(Layoutable.WidthProperty, 100d), }, Cue = new Cue(0d)
  262. };
  263. var animation = new Animation()
  264. {
  265. Duration = TimeSpan.FromSeconds(10),
  266. Delay = TimeSpan.FromSeconds(0),
  267. DelayBetweenIterations = TimeSpan.FromSeconds(0),
  268. IterationCount = new IterationCount(1),
  269. Children = { keyframe2, keyframe1 }
  270. };
  271. var border = new Border() { Height = 100d, Width = 50d };
  272. var propertyChangedCount = 0;
  273. border.PropertyChanged += (_, e) =>
  274. {
  275. if (e.Property == Layoutable.WidthProperty)
  276. {
  277. propertyChangedCount++;
  278. }
  279. };
  280. var clock = new TestClock();
  281. var cancellationTokenSource = new CancellationTokenSource();
  282. var animationRun = animation.RunAsync(border, clock, cancellationTokenSource.Token);
  283. Assert.Equal(0, propertyChangedCount);
  284. clock.Step(TimeSpan.FromSeconds(0));
  285. Assert.False(animationRun.IsCompleted);
  286. Assert.Equal(1, propertyChangedCount);
  287. clock.Step(TimeSpan.FromSeconds(10));
  288. Assert.True(animationRun.IsCompleted);
  289. Assert.Equal(2, propertyChangedCount);
  290. cancellationTokenSource.Cancel();
  291. animationRun.Wait();
  292. }
  293. }
  294. }