FileDialogTests.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. using System.IO.Abstractions.TestingHelpers;
  2. using System.Runtime.InteropServices;
  3. using UnitTests;
  4. using Xunit.Abstractions;
  5. namespace Terminal.Gui.FileServicesTests;
  6. public class FileDialogTests ()
  7. {
  8. [Theory]
  9. [InlineData (true)]
  10. [InlineData (false)]
  11. [AutoInitShutdown]
  12. public void CancelSelection (bool cancel)
  13. {
  14. FileDialog dlg = GetInitializedFileDialog ();
  15. string openIn = Path.Combine (Environment.CurrentDirectory, "zz");
  16. Directory.CreateDirectory (openIn);
  17. dlg.Path = openIn + Path.DirectorySeparatorChar;
  18. dlg.FilesSelected += (s, e) => e.Cancel = cancel;
  19. //pressing enter will complete the current selection
  20. // unless the event cancels the confirm
  21. Send ('\n', ConsoleKey.Enter);
  22. Assert.Equal (cancel, dlg.Canceled);
  23. dlg.Dispose ();
  24. }
  25. [Theory]
  26. [InlineData ("Bob", "csv")]
  27. [InlineData ("๐”นob", "CSV")]
  28. [AutoInitShutdown]
  29. public void DirectTyping_Allowed (string path, string extension)
  30. {
  31. FileDialog dlg = GetInitializedFileDialog ();
  32. TextField tf = dlg.SubViews.OfType<TextField> ().First (t => t.HasFocus);
  33. tf.ClearAllSelection ();
  34. tf.CursorPosition = tf.Text.Length;
  35. Assert.True (tf.HasFocus);
  36. SendSlash ();
  37. Assert.Equal (
  38. new DirectoryInfo (Environment.CurrentDirectory + Path.DirectorySeparatorChar).FullName,
  39. new DirectoryInfo (dlg.Path + Path.DirectorySeparatorChar).FullName
  40. );
  41. // continue typing the rest of the path
  42. Send (path);
  43. Send ('.', ConsoleKey.OemPeriod);
  44. Send (extension);
  45. Assert.True (dlg.Canceled);
  46. Send ('\n', ConsoleKey.Enter);
  47. Assert.False (dlg.Canceled);
  48. Assert.Equal ($"{path}.{extension}", Path.GetFileName (dlg.Path));
  49. dlg.Dispose ();
  50. }
  51. [Fact]
  52. [AutoInitShutdown]
  53. public void DirectTyping_AutoComplete ()
  54. {
  55. FileDialog dlg = GetInitializedFileDialog ();
  56. string openIn = Path.Combine (Environment.CurrentDirectory, "zz");
  57. Directory.CreateDirectory (openIn);
  58. string expectedDest = Path.Combine (openIn, "xx");
  59. Directory.CreateDirectory (expectedDest);
  60. dlg.Path = openIn + Path.DirectorySeparatorChar;
  61. Send ("x");
  62. // nothing selected yet
  63. Assert.True (dlg.Canceled);
  64. Assert.Equal ("x", Path.GetFileName (dlg.Path));
  65. // complete auto typing
  66. Send ('\t', ConsoleKey.Tab);
  67. // but do not close dialog
  68. Assert.True (dlg.Canceled);
  69. Assert.EndsWith ("xx" + Path.DirectorySeparatorChar, dlg.Path);
  70. // press enter again to confirm the dialog
  71. Send ('\n', ConsoleKey.Enter);
  72. Assert.False (dlg.Canceled);
  73. Assert.EndsWith ("xx" + Path.DirectorySeparatorChar, dlg.Path);
  74. dlg.Dispose ();
  75. }
  76. [Fact]
  77. [AutoInitShutdown]
  78. public void DoNotConfirmSelectionWhenFindFocused ()
  79. {
  80. FileDialog dlg = GetInitializedFileDialog ();
  81. string openIn = Path.Combine (Environment.CurrentDirectory, "zz");
  82. Directory.CreateDirectory (openIn);
  83. dlg.Path = openIn + Path.DirectorySeparatorChar;
  84. var tf = GetTextField (dlg, FileDialogPart.SearchField);
  85. tf.SetFocus ();
  86. Assert.IsType<TextField> (dlg.MostFocused);
  87. Assert.Same (tf, dlg.MostFocused);
  88. Assert.Equal ("Enter Search", tf.Caption);
  89. // Dialog has not yet been confirmed with a choice
  90. Assert.True (dlg.Canceled);
  91. //pressing enter while search focused should not confirm path
  92. Send ('\n', ConsoleKey.Enter);
  93. Assert.True (dlg.Canceled);
  94. // tabbing out of search
  95. Send ('\t', ConsoleKey.Tab);
  96. //should allow enter to confirm path
  97. Send ('\n', ConsoleKey.Enter);
  98. // Dialog has not yet been confirmed with a choice
  99. Assert.False (dlg.Canceled);
  100. dlg.Dispose ();
  101. }
  102. [Fact]
  103. [AutoInitShutdown]
  104. public void DotDot_MovesToRoot_ThenPressBack ()
  105. {
  106. FileDialog dlg = GetDialog ();
  107. dlg.OpenMode = OpenMode.Directory;
  108. dlg.AllowsMultipleSelection = true;
  109. var selected = false;
  110. dlg.FilesSelected += (s, e) => { selected = true; };
  111. AssertIsTheStartingDirectory (dlg.Path);
  112. Assert.IsType<TextField> (dlg.MostFocused);
  113. Application.RaiseKeyDownEvent (Key.CursorDown);
  114. var tv = GetTableView(dlg);
  115. tv.SetFocus ();
  116. Assert.IsType<TableView> (dlg.MostFocused);
  117. // ".." should be the first thing selected
  118. // ".." should not mess with the displayed path
  119. AssertIsTheStartingDirectory (dlg.Path);
  120. // Accept navigation up a directory
  121. Application.RaiseKeyDownEvent (Key.Enter);
  122. AssertIsTheRootDirectory (dlg.Path);
  123. Assert.True (dlg.Canceled);
  124. Assert.False (selected);
  125. Assert.IsType<TableView> (dlg.MostFocused);
  126. // Now press Backspace (in table view)
  127. Application.RaiseKeyDownEvent (Key.Backspace);
  128. // Should move us back to the root
  129. AssertIsTheStartingDirectory (dlg.Path);
  130. Assert.True (dlg.Canceled);
  131. Assert.False (selected);
  132. dlg.Dispose ();
  133. }
  134. [Theory]
  135. [AutoInitShutdown]
  136. [InlineData (true)]
  137. [InlineData (false)]
  138. public void MultiSelectDirectory_CannotToggleDotDot (bool acceptWithEnter)
  139. {
  140. FileDialog dlg = GetDialog ();
  141. dlg.OpenMode = OpenMode.Directory;
  142. dlg.AllowsMultipleSelection = true;
  143. IReadOnlyCollection<string> eventMultiSelected = null;
  144. dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
  145. var tv = GetTableView (dlg);
  146. tv.SetFocus ();
  147. Assert.IsType<TableView> (dlg.MostFocused);
  148. // Try to toggle '..'
  149. Send (' ', ConsoleKey.Spacebar);
  150. Send ('v', ConsoleKey.DownArrow);
  151. // Toggle subfolder
  152. Send (' ', ConsoleKey.Spacebar);
  153. Assert.True (dlg.Canceled);
  154. if (acceptWithEnter)
  155. {
  156. Send ('\n', ConsoleKey.Enter);
  157. }
  158. else
  159. {
  160. Send ('O', ConsoleKey.O, false, true);
  161. }
  162. Assert.False (dlg.Canceled);
  163. Assert.Multiple (
  164. () =>
  165. {
  166. // Only the subfolder should be selected
  167. Assert.Single (dlg.MultiSelected);
  168. AssertIsTheSubfolder (dlg.Path);
  169. AssertIsTheSubfolder (dlg.MultiSelected.Single ());
  170. },
  171. () =>
  172. {
  173. // Event should also agree with the final state
  174. Assert.NotNull (eventMultiSelected);
  175. Assert.Single (eventMultiSelected);
  176. AssertIsTheSubfolder (eventMultiSelected.Single ());
  177. }
  178. );
  179. dlg.Dispose ();
  180. }
  181. [Theory]
  182. [AutoInitShutdown]
  183. [InlineData (true)]
  184. [InlineData (false)]
  185. public void MultiSelectDirectory_CanToggleThenAccept (bool acceptWithEnter)
  186. {
  187. FileDialog dlg = GetDialog ();
  188. dlg.OpenMode = OpenMode.Directory;
  189. dlg.AllowsMultipleSelection = true;
  190. IReadOnlyCollection<string> eventMultiSelected = null;
  191. dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
  192. var tv = GetTableView (dlg);
  193. tv.SetFocus ();
  194. Assert.IsType<TableView> (dlg.MostFocused);
  195. // Move selection to subfolder
  196. Send ('v', ConsoleKey.DownArrow);
  197. // Toggle subfolder
  198. Send (' ', ConsoleKey.Spacebar);
  199. Assert.True (dlg.Canceled);
  200. if (acceptWithEnter)
  201. {
  202. Send ('\n', ConsoleKey.Enter);
  203. }
  204. else
  205. {
  206. Send ('O', ConsoleKey.O, false, true);
  207. }
  208. Assert.False (dlg.Canceled);
  209. Assert.Multiple (
  210. () =>
  211. {
  212. // Only the subfolder should be selected
  213. Assert.Single (dlg.MultiSelected);
  214. AssertIsTheSubfolder (dlg.Path);
  215. AssertIsTheSubfolder (dlg.MultiSelected.Single ());
  216. },
  217. () =>
  218. {
  219. // Event should also agree with the final state
  220. Assert.NotNull (eventMultiSelected);
  221. Assert.Single (eventMultiSelected);
  222. AssertIsTheSubfolder (eventMultiSelected.Single ());
  223. }
  224. );
  225. dlg.Dispose ();
  226. }
  227. [Fact]
  228. [AutoInitShutdown]
  229. public void MultiSelectDirectory_EnterOpensFolder ()
  230. {
  231. FileDialog dlg = GetDialog ();
  232. dlg.OpenMode = OpenMode.Directory;
  233. dlg.AllowsMultipleSelection = true;
  234. IReadOnlyCollection<string> eventMultiSelected = null;
  235. dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
  236. var tv = GetTableView (dlg);
  237. tv.SetFocus ();
  238. Assert.IsType<TableView> (dlg.MostFocused);
  239. // Move selection to subfolder
  240. Send ('v', ConsoleKey.DownArrow);
  241. Send ('\n', ConsoleKey.Enter);
  242. // Path should update to the newly opened folder
  243. AssertIsTheSubfolder (dlg.Path);
  244. // No selection will have been confirmed
  245. Assert.True (dlg.Canceled);
  246. Assert.Empty (dlg.MultiSelected);
  247. Assert.Null (eventMultiSelected);
  248. dlg.Dispose ();
  249. }
  250. [Fact]
  251. [AutoInitShutdown]
  252. public void OnLoad_TextBoxIsFocused ()
  253. {
  254. FileDialog dlg = GetInitializedFileDialog ();
  255. View tf = dlg.SubViews.FirstOrDefault (t => t.HasFocus);
  256. Assert.NotNull (tf);
  257. Assert.IsType<TextField> (tf);
  258. dlg.Dispose ();
  259. }
  260. [Theory]
  261. [AutoInitShutdown]
  262. [InlineData (true, true)]
  263. [InlineData (true, false)]
  264. [InlineData (false, true)]
  265. [InlineData (false, false)]
  266. public void PickDirectory_ArrowNavigation (bool openModeMixed, bool multiple)
  267. {
  268. FileDialog dlg = GetDialog ();
  269. dlg.OpenMode = openModeMixed ? OpenMode.Mixed : OpenMode.Directory;
  270. dlg.AllowsMultipleSelection = multiple;
  271. var tv = GetTableView (dlg);
  272. tv.SetFocus ();
  273. Assert.IsType<TableView> (dlg.MostFocused);
  274. // Should be selecting ..
  275. Send ('v', ConsoleKey.DownArrow);
  276. // Down to the directory
  277. Assert.True (dlg.Canceled);
  278. // Alt+O to open (enter would just navigate into the child dir)
  279. Send ('O', ConsoleKey.O, false, true);
  280. Assert.False (dlg.Canceled);
  281. AssertIsTheSubfolder (dlg.Path);
  282. dlg.Dispose ();
  283. }
  284. [Theory]
  285. [AutoInitShutdown]
  286. [InlineData (true, true)]
  287. [InlineData (true, false)]
  288. [InlineData (false, true)]
  289. [InlineData (false, false)]
  290. public void PickDirectory_DirectTyping (bool openModeMixed, bool multiple)
  291. {
  292. FileDialog dlg = GetDialog ();
  293. dlg.OpenMode = openModeMixed ? OpenMode.Mixed : OpenMode.Directory;
  294. dlg.AllowsMultipleSelection = multiple;
  295. // whe first opening the text field will have select all on
  296. // so to add to current path user must press End or right
  297. Send ('>', ConsoleKey.LeftArrow);
  298. Send ('>', ConsoleKey.RightArrow);
  299. Send ("subfolder");
  300. // Dialog has not yet been confirmed with a choice
  301. Assert.True (dlg.Canceled);
  302. // Now it has
  303. Send ('\n', ConsoleKey.Enter);
  304. Assert.False (dlg.Canceled);
  305. AssertIsTheSubfolder (dlg.Path);
  306. dlg.Dispose ();
  307. }
  308. [Theory]
  309. [InlineData (".csv", null, false)]
  310. [InlineData (".csv", "", false)]
  311. [InlineData (".csv", "c:\\MyFile.csv", true)]
  312. [InlineData (".csv", "c:\\MyFile.CSV", true)]
  313. [InlineData (".csv", "c:\\MyFile.csv.bak", false)]
  314. public void TestAllowedType_Basic (string allowed, string candidate, bool expected)
  315. {
  316. Assert.Equal (expected, new AllowedType ("Test", allowed).IsAllowed (candidate));
  317. }
  318. [Theory]
  319. [InlineData (".Designer.cs", "c:\\MyView.Designer.cs", true)]
  320. [InlineData (".Designer.cs", "c:\\temp/MyView.Designer.cs", true)]
  321. [InlineData (".Designer.cs", "MyView.Designer.cs", true)]
  322. [InlineData (".Designer.cs", "c:\\MyView.DESIGNER.CS", true)]
  323. [InlineData (".Designer.cs", "MyView.cs", false)]
  324. public void TestAllowedType_DoubleBarreled (string allowed, string candidate, bool expected)
  325. {
  326. Assert.Equal (expected, new AllowedType ("Test", allowed).IsAllowed (candidate));
  327. }
  328. [Theory]
  329. [InlineData ("Dockerfile", "c:\\temp\\Dockerfile", true)]
  330. [InlineData ("Dockerfile", "Dockerfile", true)]
  331. [InlineData ("Dockerfile", "someimg.Dockerfile", true)]
  332. public void TestAllowedType_SpecificFile (string allowed, string candidate, bool expected)
  333. {
  334. Assert.Equal (expected, new AllowedType ("Test", allowed).IsAllowed (candidate));
  335. }
  336. [Fact]
  337. [AutoInitShutdown]
  338. public void TestDirectoryContents_Linux ()
  339. {
  340. if (IsWindows ())
  341. {
  342. return;
  343. }
  344. FileDialog fd = GetLinuxDialog ();
  345. fd.Title = string.Empty;
  346. fd.Style.Culture = new ("en-US");
  347. fd.Draw ();
  348. /*
  349. *
  350. *
  351. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  352. โ”‚/demo/ โ”‚
  353. โ”‚โŸฆโ–ฒโŸง โ”‚
  354. โ”‚โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚
  355. โ”‚โ”‚Filename (โ–ฒ)โ”‚Size โ”‚Modified โ”‚Type โ”‚โ”‚
  356. โ”‚โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”คโ”‚
  357. โ”‚โ”‚.. โ”‚ โ”‚ โ”‚<Directory> โ”‚โ”‚
  358. โ”‚โ”‚/subfolder โ”‚ โ”‚2002-01-01T22:42:10 โ”‚<Directory> โ”‚โ”‚
  359. โ”‚โ”‚image.gif โ”‚4.00 B โ”‚2002-01-01T22:42:10 โ”‚.gif โ”‚โ”‚
  360. โ”‚โ”‚jQuery.js โ”‚7.00 B โ”‚2001-01-01T11:44:42 โ”‚.js โ”‚โ”‚
  361. โ”‚ โ”‚
  362. โ”‚ โ”‚
  363. โ”‚ โ”‚
  364. โ”‚โŸฆ โ–บโ–บ โŸง Enter Search โŸฆโ–บ OK โ—„โŸง โŸฆ Cancel โŸง โ”‚
  365. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  366. *
  367. */
  368. var path = GetTextField (fd, FileDialogPart.Path);
  369. Assert.Equal ("/demo/", path.Text);
  370. var tv = GetTableView (fd);
  371. // Asserting the headers
  372. Assert.Equal ("Filename (โ–ฒ)", tv.Table.ColumnNames.ElementAt (0));
  373. Assert.Equal ("Size", tv.Table.ColumnNames.ElementAt (1));
  374. Assert.Equal ("Modified", tv.Table.ColumnNames.ElementAt (2));
  375. Assert.Equal ("Type", tv.Table.ColumnNames.ElementAt (3));
  376. // Asserting the table contents
  377. Assert.Equal ("..", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [0, 0]));
  378. Assert.Equal ("/subfolder", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [1, 0]));
  379. Assert.Equal ("image.gif", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [2, 0]));
  380. Assert.Equal ("jQuery.js", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [3, 0]));
  381. Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [0, 1]));
  382. Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [1, 1]));
  383. Assert.Equal ("4.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [2, 1]));
  384. Assert.Equal ("7.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [3, 1]));
  385. Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [0, 2]));
  386. Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [1, 2]));
  387. Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [2, 2]));
  388. Assert.Equal ("2001-01-01T11:44:42", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [3, 2]));
  389. Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [0, 3]));
  390. Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [1, 3]));
  391. Assert.Equal (".gif", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [2, 3]));
  392. Assert.Equal (".js", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [3, 3]));
  393. fd.Dispose ();
  394. }
  395. [Fact]
  396. [AutoInitShutdown]
  397. public void TestDirectoryContents_Windows ()
  398. {
  399. if (!IsWindows ())
  400. {
  401. return;
  402. }
  403. FileDialog fd = GetWindowsDialog ();
  404. fd.Title = string.Empty;
  405. fd.Style.Culture = new ("en-US");
  406. fd.Draw ();
  407. /*
  408. *
  409. *
  410. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  411. โ”‚c:\demo\ โ”‚
  412. โ”‚โŸฆโ–ฒโŸง โ”‚
  413. โ”‚โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚
  414. โ”‚โ”‚Filename (โ–ฒ)โ”‚Size โ”‚Modified โ”‚Type โ”‚โ”‚
  415. โ”‚โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”คโ”‚
  416. โ”‚โ”‚.. โ”‚ โ”‚ โ”‚<Directory> โ”‚โ”‚
  417. โ”‚โ”‚\subfolder โ”‚ โ”‚2002-01-01T22:42:10 โ”‚<Directory> โ”‚โ”‚
  418. โ”‚โ”‚image.gif โ”‚4.00 B โ”‚2002-01-01T22:42:10 โ”‚.gif โ”‚โ”‚
  419. โ”‚โ”‚jQuery.js โ”‚7.00 B โ”‚2001-01-01T11:44:42 โ”‚.js โ”‚โ”‚
  420. โ”‚โ”‚mybinary.exeโ”‚7.00 B โ”‚2001-01-01T11:44:42 โ”‚.exe โ”‚โ”‚
  421. โ”‚ โ”‚
  422. โ”‚ โ”‚
  423. โ”‚โŸฆ โ–บโ–บ โŸง Enter Search โŸฆโ–บ OK โ—„โŸง โŸฆ Cancel โŸง โ”‚
  424. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  425. *
  426. */
  427. var path = GetTextField (fd, FileDialogPart.Path);
  428. Assert.Equal ("c:\\demo\\",path.Text);
  429. var tv = GetTableView (fd);
  430. // Asserting the headers
  431. Assert.Equal ("Filename (โ–ฒ)", tv.Table.ColumnNames.ElementAt (0));
  432. Assert.Equal ("Size", tv.Table.ColumnNames.ElementAt (1));
  433. Assert.Equal ("Modified", tv.Table.ColumnNames.ElementAt (2));
  434. Assert.Equal ("Type", tv.Table.ColumnNames.ElementAt (3));
  435. // Asserting the table contents
  436. Assert.Equal ("..", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [0, 0]));
  437. Assert.Equal (@"\subfolder", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [1, 0]));
  438. Assert.Equal ("image.gif", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [2, 0]));
  439. Assert.Equal ("jQuery.js", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [3, 0]));
  440. Assert.Equal ("mybinary.exe", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [4, 0]));
  441. Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [0, 1]));
  442. Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [1, 1]));
  443. Assert.Equal ("4.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [2, 1]));
  444. Assert.Equal ("7.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [3, 1]));
  445. Assert.Equal ("7.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [4, 1]));
  446. Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [0, 2]));
  447. Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [1, 2]));
  448. Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [2, 2]));
  449. Assert.Equal ("2001-01-01T11:44:42", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [3, 2]));
  450. Assert.Equal ("2001-01-01T11:44:42", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [4, 2]));
  451. Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [0, 3]));
  452. Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [1, 3]));
  453. Assert.Equal (".gif", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [2, 3]));
  454. Assert.Equal (".js", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [3, 3]));
  455. Assert.Equal (".exe", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [4, 3]));
  456. fd.Dispose ();
  457. }
  458. private void AssertIsTheRootDirectory (string path)
  459. {
  460. if (IsWindows ())
  461. {
  462. Assert.Equal (@"c:\", path);
  463. }
  464. else
  465. {
  466. Assert.Equal ("/", path);
  467. }
  468. }
  469. private void AssertIsTheStartingDirectory (string path)
  470. {
  471. if (IsWindows ())
  472. {
  473. Assert.Equal (@"c:\demo\", path);
  474. }
  475. else
  476. {
  477. Assert.Equal ("/demo/", path);
  478. }
  479. }
  480. private void AssertIsTheSubfolder (string path)
  481. {
  482. if (IsWindows ())
  483. {
  484. Assert.Equal (@"c:\demo\subfolder", path);
  485. }
  486. else
  487. {
  488. Assert.Equal ("/demo/subfolder", path);
  489. }
  490. }
  491. private void Begin (FileDialog dlg)
  492. {
  493. dlg.BeginInit ();
  494. dlg.EndInit ();
  495. Application.Begin (dlg);
  496. }
  497. private FileDialog GetDialog () { return IsWindows () ? GetWindowsDialog () : GetLinuxDialog (); }
  498. private FileDialog GetInitializedFileDialog ()
  499. {
  500. Window.DefaultBorderStyle = LineStyle.Single;
  501. Dialog.DefaultButtonAlignment = Alignment.Center;
  502. Dialog.DefaultBorderStyle = LineStyle.Single;
  503. Dialog.DefaultShadow = ShadowStyle.None;
  504. Button.DefaultShadow = ShadowStyle.None;
  505. var dlg = new FileDialog ();
  506. Begin (dlg);
  507. return dlg;
  508. }
  509. private FileDialog GetLinuxDialog ()
  510. {
  511. Window.DefaultBorderStyle = LineStyle.Single;
  512. Dialog.DefaultButtonAlignment = Alignment.Center;
  513. Dialog.DefaultBorderStyle = LineStyle.Single;
  514. Dialog.DefaultShadow = ShadowStyle.None;
  515. Button.DefaultShadow = ShadowStyle.None;
  516. // Arrange
  517. var fileSystem = new MockFileSystem (new Dictionary<string, MockFileData> (), "/");
  518. fileSystem.MockTime (() => new (2010, 01, 01, 11, 12, 43));
  519. fileSystem.AddFile (
  520. @"/myfile.txt",
  521. new ("Testing is meh.") { LastWriteTime = new DateTime (2001, 01, 01, 11, 12, 11) }
  522. );
  523. fileSystem.AddFile (
  524. @"/demo/jQuery.js",
  525. new ("some js") { LastWriteTime = new DateTime (2001, 01, 01, 11, 44, 42) }
  526. );
  527. fileSystem.AddFile (
  528. @"/demo/image.gif",
  529. new (new byte [] { 0x12, 0x34, 0x56, 0xd2 })
  530. {
  531. LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10)
  532. }
  533. );
  534. var m = (MockDirectoryInfo)fileSystem.DirectoryInfo.New (@"/demo/subfolder");
  535. m.Create ();
  536. m.LastWriteTime = new (2002, 01, 01, 22, 42, 10);
  537. fileSystem.AddFile (
  538. @"/demo/subfolder/image2.gif",
  539. new (new byte [] { 0x12, 0x34, 0x56, 0xd2 })
  540. {
  541. LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10)
  542. }
  543. );
  544. var fd = new FileDialog (fileSystem) { Height = 15, Width = 75 };
  545. fd.Path = @"/demo/";
  546. Begin (fd);
  547. return fd;
  548. }
  549. private FileDialog GetWindowsDialog ()
  550. {
  551. // Override CM
  552. Window.DefaultBorderStyle = LineStyle.Single;
  553. Dialog.DefaultButtonAlignment = Alignment.Center;
  554. Dialog.DefaultBorderStyle = LineStyle.Single;
  555. Dialog.DefaultShadow = ShadowStyle.None;
  556. Button.DefaultShadow = ShadowStyle.None;
  557. // Arrange
  558. var fileSystem = new MockFileSystem (new Dictionary<string, MockFileData> (), @"c:\");
  559. fileSystem.MockTime (() => new (2010, 01, 01, 11, 12, 43));
  560. fileSystem.AddFile (
  561. @"c:\myfile.txt",
  562. new ("Testing is meh.") { LastWriteTime = new DateTime (2001, 01, 01, 11, 12, 11) }
  563. );
  564. fileSystem.AddFile (
  565. @"c:\demo\jQuery.js",
  566. new ("some js") { LastWriteTime = new DateTime (2001, 01, 01, 11, 44, 42) }
  567. );
  568. fileSystem.AddFile (
  569. @"c:\demo\mybinary.exe",
  570. new ("some js") { LastWriteTime = new DateTime (2001, 01, 01, 11, 44, 42) }
  571. );
  572. fileSystem.AddFile (
  573. @"c:\demo\image.gif",
  574. new (new byte [] { 0x12, 0x34, 0x56, 0xd2 })
  575. {
  576. LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10)
  577. }
  578. );
  579. var m = (MockDirectoryInfo)fileSystem.DirectoryInfo.New (@"c:\demo\subfolder");
  580. m.Create ();
  581. m.LastWriteTime = new (2002, 01, 01, 22, 42, 10);
  582. fileSystem.AddFile (
  583. @"c:\demo\subfolder\image2.gif",
  584. new (new byte [] { 0x12, 0x34, 0x56, 0xd2 })
  585. {
  586. LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10)
  587. }
  588. );
  589. var fd = new FileDialog (fileSystem) { Height = 15, Width = 75 };
  590. fd.Path = @"c:\demo\";
  591. Begin (fd);
  592. return fd;
  593. }
  594. /*
  595. [Fact, AutoInitShutdown]
  596. public void Autocomplete_NoSuggestion_WhenTextMatchesExactly ()
  597. {
  598. var tb = new TextFieldWithAppendAutocomplete ();
  599. ForceFocus (tb);
  600. tb.Text = "/bob/fish";
  601. tb.CursorPosition = tb.Text.Length;
  602. tb.GenerateSuggestions (null, "fish", "fishes");
  603. // should not report success for autocompletion because we already have that exact
  604. // string
  605. Assert.False (tb.AcceptSelectionIfAny ());
  606. }
  607. [Fact, AutoInitShutdown]
  608. public void Autocomplete_AcceptSuggstion ()
  609. {
  610. var tb = new TextFieldWithAppendAutocomplete ();
  611. ForceFocus (tb);
  612. tb.Text = @"/bob/fi";
  613. tb.CursorPosition = tb.Text.Length;
  614. tb.GenerateSuggestions (null, "fish", "fishes");
  615. Assert.True (tb.AcceptSelectionIfAny ());
  616. Assert.Equal (@"/bob/fish", tb.Text);
  617. }*/
  618. private bool IsWindows () { return RuntimeInformation.IsOSPlatform (OSPlatform.Windows); }
  619. private void Send (char ch, ConsoleKey ck, bool shift = false, bool alt = false, bool control = false)
  620. {
  621. Application.Driver?.SendKeys (ch, ck, shift, alt, control);
  622. }
  623. private void Send (string chars)
  624. {
  625. foreach (char ch in chars)
  626. {
  627. ConsoleKeyInfo consoleKeyInfo = EscSeqUtils.MapConsoleKeyInfo (new (ch, ConsoleKey.None, false, false, false));
  628. Application.Driver?.SendKeys (
  629. ch,
  630. consoleKeyInfo.Key,
  631. (consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
  632. (consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
  633. (consoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0);
  634. }
  635. }
  636. private void SendSlash ()
  637. {
  638. if (Path.DirectorySeparatorChar == '/')
  639. {
  640. Send ('/', ConsoleKey.Separator);
  641. }
  642. else
  643. {
  644. Send ('\\', ConsoleKey.Separator);
  645. }
  646. }
  647. private TextField GetTextField (FileDialog dlg, FileDialogPart part)
  648. {
  649. switch (part)
  650. {
  651. case FileDialogPart.Path:
  652. return dlg.SubViews.OfType<TextField> ().ElementAt (0);
  653. case FileDialogPart.SearchField:
  654. return dlg.SubViews.OfType<TextField> ().ElementAt (1);
  655. default:
  656. throw new ArgumentOutOfRangeException (nameof (part), part, null);
  657. }
  658. }
  659. private TableView GetTableView (FileDialog dlg)
  660. {
  661. var tile = dlg.SubViews.OfType<TileView> ().Single ();
  662. return (TableView)tile.Tiles.ElementAt (1).ContentView.SubViews.ElementAt(0);
  663. }
  664. private enum FileDialogPart
  665. {
  666. Path,
  667. SearchField,
  668. }
  669. }