AnimationIterationTests.cs 13 KB

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