TextFormatterTests.cs 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  1. using System.Text;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Terminal.Gui;
  6. using Xunit;
  7. using Xunit.Abstractions;
  8. // Alias Console to MockConsole so we don't accidentally use Console
  9. using Console = Terminal.Gui.FakeConsole;
  10. namespace Terminal.Gui.TextTests {
  11. public class TextFormatterTests {
  12. readonly ITestOutputHelper output;
  13. public TextFormatterTests (ITestOutputHelper output)
  14. {
  15. this.output = output;
  16. }
  17. [Fact]
  18. public void Basic_Usage ()
  19. {
  20. var testText = "test";
  21. var expectedSize = new Size ();
  22. var testBounds = new Rect (0, 0, 100, 1);
  23. var tf = new TextFormatter ();
  24. tf.Text = testText;
  25. expectedSize = new Size (testText.Length, 1);
  26. Assert.Equal (testText, tf.Text);
  27. Assert.Equal (TextAlignment.Left, tf.Alignment);
  28. Assert.Equal (expectedSize, tf.Size);
  29. tf.Draw (testBounds, new Attribute (), new Attribute ());
  30. Assert.Equal (expectedSize, tf.Size);
  31. Assert.NotEmpty (tf.Lines);
  32. tf.Alignment = TextAlignment.Right;
  33. expectedSize = new Size (testText.Length, 1);
  34. Assert.Equal (testText, tf.Text);
  35. Assert.Equal (TextAlignment.Right, tf.Alignment);
  36. Assert.Equal (expectedSize, tf.Size);
  37. tf.Draw (testBounds, new Attribute (), new Attribute ());
  38. Assert.Equal (expectedSize, tf.Size);
  39. Assert.NotEmpty (tf.Lines);
  40. tf.Alignment = TextAlignment.Right;
  41. expectedSize = new Size (testText.Length * 2, 1);
  42. tf.Size = expectedSize;
  43. Assert.Equal (testText, tf.Text);
  44. Assert.Equal (TextAlignment.Right, tf.Alignment);
  45. Assert.Equal (expectedSize, tf.Size);
  46. tf.Draw (testBounds, new Attribute (), new Attribute ());
  47. Assert.Equal (expectedSize, tf.Size);
  48. Assert.NotEmpty (tf.Lines);
  49. tf.Alignment = TextAlignment.Centered;
  50. expectedSize = new Size (testText.Length * 2, 1);
  51. tf.Size = expectedSize;
  52. Assert.Equal (testText, tf.Text);
  53. Assert.Equal (TextAlignment.Centered, tf.Alignment);
  54. Assert.Equal (expectedSize, tf.Size);
  55. tf.Draw (testBounds, new Attribute (), new Attribute ());
  56. Assert.Equal (expectedSize, tf.Size);
  57. Assert.NotEmpty (tf.Lines);
  58. }
  59. [Fact]
  60. public void TestSize_TextChange ()
  61. {
  62. var tf = new TextFormatter () { Text = "你" };
  63. Assert.Equal (2, tf.Size.Width);
  64. tf.Text = "你你";
  65. Assert.Equal (4, tf.Size.Width);
  66. }
  67. [Fact]
  68. public void NeedsFormat_Sets ()
  69. {
  70. var testText = "test";
  71. var testBounds = new Rect (0, 0, 100, 1);
  72. var tf = new TextFormatter ();
  73. tf.Text = "test";
  74. Assert.True (tf.NeedsFormat); // get_Lines causes a Format
  75. Assert.NotEmpty (tf.Lines);
  76. Assert.False (tf.NeedsFormat); // get_Lines causes a Format
  77. Assert.Equal (testText, tf.Text);
  78. tf.Draw (testBounds, new Attribute (), new Attribute ());
  79. Assert.False (tf.NeedsFormat);
  80. tf.Size = new Size (1, 1);
  81. Assert.True (tf.NeedsFormat);
  82. Assert.NotEmpty (tf.Lines);
  83. Assert.False (tf.NeedsFormat); // get_Lines causes a Format
  84. tf.Alignment = TextAlignment.Centered;
  85. Assert.True (tf.NeedsFormat);
  86. Assert.NotEmpty (tf.Lines);
  87. Assert.False (tf.NeedsFormat); // get_Lines causes a Format
  88. }
  89. [Theory]
  90. [InlineData (null)]
  91. [InlineData ("")]
  92. [InlineData ("no hotkey")]
  93. [InlineData ("No hotkey, Upper Case")]
  94. [InlineData ("Non-english: Сохранить")]
  95. public void FindHotKey_Invalid_ReturnsFalse (string text)
  96. {
  97. Rune hotKeySpecifier = (Rune)'_';
  98. bool supportFirstUpperCase = false;
  99. int hotPos = 0;
  100. Key hotKey = Key.Unknown;
  101. bool result = false;
  102. result = TextFormatter.FindHotKey (text, hotKeySpecifier, supportFirstUpperCase, out hotPos, out hotKey);
  103. Assert.False (result);
  104. Assert.Equal (-1, hotPos);
  105. Assert.Equal (Key.Unknown, hotKey);
  106. }
  107. [Theory]
  108. [InlineData ("_K Before", true, 0, (Key)'K')]
  109. [InlineData ("a_K Second", true, 1, (Key)'K')]
  110. [InlineData ("Last _K", true, 5, (Key)'K')]
  111. [InlineData ("After K_", false, -1, Key.Unknown)]
  112. [InlineData ("Multiple _K and _R", true, 9, (Key)'K')]
  113. [InlineData ("Non-english: _Кдать", true, 13, (Key)'К')] // Cryllic K (К)
  114. [InlineData ("_K Before", true, 0, (Key)'K', true)] // Turn on FirstUpperCase and verify same results
  115. [InlineData ("a_K Second", true, 1, (Key)'K', true)]
  116. [InlineData ("Last _K", true, 5, (Key)'K', true)]
  117. [InlineData ("After K_", false, -1, Key.Unknown, true)]
  118. [InlineData ("Multiple _K and _R", true, 9, (Key)'K', true)]
  119. [InlineData ("Non-english: _Кдать", true, 13, (Key)'К', true)] // Cryllic K (К)
  120. public void FindHotKey_AlphaUpperCase_Succeeds (string text, bool expectedResult, int expectedHotPos, Key expectedKey, bool supportFirstUpperCase = false)
  121. {
  122. Rune hotKeySpecifier = (Rune)'_';
  123. var result = TextFormatter.FindHotKey (text, hotKeySpecifier, supportFirstUpperCase, out int hotPos, out Key hotKey);
  124. if (expectedResult) {
  125. Assert.True (result);
  126. } else {
  127. Assert.False (result);
  128. }
  129. Assert.Equal (expectedResult, result);
  130. Assert.Equal (expectedHotPos, hotPos);
  131. Assert.Equal (expectedKey, hotKey);
  132. }
  133. [Theory]
  134. [InlineData ("_k Before", true, 0, (Key)'K')] // lower case should return uppercase Hotkey
  135. [InlineData ("a_k Second", true, 1, (Key)'K')]
  136. [InlineData ("Last _k", true, 5, (Key)'K')]
  137. [InlineData ("After k_", false, -1, Key.Unknown)]
  138. [InlineData ("Multiple _k and _R", true, 9, (Key)'K')]
  139. [InlineData ("Non-english: _кдать", true, 13, (Key)'К')] // Lower case Cryllic K (к)
  140. [InlineData ("_k Before", true, 0, (Key)'K', true)] // Turn on FirstUpperCase and verify same results
  141. [InlineData ("a_k Second", true, 1, (Key)'K', true)]
  142. [InlineData ("Last _k", true, 5, (Key)'K', true)]
  143. [InlineData ("After k_", false, -1, Key.Unknown, true)]
  144. [InlineData ("Multiple _k and _r", true, 9, (Key)'K', true)]
  145. [InlineData ("Non-english: _кдать", true, 13, (Key)'К', true)] // Cryllic K (К)
  146. public void FindHotKey_AlphaLowerCase_Succeeds (string text, bool expectedResult, int expectedHotPos, Key expectedKey, bool supportFirstUpperCase = false)
  147. {
  148. Rune hotKeySpecifier = (Rune)'_';
  149. var result = TextFormatter.FindHotKey (text, hotKeySpecifier, supportFirstUpperCase, out int hotPos, out Key hotKey);
  150. if (expectedResult) {
  151. Assert.True (result);
  152. } else {
  153. Assert.False (result);
  154. }
  155. Assert.Equal (expectedResult, result);
  156. Assert.Equal (expectedHotPos, hotPos);
  157. Assert.Equal (expectedKey, hotKey);
  158. }
  159. [Theory]
  160. [InlineData ("_1 Before", true, 0, (Key)'1')] // Digits
  161. [InlineData ("a_1 Second", true, 1, (Key)'1')]
  162. [InlineData ("Last _1", true, 5, (Key)'1')]
  163. [InlineData ("After 1_", false, -1, Key.Unknown)]
  164. [InlineData ("Multiple _1 and _2", true, 9, (Key)'1')]
  165. [InlineData ("_1 Before", true, 0, (Key)'1', true)] // Turn on FirstUpperCase and verify same results
  166. [InlineData ("a_1 Second", true, 1, (Key)'1', true)]
  167. [InlineData ("Last _1", true, 5, (Key)'1', true)]
  168. [InlineData ("After 1_", false, -1, Key.Unknown, true)]
  169. [InlineData ("Multiple _1 and _2", true, 9, (Key)'1', true)]
  170. public void FindHotKey_Numeric_Succeeds (string text, bool expectedResult, int expectedHotPos, Key expectedKey, bool supportFirstUpperCase = false)
  171. {
  172. Rune hotKeySpecifier = (Rune)'_';
  173. var result = TextFormatter.FindHotKey (text, hotKeySpecifier, supportFirstUpperCase, out int hotPos, out Key hotKey);
  174. if (expectedResult) {
  175. Assert.True (result);
  176. } else {
  177. Assert.False (result);
  178. }
  179. Assert.Equal (expectedResult, result);
  180. Assert.Equal (expectedHotPos, hotPos);
  181. Assert.Equal (expectedKey, hotKey);
  182. }
  183. [Theory]
  184. [InlineData ("K Before", true, 0, (Key)'K')]
  185. [InlineData ("aK Second", true, 1, (Key)'K')]
  186. [InlineData ("last K", true, 5, (Key)'K')]
  187. [InlineData ("multiple K and R", true, 9, (Key)'K')]
  188. [InlineData ("non-english: Кдать", true, 13, (Key)'К')] // Cryllic K (К)
  189. public void FindHotKey_Legacy_FirstUpperCase_Succeeds (string text, bool expectedResult, int expectedHotPos, Key expectedKey)
  190. {
  191. var supportFirstUpperCase = true;
  192. Rune hotKeySpecifier = (Rune)0;
  193. var result = TextFormatter.FindHotKey (text, hotKeySpecifier, supportFirstUpperCase, out int hotPos, out Key hotKey);
  194. if (expectedResult) {
  195. Assert.True (result);
  196. } else {
  197. Assert.False (result);
  198. }
  199. Assert.Equal (expectedResult, result);
  200. Assert.Equal (expectedHotPos, hotPos);
  201. Assert.Equal (expectedKey, hotKey);
  202. }
  203. [Theory]
  204. [InlineData ("\"k before")]
  205. [InlineData ("ak second")]
  206. [InlineData ("last k")]
  207. [InlineData ("multiple k and r")]
  208. [InlineData ("12345")]
  209. [InlineData ("`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")] // punctuation
  210. [InlineData (" ~  s  gui.cs   master ↑10")] // ~IsLetterOrDigit + Unicode
  211. [InlineData ("non-english: кдать")] // Lower case Cryllic K (к)
  212. public void FindHotKey_Legacy_FirstUpperCase_NotFound_Returns_False (string text)
  213. {
  214. bool supportFirstUpperCase = true;
  215. var hotKeySpecifier = (Rune)0;
  216. var result = TextFormatter.FindHotKey (text, hotKeySpecifier, supportFirstUpperCase, out int hotPos, out Key hotKey);
  217. Assert.False (result);
  218. Assert.Equal (-1, hotPos);
  219. Assert.Equal (Key.Unknown, hotKey);
  220. }
  221. static string testHotKeyAtStart = "_K Before";
  222. static string testHotKeyAtSecondPos = "a_K Second";
  223. static string testHotKeyAtLastPos = "Last _K";
  224. static string testHotKeyAfterLastChar = "After K_";
  225. static string testMultiHotKeys = "Multiple _K and _R";
  226. static string testNonEnglish = "Non-english: _Кдать";
  227. [Theory]
  228. [InlineData (null)]
  229. [InlineData ("")]
  230. [InlineData ("a")]
  231. public void RemoveHotKeySpecifier_InValid_ReturnsOriginal (string text)
  232. {
  233. Rune hotKeySpecifier = (Rune)'_';
  234. if (text == null) {
  235. Assert.Null (TextFormatter.RemoveHotKeySpecifier (text, 0, hotKeySpecifier));
  236. Assert.Null (TextFormatter.RemoveHotKeySpecifier (text, -1, hotKeySpecifier));
  237. Assert.Null (TextFormatter.RemoveHotKeySpecifier (text, 100, hotKeySpecifier));
  238. } else {
  239. Assert.Equal (text, TextFormatter.RemoveHotKeySpecifier (text, 0, hotKeySpecifier));
  240. Assert.Equal (text, TextFormatter.RemoveHotKeySpecifier (text, -1, hotKeySpecifier));
  241. Assert.Equal (text, TextFormatter.RemoveHotKeySpecifier (text, 100, hotKeySpecifier));
  242. }
  243. }
  244. [Theory]
  245. [InlineData ("_K Before", 0, "K Before")]
  246. [InlineData ("a_K Second", 1, "aK Second")]
  247. [InlineData ("Last _K", 5, "Last K")]
  248. [InlineData ("After K_", 7, "After K")]
  249. [InlineData ("Multiple _K and _R", 9, "Multiple K and _R")]
  250. [InlineData ("Non-english: _Кдать", 13, "Non-english: Кдать")]
  251. public void RemoveHotKeySpecifier_Valid_ReturnsStripped (string text, int hotPos, string expectedText)
  252. {
  253. Rune hotKeySpecifier = (Rune)'_';
  254. Assert.Equal (expectedText, TextFormatter.RemoveHotKeySpecifier (text, hotPos, hotKeySpecifier));
  255. }
  256. [Theory]
  257. [InlineData ("all lower case", 0)]
  258. [InlineData ("K Before", 0)]
  259. [InlineData ("aK Second", 1)]
  260. [InlineData ("Last K", 5)]
  261. [InlineData ("fter K", 7)]
  262. [InlineData ("Multiple K and R", 9)]
  263. [InlineData ("Non-english: Кдать", 13)]
  264. public void RemoveHotKeySpecifier_Valid_Legacy_ReturnsOriginal (string text, int hotPos)
  265. {
  266. Rune hotKeySpecifier = (Rune)'_';
  267. Assert.Equal (text, TextFormatter.RemoveHotKeySpecifier (text, hotPos, hotKeySpecifier));
  268. }
  269. [Theory]
  270. [InlineData (null)]
  271. [InlineData ("")]
  272. public void CalcRect_Invalid_Returns_Empty (string text)
  273. {
  274. Assert.Equal (Rect.Empty, TextFormatter.CalcRect (0, 0, text));
  275. Assert.Equal (new Rect (new Point (1, 2), Size.Empty), TextFormatter.CalcRect (1, 2, text));
  276. Assert.Equal (new Rect (new Point (-1, -2), Size.Empty), TextFormatter.CalcRect (-1, -2, text));
  277. }
  278. [Theory]
  279. [InlineData ("test")]
  280. [InlineData (" ~  s  gui.cs   master ↑10")]
  281. public void CalcRect_SingleLine_Returns_1High (string text)
  282. {
  283. Assert.Equal (new Rect (0, 0, text.GetRuneCount (), 1), TextFormatter.CalcRect (0, 0, text));
  284. Assert.Equal (new Rect (0, 0, text.GetColumns (), 1), TextFormatter.CalcRect (0, 0, text));
  285. }
  286. [Theory]
  287. [InlineData ("line1\nline2", 5, 2)]
  288. [InlineData ("\nline2", 5, 2)]
  289. [InlineData ("\n\n", 0, 3)]
  290. [InlineData ("\n\n\n", 0, 4)]
  291. [InlineData ("line1\nline2\nline3long!", 10, 3)]
  292. [InlineData ("line1\nline2\n\n", 5, 4)]
  293. [InlineData ("line1\r\nline2", 5, 2)]
  294. [InlineData (" ~  s  gui.cs   master ↑10\n", 31, 2)]
  295. [InlineData ("\n ~  s  gui.cs   master ↑10", 31, 2)]
  296. [InlineData (" ~  s  gui.cs   master\n↑10", 27, 2)]
  297. public void CalcRect_MultiLine_Returns_nHigh (string text, int expectedWidth, int expectedLines)
  298. {
  299. Assert.Equal (new Rect (0, 0, expectedWidth, expectedLines), TextFormatter.CalcRect (0, 0, text));
  300. var lines = text.Split (text.Contains (Environment.NewLine) ? Environment.NewLine : "\n");
  301. var maxWidth = lines.Max (s => s.GetColumns ());
  302. var lineWider = 0;
  303. for (int i = 0; i < lines.Length; i++) {
  304. var w = lines [i].GetColumns ();
  305. if (w == maxWidth) {
  306. lineWider = i;
  307. }
  308. }
  309. Assert.Equal (new Rect (0, 0, maxWidth, expectedLines), TextFormatter.CalcRect (0, 0, text));
  310. Assert.Equal (new Rect (0, 0, lines [lineWider].ToRuneList ().Sum (r => Math.Max (r.GetColumns (), 0)), expectedLines), TextFormatter.CalcRect (0, 0, text));
  311. }
  312. [Theory]
  313. [InlineData ("")]
  314. [InlineData (null)]
  315. [InlineData ("test")]
  316. public void ClipAndJustify_Invalid_Returns_Original (string text)
  317. {
  318. var expected = string.IsNullOrEmpty (text) ? text : "";
  319. Assert.Equal (expected, TextFormatter.ClipAndJustify (text, 0, TextAlignment.Left));
  320. Assert.Equal (expected, TextFormatter.ClipAndJustify (text, 0, TextAlignment.Left));
  321. Assert.Throws<ArgumentOutOfRangeException> (() => TextFormatter.ClipAndJustify (text, -1, TextAlignment.Left));
  322. }
  323. [Theory]
  324. [InlineData ("test", "", 0)]
  325. [InlineData ("test", "te", 2)]
  326. [InlineData ("test", "test", int.MaxValue)]
  327. [InlineData ("A sentence has words.", "A sentence has words.", 22)] // should fit
  328. [InlineData ("A sentence has words.", "A sentence has words.", 21)] // should fit
  329. [InlineData ("A sentence has words.", "A sentence has words.", int.MaxValue)] // should fit
  330. [InlineData ("A sentence has words.", "A sentence has words", 20)] // Should not fit
  331. [InlineData ("A sentence has words.", "A sentence", 10)] // Should not fit
  332. [InlineData ("A\tsentence\thas\twords.", "A\tsentence\thas\twords.", int.MaxValue)]
  333. [InlineData ("A\tsentence\thas\twords.", "A\tsentence", 10)]
  334. [InlineData ("line1\nline2\nline3long!", "line1\nline2\nline3long!", int.MaxValue)]
  335. [InlineData ("line1\nline2\nline3long!", "line1\nline", 10)]
  336. [InlineData (" ~  s  gui.cs   master ↑10", " ~  s  ", 10)] // Unicode
  337. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 5)] // should fit
  338. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 4)] // should fit
  339. [InlineData ("Ð ÑÐ", "Ð Ñ", 3)] // Should not fit
  340. public void ClipAndJustify_Valid_Left (string text, string justifiedText, int maxWidth)
  341. {
  342. var align = TextAlignment.Left;
  343. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  344. var expectedClippedWidth = Math.Min (justifiedText.GetRuneCount (), maxWidth);
  345. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  346. Assert.True (justifiedText.GetRuneCount () <= maxWidth);
  347. Assert.True (justifiedText.GetColumns () <= maxWidth);
  348. Assert.Equal (expectedClippedWidth, justifiedText.GetRuneCount ());
  349. Assert.Equal (expectedClippedWidth, justifiedText.ToRuneList ().Sum (r => Math.Max (r.GetColumns (), 1)));
  350. Assert.True (expectedClippedWidth <= maxWidth);
  351. Assert.Equal (StringExtensions.ToString (justifiedText.ToRunes () [0..expectedClippedWidth]), justifiedText);
  352. }
  353. [Theory]
  354. [InlineData ("test", "", 0)]
  355. [InlineData ("test", "te", 2)]
  356. [InlineData ("test", "test", int.MaxValue)]
  357. [InlineData ("A sentence has words.", "A sentence has words.", 22)] // should fit
  358. [InlineData ("A sentence has words.", "A sentence has words.", 21)] // should fit
  359. [InlineData ("A sentence has words.", "A sentence has words.", int.MaxValue)] // should fit
  360. [InlineData ("A sentence has words.", "A sentence has words", 20)] // Should not fit
  361. [InlineData ("A sentence has words.", "A sentence", 10)] // Should not fit
  362. [InlineData ("A\tsentence\thas\twords.", "A\tsentence\thas\twords.", int.MaxValue)]
  363. [InlineData ("A\tsentence\thas\twords.", "A\tsentence", 10)]
  364. [InlineData ("line1\nline2\nline3long!", "line1\nline2\nline3long!", int.MaxValue)]
  365. [InlineData ("line1\nline2\nline3long!", "line1\nline", 10)]
  366. [InlineData (" ~  s  gui.cs   master ↑10", " ~  s  ", 10)] // Unicode
  367. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 5)] // should fit
  368. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 4)] // should fit
  369. [InlineData ("Ð ÑÐ", "Ð Ñ", 3)] // Should not fit
  370. public void ClipAndJustify_Valid_Right (string text, string justifiedText, int maxWidth)
  371. {
  372. var align = TextAlignment.Right;
  373. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  374. var expectedClippedWidth = Math.Min (justifiedText.GetRuneCount (), maxWidth);
  375. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  376. Assert.True (justifiedText.GetRuneCount () <= maxWidth);
  377. Assert.True (justifiedText.GetColumns () <= maxWidth);
  378. Assert.Equal (expectedClippedWidth, justifiedText.GetRuneCount ());
  379. Assert.Equal (expectedClippedWidth, justifiedText.ToRuneList ().Sum (r => Math.Max (r.GetColumns (), 1)));
  380. Assert.True (expectedClippedWidth <= maxWidth);
  381. Assert.Equal (StringExtensions.ToString (justifiedText.ToRunes () [0..expectedClippedWidth]), justifiedText);
  382. }
  383. [Theory]
  384. [InlineData ("test", "", 0)]
  385. [InlineData ("test", "te", 2)]
  386. [InlineData ("test", "test", int.MaxValue)]
  387. [InlineData ("A sentence has words.", "A sentence has words.", 22)] // should fit
  388. [InlineData ("A sentence has words.", "A sentence has words.", 21)] // should fit
  389. [InlineData ("A sentence has words.", "A sentence has words.", int.MaxValue)] // should fit
  390. [InlineData ("A sentence has words.", "A sentence has words", 20)] // Should not fit
  391. [InlineData ("A sentence has words.", "A sentence", 10)] // Should not fit
  392. [InlineData ("A\tsentence\thas\twords.", "A\tsentence\thas\twords.", int.MaxValue)]
  393. [InlineData ("A\tsentence\thas\twords.", "A\tsentence", 10)]
  394. [InlineData ("line1\nline2\nline3long!", "line1\nline2\nline3long!", int.MaxValue)]
  395. [InlineData ("line1\nline2\nline3long!", "line1\nline", 10)]
  396. [InlineData (" ~  s  gui.cs   master ↑10", " ~  s  ", 10)] // Unicode
  397. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 5)] // should fit
  398. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 4)] // should fit
  399. [InlineData ("Ð ÑÐ", "Ð Ñ", 3)] // Should not fit
  400. public void ClipAndJustify_Valid_Centered (string text, string justifiedText, int maxWidth)
  401. {
  402. var align = TextAlignment.Centered;
  403. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  404. var expectedClippedWidth = Math.Min (justifiedText.GetRuneCount (), maxWidth);
  405. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  406. Assert.True (justifiedText.GetRuneCount () <= maxWidth);
  407. Assert.True (justifiedText.GetColumns () <= maxWidth);
  408. Assert.Equal (expectedClippedWidth, justifiedText.GetRuneCount ());
  409. Assert.Equal (expectedClippedWidth, justifiedText.ToRuneList ().Sum (r => Math.Max (r.GetColumns (), 1)));
  410. Assert.True (expectedClippedWidth <= maxWidth);
  411. Assert.Equal (StringExtensions.ToString (justifiedText.ToRunes () [0..expectedClippedWidth]), justifiedText);
  412. }
  413. [Theory]
  414. [InlineData ("test", "", 0)]
  415. [InlineData ("test", "te", 2)]
  416. [InlineData ("test", "test", int.MaxValue)]
  417. [InlineData ("A sentence has words.", "A sentence has words.", 22)] // should fit
  418. [InlineData ("A sentence has words.", "A sentence has words.", 21)] // should fit
  419. [InlineData ("A sentence has words.", "A sentence has words.", 500)] // should fit
  420. [InlineData ("A sentence has words.", "A sentence has words", 20)] // Should not fit
  421. [InlineData ("A sentence has words.", "A sentence", 10)] // Should not fit
  422. [InlineData ("A\tsentence\thas\twords.", "A\tsentence\thas\twords.", int.MaxValue)]
  423. [InlineData ("A\tsentence\thas\twords.", "A\tsentence", 10)]
  424. [InlineData ("line1\nline2\nline3long!", "line1\nline2\nline3long!", int.MaxValue)]
  425. [InlineData ("line1\nline2\nline3long!", "line1\nline", 10)]
  426. [InlineData (" ~  s  gui.cs   master ↑10", " ~  s  ", 10)] // Unicode
  427. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 5)] // should fit
  428. [InlineData ("Ð ÑÐ", "Ð ÑÐ", 4)] // should fit
  429. [InlineData ("Ð ÑÐ", "Ð Ñ", 3)] // Should not fit
  430. public void ClipAndJustify_Valid_Justified (string text, string justifiedText, int maxWidth)
  431. {
  432. var align = TextAlignment.Justified;
  433. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  434. var expectedClippedWidth = Math.Min (justifiedText.GetRuneCount (), maxWidth);
  435. Assert.Equal (justifiedText, TextFormatter.ClipAndJustify (text, maxWidth, align));
  436. Assert.True (justifiedText.GetRuneCount () <= maxWidth);
  437. Assert.True (justifiedText.GetColumns () <= maxWidth);
  438. Assert.Equal (expectedClippedWidth, justifiedText.GetRuneCount ());
  439. Assert.Equal (expectedClippedWidth, justifiedText.ToRuneList ().Sum (r => Math.Max (r.GetColumns (), 1)));
  440. Assert.True (expectedClippedWidth <= maxWidth);
  441. Assert.Equal (StringExtensions.ToString (justifiedText.ToRunes () [0..expectedClippedWidth]), justifiedText);
  442. // see Justify_ tests below
  443. }
  444. [Theory]
  445. [InlineData ("")]
  446. [InlineData (null)]
  447. [InlineData ("test")]
  448. public void Justify_Invalid (string text)
  449. {
  450. Assert.Equal (text, TextFormatter.Justify (text, 0));
  451. Assert.Equal (text, TextFormatter.Justify (text, 0));
  452. Assert.Throws<ArgumentOutOfRangeException> (() => TextFormatter.Justify (text, -1));
  453. }
  454. [Theory]
  455. [InlineData ("word")] // Even # of chars
  456. [InlineData ("word.")] // Odd # of chars
  457. [InlineData ("пÑивеÑ")] // Unicode (even #)
  458. [InlineData ("пÑивеÑ.")] // Unicode (odd # of chars)
  459. public void Justify_SingleWord (string text)
  460. {
  461. var justifiedText = text;
  462. char fillChar = '+';
  463. int width = text.GetRuneCount ();
  464. Assert.Equal (justifiedText, TextFormatter.Justify (text, width, fillChar));
  465. width = text.GetRuneCount () + 1;
  466. Assert.Equal (justifiedText, TextFormatter.Justify (text, width, fillChar));
  467. width = text.GetRuneCount () + 2;
  468. Assert.Equal (justifiedText, TextFormatter.Justify (text, width, fillChar));
  469. width = text.GetRuneCount () + 10;
  470. Assert.Equal (justifiedText, TextFormatter.Justify (text, width, fillChar));
  471. width = text.GetRuneCount () + 11;
  472. Assert.Equal (justifiedText, TextFormatter.Justify (text, width, fillChar));
  473. }
  474. [Theory]
  475. // Even # of spaces
  476. // 0123456789
  477. [InlineData ("012 456 89", "012 456 89", 10, 0, "+", true)]
  478. [InlineData ("012 456 89", "012++456+89", 11, 1)]
  479. [InlineData ("012 456 89", "012 456 89", 12, 2, "++", true)]
  480. [InlineData ("012 456 89", "012+++456++89", 13, 3)]
  481. [InlineData ("012 456 89", "012 456 89", 14, 4, "+++", true)]
  482. [InlineData ("012 456 89", "012++++456+++89", 15, 5)]
  483. [InlineData ("012 456 89", "012 456 89", 16, 6, "++++", true)]
  484. [InlineData ("012 456 89", "012 456 89", 30, 20, "+++++++++++", true)]
  485. [InlineData ("012 456 89", "012+++++++++++++456++++++++++++89", 33, 23)]
  486. // Odd # of spaces
  487. // 01234567890123
  488. [InlineData ("012 456 89 end", "012 456 89 end", 14, 0, "+", true)]
  489. [InlineData ("012 456 89 end", "012++456+89+end", 15, 1)]
  490. [InlineData ("012 456 89 end", "012++456++89+end", 16, 2)]
  491. [InlineData ("012 456 89 end", "012 456 89 end", 17, 3, "++", true)]
  492. [InlineData ("012 456 89 end", "012+++456++89++end", 18, 4)]
  493. [InlineData ("012 456 89 end", "012+++456+++89++end", 19, 5)]
  494. [InlineData ("012 456 89 end", "012 456 89 end", 20, 6, "+++", true)]
  495. [InlineData ("012 456 89 end", "012++++++++456++++++++89+++++++end", 34, 20)]
  496. [InlineData ("012 456 89 end", "012+++++++++456+++++++++89++++++++end", 37, 23)]
  497. // Unicode
  498. // Even # of chars
  499. // 0123456789
  500. [InlineData ("пÑРвРÑ", "пÑРвРÑ", 10, 0, "+", true)]
  501. [InlineData ("пÑРвРÑ", "пÑÐ++вÐ+Ñ", 11, 1)]
  502. [InlineData ("пÑРвРÑ", "пÑРвРÑ", 12, 2, "++", true)]
  503. [InlineData ("пÑРвРÑ", "пÑÐ+++вÐ++Ñ", 13, 3)]
  504. [InlineData ("пÑРвРÑ", "пÑРвРÑ", 14, 4, "+++", true)]
  505. [InlineData ("пÑРвРÑ", "пÑÐ++++вÐ+++Ñ", 15, 5)]
  506. [InlineData ("пÑРвРÑ", "пÑРвРÑ", 16, 6, "++++", true)]
  507. [InlineData ("пÑРвРÑ", "пÑРвРÑ", 30, 20, "+++++++++++", true)]
  508. [InlineData ("пÑРвРÑ", "пÑÐ+++++++++++++вÐ++++++++++++Ñ", 33, 23)]
  509. // Unicode
  510. // Odd # of chars
  511. // 0123456789
  512. [InlineData ("Ð ÑРвРÑ", "Ð ÑРвРÑ", 10, 0, "+", true)]
  513. [InlineData ("Ð ÑРвРÑ", "Ð++ÑÐ+вÐ+Ñ", 11, 1)]
  514. [InlineData ("Ð ÑРвРÑ", "Ð++ÑÐ++вÐ+Ñ", 12, 2)]
  515. [InlineData ("Ð ÑРвРÑ", "Ð ÑРвРÑ", 13, 3, "++", true)]
  516. [InlineData ("Ð ÑРвРÑ", "Ð+++ÑÐ++вÐ++Ñ", 14, 4)]
  517. [InlineData ("Ð ÑРвРÑ", "Ð+++ÑÐ+++вÐ++Ñ", 15, 5)]
  518. [InlineData ("Ð ÑРвРÑ", "Ð ÑРвРÑ", 16, 6, "+++", true)]
  519. [InlineData ("Ð ÑРвРÑ", "Ð++++++++ÑÐ++++++++вÐ+++++++Ñ", 30, 20)]
  520. [InlineData ("Ð ÑРвРÑ", "Ð+++++++++ÑÐ+++++++++вÐ++++++++Ñ", 33, 23)]
  521. public void Justify_Sentence (string text, string justifiedText, int forceToWidth, int widthOffset, string replaceWith = null, bool replace = false)
  522. {
  523. char fillChar = '+';
  524. Assert.Equal (forceToWidth, text.GetRuneCount () + widthOffset);
  525. if (replace) {
  526. justifiedText = text.Replace (" ", replaceWith);
  527. }
  528. Assert.Equal (justifiedText, TextFormatter.Justify (text, forceToWidth, fillChar));
  529. Assert.True (Math.Abs (forceToWidth - justifiedText.GetRuneCount ()) < text.Count (s => s == ' '));
  530. Assert.True (Math.Abs (forceToWidth - justifiedText.GetColumns ()) < text.Count (s => s == ' '));
  531. }
  532. [Fact]
  533. public void WordWrap_Invalid ()
  534. {
  535. var text = string.Empty;
  536. int width = 0;
  537. Assert.Empty (TextFormatter.WordWrapText (null, width));
  538. Assert.Empty (TextFormatter.WordWrapText (text, width));
  539. Assert.Throws<ArgumentOutOfRangeException> (() => TextFormatter.WordWrapText (text, -1));
  540. }
  541. [Fact]
  542. public void WordWrap_BigWidth ()
  543. {
  544. List<string> wrappedLines;
  545. var text = "Constantinople";
  546. wrappedLines = TextFormatter.WordWrapText (text, 100);
  547. Assert.True (wrappedLines.Count == 1);
  548. Assert.Equal ("Constantinople", wrappedLines [0]);
  549. }
  550. [Theory]
  551. [InlineData ("Constantinople", 14, 0, new string [] { "Constantinople" })]
  552. [InlineData ("Constantinople", 12, -2, new string [] { "Constantinop", "le" })]
  553. [InlineData ("Constantinople", 9, -5, new string [] { "Constanti", "nople" })]
  554. [InlineData ("Constantinople", 7, -7, new string [] { "Constan", "tinople" })]
  555. [InlineData ("Constantinople", 5, -9, new string [] { "Const", "antin", "ople" })]
  556. [InlineData ("Constantinople", 4, -10, new string [] { "Cons", "tant", "inop", "le" })]
  557. [InlineData ("Constantinople", 1, -13, new string [] { "C", "o", "n", "s", "t", "a", "n", "t", "i", "n", "o", "p", "l", "e" })]
  558. public void WordWrap_SingleWordLine (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  559. {
  560. List<string> wrappedLines;
  561. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  562. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  563. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  564. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  565. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  566. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  567. Assert.Equal (resultLines, wrappedLines);
  568. }
  569. [Theory]
  570. [InlineData ("กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ", 51, 0, new string [] { "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ" })]
  571. [InlineData ("กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ", 50, -1, new string [] { "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัา", "ำ" })]
  572. [InlineData ("กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ", 46, -5, new string [] { "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮ", "ฯะัาำ" })]
  573. [InlineData ("กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ", 26, -25, new string [] { "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบ", "ปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ" })]
  574. [InlineData ("กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ", 17, -34, new string [] { "กขฃคฅฆงจฉชซฌญฎฏฐฑ", "ฒณดตถทธนบปผฝพฟภมย", "รฤลฦวศษสหฬอฮฯะัาำ" })]
  575. [InlineData ("กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ", 13, -38, new string [] { "กขฃคฅฆงจฉชซฌญ", "ฎฏฐฑฒณดตถทธนบ", "ปผฝพฟภมยรฤลฦว", "ศษสหฬอฮฯะัาำ" })]
  576. [InlineData ("กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำ", 1, -50, new string [] { "ก", "ข", "ฃ", "ค", "ฅ", "ฆ", "ง", "จ", "ฉ", "ช", "ซ", "ฌ", "ญ", "ฎ", "ฏ", "ฐ", "ฑ", "ฒ", "ณ", "ด", "ต", "ถ", "ท", "ธ", "น", "บ", "ป", "ผ", "ฝ", "พ", "ฟ", "ภ", "ม", "ย", "ร", "ฤ", "ล", "ฦ", "ว", "ศ", "ษ", "ส", "ห", "ฬ", "อ", "ฮ", "ฯ", "ะ", "ั", "า", "ำ" })]
  577. public void WordWrap_Unicode_SingleWordLine (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  578. {
  579. List<string> wrappedLines;
  580. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  581. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  582. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  583. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  584. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  585. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  586. Assert.Equal (resultLines, wrappedLines);
  587. }
  588. [Theory]
  589. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 19, 0, new string [] { "This\u00A0is\u00A0a\u00A0sentence." })]
  590. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 18, -1, new string [] { "This\u00A0is\u00A0a\u00A0sentence", "." })]
  591. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 17, -2, new string [] { "This\u00A0is\u00A0a\u00A0sentenc", "e." })]
  592. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 14, -5, new string [] { "This\u00A0is\u00A0a\u00A0sent", "ence." })]
  593. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 10, -9, new string [] { "This\u00A0is\u00A0a\u00A0", "sentence." })]
  594. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 7, -12, new string [] { "This\u00A0is", "\u00A0a\u00A0sent", "ence." })]
  595. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 5, -14, new string [] { "This\u00A0", "is\u00A0a\u00A0", "sente", "nce." })]
  596. [InlineData ("This\u00A0is\u00A0a\u00A0sentence.", 1, -18, new string [] { "T", "h", "i", "s", "\u00A0", "i", "s", "\u00A0", "a", "\u00A0", "s", "e", "n", "t", "e", "n", "c", "e", "." })]
  597. public void WordWrap_Unicode_LineWithNonBreakingSpace (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  598. {
  599. List<string> wrappedLines;
  600. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  601. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  602. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  603. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  604. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  605. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  606. Assert.Equal (resultLines, wrappedLines);
  607. }
  608. [Theory]
  609. [InlineData ("This\u00A0is\n\u00A0a\u00A0sentence.", 20, 0, new string [] { "This\u00A0is\u00A0a\u00A0sentence." })]
  610. [InlineData ("This\u00A0is\n\u00A0a\u00A0sentence.", 19, -1, new string [] { "This\u00A0is\u00A0a\u00A0sentence." })]
  611. [InlineData ("\u00A0\u00A0\u00A0\u00A0\u00A0test\u00A0sentence.", 19, 0, new string [] { "\u00A0\u00A0\u00A0\u00A0\u00A0test\u00A0sentence." })]
  612. public void WordWrap_Unicode_2LinesWithNonBreakingSpace (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  613. {
  614. List<string> wrappedLines;
  615. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  616. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  617. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  618. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  619. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  620. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  621. Assert.Equal (resultLines, wrappedLines);
  622. }
  623. [Theory]
  624. [InlineData ("A sentence has words.", 21, 0, new string [] { "A sentence has words." })]
  625. [InlineData ("A sentence has words.", 20, -1, new string [] { "A sentence has", "words." })]
  626. [InlineData ("A sentence has words.", 15, -6, new string [] { "A sentence has", "words." })]
  627. [InlineData ("A sentence has words.", 14, -7, new string [] { "A sentence has", "words." })]
  628. [InlineData ("A sentence has words.", 13, -8, new string [] { "A sentence", "has words." })]
  629. // Unicode
  630. [InlineData ("A Unicode sentence (пÑивеÑ) has words.", 42, 0, new string [] { "A Unicode sentence (пÑивеÑ) has words." })]
  631. [InlineData ("A Unicode sentence (пÑивеÑ) has words.", 41, -1, new string [] { "A Unicode sentence (пÑивеÑ) has", "words." })]
  632. [InlineData ("A Unicode sentence (пÑивеÑ) has words.", 36, -6, new string [] { "A Unicode sentence (пÑивеÑ) has", "words." })]
  633. [InlineData ("A Unicode sentence (пÑивеÑ) has words.", 35, -7, new string [] { "A Unicode sentence (пÑивеÑ) has", "words." })]
  634. [InlineData ("A Unicode sentence (пÑивеÑ) has words.", 34, -8, new string [] { "A Unicode sentence (пÑивеÑ)", "has words." })]
  635. [InlineData ("A Unicode sentence (пÑивеÑ) has words.", 25, -17, new string [] { "A Unicode sentence", "(пÑивеÑ) has words." })]
  636. public void WordWrap_NoNewLines_Default (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  637. {
  638. // Calls WordWrapText (text, width) and thus preserveTrailingSpaces defaults to false
  639. List<string> wrappedLines;
  640. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  641. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  642. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  643. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  644. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  645. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  646. Assert.Equal (resultLines, wrappedLines);
  647. }
  648. /// <summary>
  649. /// WordWrap strips CRLF
  650. /// </summary>
  651. [Theory]
  652. [InlineData ("A sentence has words.\nA paragraph has lines.", 44, 0, new string [] { "A sentence has words.A paragraph has lines." })]
  653. [InlineData ("A sentence has words.\nA paragraph has lines.", 43, -1, new string [] { "A sentence has words.A paragraph has lines." })]
  654. [InlineData ("A sentence has words.\nA paragraph has lines.", 38, -6, new string [] { "A sentence has words.A paragraph has", "lines." })]
  655. [InlineData ("A sentence has words.\nA paragraph has lines.", 34, -10, new string [] { "A sentence has words.A paragraph", "has lines." })]
  656. [InlineData ("A sentence has words.\nA paragraph has lines.", 27, -17, new string [] { "A sentence has words.A", "paragraph has lines." })]
  657. // Unicode
  658. [InlineData ("A Unicode sentence (пÑивеÑ) has words.\nA Unicode Пункт has Линии.", 69, 0, new string [] { "A Unicode sentence (пÑивеÑ) has words.A Unicode Пункт has Линии." })]
  659. [InlineData ("A Unicode sentence (пÑивеÑ) has words.\nA Unicode Пункт has Линии.", 68, -1, new string [] { "A Unicode sentence (пÑивеÑ) has words.A Unicode Пункт has Линии." })]
  660. [InlineData ("A Unicode sentence (пÑивеÑ) has words.\nA Unicode Пункт has Линии.", 63, -6, new string [] { "A Unicode sentence (пÑивеÑ) has words.A Unicode Пункт has", "Линии." })]
  661. [InlineData ("A Unicode sentence (пÑивеÑ) has words.\nA Unicode Пункт has Линии.", 59, -10, new string [] { "A Unicode sentence (пÑивеÑ) has words.A Unicode Пункт", "has Линии." })]
  662. [InlineData ("A Unicode sentence (пÑивеÑ) has words.\nA Unicode Пункт has Линии.", 52, -17, new string [] { "A Unicode sentence (пÑивеÑ) has words.A Unicode", "Пункт has Линии." })]
  663. public void WordWrap_WithNewLines (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  664. {
  665. List<string> wrappedLines;
  666. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  667. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  668. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  669. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  670. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  671. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  672. Assert.Equal (resultLines, wrappedLines);
  673. }
  674. [Theory]
  675. [InlineData ("A sentence has words.", 3, -18, new string [] { "A", "sen", "ten", "ce", "has", "wor", "ds." })]
  676. [InlineData ("A sentence has words.", 2, -19, new string [] { "A", "se", "nt", "en", "ce", "ha", "s", "wo", "rd", "s." })]
  677. [InlineData ("A sentence has words.", 1, -20, new string [] { "A", "s", "e", "n", "t", "e", "n", "c", "e", "h", "a", "s", "w", "o", "r", "d", "s", "." })]
  678. public void WordWrap_Narrow_Default (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  679. {
  680. // Calls WordWrapText (text, width) and thus preserveTrailingSpaces defaults to false
  681. List<string> wrappedLines;
  682. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  683. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  684. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  685. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  686. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  687. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  688. Assert.Equal (resultLines, wrappedLines);
  689. }
  690. [Theory]
  691. [InlineData ("A sentence has words.", 14, -7, new string [] { "A sentence ", "has words." })]
  692. [InlineData ("A sentence has words.", 8, -13, new string [] { "A ", "sentence", " has ", "words." })]
  693. [InlineData ("A sentence has words.", 6, -15, new string [] { "A ", "senten", "ce ", "has ", "words." })]
  694. [InlineData ("A sentence has words.", 3, -18, new string [] { "A ", "sen", "ten", "ce ", "has", " ", "wor", "ds." })]
  695. [InlineData ("A sentence has words.", 2, -19, new string [] { "A ", "se", "nt", "en", "ce", " ", "ha", "s ", "wo", "rd", "s." })]
  696. [InlineData ("A sentence has words.", 1, -20, new string [] { "A", " ", "s", "e", "n", "t", "e", "n", "c", "e", " ", "h", "a", "s", " ", "w", "o", "r", "d", "s", "." })]
  697. public void WordWrap_PreserveTrailingSpaces_True (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  698. {
  699. List<string> wrappedLines;
  700. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  701. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  702. wrappedLines = TextFormatter.WordWrapText (text, maxWidth, preserveTrailingSpaces: true);
  703. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  704. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  705. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  706. Assert.Equal (resultLines, wrappedLines);
  707. }
  708. [Theory]
  709. [InlineData ("文に は言葉 があり ます。", 14, 0, new string [] { "文に は言葉 ", "があり ます。" })]
  710. [InlineData ("文に は言葉 があり ます。", 3, -11, new string [] { "文", "に ", "は", "言", "葉 ", "が", "あ", "り ", "ま", "す", "。" })]
  711. [InlineData ("文に は言葉 があり ます。", 2, -12, new string [] { "文", "に", " ", "は", "言", "葉", " ", "が", "あ", "り", " ", "ま", "す", "。" })]
  712. [InlineData ("文に は言葉 があり ます。", 1, -13, new string [] { })]
  713. public void WordWrap_PreserveTrailingSpaces_True_Wide_Runes (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  714. {
  715. List<string> wrappedLines;
  716. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  717. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  718. wrappedLines = TextFormatter.WordWrapText (text, maxWidth, preserveTrailingSpaces: true);
  719. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  720. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  721. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  722. Assert.Equal (resultLines, wrappedLines);
  723. }
  724. [Theory]
  725. [InlineData ("文に は言葉 があり ます。", 14, 0, new string [] { "文に は言葉", "があり ます。" })]
  726. [InlineData ("文に は言葉 があり ます。", 3, -11, new string [] { "文", "に", "は", "言", "葉", "が", "あ", "り", "ま", "す", "。" })]
  727. [InlineData ("文に は言葉 があり ます。", 2, -12, new string [] { "文", "に", "は", "言", "葉", "が", "あ", "り", "ま", "す", "。" })]
  728. [InlineData ("文に は言葉 があり ます。", 1, -13, new string [] { })]
  729. public void WordWrap_PreserveTrailingSpaces_False_Wide_Runes (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  730. {
  731. List<string> wrappedLines;
  732. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  733. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  734. wrappedLines = TextFormatter.WordWrapText (text, maxWidth);
  735. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  736. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  737. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  738. Assert.Equal (resultLines, wrappedLines);
  739. }
  740. [Theory]
  741. [InlineData ("A sentence has words. ", 3, new string [] { "A ", "sen", "ten", "ce ", "has", " ", "wor", "ds.", " " })]
  742. [InlineData ("A sentence has words. ", 3, new string [] { "A ", " ", "sen", "ten", "ce ", " ", " ", " ", "has", " ", "wor", "ds.", " " })]
  743. public void WordWrap_PreserveTrailingSpaces_True_With_Simple_Runes_Width_3 (string text, int width, IEnumerable<string> resultLines)
  744. {
  745. var wrappedLines = TextFormatter.WordWrapText (text, width, preserveTrailingSpaces: true);
  746. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  747. Assert.Equal (resultLines, wrappedLines);
  748. var breakLines = "";
  749. foreach (var line in wrappedLines) {
  750. breakLines += $"{line}{Environment.NewLine}";
  751. }
  752. var expected = string.Empty;
  753. foreach (var line in resultLines) {
  754. expected += $"{line}{Environment.NewLine}";
  755. }
  756. Assert.Equal (expected, breakLines);
  757. // Double space Complex example - this is how VS 2022 does it
  758. //text = "A sentence has words. ";
  759. //breakLines = "";
  760. //wrappedLines = TextFormatter.WordWrapText (text, width, preserveTrailingSpaces: true);
  761. //foreach (var line in wrappedLines) {
  762. // breakLines += $"{line}{Environment.NewLine}";
  763. //}
  764. //expected = "A " + Environment.NewLine +
  765. // " se" + Environment.NewLine +
  766. // " nt" + Environment.NewLine +
  767. // " en" + Environment.NewLine +
  768. // " ce" + Environment.NewLine +
  769. // " " + Environment.NewLine +
  770. // " " + Environment.NewLine +
  771. // " " + Environment.NewLine +
  772. // " ha" + Environment.NewLine +
  773. // " s " + Environment.NewLine +
  774. // " wo" + Environment.NewLine +
  775. // " rd" + Environment.NewLine +
  776. // " s." + Environment.NewLine;
  777. //Assert.Equal (expected, breakLines);
  778. }
  779. [Theory]
  780. [InlineData (null, 1, new string [] { })] // null input
  781. [InlineData ("", 1, new string [] { })] // Empty input
  782. [InlineData ("1 34", 1, new string [] { "1", "3", "4" })] // Single Spaces
  783. [InlineData ("1", 1, new string [] { "1" })] // Short input
  784. [InlineData ("12", 1, new string [] { "1", "2" })]
  785. [InlineData ("123", 1, new string [] { "1", "2", "3" })]
  786. [InlineData ("123456", 1, new string [] { "1", "2", "3", "4", "5", "6" })] // No spaces
  787. [InlineData (" ", 1, new string [] { " " })] // Just Spaces; should result in a single space
  788. [InlineData (" ", 1, new string [] { " " })]
  789. [InlineData (" ", 1, new string [] { " ", " " })]
  790. [InlineData (" ", 1, new string [] { " ", " " })]
  791. [InlineData ("12 456", 1, new string [] { "1", "2", "4", "5", "6" })] // Single Spaces
  792. [InlineData (" 2 456", 1, new string [] { " ", "2", "4", "5", "6" })] // Leading spaces should be preserved.
  793. [InlineData (" 2 456 8", 1, new string [] { " ", "2", "4", "5", "6", "8" })]
  794. [InlineData ("A sentence has words. ", 1, new string [] { "A", "s", "e", "n", "t", "e", "n", "c", "e", "h", "a", "s", "w", "o", "r", "d", "s", "." })] // Complex example
  795. [InlineData ("12 567", 1, new string [] { "1", "2", " ", "5", "6", "7" })] // Double Spaces
  796. [InlineData (" 3 567", 1, new string [] { " ", "3", "5", "6", "7" })] // Double Leading spaces should be preserved.
  797. [InlineData (" 3 678 1", 1, new string [] { " ", "3", " ", "6", "7", "8", " ", "1" })]
  798. [InlineData ("1 456", 1, new string [] { "1", " ", "4", "5", "6" })]
  799. [InlineData ("A sentence has words. ", 1, new string [] { "A", " ", "s", "e", "n", "t", "e", "n", "c", "e", " ", "h", "a", "s", "w", "o", "r", "d", "s", ".", " " })] // Double space Complex example
  800. public void WordWrap_PreserveTrailingSpaces_False_With_Simple_Runes_Width_1 (string text, int width, IEnumerable<string> resultLines)
  801. {
  802. var wrappedLines = TextFormatter.WordWrapText (text, width, preserveTrailingSpaces: false);
  803. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  804. Assert.Equal (resultLines, wrappedLines);
  805. var breakLines = "";
  806. foreach (var line in wrappedLines) {
  807. breakLines += $"{line}{Environment.NewLine}";
  808. }
  809. var expected = string.Empty;
  810. foreach (var line in resultLines) {
  811. expected += $"{line}{Environment.NewLine}";
  812. }
  813. Assert.Equal (expected, breakLines);
  814. }
  815. [Theory]
  816. [InlineData (null, 3, new string [] { })] // null input
  817. [InlineData ("", 3, new string [] { })] // Empty input
  818. [InlineData ("1", 3, new string [] { "1" })] // Short input
  819. [InlineData ("12", 3, new string [] { "12" })]
  820. [InlineData ("123", 3, new string [] { "123" })]
  821. [InlineData ("123456", 3, new string [] { "123", "456" })] // No spaces
  822. [InlineData ("1234567", 3, new string [] { "123", "456", "7" })] // No spaces
  823. [InlineData (" ", 3, new string [] { " " })] // Just Spaces; should result in a single space
  824. [InlineData (" ", 3, new string [] { " " })]
  825. [InlineData (" ", 3, new string [] { " " })]
  826. [InlineData (" ", 3, new string [] { " " })]
  827. [InlineData ("12 456", 3, new string [] { "12", "456" })] // Single Spaces
  828. [InlineData (" 2 456", 3, new string [] { " 2", "456" })] // Leading spaces should be preserved.
  829. [InlineData (" 2 456 8", 3, new string [] { " 2", "456", "8" })]
  830. [InlineData ("A sentence has words. ", 3, new string [] { "A", "sen", "ten", "ce", "has", "wor", "ds." })] // Complex example
  831. [InlineData ("12 567", 3, new string [] { "12 ", "567" })] // Double Spaces
  832. [InlineData (" 3 567", 3, new string [] { " 3", "567" })] // Double Leading spaces should be preserved.
  833. [InlineData (" 3 678 1", 3, new string [] { " 3", " 67", "8 ", "1" })]
  834. [InlineData ("1 456", 3, new string [] { "1 ", "456" })]
  835. [InlineData ("A sentence has words. ", 3, new string [] { "A ", "sen", "ten", "ce ", " ", "has", "wor", "ds.", " " })] // Double space Complex example
  836. public void WordWrap_PreserveTrailingSpaces_False_With_Simple_Runes_Width_3 (string text, int width, IEnumerable<string> resultLines)
  837. {
  838. var wrappedLines = TextFormatter.WordWrapText (text, width, preserveTrailingSpaces: false);
  839. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  840. Assert.Equal (resultLines, wrappedLines);
  841. var breakLines = "";
  842. foreach (var line in wrappedLines) {
  843. breakLines += $"{line}{Environment.NewLine}";
  844. }
  845. var expected = string.Empty;
  846. foreach (var line in resultLines) {
  847. expected += $"{line}{Environment.NewLine}";
  848. }
  849. Assert.Equal (expected, breakLines);
  850. }
  851. [Theory]
  852. [InlineData (null, 50, new string [] { })] // null input
  853. [InlineData ("", 50, new string [] { })] // Empty input
  854. [InlineData ("1", 50, new string [] { "1" })] // Short input
  855. [InlineData ("12", 50, new string [] { "12" })]
  856. [InlineData ("123", 50, new string [] { "123" })]
  857. [InlineData ("123456", 50, new string [] { "123456" })] // No spaces
  858. [InlineData ("1234567", 50, new string [] { "1234567" })] // No spaces
  859. [InlineData (" ", 50, new string [] { " " })] // Just Spaces; should result in a single space
  860. [InlineData (" ", 50, new string [] { " " })]
  861. [InlineData (" ", 50, new string [] { " " })]
  862. [InlineData ("12 456", 50, new string [] { "12 456" })] // Single Spaces
  863. [InlineData (" 2 456", 50, new string [] { " 2 456" })] // Leading spaces should be preserved.
  864. [InlineData (" 2 456 8", 50, new string [] { " 2 456 8" })]
  865. [InlineData ("A sentence has words. ", 50, new string [] { "A sentence has words. " })] // Complex example
  866. [InlineData ("12 567", 50, new string [] { "12 567" })] // Double Spaces
  867. [InlineData (" 3 567", 50, new string [] { " 3 567" })] // Double Leading spaces should be preserved.
  868. [InlineData (" 3 678 1", 50, new string [] { " 3 678 1" })]
  869. [InlineData ("1 456", 50, new string [] { "1 456" })]
  870. [InlineData ("A sentence has words. ", 50, new string [] { "A sentence has words. " })] // Double space Complex example
  871. public void WordWrap_PreserveTrailingSpaces_False_With_Simple_Runes_Width_50 (string text, int width, IEnumerable<string> resultLines)
  872. {
  873. var wrappedLines = TextFormatter.WordWrapText (text, width, preserveTrailingSpaces: false);
  874. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  875. Assert.Equal (resultLines, wrappedLines);
  876. var breakLines = "";
  877. foreach (var line in wrappedLines) {
  878. breakLines += $"{line}{Environment.NewLine}";
  879. }
  880. var expected = string.Empty;
  881. foreach (var line in resultLines) {
  882. expected += $"{line}{Environment.NewLine}";
  883. }
  884. Assert.Equal (expected, breakLines);
  885. }
  886. [Theory]
  887. [InlineData ("A sentence\t\t\t has words.", 14, -10, new string [] { "A sentence\t", "\t\t has ", "words." })]
  888. [InlineData ("A sentence\t\t\t has words.", 8, -16, new string [] { "A ", "sentence", "\t\t", "\t ", "has ", "words." })]
  889. [InlineData ("A sentence\t\t\t has words.", 3, -21, new string [] { "A ", "sen", "ten", "ce", "\t", "\t", "\t", " ", "has", " ", "wor", "ds." })]
  890. [InlineData ("A sentence\t\t\t has words.", 2, -22, new string [] { "A ", "se", "nt", "en", "ce", "\t", "\t", "\t", " ", "ha", "s ", "wo", "rd", "s." })]
  891. [InlineData ("A sentence\t\t\t has words.", 1, -23, new string [] { "A", " ", "s", "e", "n", "t", "e", "n", "c", "e", "\t", "\t", "\t", " ", "h", "a", "s", " ", "w", "o", "r", "d", "s", "." })]
  892. public void WordWrap_PreserveTrailingSpaces_True_With_Tab (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines, int tabWidth = 4)
  893. {
  894. List<string> wrappedLines;
  895. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  896. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  897. wrappedLines = TextFormatter.WordWrapText (text, maxWidth, preserveTrailingSpaces: true, tabWidth: tabWidth);
  898. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  899. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  900. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  901. Assert.Equal (resultLines, wrappedLines);
  902. }
  903. [Theory]
  904. [InlineData ("これが最初の行です。 こんにちは世界。 これが2行目です。", 29, 0, new string [] { "これが最初の行です。", "こんにちは世界。", "これが2行目です。" })]
  905. public void WordWrap_PreserveTrailingSpaces_False_Unicode_Wide_Runes (string text, int maxWidth, int widthOffset, IEnumerable<string> resultLines)
  906. {
  907. List<string> wrappedLines;
  908. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  909. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  910. wrappedLines = TextFormatter.WordWrapText (text, maxWidth, preserveTrailingSpaces: false);
  911. Assert.Equal (wrappedLines.Count, resultLines.Count ());
  912. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetRuneCount ()) : 0));
  913. Assert.True (expectedClippedWidth >= (wrappedLines.Count > 0 ? wrappedLines.Max (l => l.GetColumns ()) : 0));
  914. Assert.Equal (resultLines, wrappedLines);
  915. }
  916. [Theory]
  917. [InlineData ("test", 0, 't', "test")]
  918. [InlineData ("test", 1, 'e', "test")]
  919. [InlineData ("Ok", 0, 'O', "Ok")]
  920. [InlineData ("[◦ Ok ◦]", 3, 'O', "[◦ Ok ◦]")]
  921. [InlineData ("^k", 0, '^', "^k")]
  922. public void ReplaceHotKeyWithTag (string text, int hotPos, uint tag, string expected)
  923. {
  924. var tf = new TextFormatter ();
  925. var runes = text.ToRuneList ();
  926. Rune rune;
  927. if (Rune.TryGetRuneAt (text, hotPos, out rune)) {
  928. Assert.Equal (rune, (Rune)tag);
  929. }
  930. var result = tf.ReplaceHotKeyWithTag (text, hotPos);
  931. Assert.Equal (result, expected);
  932. Assert.Equal ((Rune)tag, result.ToRunes () [hotPos]);
  933. Assert.Equal (text.GetRuneCount (), runes.Count);
  934. Assert.Equal (text, StringExtensions.ToString (runes));
  935. }
  936. [Theory]
  937. [InlineData ("", -1, TextAlignment.Left, false, 0)]
  938. [InlineData (null, 0, TextAlignment.Left, false, 1)]
  939. [InlineData (null, 0, TextAlignment.Left, true, 1)]
  940. [InlineData ("", 0, TextAlignment.Left, false, 1)]
  941. [InlineData ("", 0, TextAlignment.Left, true, 1)]
  942. public void Reformat_Invalid (string text, int maxWidth, TextAlignment textAlignment, bool wrap, int linesCount)
  943. {
  944. if (maxWidth < 0) {
  945. Assert.Throws<ArgumentOutOfRangeException> (() => TextFormatter.Format (text, maxWidth, textAlignment, wrap));
  946. } else {
  947. var list = TextFormatter.Format (text, maxWidth, textAlignment, wrap);
  948. Assert.NotEmpty (list);
  949. Assert.True (list.Count == linesCount);
  950. Assert.Equal (string.Empty, list [0]);
  951. }
  952. }
  953. [Theory]
  954. [InlineData ("", 0, 0, TextAlignment.Left, false, 1, true)]
  955. [InlineData ("", 1, 1, TextAlignment.Left, false, 1, true)]
  956. [InlineData ("A sentence has words.", 0, -21, TextAlignment.Left, false, 1, true)]
  957. [InlineData ("A sentence has words.", 1, -20, TextAlignment.Left, false, 1, false)]
  958. [InlineData ("A sentence has words.", 5, -16, TextAlignment.Left, false, 1, false)]
  959. [InlineData ("A sentence has words.", 20, -1, TextAlignment.Left, false, 1, false)]
  960. // no clip
  961. [InlineData ("A sentence has words.", 21, 0, TextAlignment.Left, false, 1, false)]
  962. [InlineData ("A sentence has words.", 22, 1, TextAlignment.Left, false, 1, false)]
  963. public void Reformat_NoWordrap_SingleLine (string text, int maxWidth, int widthOffset, TextAlignment textAlignment, bool wrap, int linesCount, bool stringEmpty)
  964. {
  965. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  966. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  967. var list = TextFormatter.Format (text, maxWidth, textAlignment, wrap);
  968. Assert.NotEmpty (list);
  969. Assert.True (list.Count == linesCount);
  970. if (stringEmpty) {
  971. Assert.Equal (string.Empty, list [0]);
  972. } else {
  973. Assert.NotEqual (string.Empty, list [0]);
  974. }
  975. Assert.Equal (StringExtensions.ToString (text.ToRunes () [0..expectedClippedWidth]), list [0]);
  976. }
  977. [Theory]
  978. [InlineData ("A sentence has words.\nLine 2.", 0, -29, TextAlignment.Left, false, 1, true)]
  979. [InlineData ("A sentence has words.\nLine 2.", 1, -28, TextAlignment.Left, false, 1, false)]
  980. [InlineData ("A sentence has words.\nLine 2.", 5, -24, TextAlignment.Left, false, 1, false)]
  981. [InlineData ("A sentence has words.\nLine 2.", 28, -1, TextAlignment.Left, false, 1, false)]
  982. // no clip
  983. [InlineData ("A sentence has words.\nLine 2.", 29, 0, TextAlignment.Left, false, 1, false)]
  984. [InlineData ("A sentence has words.\nLine 2.", 30, 1, TextAlignment.Left, false, 1, false)]
  985. [InlineData ("A sentence has words.\r\nLine 2.", 0, -30, TextAlignment.Left, false, 1, true)]
  986. [InlineData ("A sentence has words.\r\nLine 2.", 1, -29, TextAlignment.Left, false, 1, false)]
  987. [InlineData ("A sentence has words.\r\nLine 2.", 5, -25, TextAlignment.Left, false, 1, false)]
  988. [InlineData ("A sentence has words.\r\nLine 2.", 29, -1, TextAlignment.Left, false, 1, false, 1)]
  989. [InlineData ("A sentence has words.\r\nLine 2.", 30, 0, TextAlignment.Left, false, 1, false)]
  990. [InlineData ("A sentence has words.\r\nLine 2.", 31, 1, TextAlignment.Left, false, 1, false)]
  991. public void Reformat_NoWordrap_NewLines (string text, int maxWidth, int widthOffset, TextAlignment textAlignment, bool wrap, int linesCount, bool stringEmpty, int clipWidthOffset = 0)
  992. {
  993. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  994. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth) + clipWidthOffset;
  995. var list = TextFormatter.Format (text, maxWidth, textAlignment, wrap);
  996. Assert.NotEmpty (list);
  997. Assert.True (list.Count == linesCount);
  998. if (stringEmpty) {
  999. Assert.Equal (string.Empty, list [0]);
  1000. } else {
  1001. Assert.NotEqual (string.Empty, list [0]);
  1002. }
  1003. if (text.Contains ("\r\n") && maxWidth > 0) {
  1004. Assert.Equal (StringExtensions.ToString (text.ToRunes () [0..expectedClippedWidth]).Replace ("\r\n", " "), list [0]);
  1005. } else if (text.Contains ('\n') && maxWidth > 0) {
  1006. Assert.Equal (StringExtensions.ToString (text.ToRunes () [0..expectedClippedWidth]).Replace ("\n", " "), list [0]);
  1007. } else {
  1008. Assert.Equal (StringExtensions.ToString (text.ToRunes () [0..expectedClippedWidth]), list [0]);
  1009. }
  1010. }
  1011. [Theory]
  1012. // Even # of spaces
  1013. // 0123456789
  1014. [InlineData ("012 456 89", 0, -10, TextAlignment.Left, true, true, true, new string [] { "" })]
  1015. [InlineData ("012 456 89", 1, -9, TextAlignment.Left, true, true, false, new string [] { "0", "1", "2", " ", "4", "5", "6", " ", "8", "9" }, "01245689")]
  1016. [InlineData ("012 456 89", 5, -5, TextAlignment.Left, true, true, false, new string [] { "012 ", "456 ", "89" })]
  1017. [InlineData ("012 456 89", 9, -1, TextAlignment.Left, true, true, false, new string [] { "012 456 ", "89" })]
  1018. // no clip
  1019. [InlineData ("012 456 89", 10, 0, TextAlignment.Left, true, true, false, new string [] { "012 456 89" })]
  1020. [InlineData ("012 456 89", 11, 1, TextAlignment.Left, true, true, false, new string [] { "012 456 89" })]
  1021. // Odd # of spaces
  1022. // 01234567890123
  1023. [InlineData ("012 456 89 end", 13, -1, TextAlignment.Left, true, true, false, new string [] { "012 456 89 ", "end" })]
  1024. // no clip
  1025. [InlineData ("012 456 89 end", 14, 0, TextAlignment.Left, true, true, false, new string [] { "012 456 89 end" })]
  1026. [InlineData ("012 456 89 end", 15, 1, TextAlignment.Left, true, true, false, new string [] { "012 456 89 end" })]
  1027. public void Reformat_Wrap_Spaces_No_NewLines (string text, int maxWidth, int widthOffset, TextAlignment textAlignment, bool wrap, bool preserveTrailingSpaces, bool stringEmpty, IEnumerable<string> resultLines, string noSpaceText = "")
  1028. {
  1029. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  1030. var expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth);
  1031. var list = TextFormatter.Format (text, maxWidth, textAlignment, wrap, preserveTrailingSpaces);
  1032. Assert.NotEmpty (list);
  1033. Assert.True (list.Count == resultLines.Count ());
  1034. if (stringEmpty) {
  1035. Assert.Equal (string.Empty, list [0]);
  1036. } else {
  1037. Assert.NotEqual (string.Empty, list [0]);
  1038. }
  1039. Assert.Equal (resultLines, list);
  1040. if (maxWidth > 0) {
  1041. // remove whitespace chars
  1042. if (maxWidth < 5) {
  1043. expectedClippedWidth = text.GetRuneCount () - text.Sum (r => r == ' ' ? 1 : 0);
  1044. } else {
  1045. expectedClippedWidth = Math.Min (text.GetRuneCount (), maxWidth - text.Sum (r => r == ' ' ? 1 : 0));
  1046. }
  1047. list = TextFormatter.Format (text, maxWidth, TextAlignment.Left, wrap, preserveTrailingSpaces: false);
  1048. if (maxWidth == 1) {
  1049. Assert.Equal (expectedClippedWidth, list.Count);
  1050. Assert.Equal (noSpaceText, string.Concat (list.ToArray ()));
  1051. }
  1052. if (maxWidth > 1 && maxWidth < 10) {
  1053. Assert.Equal (StringExtensions.ToString (text.ToRunes () [0..expectedClippedWidth]), list [0]);
  1054. }
  1055. }
  1056. }
  1057. [Theory]
  1058. // Unicode
  1059. // Even # of chars
  1060. // 0123456789
  1061. [InlineData ("\u2660пÑРвРÑ", 10, -1, TextAlignment.Left, true, false, new string [] { "\u2660пÑРвÐ", "Ñ" })]
  1062. // no clip
  1063. [InlineData ("\u2660пÑРвРÑ", 11, 0, TextAlignment.Left, true, false, new string [] { "\u2660пÑРвРÑ" })]
  1064. [InlineData ("\u2660пÑРвРÑ", 12, 1, TextAlignment.Left, true, false, new string [] { "\u2660пÑРвРÑ" })]
  1065. // Unicode
  1066. // Odd # of chars
  1067. // 0123456789
  1068. [InlineData ("\u2660 ÑРвРÑ", 9, -1, TextAlignment.Left, true, false, new string [] { "\u2660 ÑРвÐ", "Ñ" })]
  1069. // no clip
  1070. [InlineData ("\u2660 ÑРвРÑ", 10, 0, TextAlignment.Left, true, false, new string [] { "\u2660 ÑРвРÑ" })]
  1071. [InlineData ("\u2660 ÑРвРÑ", 11, 1, TextAlignment.Left, true, false, new string [] { "\u2660 ÑРвРÑ" })]
  1072. public void Reformat_Unicode_Wrap_Spaces_No_NewLines (string text, int maxWidth, int widthOffset, TextAlignment textAlignment, bool wrap, bool preserveTrailingSpaces, IEnumerable<string> resultLines)
  1073. {
  1074. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  1075. var list = TextFormatter.Format (text, maxWidth, textAlignment, wrap, preserveTrailingSpaces);
  1076. Assert.Equal (list.Count, resultLines.Count ());
  1077. Assert.Equal (resultLines, list);
  1078. }
  1079. [Theory]
  1080. // Unicode
  1081. [InlineData ("\u2460\u2461\u2462\n\u2460\u2461\u2462\u2463\u2464", 8, -1, TextAlignment.Left, true, false, new string [] { "\u2460\u2461\u2462", "\u2460\u2461\u2462\u2463\u2464" })]
  1082. // no clip
  1083. [InlineData ("\u2460\u2461\u2462\n\u2460\u2461\u2462\u2463\u2464", 9, 0, TextAlignment.Left, true, false, new string [] { "\u2460\u2461\u2462", "\u2460\u2461\u2462\u2463\u2464" })]
  1084. [InlineData ("\u2460\u2461\u2462\n\u2460\u2461\u2462\u2463\u2464", 10, 1, TextAlignment.Left, true, false, new string [] { "\u2460\u2461\u2462", "\u2460\u2461\u2462\u2463\u2464" })]
  1085. public void Reformat_Unicode_Wrap_Spaces_NewLines (string text, int maxWidth, int widthOffset, TextAlignment textAlignment, bool wrap, bool preserveTrailingSpaces, IEnumerable<string> resultLines)
  1086. {
  1087. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  1088. var list = TextFormatter.Format (text, maxWidth, textAlignment, wrap, preserveTrailingSpaces);
  1089. Assert.Equal (list.Count, resultLines.Count ());
  1090. Assert.Equal (resultLines, list);
  1091. }
  1092. [Theory]
  1093. [InlineData (" A sentence has words. \n This is the second Line - 2. ", 4, -50, TextAlignment.Left, true, false, new string [] { " A", "sent", "ence", "has", "word", "s. ", " Thi", "s is", "the", "seco", "nd", "Line", "- 2." }, " Asentencehaswords. This isthesecondLine- 2.")]
  1094. [InlineData (" A sentence has words. \n This is the second Line - 2. ", 4, -50, TextAlignment.Left, true, true, new string [] { " A ", "sent", "ence", " ", "has ", "word", "s. ", " ", "This", " is ", "the ", "seco", "nd ", "Line", " - ", "2. " }, " A sentence has words. This is the second Line - 2. ")]
  1095. public void Format_WordWrap_PreserveTrailingSpaces (string text, int maxWidth, int widthOffset, TextAlignment textAlignment, bool wrap, bool preserveTrailingSpaces, IEnumerable<string> resultLines, string expectedWrappedText)
  1096. {
  1097. Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
  1098. var list = TextFormatter.Format (text, maxWidth, textAlignment, wrap, preserveTrailingSpaces);
  1099. Assert.Equal (list.Count, resultLines.Count ());
  1100. Assert.Equal (resultLines, list);
  1101. string wrappedText = string.Empty;
  1102. foreach (var txt in list) wrappedText += txt;
  1103. Assert.Equal (expectedWrappedText, wrappedText);
  1104. }
  1105. [Fact]
  1106. public void Format_Dont_Throw_ArgumentException_With_WordWrap_As_False_And_Keep_End_Spaces_As_True ()
  1107. {
  1108. var exception = Record.Exception (() => TextFormatter.Format ("Some text", 4, TextAlignment.Left, false, true));
  1109. Assert.Null (exception);
  1110. }
  1111. [Theory]
  1112. [InlineData ("Hello world, how are you today? Pretty neat!", 44, 80, "Hello world, how are you today? Pretty neat!")]
  1113. public void Format_Justified_Always_Returns_Text_Width_Equal_To_Passed_Width_Horizontal (string text, int runeCount, int maxWidth, string justifiedText)
  1114. {
  1115. Assert.Equal (runeCount, text.GetRuneCount ());
  1116. var fmtText = string.Empty;
  1117. for (int i = text.GetRuneCount (); i < maxWidth; i++) {
  1118. fmtText = TextFormatter.Format (text, i, TextAlignment.Justified, false, true) [0];
  1119. Assert.Equal (i, fmtText.GetRuneCount ());
  1120. var c = fmtText [^1];
  1121. Assert.True (text.EndsWith (c));
  1122. }
  1123. Assert.Equal (justifiedText, fmtText);
  1124. }
  1125. [Theory]
  1126. [InlineData ("Hello world, how are you today? Pretty neat!", 44, 80, "Hello world, how are you today? Pretty neat!")]
  1127. public void Format_Justified_Always_Returns_Text_Width_Equal_To_Passed_Width_Vertical (string text, int runeCount, int maxWidth, string justifiedText)
  1128. {
  1129. Assert.Equal (runeCount, text.GetRuneCount ());
  1130. var fmtText = string.Empty;
  1131. for (int i = text.GetRuneCount (); i < maxWidth; i++) {
  1132. fmtText = TextFormatter.Format (text, i, TextAlignment.Justified, false, true, 0, TextDirection.TopBottom_LeftRight) [0];
  1133. Assert.Equal (i, fmtText.GetRuneCount ());
  1134. var c = fmtText [^1];
  1135. Assert.True (text.EndsWith (c));
  1136. }
  1137. Assert.Equal (justifiedText, fmtText);
  1138. }
  1139. [Theory]
  1140. [InlineData ("fff", 6, "fff ")]
  1141. [InlineData ("Hello World", 16, "Hello World ")]
  1142. public void TestClipOrPad_ShortWord (string text, int fillPad, string expectedText)
  1143. {
  1144. // word is short but we want it to fill # so it should be padded
  1145. Assert.Equal (expectedText, TextFormatter.ClipOrPad (text, fillPad));
  1146. }
  1147. [Theory]
  1148. [InlineData ("123456789", 3, "123")]
  1149. [InlineData ("Hello World", 8, "Hello Wo")]
  1150. public void TestClipOrPad_LongWord (string text, int fillPad, string expectedText)
  1151. {
  1152. // word is long but we want it to fill # space only
  1153. Assert.Equal (expectedText, TextFormatter.ClipOrPad (text, fillPad));
  1154. }
  1155. [Fact]
  1156. public void Internal_Tests ()
  1157. {
  1158. var tf = new TextFormatter ();
  1159. Assert.Equal (Key.Null, tf.HotKey);
  1160. tf.HotKey = Key.CtrlMask | Key.Q;
  1161. Assert.Equal (Key.CtrlMask | Key.Q, tf.HotKey);
  1162. }
  1163. [Theory]
  1164. [InlineData ("Hello World", 11)]
  1165. [InlineData ("こんにちは世界", 14)]
  1166. public void GetColumns_Simple_And_Wide_Runes (string text, int width)
  1167. {
  1168. Assert.Equal (width, text.GetColumns ());
  1169. }
  1170. [Theory]
  1171. [InlineData ("Hello World", 11, 6, 1, 1)]
  1172. [InlineData ("こんにちは 世界", 15, 6, 1, 2)]
  1173. public void GetSumMaxCharWidth_Simple_And_Wide_Runes (string text, int width, int index, int length, int indexWidth)
  1174. {
  1175. Assert.Equal (width, TextFormatter.GetSumMaxCharWidth (text));
  1176. Assert.Equal (indexWidth, TextFormatter.GetSumMaxCharWidth (text, index, length));
  1177. }
  1178. [Theory]
  1179. [InlineData (new string [] { "Hello", "World" }, 2, 1, 1, 1)]
  1180. [InlineData (new string [] { "こんにちは", "世界" }, 4, 1, 1, 2)]
  1181. public void GetSumMaxCharWidth_List_Simple_And_Wide_Runes (IEnumerable<string> text, int width, int index, int length, int indexWidth)
  1182. {
  1183. Assert.Equal (width, TextFormatter.GetSumMaxCharWidth (text.ToList ()));
  1184. Assert.Equal (indexWidth, TextFormatter.GetSumMaxCharWidth (text.ToList (), index, length));
  1185. }
  1186. [Theory]
  1187. [InlineData ("test", 3, 3)]
  1188. [InlineData ("test", 4, 4)]
  1189. [InlineData ("test", 10, 4)]
  1190. public void GetLengthThatFits_Runelist (string text, int columns, int expectedLength)
  1191. {
  1192. var runes = text.ToRuneList ();
  1193. Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (runes, columns));
  1194. }
  1195. [Theory]
  1196. [InlineData ("test", 3, 3)]
  1197. [InlineData ("test", 4, 4)]
  1198. [InlineData ("test", 10, 4)]
  1199. [InlineData ("test", 1, 1)]
  1200. [InlineData ("test", 0, 0)]
  1201. [InlineData ("test", -1, 0)]
  1202. [InlineData (null, -1, 0)]
  1203. [InlineData ("", -1, 0)]
  1204. public void GetLengthThatFits_String (string text, int columns, int expectedLength)
  1205. {
  1206. Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (text, columns));
  1207. }
  1208. [Theory]
  1209. [InlineData ("Hello World", 6, 6)]
  1210. [InlineData ("こんにちは 世界", 6, 3)]
  1211. public void GetLengthThatFits_Simple_And_Wide_Runes (string text, int columns, int expectedLength)
  1212. {
  1213. Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (text, columns));
  1214. }
  1215. [Theory]
  1216. [InlineData ("Hello World", 6, 6)]
  1217. [InlineData ("こんにちは 世界", 6, 3)]
  1218. [MemberData (nameof (CMGlyphs))]
  1219. public void GetLengthThatFits_List_Simple_And_Wide_Runes (string text, int columns, int expectedLength)
  1220. {
  1221. var runes = text.ToRuneList ();
  1222. Assert.Equal (expectedLength, TextFormatter.GetLengthThatFits (runes, columns));
  1223. }
  1224. public static IEnumerable<object []> CMGlyphs =>
  1225. new List<object []>
  1226. {
  1227. new object[] { $"{CM.Glyphs.LeftBracket} Say Hello 你 {CM.Glyphs.RightBracket}", 16, 15 }
  1228. };
  1229. [Theory]
  1230. [InlineData ("Truncate", 3, "Tru")]
  1231. [InlineData ("デモエムポンズ", 3, "デ")]
  1232. public void Format_Truncate_Simple_And_Wide_Runes (string text, int width, string expected)
  1233. {
  1234. var list = TextFormatter.Format (text, width, false, false);
  1235. Assert.Equal (expected, list [^1]);
  1236. }
  1237. [Theory]
  1238. [MemberData (nameof (FormatEnvironmentNewLine))]
  1239. public void Format_With_PreserveTrailingSpaces_And_Without_PreserveTrailingSpaces (string text, int width, IEnumerable<string> expected)
  1240. {
  1241. var preserveTrailingSpaces = false;
  1242. var formated = TextFormatter.Format (text, width, false, true, preserveTrailingSpaces);
  1243. Assert.Equal (expected, formated);
  1244. preserveTrailingSpaces = true;
  1245. formated = TextFormatter.Format (text, width, false, true, preserveTrailingSpaces);
  1246. Assert.Equal (expected, formated);
  1247. }
  1248. public static IEnumerable<object []> FormatEnvironmentNewLine =>
  1249. new List<object []>
  1250. {
  1251. new object[] { $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3{Environment.NewLine}", 60, new string [] { "Line1", "Line2", "Line3" } }
  1252. };
  1253. [Theory]
  1254. [MemberData (nameof (SplitEnvironmentNewLine))]
  1255. public void SplitNewLine_Ending__With_Or_Without_NewLine_Probably_CRLF (string text, IEnumerable<string> expected)
  1256. {
  1257. var splited = TextFormatter.SplitNewLine (text);
  1258. Assert.Equal (expected, splited);
  1259. }
  1260. public static IEnumerable<object []> SplitEnvironmentNewLine =>
  1261. new List<object []>
  1262. {
  1263. new object[] { $"First Line 界{Environment.NewLine}Second Line 界{Environment.NewLine}Third Line 界", new string [] { "First Line 界", "Second Line 界", "Third Line 界" } },
  1264. new object[] { $"First Line 界{Environment.NewLine}Second Line 界{Environment.NewLine}Third Line 界{Environment.NewLine}", new string [] { "First Line 界", "Second Line 界", "Third Line 界", "" } }
  1265. };
  1266. [Theory]
  1267. [InlineData ($"First Line 界\nSecond Line 界\nThird Line 界", new string [] { "First Line 界", "Second Line 界", "Third Line 界" })]
  1268. public void SplitNewLine_Ending_Without_NewLine_Only_LF (string text, IEnumerable<string> expected)
  1269. {
  1270. var splited = TextFormatter.SplitNewLine (text);
  1271. Assert.Equal (expected, splited);
  1272. }
  1273. [Theory]
  1274. [InlineData ($"First Line 界\nSecond Line 界\nThird Line 界\n", new string [] { "First Line 界", "Second Line 界", "Third Line 界", "" })]
  1275. public void SplitNewLine_Ending_With_NewLine_Only_LF (string text, IEnumerable<string> expected)
  1276. {
  1277. var splited = TextFormatter.SplitNewLine (text);
  1278. Assert.Equal (expected, splited);
  1279. }
  1280. [Theory]
  1281. [InlineData ("Single Line 界", 14)]
  1282. [InlineData ($"First Line 界\nSecond Line 界\nThird Line 界\n", 14)]
  1283. public void MaxWidthLine_With_And_Without_Newlines (string text, int expected)
  1284. {
  1285. Assert.Equal (expected, TextFormatter.MaxWidthLine (text));
  1286. }
  1287. [Theory]
  1288. [InlineData ("New Test 你", 10, 10, 20320, 20320, 9, "你")]
  1289. [InlineData ("New Test \U0001d539", 10, 11, 120121, 55349, 9, "𝔹")]
  1290. public void String_Array_Is_Not_Always_Equal_ToRunes_Array (string text, int runesLength, int stringLength, int runeValue, int stringValue, int index, string expected)
  1291. {
  1292. var usToRunes = text.ToRunes ();
  1293. Assert.Equal (runesLength, usToRunes.Length);
  1294. Assert.Equal (stringLength, text.Length);
  1295. Assert.Equal (runeValue, usToRunes [index].Value);
  1296. Assert.Equal (stringValue, text [index]);
  1297. Assert.Equal (expected, usToRunes [index].ToString ());
  1298. if (char.IsHighSurrogate (text [index])) {
  1299. // Rune array length isn't equal to string array
  1300. Assert.Equal (expected, new string (new char [] { text [index], text [index + 1] }));
  1301. } else {
  1302. // Rune array length is equal to string array
  1303. Assert.Equal (expected, text [index].ToString ());
  1304. }
  1305. }
  1306. }
  1307. }