AdvanceFocusTests.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. using Xunit.Abstractions;
  2. namespace Terminal.Gui.ViewTests;
  3. public class AdvanceFocusTests (ITestOutputHelper _output)
  4. {
  5. [Fact]
  6. public void Subviews_TabIndexes_AreEqual ()
  7. {
  8. var r = new View ();
  9. var v1 = new View { CanFocus = true };
  10. var v2 = new View { CanFocus = true };
  11. var v3 = new View { CanFocus = true };
  12. r.Add (v1, v2, v3);
  13. Assert.True (r.Subviews.IndexOf (v1) == 0);
  14. Assert.True (r.Subviews.IndexOf (v2) == 1);
  15. Assert.True (r.Subviews.IndexOf (v3) == 2);
  16. Assert.True (r.TabIndexes.IndexOf (v1) == 0);
  17. Assert.True (r.TabIndexes.IndexOf (v2) == 1);
  18. Assert.True (r.TabIndexes.IndexOf (v3) == 2);
  19. Assert.Equal (r.Subviews.IndexOf (v1), r.TabIndexes.IndexOf (v1));
  20. Assert.Equal (r.Subviews.IndexOf (v2), r.TabIndexes.IndexOf (v2));
  21. Assert.Equal (r.Subviews.IndexOf (v3), r.TabIndexes.IndexOf (v3));
  22. r.Dispose ();
  23. }
  24. [Fact]
  25. public void TabIndex_Invert_Order ()
  26. {
  27. var r = new View ();
  28. var v1 = new View { Id = "1", CanFocus = true };
  29. var v2 = new View { Id = "2", CanFocus = true };
  30. var v3 = new View { Id = "3", CanFocus = true };
  31. r.Add (v1, v2, v3);
  32. v1.TabIndex = 2;
  33. v2.TabIndex = 1;
  34. v3.TabIndex = 0;
  35. Assert.True (r.TabIndexes.IndexOf (v1) == 2);
  36. Assert.True (r.TabIndexes.IndexOf (v2) == 1);
  37. Assert.True (r.TabIndexes.IndexOf (v3) == 0);
  38. Assert.True (r.Subviews.IndexOf (v1) == 0);
  39. Assert.True (r.Subviews.IndexOf (v2) == 1);
  40. Assert.True (r.Subviews.IndexOf (v3) == 2);
  41. }
  42. [Fact]
  43. public void TabIndex_Invert_Order_Added_One_By_One_Does_Not_Do_What_Is_Expected ()
  44. {
  45. var r = new View ();
  46. var v1 = new View { Id = "1", CanFocus = true };
  47. r.Add (v1);
  48. v1.TabIndex = 2;
  49. var v2 = new View { Id = "2", CanFocus = true };
  50. r.Add (v2);
  51. v2.TabIndex = 1;
  52. var v3 = new View { Id = "3", CanFocus = true };
  53. r.Add (v3);
  54. v3.TabIndex = 0;
  55. Assert.False (r.TabIndexes.IndexOf (v1) == 2);
  56. Assert.True (r.TabIndexes.IndexOf (v1) == 1);
  57. Assert.False (r.TabIndexes.IndexOf (v2) == 1);
  58. Assert.True (r.TabIndexes.IndexOf (v2) == 2);
  59. // Only the last is in the expected index
  60. Assert.True (r.TabIndexes.IndexOf (v3) == 0);
  61. Assert.True (r.Subviews.IndexOf (v1) == 0);
  62. Assert.True (r.Subviews.IndexOf (v2) == 1);
  63. Assert.True (r.Subviews.IndexOf (v3) == 2);
  64. }
  65. [Fact]
  66. public void TabIndex_Invert_Order_Mixed ()
  67. {
  68. var r = new View ();
  69. var vl1 = new View { Id = "vl1" };
  70. var v1 = new View { Id = "v1", CanFocus = true };
  71. var vl2 = new View { Id = "vl2" };
  72. var v2 = new View { Id = "v2", CanFocus = true };
  73. var vl3 = new View { Id = "vl3" };
  74. var v3 = new View { Id = "v3", CanFocus = true };
  75. r.Add (vl1, v1, vl2, v2, vl3, v3);
  76. v1.TabIndex = 2;
  77. v2.TabIndex = 1;
  78. v3.TabIndex = 0;
  79. Assert.True (r.TabIndexes.IndexOf (v1) == 4);
  80. Assert.True (r.TabIndexes.IndexOf (v2) == 2);
  81. Assert.True (r.TabIndexes.IndexOf (v3) == 0);
  82. Assert.True (r.Subviews.IndexOf (v1) == 1);
  83. Assert.True (r.Subviews.IndexOf (v2) == 3);
  84. Assert.True (r.Subviews.IndexOf (v3) == 5);
  85. }
  86. [Fact]
  87. public void TabIndex_Set_CanFocus_False ()
  88. {
  89. var r = new View ();
  90. var v1 = new View { CanFocus = true };
  91. var v2 = new View { CanFocus = true };
  92. var v3 = new View { CanFocus = true };
  93. r.Add (v1, v2, v3);
  94. v1.CanFocus = false;
  95. v1.TabIndex = 0;
  96. Assert.True (r.Subviews.IndexOf (v1) == 0);
  97. Assert.True (r.TabIndexes.IndexOf (v1) == 0);
  98. Assert.NotEqual (-1, v1.TabIndex);
  99. r.Dispose ();
  100. }
  101. [Fact]
  102. public void TabIndex_Set_CanFocus_False_To_True ()
  103. {
  104. var r = new View ();
  105. var v1 = new View ();
  106. var v2 = new View { CanFocus = true };
  107. var v3 = new View { CanFocus = true };
  108. r.Add (v1, v2, v3);
  109. v1.CanFocus = true;
  110. v1.TabIndex = 1;
  111. Assert.True (r.Subviews.IndexOf (v1) == 0);
  112. Assert.True (r.TabIndexes.IndexOf (v1) == 1);
  113. r.Dispose ();
  114. }
  115. [Fact]
  116. public void TabIndex_Set_CanFocus_HigherValues ()
  117. {
  118. var r = new View ();
  119. var v1 = new View { CanFocus = true };
  120. var v2 = new View { CanFocus = true };
  121. var v3 = new View { CanFocus = true };
  122. r.Add (v1, v2, v3);
  123. v1.TabIndex = 3;
  124. Assert.True (r.Subviews.IndexOf (v1) == 0);
  125. Assert.True (r.TabIndexes.IndexOf (v1) == 2);
  126. r.Dispose ();
  127. }
  128. [Fact]
  129. public void TabIndex_Set_CanFocus_LowerValues ()
  130. {
  131. var r = new View ();
  132. var v1 = new View { CanFocus = true };
  133. var v2 = new View { CanFocus = true };
  134. var v3 = new View { CanFocus = true };
  135. r.Add (v1, v2, v3);
  136. //v1.TabIndex = -1;
  137. Assert.True (r.Subviews.IndexOf (v1) == 0);
  138. Assert.True (r.TabIndexes.IndexOf (v1) == 0);
  139. r.Dispose ();
  140. }
  141. [Fact]
  142. public void TabIndex_Set_CanFocus_ValidValues ()
  143. {
  144. var r = new View ();
  145. var v1 = new View { CanFocus = true };
  146. var v2 = new View { CanFocus = true };
  147. var v3 = new View { CanFocus = true };
  148. r.Add (v1, v2, v3);
  149. v1.TabIndex = 1;
  150. Assert.True (r.Subviews.IndexOf (v1) == 0);
  151. Assert.True (r.TabIndexes.IndexOf (v1) == 1);
  152. v1.TabIndex = 2;
  153. Assert.True (r.Subviews.IndexOf (v1) == 0);
  154. Assert.True (r.TabIndexes.IndexOf (v1) == 2);
  155. r.Dispose ();
  156. }
  157. [Theory]
  158. [CombinatorialData]
  159. public void TabStop_And_CanFocus_Are_Decoupled (bool canFocus, TabBehavior tabStop)
  160. {
  161. var view = new View { CanFocus = canFocus, TabStop = tabStop };
  162. Assert.Equal (canFocus, view.CanFocus);
  163. Assert.Equal (tabStop, view.TabStop);
  164. }
  165. [Fact]
  166. public void AdvanceFocus_Compound_Subview ()
  167. {
  168. var top = new View () { Id = "top", CanFocus = true };
  169. var compoundSubview = new View ()
  170. {
  171. CanFocus = true,
  172. Id = "compoundSubview",
  173. };
  174. var v1 = new View { Id = "v1", CanFocus = true };
  175. var v2 = new View { Id = "v2", CanFocus = true };
  176. var v3 = new View { Id = "v3", CanFocus = false };
  177. compoundSubview.Add (v1, v2, v3);
  178. top.Add (compoundSubview);
  179. // Cycle through v1 & v2
  180. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  181. Assert.True (v1.HasFocus);
  182. Assert.False (v2.HasFocus);
  183. Assert.False (v3.HasFocus);
  184. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  185. Assert.False (v1.HasFocus);
  186. Assert.True (v2.HasFocus);
  187. Assert.False (v3.HasFocus);
  188. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  189. Assert.True (v1.HasFocus);
  190. Assert.False (v2.HasFocus);
  191. Assert.False (v3.HasFocus);
  192. // Add another subview
  193. View otherSubview = new ()
  194. {
  195. CanFocus = true,
  196. Id = "otherSubview",
  197. };
  198. top.Add (otherSubview);
  199. // Adding a focusable subview causes advancefocus
  200. Assert.True (otherSubview.HasFocus);
  201. Assert.False (v1.HasFocus);
  202. // Cycle through v1 & v2
  203. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  204. Assert.True (v1.HasFocus);
  205. Assert.False (v2.HasFocus);
  206. Assert.False (v3.HasFocus);
  207. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  208. Assert.False (v1.HasFocus);
  209. Assert.True (v2.HasFocus);
  210. Assert.False (v3.HasFocus);
  211. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  212. Assert.False (v1.HasFocus);
  213. Assert.False (v2.HasFocus);
  214. Assert.False (v3.HasFocus);
  215. Assert.True (otherSubview.HasFocus);
  216. // v2 was previously focused down the compoundSubView focus chain
  217. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  218. Assert.False (v1.HasFocus);
  219. Assert.True (v2.HasFocus);
  220. Assert.False (v3.HasFocus);
  221. top.Dispose ();
  222. }
  223. [Fact]
  224. public void AdvanceFocus_With_CanFocus_Are_All_True ()
  225. {
  226. var top = new View () { Id = "top", CanFocus = true };
  227. var v1 = new View { Id = "v1", CanFocus = true };
  228. var v2 = new View { Id = "v2", CanFocus = true };
  229. var v3 = new View { Id = "v3", CanFocus = true };
  230. top.Add (v1, v2, v3);
  231. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  232. Assert.True (v1.HasFocus);
  233. Assert.False (v2.HasFocus);
  234. Assert.False (v3.HasFocus);
  235. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  236. Assert.False (v1.HasFocus);
  237. Assert.True (v2.HasFocus);
  238. Assert.False (v3.HasFocus);
  239. top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  240. Assert.False (v1.HasFocus);
  241. Assert.False (v2.HasFocus);
  242. Assert.True (v3.HasFocus);
  243. top.Dispose ();
  244. }
  245. [Fact]
  246. public void AdvanceFocus_CanFocus_Mixed ()
  247. {
  248. var r = new View ();
  249. var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  250. var v2 = new View { CanFocus = false, TabStop = TabBehavior.TabStop };
  251. var v3 = new View { CanFocus = false, TabStop = TabBehavior.NoStop };
  252. r.Add (v1, v2, v3);
  253. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  254. Assert.False (v1.HasFocus);
  255. Assert.False (v2.HasFocus);
  256. Assert.False (v3.HasFocus);
  257. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  258. Assert.False (v1.HasFocus);
  259. Assert.False (v2.HasFocus);
  260. Assert.False (v3.HasFocus);
  261. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  262. Assert.False (v1.HasFocus);
  263. Assert.False (v2.HasFocus);
  264. Assert.False (v3.HasFocus);
  265. r.Dispose ();
  266. }
  267. [Theory]
  268. [CombinatorialData]
  269. public void AdvanceFocus_Change_CanFocus_Works ([CombinatorialValues (TabBehavior.NoStop, TabBehavior.TabStop, TabBehavior.TabGroup)] TabBehavior behavior)
  270. {
  271. var r = new View () { CanFocus = true };
  272. var v1 = new View ();
  273. var v2 = new View ();
  274. var v3 = new View ();
  275. Assert.True (r.CanFocus);
  276. Assert.False (v1.CanFocus);
  277. Assert.False (v2.CanFocus);
  278. Assert.False (v3.CanFocus);
  279. r.Add (v1, v2, v3);
  280. r.AdvanceFocus (NavigationDirection.Forward, behavior);
  281. Assert.False (v1.HasFocus);
  282. Assert.False (v2.HasFocus);
  283. Assert.False (v3.HasFocus);
  284. v1.CanFocus = true;
  285. v1.TabStop = behavior;
  286. r.AdvanceFocus (NavigationDirection.Forward, behavior);
  287. Assert.True (v1.HasFocus);
  288. Assert.False (v2.HasFocus);
  289. Assert.False (v3.HasFocus);
  290. v2.CanFocus = true;
  291. v2.TabStop = behavior;
  292. r.AdvanceFocus (NavigationDirection.Forward, behavior);
  293. Assert.False (v1.HasFocus);
  294. Assert.True (v2.HasFocus);
  295. Assert.False (v3.HasFocus);
  296. v3.CanFocus = true;
  297. v3.TabStop = behavior;
  298. r.AdvanceFocus (NavigationDirection.Forward, behavior);
  299. Assert.False (v1.HasFocus);
  300. Assert.False (v2.HasFocus);
  301. Assert.True (v3.HasFocus);
  302. r.Dispose ();
  303. }
  304. [Fact]
  305. public void AdvanceFocus_NoStop_And_CanFocus_True_No_Focus ()
  306. {
  307. var r = new View ();
  308. var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  309. var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  310. var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  311. r.Add (v1, v2, v3);
  312. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  313. Assert.False (v1.HasFocus);
  314. Assert.False (v2.HasFocus);
  315. Assert.False (v3.HasFocus);
  316. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  317. Assert.False (v1.HasFocus);
  318. Assert.False (v2.HasFocus);
  319. Assert.False (v3.HasFocus);
  320. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  321. Assert.False (v1.HasFocus);
  322. Assert.False (v2.HasFocus);
  323. Assert.False (v3.HasFocus);
  324. r.Dispose ();
  325. }
  326. [Fact]
  327. public void AdvanceFocus_NoStop_Change_Enables_Stop ()
  328. {
  329. var r = new View { CanFocus = true };
  330. var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  331. var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  332. var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  333. r.Add (v1, v2, v3);
  334. v1.TabStop = TabBehavior.TabStop;
  335. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  336. Assert.True (v1.HasFocus);
  337. Assert.False (v2.HasFocus);
  338. Assert.False (v3.HasFocus);
  339. v2.TabStop = TabBehavior.TabStop;
  340. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  341. Assert.False (v1.HasFocus);
  342. Assert.True (v2.HasFocus);
  343. Assert.False (v3.HasFocus);
  344. v3.TabStop = TabBehavior.TabStop;
  345. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  346. Assert.False (v1.HasFocus);
  347. Assert.False (v2.HasFocus);
  348. Assert.True (v3.HasFocus);
  349. r.Dispose ();
  350. }
  351. [Fact]
  352. public void AdvanceFocus_NoStop_Prevents_Stop ()
  353. {
  354. var r = new View ();
  355. var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  356. var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  357. var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
  358. r.Add (v1, v2, v3);
  359. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  360. Assert.False (v1.HasFocus);
  361. Assert.False (v2.HasFocus);
  362. Assert.False (v3.HasFocus);
  363. }
  364. [Fact]
  365. public void AdvanceFocus_Null_And_CanFocus_False_No_Advance ()
  366. {
  367. var r = new View ();
  368. var v1 = new View ();
  369. var v2 = new View ();
  370. var v3 = new View ();
  371. Assert.False (v1.CanFocus);
  372. Assert.Null (v1.TabStop);
  373. r.Add (v1, v2, v3);
  374. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  375. Assert.False (v1.HasFocus);
  376. Assert.False (v2.HasFocus);
  377. Assert.False (v3.HasFocus);
  378. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  379. Assert.False (v1.HasFocus);
  380. Assert.False (v2.HasFocus);
  381. Assert.False (v3.HasFocus);
  382. r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  383. Assert.False (v1.HasFocus);
  384. Assert.False (v2.HasFocus);
  385. Assert.False (v3.HasFocus);
  386. r.Dispose ();
  387. }
  388. }