line_test.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package door
  2. import (
  3. "bytes"
  4. "fmt"
  5. "testing"
  6. "unicode"
  7. )
  8. func TestLine(t *testing.T) {
  9. var textBuff *bytes.Buffer = &bytes.Buffer{}
  10. textBuff.WriteString("Test Me")
  11. var line *Line = &Line{Text: textBuff}
  12. var output string = string(line.Output())
  13. var expect string = string("Test Me")
  14. if output != expect {
  15. t.Errorf("Line: Expected %#v, got %#v", expect, output)
  16. }
  17. if line.Update() {
  18. t.Error("Line: No updater, should return false")
  19. }
  20. line.DefaultColor = Color([]int{0})
  21. line.Width = 8
  22. output = string(line.Output())
  23. expect = "\x1b[0mTest Me "
  24. if output != expect {
  25. t.Errorf("Line: Expected %#v, got %#v", expect, output)
  26. }
  27. // leave the default color, it is ignored when there's a render function
  28. // line.DefaultColor = ""
  29. line.RenderF = RenderBlueYellow
  30. output = string(line.Output())
  31. var blue string = string(ColorText("BOLD BLUE"))
  32. var yellow string = string(ColorText("BOLD YELLOW"))
  33. expect = blue + "T" + yellow + "est " + blue + "M" + yellow + "e "
  34. if output != expect {
  35. t.Errorf("Line: Expected %#v, got %#v", expect, output)
  36. }
  37. }
  38. func TestLineUpdate(t *testing.T) {
  39. var counter int = 0
  40. uf := func(u *bytes.Buffer) {
  41. u.Reset()
  42. fmt.Fprintf(u, "Count: %d", counter)
  43. }
  44. var line *Line = &Line{UpdateF: uf}
  45. line.Update()
  46. var output string = string(line.Output())
  47. var expect string = "Count: 0"
  48. if output != expect {
  49. t.Errorf("LineUpdate: Expected %#v, got %#v", expect, output)
  50. }
  51. if line.Update() {
  52. t.Error("Unexpected Update: should have returned false. (no change)")
  53. }
  54. counter++
  55. if !line.Update() {
  56. t.Error("Missing Update: value was changed, Text should have changed")
  57. }
  58. output = string(line.Output())
  59. expect = "Count: 1"
  60. if output != expect {
  61. t.Errorf("LineUpdate: Expected %#v, got %#v", expect, output)
  62. }
  63. }
  64. func TestLineUnicode(t *testing.T) {
  65. Unicode = true
  66. // code point > FFFF, use \U00000000 (not \u).
  67. var lineBuff *bytes.Buffer = &bytes.Buffer{}
  68. lineBuff.WriteString("Howdy \U0001f920")
  69. var line *Line = &Line{Text: lineBuff}
  70. var output []byte = line.Output()
  71. var expect []byte = []byte("Howdy 🤠")
  72. if bytes.Compare(output, expect) != 0 {
  73. t.Errorf("LineUnicode: Expected %s, got %s", expect, output)
  74. }
  75. if StringLen(expect) != 8 {
  76. t.Errorf("LineUnicode Strlen: Expected 8, got %d", StringLen(expect))
  77. }
  78. // 🤠 = 2 chars.
  79. line.Width = 9
  80. output = line.Output()
  81. expect = []byte("Howdy 🤠 ")
  82. if bytes.Compare(output, expect) != 0 {
  83. t.Errorf("LineUnicode: Expected %#v, got %#v", expect, output)
  84. }
  85. }
  86. func TestLineCP437(t *testing.T) {
  87. Unicode = false
  88. var tests []string = []string{"\xdb TEXT \xdb",
  89. "\xf1 F1", "\xf2 F2", "\xf3 F3"}
  90. for _, test := range tests {
  91. var lineBuff *bytes.Buffer = &bytes.Buffer{}
  92. lineBuff.WriteString(test)
  93. var line *Line = &Line{Text: lineBuff}
  94. var output string = string(line.Output())
  95. var expect string = test
  96. if output != expect {
  97. t.Errorf("LineCP437: Expected %#v, got %#v", expect, output)
  98. }
  99. }
  100. }
  101. // Benchmarks for profiling
  102. // go test -bench=BenchmarkLine -benchmem -memprofile memory.out -cpuprofile cpu.out
  103. // go tool pprof memory.out
  104. // go tool pprof cpu.out
  105. func BenchmarkLine(b *testing.B) {
  106. Unicode = false
  107. for n := 0; n < b.N; n++ {
  108. var lineBuff *bytes.Buffer = &bytes.Buffer{}
  109. fmt.Fprintf(lineBuff, "Line %d of %d", n, b.N)
  110. // lineBuff.WriteString(fmt.Sprintf("Line %d of %d", n, b.N))
  111. var line *Line = &Line{Text: lineBuff}
  112. line.Output()
  113. }
  114. }
  115. func BenchmarkLineUnicode(b *testing.B) {
  116. Unicode = true
  117. for n := 0; n < b.N; n++ {
  118. var lineBuff *bytes.Buffer = &bytes.Buffer{}
  119. fmt.Fprintf(lineBuff, "Line %d of %d", n, b.N)
  120. // lineBuff.WriteString(fmt.Sprintf("Line %d of %d", n, b.N))
  121. var line *Line = &Line{Text: lineBuff}
  122. line.Output()
  123. }
  124. }
  125. func BenchmarkLineColor(b *testing.B) {
  126. Unicode = false
  127. color := ColorText("BRI WHI ON BLUE")
  128. for n := 0; n < b.N; n++ {
  129. var lineBuff *bytes.Buffer = &bytes.Buffer{}
  130. fmt.Fprintf(lineBuff, "Line %d of %d", n, b.N)
  131. // lineBuff.WriteString(fmt.Sprintf("Line %d of %d", n, b.N))
  132. var line *Line = &Line{Text: lineBuff, DefaultColor: color}
  133. line.Output()
  134. }
  135. }
  136. func BenchmarkLineColorUnicode(b *testing.B) {
  137. Unicode = true
  138. color := ColorText("BRI WHI ON BLUE")
  139. for n := 0; n < b.N; n++ {
  140. var lineBuff *bytes.Buffer = &bytes.Buffer{}
  141. fmt.Fprintf(lineBuff, "Line %d of %d", n, b.N)
  142. // lineBuff.WriteString(fmt.Sprintf("Line %d of %d", n, b.N))
  143. var line *Line = &Line{Text: lineBuff, DefaultColor: color}
  144. line.Output()
  145. }
  146. }
  147. // Using RenderUppercase vs. RenderBlueYellow
  148. // BenchmarkLineRender-4 739462 1709 ns/op 376 B/op 13 allocs/op
  149. // BenchmarkLineRender-4 862102 1434 ns/op 648 B/op 9 allocs/op
  150. /*
  151. // This actually made BenchmarkLineUpdate worse.
  152. func printd(value int64, write io.Writer) {
  153. var buffer [32]byte
  154. var pos int
  155. if value == 0 {
  156. write.Write([]byte{'0'})
  157. return
  158. }
  159. for value > 0 {
  160. buffer[pos] = byte(int64('0') + value%10)
  161. pos++
  162. value = value / 10
  163. }
  164. for pos != 0 {
  165. pos--
  166. write.Write(buffer[pos : pos+1])
  167. }
  168. }
  169. */
  170. func BenchmarkLineUpdate(b *testing.B) {
  171. Unicode = false
  172. var line *Line = &Line{}
  173. var n int
  174. line.UpdateF = func(u *bytes.Buffer) {
  175. u.Reset()
  176. /*
  177. u.WriteString("Line ")
  178. printd(int64(n), u)
  179. u.WriteString(" of ")
  180. printd(int64(b.N), u)
  181. */
  182. fmt.Fprintf(u, "Line # %d of %d", n, b.N)
  183. }
  184. line.Update()
  185. for n = 0; n < b.N; n++ {
  186. line.Update()
  187. line.Output()
  188. }
  189. }
  190. func BenchmarkLineUpdateUnicode(b *testing.B) {
  191. Unicode = true
  192. var line *Line = &Line{}
  193. var n int
  194. line.UpdateF = func(u *bytes.Buffer) {
  195. u.Reset()
  196. /*
  197. u.WriteString("Line ")
  198. printd(int64(n), u)
  199. u.WriteString(" of ")
  200. printd(int64(b.N), u)
  201. */
  202. // № \u2116
  203. fmt.Fprintf(u, "Line № %d of %d", n, b.N)
  204. }
  205. line.Update()
  206. for n = 0; n < b.N; n++ {
  207. line.Update()
  208. line.Output()
  209. }
  210. }
  211. func BenchmarkLineRender(b *testing.B) {
  212. Unicode = false
  213. var rf ColorRender = RenderUppercase("RED", "GREEN")
  214. var line *Line = NewLine("ThIs Is CrAzY TeXt HeRe")
  215. line.RenderF = rf
  216. var n int
  217. for n = 0; n < b.N; n++ {
  218. line.Output()
  219. }
  220. }
  221. func BenchmarkLineRenderUnicode(b *testing.B) {
  222. Unicode = true
  223. var rf ColorRender = RenderUppercase("RED", "GREEN")
  224. // ₿ /u208f
  225. var line *Line = NewLine("ThIs Is CrAzY ₿ TeXt HeRe")
  226. line.RenderF = rf
  227. var n int
  228. for n = 0; n < b.N; n++ {
  229. line.Output()
  230. }
  231. }
  232. // Benchmarks / profiling
  233. // BenchmarkLineColor-4 2868162 403.9 ns/op 8 B/op 0 allocs/op
  234. // BenchmarkLineColor-4 2944704 400.0 ns/op 8 B/op 0 allocs/op
  235. // No change making Color strings to []byte. (reverted change)
  236. func BenchmarkLineRenderUpdate(b *testing.B) {
  237. Unicode = false
  238. var Up = ColorText("BLUE")
  239. var Down = ColorText("BOLD BLUE")
  240. var Num = ColorText("BRI GREEN")
  241. var Sym = ColorText("CYAN")
  242. var render = func(output *bytes.Buffer, text []byte) {
  243. output.Reset()
  244. var last *[]byte
  245. // var r Render = Render{Line: text}
  246. for _, letter := range text {
  247. if unicode.IsUpper(rune(letter)) {
  248. if last != &Up {
  249. output.Write(Up)
  250. last = &Up
  251. }
  252. // r.Append(Up, 1)
  253. } else if unicode.IsLower(rune(letter)) {
  254. if last != &Down {
  255. output.Write(Down)
  256. last = &Down
  257. }
  258. // r.Append(Down, 1)
  259. } else if unicode.IsDigit(rune(letter)) {
  260. if last != &Num {
  261. output.Write(Num)
  262. last = &Num
  263. }
  264. // r.Append(Num, 1)
  265. } else {
  266. if last != &Sym {
  267. output.Write(Sym)
  268. last = &Sym
  269. }
  270. //r.Append(Sym, 1)
  271. }
  272. output.WriteByte(letter)
  273. // output.WriteString(string(letter))
  274. }
  275. // return output.Bytes()
  276. // return r.Result
  277. }
  278. var up int
  279. var updater = func(u *bytes.Buffer) {
  280. u.Reset()
  281. fmt.Fprintf(u, "The Value: %d", up)
  282. // u.WriteString("The Value: ")
  283. // u.WriteString(strconv.Itoa(up))
  284. up++
  285. // return fmt.Sprintf("The Value: %d", up)
  286. }
  287. var line *Line = &Line{UpdateF: updater,
  288. RenderF: render,
  289. Width: 18}
  290. for i := 0; i < b.N; i++ {
  291. line.Update()
  292. line.Output()
  293. }
  294. }
  295. func BenchmarkLineRenderUpdateUnicode(b *testing.B) {
  296. Unicode = true
  297. var Up = ColorText("BLUE")
  298. var Down = ColorText("BOLD BLUE")
  299. var Num = ColorText("BRI GREEN")
  300. var Sym = ColorText("CYAN")
  301. // var unicodeBuff *bytes.Buffer = &bytes.Buffer{}
  302. var render = func(output *bytes.Buffer, text []byte) {
  303. output.Reset()
  304. var last *[]byte
  305. // var r Render = Render{Line: text}
  306. for _, letter := range text {
  307. if unicode.IsUpper(rune(letter)) {
  308. if last != &Up {
  309. output.Write(Up)
  310. last = &Up
  311. }
  312. // r.Append(Up, 1)
  313. } else if unicode.IsLower(rune(letter)) {
  314. if last != &Down {
  315. output.Write(Down)
  316. last = &Down
  317. }
  318. // r.Append(Down, 1)
  319. } else if unicode.IsDigit(rune(letter)) {
  320. if last != &Num {
  321. output.Write(Num)
  322. last = &Num
  323. }
  324. // r.Append(Num, 1)
  325. } else {
  326. if last != &Sym {
  327. output.Write(Sym)
  328. last = &Sym
  329. }
  330. //r.Append(Sym, 1)
  331. }
  332. output.WriteByte(letter)
  333. // output.WriteString(string(letter))
  334. }
  335. // return output.Bytes()
  336. // return r.Result
  337. }
  338. var up int
  339. var updater = func(u *bytes.Buffer) {
  340. u.Reset()
  341. fmt.Fprintf(u, "The Value: %d", up)
  342. // u.WriteString("The Value: ")
  343. // u.WriteString(strconv.Itoa(up))
  344. up++
  345. // return fmt.Sprintf("The Value: %d", up)
  346. }
  347. var line *Line = &Line{UpdateF: updater,
  348. RenderF: render,
  349. Width: 18}
  350. for i := 0; i < b.N; i++ {
  351. line.Update()
  352. line.Output()
  353. }
  354. }