github.com/mitranim/gg@v0.1.17/text_test.go (about) 1 package gg_test 2 3 import ( 4 "math" 5 "regexp" 6 "strings" 7 "testing" 8 u "unsafe" 9 10 "github.com/mitranim/gg" 11 "github.com/mitranim/gg/gtest" 12 ) 13 14 func TestTextDat(t *testing.T) { 15 defer gtest.Catch(t) 16 17 const init = `hello world` 18 var sliced string = init[:0] 19 var empty string 20 21 gtest.NotZero(init) 22 gtest.Zero(sliced) 23 gtest.Zero(empty) 24 25 gtest.NotZero(gg.TextDat(init)) 26 gtest.NotZero(gg.TextDat(sliced)) 27 gtest.Zero(gg.TextDat(empty)) 28 29 gtest.Eq(gg.TextDat(sliced), gg.TextDat(init)) 30 } 31 32 func TestToText(t *testing.T) { 33 defer gtest.Catch(t) 34 35 testToString(gg.ToText[string, []byte]) 36 testToBytes(gg.ToText[[]byte, string]) 37 38 t.Run(`between_byte_slices`, func(t *testing.T) { 39 defer gtest.Catch(t) 40 41 type Src []byte 42 43 src := Src(`one_two`)[:len(`one`)] 44 gtest.TextEq(src, Src(`one`)) 45 gtest.Len(src, 3) 46 gtest.Cap(src, 7) 47 48 type Tar []byte 49 50 gtest.Is(Src(gg.ToText[Tar](src)), src) 51 gtest.Is(gg.ToText[Src](src), src) 52 gtest.Is(gg.ToText[[]byte](src), []byte(src)) 53 gtest.Is([]byte(gg.ToText[Tar](src)), []byte(src)) 54 }) 55 } 56 57 func testToString(fun func([]byte) string) { 58 test := func(src []byte) { 59 tar := fun(src) 60 gtest.Eq(string(tar), string(src)) 61 gtest.Eq(gg.TextDat(src), gg.TextDat(tar)) 62 } 63 64 test(nil) 65 test([]byte{}) 66 test([]byte(`one`)) 67 test([]byte(`two`)) 68 test([]byte(`three`)) 69 } 70 71 func testToBytes(fun func(string) []byte) { 72 test := func(src string) { 73 tar := fun(src) 74 gtest.Eq(string(tar), string(src)) 75 gtest.Eq(gg.TextDat(src), gg.TextDat(tar)) 76 gtest.Len(tar, len(src)) 77 gtest.Cap(tar, len(src)) 78 } 79 80 test(``) 81 test(`one`) 82 test(`two`) 83 test(`three`) 84 } 85 86 func BenchmarkTextDat_string(b *testing.B) { 87 defer gtest.Catch(b) 88 89 for ind := 0; ind < b.N; ind++ { 90 gg.Nop1(gg.TextDat(`b5c298d773c048b2a88e7fe4a2bd5b0d`)) 91 } 92 } 93 94 func BenchmarkTextDat_bytes(b *testing.B) { 95 defer gtest.Catch(b) 96 97 src := []byte(`b5c298d773c048b2a88e7fe4a2bd5b0d`) 98 b.ResetTimer() 99 100 for ind := 0; ind < b.N; ind++ { 101 gg.Nop1(gg.TextDat(src)) 102 } 103 } 104 105 func BenchmarkToText_string_to_string(b *testing.B) { 106 defer gtest.Catch(b) 107 108 type Src string 109 type Out string 110 src := Src(`742af97969e845408f0261c213a4c01f`) 111 112 for ind := 0; ind < b.N; ind++ { 113 gg.ToText[Out](src) 114 } 115 } 116 117 func BenchmarkToText_string_to_bytes(b *testing.B) { 118 defer gtest.Catch(b) 119 120 type Src string 121 type Out []byte 122 src := Src(`742af97969e845408f0261c213a4c01f`) 123 124 for ind := 0; ind < b.N; ind++ { 125 gg.ToText[Out](src) 126 } 127 } 128 129 func BenchmarkToText_bytes_to_string(b *testing.B) { 130 defer gtest.Catch(b) 131 132 type Src []byte 133 type Out string 134 src := Src(`742af97969e845408f0261c213a4c01f`) 135 136 for ind := 0; ind < b.N; ind++ { 137 gg.ToText[Out](src) 138 } 139 } 140 141 func BenchmarkToText_bytes_to_bytes(b *testing.B) { 142 defer gtest.Catch(b) 143 144 type Src []byte 145 type Out []byte 146 src := Src(`742af97969e845408f0261c213a4c01f`) 147 148 for ind := 0; ind < b.N; ind++ { 149 gg.ToText[Out](src) 150 } 151 } 152 153 // TODO dedup with `TestBuf_String`. 154 func TestToString(t *testing.T) { 155 defer gtest.Catch(t) 156 157 testToString(gg.ToString[[]byte]) 158 159 t.Run(`mutation`, func(t *testing.T) { 160 defer gtest.Catch(t) 161 162 src := []byte(`abc`) 163 tar := gg.ToString(src) 164 gtest.Eq(tar, `abc`) 165 166 src[0] = 'd' 167 gtest.Eq(tar, `dbc`) 168 }) 169 } 170 171 func TestToBytes(t *testing.T) { 172 defer gtest.Catch(t) 173 174 testToBytes(gg.ToBytes[string]) 175 } 176 177 func TestTextPop(t *testing.T) { 178 defer gtest.Catch(t) 179 180 rem := `{one,two,,three}` 181 182 gtest.Eq(gg.TextPop(&rem, `,`), `{one`) 183 gtest.Eq(rem, `two,,three}`) 184 185 gtest.Eq(gg.TextPop(&rem, `,`), `two`) 186 gtest.Eq(rem, `,three}`) 187 188 gtest.Eq(gg.TextPop(&rem, `,`), ``) 189 gtest.Eq(rem, `three}`) 190 191 gtest.Eq(gg.TextPop(&rem, `,`), `three}`) 192 gtest.Eq(rem, ``) 193 } 194 195 func TestJoinAny(t *testing.T) { 196 gtest.Catch(t) 197 198 gtest.Zero(gg.JoinAny(nil, ``)) 199 gtest.Zero(gg.JoinAny([]any{}, ``)) 200 gtest.Zero(gg.JoinAny([]any{}, `_`)) 201 202 gtest.Zero(gg.JoinAny([]any{``}, ``)) 203 gtest.Zero(gg.JoinAny([]any{``, ``}, ``)) 204 gtest.Zero(gg.JoinAny([]any{``, ``, ``}, ``)) 205 206 gtest.Eq(gg.JoinAny([]any{``}, `_`), ``) 207 gtest.Eq(gg.JoinAny([]any{``, ``}, `_`), `_`) 208 gtest.Eq(gg.JoinAny([]any{``, ``, ``}, `_`), `__`) 209 210 gtest.Eq(gg.JoinAny([]any{12}, ``), `12`) 211 gtest.Eq(gg.JoinAny([]any{12}, `_`), `12`) 212 213 gtest.Eq(gg.JoinAny([]any{12, 34}, ``), `1234`) 214 gtest.Eq(gg.JoinAny([]any{12, 34}, `_`), `12_34`) 215 216 gtest.Eq(gg.JoinAny([]any{12, 34, 56}, ``), `123456`) 217 gtest.Eq(gg.JoinAny([]any{12, 34, 56}, `_`), `12_34_56`) 218 219 gtest.Eq(gg.JoinAny([]any{12, `str`}, ``), `12str`) 220 gtest.Eq(gg.JoinAny([]any{12, `str`}, `_`), `12_str`) 221 222 gtest.Eq(gg.JoinAny([]any{`one`, ``, `two`, ``, `three`}, ``), `onetwothree`) 223 gtest.Eq(gg.JoinAny([]any{`one`, ``, `two`, ``, `three`}, `_`), `one__two__three`) 224 } 225 226 func BenchmarkJoinAny(b *testing.B) { 227 src := gg.Map(gg.Span(128), gg.ToAny[int]) 228 b.ResetTimer() 229 230 for ind := 0; ind < b.N; ind++ { 231 gg.Nop1(gg.JoinAny(src, ` `)) 232 } 233 } 234 235 func TestJoinAnyOpt(t *testing.T) { 236 gtest.Catch(t) 237 238 gtest.Zero(gg.JoinAnyOpt(nil, ``)) 239 gtest.Zero(gg.JoinAnyOpt([]any{}, ``)) 240 gtest.Zero(gg.JoinAnyOpt([]any{}, `_`)) 241 242 gtest.Zero(gg.JoinAnyOpt([]any{``}, ``)) 243 gtest.Zero(gg.JoinAnyOpt([]any{``, ``}, ``)) 244 gtest.Zero(gg.JoinAnyOpt([]any{``, ``, ``}, ``)) 245 246 gtest.Zero(gg.JoinAnyOpt([]any{``}, `_`)) 247 gtest.Zero(gg.JoinAnyOpt([]any{``, ``}, `_`)) 248 gtest.Zero(gg.JoinAnyOpt([]any{``, ``, ``}, `_`)) 249 250 gtest.Eq(gg.JoinAnyOpt([]any{12}, ``), `12`) 251 gtest.Eq(gg.JoinAnyOpt([]any{12}, `_`), `12`) 252 253 gtest.Eq(gg.JoinAnyOpt([]any{12, 34}, ``), `1234`) 254 gtest.Eq(gg.JoinAnyOpt([]any{12, 34}, `_`), `12_34`) 255 256 gtest.Eq(gg.JoinAnyOpt([]any{12, 34, 56}, ``), `123456`) 257 gtest.Eq(gg.JoinAnyOpt([]any{12, 34, 56}, `_`), `12_34_56`) 258 259 gtest.Eq(gg.JoinAnyOpt([]any{12, `str`}, ``), `12str`) 260 gtest.Eq(gg.JoinAnyOpt([]any{12, `str`}, `_`), `12_str`) 261 262 gtest.Eq(gg.JoinAnyOpt([]any{`one`, ``, `two`, ``, `three`}, ``), `onetwothree`) 263 gtest.Eq(gg.JoinAnyOpt([]any{`one`, ``, `two`, ``, `three`}, `_`), `one_two_three`) 264 } 265 266 func BenchmarkJoinAnyOpt(b *testing.B) { 267 src := gg.Map(gg.Span(128), gg.ToAny[int]) 268 b.ResetTimer() 269 270 for ind := 0; ind < b.N; ind++ { 271 gg.Nop1(gg.JoinAnyOpt(src, ` `)) 272 } 273 } 274 275 func Benchmark_strings_Join(b *testing.B) { 276 src := gg.Map(gg.Span(128), gg.String[int]) 277 b.ResetTimer() 278 279 for ind := 0; ind < b.N; ind++ { 280 gg.Nop1(strings.Join(src, ` `)) 281 } 282 } 283 284 func BenchmarkJoin(b *testing.B) { 285 src := gg.Map(gg.Span(128), gg.String[int]) 286 b.ResetTimer() 287 288 for ind := 0; ind < b.N; ind++ { 289 gg.Nop1(gg.Join(src, ` `)) 290 } 291 } 292 293 func BenchmarkJoinOpt(b *testing.B) { 294 src := gg.Map(gg.Span(128), gg.String[int]) 295 b.ResetTimer() 296 297 for ind := 0; ind < b.N; ind++ { 298 gg.Nop1(gg.JoinOpt(src, ` `)) 299 } 300 } 301 302 // TODO test Unicode. 303 func TestToWords(t *testing.T) { 304 defer gtest.Catch(t) 305 306 test := func(src string, exp gg.Words) { gtest.Equal(gg.ToWords(src), exp) } 307 308 test(``, nil) 309 test(` `, nil) 310 311 test(`one`, gg.Words{`one`}) 312 test(`one two`, gg.Words{`one`, `two`}) 313 test(`one two three`, gg.Words{`one`, `two`, `three`}) 314 test(`one two three`, gg.Words{`one`, `two`, `three`}) 315 test(`One Two Three`, gg.Words{`One`, `Two`, `Three`}) 316 test(`ONE TWO THREE`, gg.Words{`ONE`, `TWO`, `THREE`}) 317 test(`one12 two34 three56`, gg.Words{`one12`, `two34`, `three56`}) 318 test(`One12 Two34 Three56`, gg.Words{`One12`, `Two34`, `Three56`}) 319 test(`ONE12 TWO34 THREE56`, gg.Words{`ONE12`, `TWO34`, `THREE56`}) 320 321 test(`one_two_three`, gg.Words{`one`, `two`, `three`}) 322 test(`one_Two_Three`, gg.Words{`one`, `Two`, `Three`}) 323 test(`One_Two_Three`, gg.Words{`One`, `Two`, `Three`}) 324 test(`ONE_TWO_THREE`, gg.Words{`ONE`, `TWO`, `THREE`}) 325 test(`one12_two34_three56`, gg.Words{`one12`, `two34`, `three56`}) 326 test(`one12_Two34_Three56`, gg.Words{`one12`, `Two34`, `Three56`}) 327 test(`One12_Two34_Three56`, gg.Words{`One12`, `Two34`, `Three56`}) 328 test(`ONE12_TWO34_THREE56`, gg.Words{`ONE12`, `TWO34`, `THREE56`}) 329 330 test(`oneTwoThree`, gg.Words{`one`, `Two`, `Three`}) 331 test(`OneTwoThree`, gg.Words{`One`, `Two`, `Three`}) 332 test(`one12Two34Three56`, gg.Words{`one12`, `Two34`, `Three56`}) 333 test(`One12Two34Three56`, gg.Words{`One12`, `Two34`, `Three56`}) 334 335 test(`one-two-three`, gg.Words{`one`, `two`, `three`}) 336 test(`one-Two-Three`, gg.Words{`one`, `Two`, `Three`}) 337 test(`One-Two-Three`, gg.Words{`One`, `Two`, `Three`}) 338 test(`ONE-TWO-THREE`, gg.Words{`ONE`, `TWO`, `THREE`}) 339 test(`one12-two34-three56`, gg.Words{`one12`, `two34`, `three56`}) 340 test(`one12-Two34-Three56`, gg.Words{`one12`, `Two34`, `Three56`}) 341 test(`One12-Two34-Three56`, gg.Words{`One12`, `Two34`, `Three56`}) 342 test(`ONE12-TWO34-THREE56`, gg.Words{`ONE12`, `TWO34`, `THREE56`}) 343 344 test(`one&two|three`, gg.Words{`one`, `two`, `three`}) 345 test(`one&two|three:four`, gg.Words{`one`, `two`, `three`, `four`}) 346 347 test(`12a33fe0-4b4a-48e5-bb90-53a068ad376b`, gg.Words{`12a33fe0`, `4b4a`, `48e5`, `bb90`, `53a068ad376b`}) 348 test(`2af310ac-f7b8-470d-b04c-98a286b8bf3f`, gg.Words{`2af310ac`, `f7b8`, `470d`, `b04c`, `98a286b8bf3f`}) 349 test(`154cd2d1-fade-4cab-ab01-a7df8b760569`, gg.Words{`154cd2d1`, `fade`, `4cab`, `ab01`, `a7df8b760569`}) 350 test(`c7ddacf8-4117-49c3-8a7e-a3c9627dc199`, gg.Words{`c7ddacf8`, `4117`, `49c3`, `8a7e`, `a3c9627dc199`}) 351 test(`cf1a86ed-6db7-4c6f-aad3-c8e6cb1cb2f2`, gg.Words{`cf1a86ed`, `6db7`, `4c6f`, `aad3`, `c8e6cb1cb2f2`}) 352 test(`78437a9e-45fd-4007-8a04-bace0147df30`, gg.Words{`78437a9e`, `45fd`, `4007`, `8a04`, `bace0147df30`}) 353 } 354 355 // TODO test Unicode. 356 func TestWords(t *testing.T) { 357 defer gtest.Catch(t) 358 359 src := func() gg.Words { return gg.Words{`one`, `two`, `three`} } 360 361 gtest.Equal(gg.ToWords(`one two`).Lower(), gg.Words{`one`, `two`}) 362 gtest.Equal(gg.ToWords(`One Two`).Lower(), gg.Words{`one`, `two`}) 363 gtest.Equal(gg.ToWords(`ONE TWO`).Lower(), gg.Words{`one`, `two`}) 364 365 gtest.Equal(src().Lower(), gg.Words{`one`, `two`, `three`}) 366 gtest.Equal(src().Upper(), gg.Words{`ONE`, `TWO`, `THREE`}) 367 gtest.Equal(src().Title(), gg.Words{`One`, `Two`, `Three`}) 368 gtest.Equal(src().Sentence(), gg.Words{`One`, `two`, `three`}) 369 gtest.Equal(src().Camel(), gg.Words{`one`, `Two`, `Three`}) 370 371 gtest.Eq(src().Dense(), `onetwothree`) 372 gtest.Eq(src().Spaced(), `one two three`) 373 gtest.Eq(src().Snake(), `one_two_three`) 374 gtest.Eq(src().Kebab(), `one-two-three`) 375 gtest.Eq(src().Comma(), `one,two,three`) 376 gtest.Eq(src().Piped(), `one|two|three`) 377 378 gtest.Eq(src().Lower().Dense(), `onetwothree`) 379 gtest.Eq(src().Lower().Spaced(), `one two three`) 380 gtest.Eq(src().Lower().Snake(), `one_two_three`) 381 gtest.Eq(src().Lower().Kebab(), `one-two-three`) 382 gtest.Eq(src().Lower().Comma(), `one,two,three`) 383 gtest.Eq(src().Lower().Piped(), `one|two|three`) 384 385 gtest.Eq(src().Upper().Dense(), `ONETWOTHREE`) 386 gtest.Eq(src().Upper().Spaced(), `ONE TWO THREE`) 387 gtest.Eq(src().Upper().Snake(), `ONE_TWO_THREE`) 388 gtest.Eq(src().Upper().Kebab(), `ONE-TWO-THREE`) 389 gtest.Eq(src().Upper().Comma(), `ONE,TWO,THREE`) 390 gtest.Eq(src().Upper().Piped(), `ONE|TWO|THREE`) 391 392 gtest.Eq(src().Title().Dense(), `OneTwoThree`) 393 gtest.Eq(src().Title().Spaced(), `One Two Three`) 394 gtest.Eq(src().Title().Snake(), `One_Two_Three`) 395 gtest.Eq(src().Title().Kebab(), `One-Two-Three`) 396 gtest.Eq(src().Title().Comma(), `One,Two,Three`) 397 gtest.Eq(src().Title().Piped(), `One|Two|Three`) 398 399 gtest.Eq(src().Sentence().Dense(), `Onetwothree`) 400 gtest.Eq(src().Sentence().Spaced(), `One two three`) 401 gtest.Eq(src().Sentence().Snake(), `One_two_three`) 402 gtest.Eq(src().Sentence().Kebab(), `One-two-three`) 403 gtest.Eq(src().Sentence().Comma(), `One,two,three`) 404 gtest.Eq(src().Sentence().Piped(), `One|two|three`) 405 406 gtest.Eq(src().Camel().Dense(), `oneTwoThree`) 407 gtest.Eq(src().Camel().Spaced(), `one Two Three`) 408 gtest.Eq(src().Camel().Snake(), `one_Two_Three`) 409 gtest.Eq(src().Camel().Kebab(), `one-Two-Three`) 410 gtest.Eq(src().Camel().Comma(), `one,Two,Three`) 411 gtest.Eq(src().Camel().Piped(), `one|Two|Three`) 412 } 413 414 func BenchmarkReWord_init(b *testing.B) { 415 src := gg.ReWord.Get().String() 416 417 for ind := 0; ind < b.N; ind++ { 418 regexp.MustCompile(src) 419 } 420 } 421 422 func BenchmarkReWord_reuse(b *testing.B) { 423 gg.Nop1(gg.ReWord.Get()) 424 425 for ind := 0; ind < b.N; ind++ { 426 gg.Nop1(gg.ReWord.Get()) 427 } 428 } 429 430 func TestSplitLines(t *testing.T) { 431 defer gtest.Catch(t) 432 433 var Split = gg.SplitLines[string] 434 435 gtest.Empty(Split(``)) 436 gtest.Equal(Split(` `), []string{` `}) 437 438 gtest.Equal(Split("\n"), []string{``, ``}) 439 gtest.Equal(Split("\r"), []string{``, ``}) 440 gtest.Equal(Split("\r\n"), []string{``, ``}) 441 442 gtest.Equal(Split("one"), []string{`one`}) 443 gtest.Equal(Split("one\n"), []string{`one`, ``}) 444 gtest.Equal(Split("one\r"), []string{`one`, ``}) 445 gtest.Equal(Split("one\r\n"), []string{`one`, ``}) 446 447 gtest.Equal(Split("\none"), []string{``, `one`}) 448 gtest.Equal(Split("\rone"), []string{``, `one`}) 449 gtest.Equal(Split("\r\none"), []string{``, `one`}) 450 451 gtest.Equal(Split("\none\n"), []string{``, `one`, ``}) 452 gtest.Equal(Split("\rone\r"), []string{``, `one`, ``}) 453 gtest.Equal(Split("\r\none\r\n"), []string{``, `one`, ``}) 454 455 gtest.Equal(Split("one\ntwo"), []string{`one`, `two`}) 456 gtest.Equal(Split("one\rtwo"), []string{`one`, `two`}) 457 gtest.Equal(Split("one\r\ntwo"), []string{`one`, `two`}) 458 459 gtest.Equal(Split("one\ntwo\n"), []string{`one`, `two`, ``}) 460 gtest.Equal(Split("one\rtwo\r"), []string{`one`, `two`, ``}) 461 gtest.Equal(Split("one\r\ntwo\r\n"), []string{`one`, `two`, ``}) 462 463 gtest.Equal(Split("\none\ntwo"), []string{``, `one`, `two`}) 464 gtest.Equal(Split("\rone\rtwo"), []string{``, `one`, `two`}) 465 gtest.Equal(Split("\r\none\r\ntwo"), []string{``, `one`, `two`}) 466 467 gtest.Equal(Split("\none\ntwo\n"), []string{``, `one`, `two`, ``}) 468 gtest.Equal(Split("\rone\rtwo\r"), []string{``, `one`, `two`, ``}) 469 gtest.Equal(Split("\r\none\r\ntwo\r\n"), []string{``, `one`, `two`, ``}) 470 } 471 472 func BenchmarkSplitLines(b *testing.B) { 473 defer gtest.Catch(b) 474 src := makeLines() 475 b.ResetTimer() 476 477 for ind := 0; ind < b.N; ind++ { 478 gg.Nop1(gg.SplitLines(src)) 479 } 480 } 481 482 func makeLines() []byte { 483 var buf gg.Buf 484 buf.GrowLen(1024 * 1024) 485 for ind := range buf { 486 if ind%64 == 0 { 487 buf[ind] = '\n' 488 } else { 489 buf[ind] = ' ' 490 } 491 } 492 return buf 493 } 494 495 func TestSplitLines2(t *testing.T) { 496 defer gtest.Catch(t) 497 498 test := func(src, oneExp, twoExp string, sizeExp int) { 499 one, two, size := gg.SplitLines2(src) 500 gtest.Eq([2]string{one, two}, [2]string{oneExp, twoExp}) 501 gtest.Eq(size, sizeExp) 502 } 503 504 test(``, ``, ``, 0) 505 test("one\n", `one`, ``, 1) 506 test("one\ntwo", `one`, `two`, 1) 507 test("one\r\ntwo", `one`, `two`, 2) 508 test("one\rtwo", `one`, `two`, 1) 509 test("\ntwo", ``, `two`, 1) 510 test("\r\ntwo", ``, `two`, 2) 511 test("\rtwo", ``, `two`, 1) 512 test("one\ntwo\nthree", `one`, "two\nthree", 1) 513 } 514 515 func TestTextCut_ours(t *testing.T) { 516 defer gtest.Catch(t) 517 testTextCut(gg.TextCut[string]) 518 } 519 520 func TestTextCut_alternate(t *testing.T) { 521 defer gtest.Catch(t) 522 testTextCut(TextCutRuneSlice[string]) 523 } 524 525 func testTextCut(fun func(string, int, int) string) { 526 const src = `🐒🐴🦖🦔🐲🐈` 527 528 gtest.Zero(fun(src, 0, 0)) 529 gtest.Eq(fun(src, 0, 1), `🐒`) 530 gtest.Eq(fun(src, 0, 2), `🐒🐴`) 531 gtest.Eq(fun(src, 0, 3), `🐒🐴🦖`) 532 gtest.Eq(fun(src, 0, 4), `🐒🐴🦖🦔`) 533 gtest.Eq(fun(src, 0, 5), `🐒🐴🦖🦔🐲`) 534 gtest.Eq(fun(src, 0, 6), `🐒🐴🦖🦔🐲🐈`) 535 gtest.Eq(fun(src, 0, 7), `🐒🐴🦖🦔🐲🐈`) 536 gtest.Eq(fun(src, 0, 8), `🐒🐴🦖🦔🐲🐈`) 537 538 gtest.Eq(fun(src, -1, 1), `🐒`) 539 gtest.Eq(fun(src, -1, 6), `🐒🐴🦖🦔🐲🐈`) 540 541 gtest.Zero(fun(src, 1, 0)) 542 gtest.Zero(fun(src, 1, 1)) 543 gtest.Eq(fun(src, 1, 2), `🐴`) 544 gtest.Eq(fun(src, 1, 6), `🐴🦖🦔🐲🐈`) 545 546 gtest.Eq(fun(`one two three four`, 4, 13), `two three`) 547 } 548 549 // Alternate implementation for comparison with ours. 550 func TextCutRuneSlice[A ~string](src A, start, end int) A { 551 if !(end > start) { 552 return `` 553 } 554 555 runes := []rune(src) 556 size := len(runes) 557 558 if start < 0 { 559 start = 0 560 } else if start > size { 561 start = size 562 } 563 if end < 0 { 564 end = 0 565 } else if end > size { 566 end = size 567 } 568 569 return A(runes[start:end]) 570 } 571 572 func BenchmarkTextCut_ours(b *testing.B) { 573 const src = `🐒🐴🦖🦔🐲🐈` 574 575 for ind := 0; ind < b.N; ind++ { 576 for start := range gg.Iter(3) { 577 start-- 578 for end := range gg.Iter(6) { 579 gg.Nop1(gg.TextCut(src, start, end)) 580 } 581 } 582 } 583 } 584 585 func BenchmarkTextCut_alternate(b *testing.B) { 586 const src = `🐒🐴🦖🦔🐲🐈` 587 588 for ind := 0; ind < b.N; ind++ { 589 for start := range gg.Iter(3) { 590 start-- 591 for end := range gg.Iter(6) { 592 gg.Nop1(TextCutRuneSlice(src, start, end)) 593 } 594 } 595 } 596 } 597 598 func TestStr(t *testing.T) { 599 defer gtest.Catch(t) 600 601 gtest.Zero(gg.Str()) 602 gtest.Zero(gg.Str(nil)) 603 gtest.Zero(gg.Str(nil, nil)) 604 gtest.Zero(gg.Str(``)) 605 gtest.Zero(gg.Str(``, nil)) 606 gtest.Zero(gg.Str(``, nil, ``)) 607 gtest.Zero(gg.Str(``, nil, ``, nil)) 608 609 gtest.Eq(gg.Str(0), `0`) 610 gtest.Eq(gg.Str(0, 0), `00`) 611 gtest.Eq(gg.Str(0, 10), `010`) 612 gtest.Eq(gg.Str(0, 10, 20), `01020`) 613 gtest.Eq(gg.Str(`one`), `one`) 614 gtest.Eq(gg.Str(`one`, ``), `one`) 615 gtest.Eq(gg.Str(`one`, ``, `two`), `onetwo`) 616 gtest.Eq(gg.Str(`one`, `_`, `two`), `one_two`) 617 gtest.Eq(gg.Str(10, `_`, 20), `10_20`) 618 } 619 620 func BenchmarkStr_0(b *testing.B) { 621 for ind := 0; ind < b.N; ind++ { 622 gg.Str() 623 } 624 } 625 626 func BenchmarkStr_1(b *testing.B) { 627 for ind := 0; ind < b.N; ind++ { 628 gg.Str(`one`) 629 } 630 } 631 632 func BenchmarkStr_2(b *testing.B) { 633 for ind := 0; ind < b.N; ind++ { 634 gg.Str(`one`, `two`) 635 } 636 } 637 638 func BenchmarkStr_3(b *testing.B) { 639 for ind := 0; ind < b.N; ind++ { 640 gg.Str(`one`, `two`, `three`) 641 } 642 } 643 644 func TestTextEllipsis(t *testing.T) { 645 defer gtest.Catch(t) 646 647 const src = `🐒🐴🦖🦔🐲🐈` 648 649 gtest.Zero(gg.TextEllipsis(src, 0)) 650 gtest.Eq(gg.TextEllipsis(src, 1), `…`) 651 gtest.Eq(gg.TextEllipsis(src, 2), `🐒…`) 652 gtest.Eq(gg.TextEllipsis(src, 3), `🐒🐴…`) 653 gtest.Eq(gg.TextEllipsis(src, 4), `🐒🐴🦖…`) 654 gtest.Eq(gg.TextEllipsis(src, 5), `🐒🐴🦖🦔…`) 655 gtest.Eq(gg.TextEllipsis(src, 6), `🐒🐴🦖🦔🐲🐈`) 656 gtest.Eq(gg.TextEllipsis(src, 7), `🐒🐴🦖🦔🐲🐈`) 657 gtest.Eq(gg.TextEllipsis(src, 8), `🐒🐴🦖🦔🐲🐈`) 658 gtest.Eq(gg.TextEllipsis(src, 9), `🐒🐴🦖🦔🐲🐈`) 659 gtest.Eq(gg.TextEllipsis(src, math.MaxUint), `🐒🐴🦖🦔🐲🐈`) 660 } 661 662 func BenchmarkTextEllipsis_changed(b *testing.B) { 663 for ind := 0; ind < b.N; ind++ { 664 gg.TextEllipsis(`🐒🐴🦖🦔🐲🐈`, 4) 665 } 666 } 667 668 func BenchmarkTextEllipsis_unchanged(b *testing.B) { 669 for ind := 0; ind < b.N; ind++ { 670 gg.TextEllipsis(`🐒🐴🦖🦔🐲🐈`, 6) 671 } 672 } 673 674 func BenchmarkTextTrunc_changed(b *testing.B) { 675 for ind := 0; ind < b.N; ind++ { 676 gg.TextTrunc(`🐒🐴🦖🦔🐲🐈`, 4) 677 } 678 } 679 680 func BenchmarkTextTrunc_unchanged(b *testing.B) { 681 for ind := 0; ind < b.N; ind++ { 682 gg.TextTrunc(`🐒🐴🦖🦔🐲🐈`, 6) 683 } 684 } 685 686 func TestTextHeadChar(t *testing.T) { 687 defer gtest.Catch(t) 688 689 test := func(src string, valExp rune, sizeExp int) { 690 val, size := gg.TextHeadChar(src) 691 gtest.Eq(val, valExp, `matching char`) 692 gtest.Eq(size, sizeExp, `matching size`) 693 } 694 695 test(``, 0, 0) 696 test(`one`, 'o', 1) 697 test(`🐒🐴🦖🦔🐲🐈`, '🐒', 4) 698 } 699 700 func TestAppendNewlineOpt(t *testing.T) { 701 defer gtest.Catch(t) 702 703 testAppendNewlineOptSame(``) 704 testAppendNewlineOptSame([]byte(nil)) 705 testAppendNewlineOptSame([]byte{}) 706 testAppendNewlineOptSame("\n") 707 testAppendNewlineOptSame("one\n") 708 testAppendNewlineOptSame("one\r") 709 testAppendNewlineOptSame("one\r\n") 710 testAppendNewlineOptSame([]byte("\n")) 711 testAppendNewlineOptSame([]byte("one\n")) 712 testAppendNewlineOptSame([]byte("one\r")) 713 testAppendNewlineOptSame([]byte("one\r\n")) 714 715 gtest.TextEq(gg.AppendNewlineOpt(`one`), "one\n") 716 gtest.TextEq(gg.AppendNewlineOpt([]byte(`one`)), []byte("one\n")) 717 718 { 719 src := []byte("one two") 720 tar := src[:len(`one`)] 721 out := gg.AppendNewlineOpt(tar) 722 723 gtest.TextEq(src, []byte("one\ntwo")) 724 gtest.TextEq(out, []byte("one\n")) 725 gtest.Eq(u.SliceData(src), u.SliceData(tar)) 726 gtest.Eq(u.SliceData(src), u.SliceData(out)) 727 } 728 } 729 730 func testAppendNewlineOptSame[A gg.Text](src A) { 731 gtest.Is(gg.AppendNewlineOpt(src), src) 732 }