AdvanceFocusTests.cs 18 KB

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