ansi_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. package ansi
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. func TestWrap(t *testing.T) {
  7. // These test were pulled and modified from:
  8. // https://github.com/muesli/reflow/blob/d4603be2c4a9017b4cf38856841116ffe0f04c59/wordwrap/wordwrap_test.go
  9. tests := []struct {
  10. Input string
  11. Expected string
  12. Limit int
  13. }{
  14. // Nothing to wrap here, should pass through:
  15. {
  16. "foo",
  17. "foo",
  18. 4,
  19. },
  20. // Snap words
  21. {
  22. "foobarfoo",
  23. "foob\narfo\no",
  24. 4,
  25. },
  26. // Lines are broken at whitespace:
  27. {
  28. "foo bar foo",
  29. "foo\nbar\nfoo",
  30. 4,
  31. },
  32. // Space buffer needs to be emptied before breakpoints:
  33. {
  34. "foo --bar",
  35. "foo --bar",
  36. 9,
  37. },
  38. // Lines are broken at whitespace, and long words break as well
  39. {
  40. "foo bars foobars",
  41. "foo\nbars\nfoob\nars",
  42. 4,
  43. },
  44. // A word that would run beyond the limit is wrapped:
  45. {
  46. "foo bar",
  47. "foo\nbar",
  48. 5,
  49. },
  50. // Whitespace prefixing an explicit line break remains:
  51. {
  52. "foo\nb a\n bar",
  53. "foo\nb a\n bar",
  54. 4,
  55. },
  56. // Trailing whitespace is removed if it doesn't fit the width.
  57. // Runs of whitespace on which a line is broken are removed:
  58. {
  59. "foo \nb ar ",
  60. "foo\nb\nar",
  61. 4,
  62. },
  63. // An explicit line break at the end of the input is preserved:
  64. {
  65. "foo bar foo\n",
  66. "foo\nbar\nfoo\n",
  67. 4,
  68. },
  69. // Explicit break are always preserved:
  70. {
  71. "\nfoo bar\n\n\nfoo\n",
  72. "\nfoo\nbar\n\n\nfoo\n",
  73. 4,
  74. },
  75. // Complete example:
  76. {
  77. " This is a list: \n\n * foo\n * bar\n\n\n * foo \nbar ",
  78. " This\nis a\nlist: \n\n * foo\n * bar\n\n\n * foo\nbar",
  79. 6,
  80. },
  81. // ANSI sequence codes don't affect length calculation:
  82. {
  83. "\x1B[38;2;249;38;114mfoo\x1B[0m\x1B[38;2;248;248;242m \x1B[0m\x1B[38;2;230;219;116mbar\x1B[0m",
  84. "\x1B[38;2;249;38;114mfoo\x1B[0m\x1B[38;2;248;248;242m \x1B[0m\x1B[38;2;230;219;116mbar\x1B[0m",
  85. 7,
  86. },
  87. // ANSI control codes don't get wrapped:
  88. {
  89. "\x1B[38;2;249;38;114m(\x1B[0m\x1B[38;2;248;248;242mjust another test\x1B[38;2;249;38;114m)\x1B[0m",
  90. "\x1B[38;2;249;38;114m(\x1B[0m\x1B[38;2;248;248;242mju\nst\nano\nthe\nr\ntes\nt\x1B[38;2;249;38;114m)\x1B[0m",
  91. 3,
  92. },
  93. // Many, many newlines shouldn't collapse:
  94. {
  95. "multi-space \n\n\n\n\n far down",
  96. "multi-sp\nace \n\n\n\n\n far\ndown",
  97. 8,
  98. },
  99. }
  100. for _, test := range tests {
  101. output := Wrap(test.Input, test.Limit)
  102. if test.Expected != output {
  103. t.Fatalf("expected %s but got %s", test.Expected, output)
  104. }
  105. // Test that `Wrap` is idempotent
  106. identical := Wrap(test.Expected, test.Limit)
  107. if test.Expected != identical {
  108. t.Fatalf("expected %s but got %s", test.Expected, identical)
  109. }
  110. }
  111. }
  112. func TestCodeBlock(t *testing.T) {
  113. input := "Soft-wrapped code block used to test everything"
  114. wrapped := Wrap(input, 6)
  115. padded := Pad(wrapped, 6)
  116. indented := Indent(padded, " ", true)
  117. expected := ` Soft-w
  118. rapped
  119. code
  120. block
  121. used
  122. to
  123. test
  124. everyt
  125. hing `
  126. if expected != indented {
  127. t.Fatalf("expected %s but got %s", expected, indented)
  128. }
  129. fmt.Println("This should look like a nice, indented code block:")
  130. styled := Indent(Apply(padded, "48;2;75;75;75"), " ", true)
  131. fmt.Println(styled)
  132. }
  133. func TestSnip(t *testing.T) {
  134. // These test were pulled and modified from:
  135. // https://github.com/muesli/reflow/blob/d4603be2c4a9017b4cf38856841116ffe0f04c59/wordwrap/wordwrap_test.go
  136. tests := []struct {
  137. Input string
  138. Expected string
  139. Height int
  140. Width int
  141. }{
  142. // Restrict lines down:
  143. {
  144. "one\n\nthree\nfour",
  145. "one\n\nthree…",
  146. 3,
  147. 25,
  148. },
  149. // Don't restrict lines when not necessary:
  150. {
  151. "one\n\nthree\nfour",
  152. "one\n\nthree\nfour",
  153. 5,
  154. 25,
  155. },
  156. // Remove last character to insert ellipsis:
  157. {
  158. "one\ntwo\nthree\nfour",
  159. "one\ntwo\nthre…",
  160. 3,
  161. 5,
  162. },
  163. // Omit trailing whitespace only lines:
  164. {
  165. "one\n\n \nfour",
  166. "one…",
  167. 3,
  168. 25,
  169. },
  170. // Omit trailing whitespace and last character for ellipsis:
  171. {
  172. "one\n\n \nfour",
  173. "on…",
  174. 3,
  175. 3,
  176. },
  177. // Omit ellipsis when perfect fit
  178. {
  179. "one\ntwo\nthree",
  180. "one\ntwo\nthree",
  181. 3,
  182. 5,
  183. },
  184. }
  185. for _, test := range tests {
  186. output := Snip(test.Input, test.Width, test.Height, "…")
  187. if test.Expected != output {
  188. t.Fatalf("expected %s but got %s", test.Expected, output)
  189. }
  190. }
  191. }
  192. func TestCenterVertically(t *testing.T) {
  193. tests := []struct {
  194. prefix string
  195. centered string
  196. suffix string
  197. height uint
  198. output string
  199. }{
  200. // normal case
  201. {
  202. "p1\np2",
  203. "c1\nc2",
  204. "s1\ns2",
  205. 6,
  206. "p1\np2\nc1\nc2\ns1\ns2",
  207. },
  208. // offset center with even height
  209. {
  210. "p1",
  211. "c1",
  212. "s1\ns2",
  213. 4,
  214. "p1\nc1\ns1\ns2",
  215. },
  216. // offset center with odd height
  217. {
  218. "p1",
  219. "c1\nc2",
  220. "s1\ns2",
  221. 5,
  222. "p1\nc1\nc2\ns1\ns2",
  223. },
  224. // trimmed top
  225. {
  226. "p1\np2",
  227. "c1\nc2",
  228. "s1",
  229. 4,
  230. "p2\nc1\nc2\ns1",
  231. },
  232. // buffered top (with offset)
  233. {
  234. "p1",
  235. "c1",
  236. "s1\ns2\ns3",
  237. 6,
  238. "\np1\nc1\ns1\ns2\ns3",
  239. },
  240. // trimmed bottom
  241. {
  242. "p1",
  243. "c1",
  244. "s1\ns2",
  245. 3,
  246. "p1\nc1\ns1",
  247. },
  248. // buffered bottom
  249. {
  250. "p1",
  251. "c1",
  252. "",
  253. 3,
  254. "p1\nc1\n",
  255. },
  256. // center too big
  257. {
  258. "top",
  259. "middle\nis\nbig",
  260. "bottom",
  261. 2,
  262. "middle\nis",
  263. },
  264. // perfect center
  265. {
  266. "top",
  267. "middle\nis\nbig",
  268. "bottom",
  269. 3,
  270. "middle\nis\nbig",
  271. },
  272. }
  273. for i, test := range tests {
  274. actual := CenterVertically(test.prefix, test.centered, test.suffix, test.height)
  275. if test.output != actual {
  276. t.Fatalf("Expected %v but received %v for test %v", test.output, actual, i)
  277. }
  278. }
  279. }