github.com/schollz/progressbar/v3@v3.14.2/progressbar_test.go (about) 1 package progressbar 2 3 import ( 4 "bytes" 5 "crypto/md5" 6 "encoding/hex" 7 "fmt" 8 "io" 9 "net/http" 10 "os" 11 "strings" 12 "sync" 13 "testing" 14 "time" 15 16 "github.com/stretchr/testify/assert" 17 ) 18 19 func TestMain(m *testing.M) { 20 termWidth = func() (int, error) { 21 return 0, os.ErrPermission 22 } 23 os.Exit(m.Run()) 24 } 25 26 func BenchmarkRender(b *testing.B) { 27 bar := NewOptions64(100000000, 28 OptionSetWriter(os.Stderr), 29 OptionShowIts(), 30 ) 31 for i := 0; i < b.N; i++ { 32 bar.Add(1) 33 } 34 } 35 36 func ExampleProgressBar() { 37 bar := New(100) 38 bar.Add(10) 39 // Output: 40 // 10% |████ | [0s:0s] 41 } 42 43 func ExampleProgressBar_Set() { 44 bar := New(100) 45 bar.Set(10) 46 // Output: 47 // 10% |████ | [0s:0s] 48 } 49 50 func ExampleProgressBar_Set64() { 51 bar := New(100) 52 bar.Set64(10) 53 // Output: 54 // 10% |████ | [0s:0s] 55 } 56 57 func ExampleProgressBar_basic() { 58 bar := NewOptions(100, OptionSetWidth(10)) 59 bar.Reset() 60 time.Sleep(1 * time.Second) 61 bar.Add(10) 62 // Output: 63 // 10% |█ | [1s:9s] 64 } 65 66 func ExampleProgressBar_invisible() { 67 bar := NewOptions(100, OptionSetWidth(10), OptionSetRenderBlankState(true), OptionSetVisibility(false)) 68 bar.Reset() 69 fmt.Println("hello, world") 70 time.Sleep(1 * time.Second) 71 bar.Add(10) 72 // Output: 73 // hello, world 74 } 75 76 func ExampleOptionThrottle() { 77 bar := NewOptions(100, OptionSetWidth(10), OptionThrottle(100*time.Millisecond)) 78 bar.Reset() 79 bar.Add(5) 80 time.Sleep(150 * time.Millisecond) 81 bar.Add(5) 82 bar.Add(10) 83 // Output: 84 // 10% |█ | [0s:1s] 85 } 86 87 func ExampleOptionClearOnFinish() { 88 bar := NewOptions(100, OptionSetWidth(10), OptionClearOnFinish()) 89 bar.Reset() 90 bar.Finish() 91 fmt.Println("Finished") 92 // Output: 93 // Finished 94 } 95 96 func ExampleProgressBar_Finish() { 97 bar := NewOptions(100, OptionSetWidth(10)) 98 bar.Finish() 99 // Output: 100 // 100% |██████████| 101 } 102 103 func Example_xOutOfY() { 104 bar := NewOptions(100, OptionSetPredictTime(true)) 105 106 for i := 0; i < 100; i++ { 107 bar.Add(1) 108 time.Sleep(1 * time.Millisecond) 109 } 110 } 111 112 func ExampleOptionShowIts_count() { 113 bar := NewOptions(100, OptionSetWidth(10), OptionShowIts(), OptionShowCount()) 114 bar.Reset() 115 time.Sleep(1 * time.Second) 116 bar.Add(10) 117 // Output: 118 // 10% |█ | (10/100, 10 it/s) [1s:9s] 119 } 120 121 func ExampleOptionShowIts() { 122 bar := NewOptions(100, OptionSetWidth(10), OptionShowIts(), OptionSetPredictTime(false)) 123 bar.Reset() 124 time.Sleep(1 * time.Second) 125 bar.Add(10) 126 // Output: 127 // 10% |█ | (10 it/s) 128 } 129 130 func ExampleOptionShowCount_minuscule() { 131 bar := NewOptions(10000, OptionSetWidth(10), OptionShowCount(), OptionSetPredictTime(false)) 132 bar.Add(1) 133 // Output: 134 // 0% | | (1/10000) 135 } 136 137 func ExampleOptionSetPredictTime() { 138 bar := NewOptions(100, OptionSetWidth(10), OptionSetPredictTime(false)) 139 _ = bar.Add(10) 140 // Output: 141 // 10% |█ | 142 } 143 144 func ExampleOptionShowDescriptionAtLineEnd() { 145 bar := NewOptions(100, OptionSetWidth(10), OptionShowDescriptionAtLineEnd(), OptionSetDescription("hello")) 146 _ = bar.Add(10) 147 // Output: 148 // 10% |█ | [0s:0s] hello 149 } 150 151 func ExampleOptionShowDescriptionAtLineEnd_spinner() { 152 bar := NewOptions(-1, OptionSetWidth(10), OptionShowDescriptionAtLineEnd(), OptionSetDescription("hello")) 153 _ = bar.Add(1) 154 // Output: 155 // | [0s] hello 156 } 157 158 func ExampleDefault() { 159 bar := Default(100) 160 for i := 0; i < 50; i++ { 161 bar.Add(1) 162 time.Sleep(10 * time.Millisecond) 163 } 164 // Output: 165 // 166 } 167 168 func ExampleProgressBar_ChangeMax() { 169 bar := NewOptions(100, OptionSetWidth(10), OptionSetPredictTime(false)) 170 bar.ChangeMax(50) 171 bar.Add(50) 172 // Output: 173 // 100% |██████████| 174 } 175 176 func ExampleOptionShowIts_spinner() { 177 /* 178 Spinner test with iteration count and iteration rate 179 */ 180 bar := NewOptions(-1, 181 OptionSetWidth(10), 182 OptionShowIts(), 183 OptionShowCount(), 184 ) 185 bar.Reset() 186 time.Sleep(1 * time.Second) 187 bar.Add(5) 188 189 // Output: 190 // - (5/-, 5 it/s) [1s] 191 } 192 193 func TestSpinnerType(t *testing.T) { 194 bar := NewOptions(-1, 195 OptionSetWidth(10), 196 OptionSetDescription("indeterminate spinner"), 197 OptionShowIts(), 198 OptionShowCount(), 199 OptionSpinnerType(9), 200 ) 201 bar.Reset() 202 for i := 0; i < 10; i++ { 203 time.Sleep(120 * time.Millisecond) 204 err := bar.Add(1) 205 if err != nil { 206 t.Errorf("Successfully tested one spinner option can be used.") 207 } 208 } 209 if false { 210 t.Errorf("error") 211 } 212 } 213 214 func TestSpinnerCustom(t *testing.T) { 215 bar := NewOptions(-1, 216 OptionSetWidth(10), 217 OptionSetDescription("indeterminate spinner"), 218 OptionShowIts(), 219 OptionShowCount(), 220 OptionSpinnerCustom([]string{"🐰", "🐰", "🥕", "🥕"}), 221 ) 222 bar.Reset() 223 for i := 0; i < 10; i++ { 224 time.Sleep(120 * time.Millisecond) 225 err := bar.Add(1) 226 if err != nil { 227 t.Errorf("Successfully tested one spinner option can be used.") 228 } 229 } 230 if false { 231 t.Errorf("error") 232 } 233 } 234 235 func TestSpinnerTypeAndCustom(t *testing.T) { 236 bar := NewOptions(-1, 237 OptionSetWidth(10), 238 OptionSetDescription("indeterminate spinner"), 239 OptionShowIts(), 240 OptionShowCount(), 241 OptionSpinnerCustom([]string{"🐰", "🐰", "🥕", "🥕"}), 242 OptionSpinnerType(9), 243 ) 244 bar.Reset() 245 for i := 0; i < 10; i++ { 246 time.Sleep(120 * time.Millisecond) 247 err := bar.Add(1) 248 if err == nil { 249 t.Errorf("Successfully tested both spinner options cannot be used together.") 250 } 251 } 252 } 253 254 func Test_IsFinished(t *testing.T) { 255 isCalled := false 256 bar := NewOptions(72, OptionOnCompletion(func() { 257 isCalled = true 258 })) 259 260 // Test1: If bar is not fully completed. 261 bar.Add(5) 262 if bar.IsFinished() || isCalled { 263 t.Errorf("Successfully tested bar is not yet finished.") 264 } 265 266 // Test2: Bar fully completed. 267 bar.Add(67) 268 if !bar.IsFinished() || !isCalled { 269 t.Errorf("Successfully tested bar is finished.") 270 } 271 272 // Test3: If increases maximum bytes error should be thrown and 273 // bar finished will remain false. 274 bar.Reset() 275 err := bar.Add(73) 276 if err == nil || bar.IsFinished() { 277 t.Errorf("Successfully got error when bytes increases max bytes, bar finished: %v", bar.IsFinished()) 278 } 279 } 280 281 func ExampleOptionShowBytes_spinner() { 282 /* 283 Spinner test with iterations and count 284 */ 285 bar := NewOptions(-1, 286 OptionSetWidth(10), 287 OptionShowBytes(true), 288 ) 289 290 bar.Reset() 291 time.Sleep(1 * time.Second) 292 // since 10 is the width and we don't know the max bytes 293 // it will do a infinite scrolling. 294 bar.Add(11) 295 296 // Output: 297 // - (11 B/s) [1s] 298 } 299 300 func TestBarSlowAdd(t *testing.T) { 301 buf := strings.Builder{} 302 bar := NewOptions(100, OptionSetWidth(10), OptionShowIts(), OptionSetWriter(&buf)) 303 bar.Reset() 304 time.Sleep(3 * time.Second) 305 bar.Add(1) 306 if !strings.Contains(buf.String(), "1%") { 307 t.Errorf("wrong string: %s", buf.String()) 308 } 309 if !strings.Contains(buf.String(), "20 it/min") { 310 t.Errorf("wrong string: %s", buf.String()) 311 } 312 if !strings.Contains(buf.String(), "[3s:") { 313 t.Errorf("wrong string: %s", buf.String()) 314 } 315 // Output: 316 // 1% | | (20 it/min) [3s:4m57s] 317 } 318 319 func TestBarSmallBytes(t *testing.T) { 320 buf := strings.Builder{} 321 bar := NewOptions64(100000000, OptionShowBytes(true), OptionShowCount(), OptionSetWidth(10), OptionSetWriter(&buf)) 322 for i := 1; i < 10; i++ { 323 time.Sleep(100 * time.Millisecond) 324 bar.Add(1000) 325 } 326 if !strings.Contains(buf.String(), "9.0 kB/100 MB") { 327 t.Errorf("wrong string: %s", buf.String()) 328 } 329 for i := 1; i < 10; i++ { 330 time.Sleep(10 * time.Millisecond) 331 bar.Add(1000000) 332 } 333 if !strings.Contains(buf.String(), "9.0/100 MB") { 334 t.Errorf("wrong string: %s", buf.String()) 335 } 336 } 337 338 func TestBarFastBytes(t *testing.T) { 339 buf := strings.Builder{} 340 bar := NewOptions64(1e8, OptionShowBytes(true), OptionShowCount(), OptionSetWidth(10), OptionSetWriter(&buf)) 341 time.Sleep(time.Millisecond) 342 bar.Add(1e7) 343 if !strings.Contains(buf.String(), " GB/s)") { 344 t.Errorf("wrong string: %s", buf.String()) 345 } 346 } 347 348 func TestBar(t *testing.T) { 349 bar := New(0) 350 if err := bar.Add(1); err == nil { 351 t.Error("should have an error for 0 bar") 352 } 353 bar = New(10) 354 if err := bar.Add(11); err == nil { 355 t.Error("should have an error for adding > bar") 356 } 357 } 358 359 func TestState(t *testing.T) { 360 bar := NewOptions(100, OptionSetWidth(10)) 361 bar.Reset() 362 time.Sleep(1 * time.Second) 363 bar.Add(10) 364 s := bar.State() 365 if s.CurrentPercent != 0.1 { 366 t.Error(s) 367 } 368 } 369 370 func ExampleOptionSetRenderBlankState() { 371 NewOptions(10, OptionSetWidth(10), OptionSetRenderBlankState(true)) 372 // Output: 373 // 0% | | [0s:0s] 374 } 375 376 func TestBasicSets(t *testing.T) { 377 b := NewOptions( 378 999, 379 OptionSetWidth(888), 380 OptionSetRenderBlankState(true), 381 OptionSetWriter(io.Discard), // suppressing output for this test 382 ) 383 384 tc := b.config 385 386 if tc.max != 999 { 387 t.Errorf("Expected %s to be %d, instead I got %d\n%+v", "max", 999, tc.max, b) 388 } 389 390 if tc.width != 888 { 391 t.Errorf("Expected %s to be %d, instead I got %d\n%+v", "width", 999, tc.max, b) 392 } 393 394 if !tc.renderWithBlankState { 395 t.Errorf("Expected %s to be %t, instead I got %t\n%+v", "renderWithBlankState", true, tc.renderWithBlankState, b) 396 } 397 } 398 399 func TestOptionSetTheme(t *testing.T) { 400 buf := strings.Builder{} 401 bar := NewOptions( 402 10, 403 OptionSetTheme(Theme{Saucer: "#", SaucerPadding: "-", BarStart: ">", BarEnd: "<"}), 404 OptionSetWidth(10), 405 OptionSetWriter(&buf), 406 ) 407 bar.Add(5) 408 result := strings.TrimSpace(buf.String()) 409 expect := "50% >#####-----< [0s:0s]" 410 if result != expect { 411 t.Errorf("Render miss-match\nResult: '%s'\nExpect: '%s'\n%+v", result, expect, bar) 412 } 413 } 414 415 // TestOptionSetPredictTime ensures that when predict time is turned off, the progress 416 // bar is showing the total steps completed of the given max, otherwise the predicted 417 // time in seconds is specified. 418 func TestOptionSetPredictTime(t *testing.T) { 419 buf := strings.Builder{} 420 bar := NewOptions( 421 10, 422 OptionSetPredictTime(false), 423 OptionSetWidth(10), 424 OptionSetWriter(&buf), 425 ) 426 427 _ = bar.Add(2) 428 result := strings.TrimSpace(buf.String()) 429 expect := "20% |██ |" 430 431 if result != expect { 432 t.Errorf("Render miss-match\nResult: '%s'\nExpect: '%s'\n%+v", result, expect, bar) 433 } 434 435 bar.Reset() 436 bar.config.predictTime = true 437 buf.Reset() 438 439 _ = bar.Add(7) 440 result = strings.TrimSpace(buf.String()) 441 expect = "70% |███████ | [0s:0s]" 442 443 if result != expect { 444 t.Errorf("Render miss-match\nResult: '%s'\nExpect: '%s'\n%+v", result, expect, bar) 445 } 446 } 447 448 func TestOptionSetElapsedTime_spinner(t *testing.T) { 449 buf := strings.Builder{} 450 bar := NewOptions(-1, 451 OptionSetWidth(10), 452 OptionSetWriter(&buf), 453 OptionShowIts(), 454 OptionShowCount(), 455 OptionSetElapsedTime(false), 456 ) 457 bar.Reset() 458 time.Sleep(1 * time.Second) 459 bar.Add(5) 460 result := strings.TrimSpace(buf.String()) 461 expect := "- (5/-, 5 it/s)" 462 if result != expect { 463 t.Errorf("Render miss-match\nResult: '%s'\nExpect: '%s'\n%+v", result, expect, bar) 464 } 465 } 466 467 func TestShowElapsedTimeOnFinish(t *testing.T) { 468 buf := strings.Builder{} 469 bar := NewOptions(10, 470 OptionShowElapsedTimeOnFinish(), 471 OptionSetWidth(10), 472 OptionSetWriter(&buf), 473 ) 474 bar.Reset() 475 time.Sleep(3 * time.Second) 476 bar.Add(10) 477 result := strings.TrimSpace(buf.String()) 478 expect := "100% |██████████| [3s]" 479 if result != expect { 480 t.Errorf("Render miss-match\nResult: '%s'\nExpect: '%s'\n%+v", result, expect, bar) 481 } 482 } 483 484 func TestSpinnerState(t *testing.T) { 485 bar := NewOptions( 486 -1, 487 OptionSetWidth(100), 488 ) 489 bar.Reset() 490 time.Sleep(1 * time.Second) 491 bar.Add(10) 492 493 state := bar.State() 494 if state.Max != -1 { 495 t.Errorf("Max mismatched gotMax %d wantMax %d", state.Max, -1) 496 } 497 if state.CurrentNum != 10 { 498 t.Errorf("Number mismatched gotNum %d wantNum %d", state.CurrentNum, 10) 499 } 500 if state.CurrentBytes != 10.0 { 501 t.Errorf("Number of bytes mismatched gotBytes %f wantBytes %f", state.CurrentBytes, 10.0) 502 } 503 if state.CurrentPercent != 0.1 { 504 t.Errorf("Percent of bar mismatched got %f want %f", state.CurrentPercent, 0.1) 505 } 506 507 kbPerSec := fmt.Sprintf("%2.2f", state.KBsPerSecond) 508 if kbPerSec != "0.01" { 509 t.Errorf("Speed mismatched got %s want %s", kbPerSec, "0.01") 510 } 511 } 512 513 func TestReaderToBuffer(t *testing.T) { 514 if testing.Short() { 515 t.SkipNow() 516 } 517 518 urlToGet := "https://dl.google.com/go/go1.14.1.src.tar.gz" 519 req, err := http.NewRequest("GET", urlToGet, nil) 520 assert.Nil(t, err) 521 resp, err := http.DefaultClient.Do(req) 522 assert.Nil(t, err) 523 defer resp.Body.Close() 524 525 buf := new(bytes.Buffer) 526 bar := NewOptions(int(resp.ContentLength), OptionShowBytes(true), OptionShowCount()) 527 out := io.MultiWriter(buf, bar) 528 _, err = io.Copy(out, resp.Body) 529 assert.Nil(t, err) 530 531 md5, err := md5sum(buf) 532 assert.Nil(t, err) 533 assert.Equal(t, "d441819a800f8c90825355dfbede7266", md5) 534 } 535 536 func TestReaderToFile(t *testing.T) { 537 if testing.Short() { 538 t.SkipNow() 539 } 540 541 urlToGet := "https://dl.google.com/go/go1.14.1.src.tar.gz" 542 req, err := http.NewRequest("GET", urlToGet, nil) 543 assert.Nil(t, err) 544 resp, err := http.DefaultClient.Do(req) 545 assert.Nil(t, err) 546 defer resp.Body.Close() 547 548 f, err := os.CreateTemp("", "progressbar_testfile") 549 if err != nil { 550 t.Fatal() 551 } 552 defer os.Remove(f.Name()) 553 defer f.Close() 554 555 realStdout := os.Stdout 556 defer func() { os.Stdout = realStdout }() 557 r, fakeStdout, err := os.Pipe() 558 if err != nil { 559 t.Fatal(err) 560 } 561 os.Stdout = fakeStdout 562 563 bar := DefaultBytes(resp.ContentLength) 564 out := io.MultiWriter(f, bar) 565 _, err = io.Copy(out, resp.Body) 566 assert.Nil(t, err) 567 f.Sync() 568 f.Seek(0, 0) 569 570 if err := fakeStdout.Close(); err != nil { 571 t.Fatal(err) 572 } 573 574 b, err := io.ReadAll(r) 575 if err != nil { 576 t.Fatal(err) 577 } 578 579 if err := r.Close(); err != nil { 580 t.Fatal(err) 581 } 582 583 assert.Equal(t, "", string(b)) 584 585 md5, err := md5sum(f) 586 assert.Nil(t, err) 587 assert.Equal(t, "d441819a800f8c90825355dfbede7266", md5) 588 } 589 590 func TestReaderToFileUnknownLength(t *testing.T) { 591 if testing.Short() { 592 t.SkipNow() 593 } 594 595 urlToGet := "https://dl.google.com/go/go1.14.1.src.tar.gz" 596 req, err := http.NewRequest("GET", urlToGet, nil) 597 assert.Nil(t, err) 598 resp, err := http.DefaultClient.Do(req) 599 assert.Nil(t, err) 600 defer resp.Body.Close() 601 602 f, err := os.CreateTemp("", "progressbar_testfile") 603 if err != nil { 604 t.Fatal() 605 } 606 defer os.Remove(f.Name()) 607 defer f.Close() 608 609 realStdout := os.Stdout 610 defer func() { os.Stdout = realStdout }() 611 r, fakeStdout, err := os.Pipe() 612 if err != nil { 613 t.Fatal(err) 614 } 615 os.Stdout = fakeStdout 616 617 bar := DefaultBytes(-1, " downloading") 618 out := io.MultiWriter(f, bar) 619 _, err = io.Copy(out, resp.Body) 620 assert.Nil(t, err) 621 f.Sync() 622 f.Seek(0, 0) 623 624 if err := fakeStdout.Close(); err != nil { 625 t.Fatal(err) 626 } 627 628 b, err := io.ReadAll(r) 629 if err != nil { 630 t.Fatal(err) 631 } 632 633 if err := r.Close(); err != nil { 634 t.Fatal(err) 635 } 636 637 assert.Equal(t, "", string(b)) 638 639 md5, err := md5sum(f) 640 assert.Nil(t, err) 641 assert.Equal(t, "d441819a800f8c90825355dfbede7266", md5) 642 } 643 644 func TestConcurrency(t *testing.T) { 645 buf := strings.Builder{} 646 bar := NewOptions( 647 1000, 648 OptionSetWriter(&buf), 649 ) 650 var wg sync.WaitGroup 651 for i := 0; i < 900; i++ { 652 wg.Add(1) 653 go func(b *ProgressBar, wg *sync.WaitGroup) { 654 bar.Add(1) 655 wg.Done() 656 }(bar, &wg) 657 } 658 wg.Wait() 659 result := bar.state.currentNum 660 expect := int64(900) 661 assert.Equal(t, expect, result) 662 } 663 664 func TestIterationNames(t *testing.T) { 665 b := Default(20) 666 tc := b.config 667 668 // Checking for the default iterations per second or "it/s" 669 if tc.iterationString != "it" { 670 t.Errorf("Expected %s to be %s, instead I got %s", "iterationString", "it", tc.iterationString) 671 } 672 673 // Change the default "it/s" to provide context, downloads per second or "dl/s" 674 b = NewOptions(20, OptionSetItsString("dl")) 675 tc = b.config 676 677 if tc.iterationString != "dl" { 678 t.Errorf("Expected %s to be %s, instead I got %s", "iterationString", "dl", tc.iterationString) 679 } 680 } 681 682 func md5sum(r io.Reader) (string, error) { 683 hash := md5.New() 684 _, err := io.Copy(hash, r) 685 return hex.EncodeToString(hash.Sum(nil)), err 686 } 687 688 func TestProgressBar_Describe(t *testing.T) { 689 buf := strings.Builder{} 690 bar := NewOptions(100, OptionSetWidth(10), OptionSetWriter(&buf)) 691 bar.Describe("performing axial adjustments") 692 bar.Add(10) 693 result := buf.String() 694 expect := "" + 695 "\rperforming axial adjustments 0% | | [0s:0s]" + 696 "\r \r" + 697 "\rperforming axial adjustments 10% |█ | [0s:0s]" 698 if result != expect { 699 t.Errorf("Render miss-match\nResult: '%s'\nExpect: '%s'\n%+v", result, expect, bar) 700 } 701 } 702 703 func TestRenderBlankStateWithThrottle(t *testing.T) { 704 buf := strings.Builder{} 705 bar := NewOptions(100, OptionSetWidth(10), OptionSetRenderBlankState(true), OptionThrottle(time.Millisecond), OptionSetWriter(&buf)) 706 result := strings.TrimSpace(buf.String()) 707 expect := "0% | | [0s:0s]" 708 if result != expect { 709 t.Errorf("Render miss-match\nResult: '%s'\nExpect: '%s'\n%+v", result, expect, bar) 710 } 711 } 712 713 func TestOptionFullWidth(t *testing.T) { 714 var tests = []struct { 715 opts []Option 716 expected string 717 }{ 718 { // 1 719 []Option{}, 720 "" + 721 "\r 10% |██████ | [1s:9s]" + 722 "\r \r" + 723 "\r 100% |██████████████████████████████████████████████████████████████| ", 724 }, 725 { // 2 726 []Option{OptionSetDescription("Progress:")}, 727 "" + 728 "\rProgress: 10% |█████ | [1s:9s]" + 729 "\r \r" + 730 "\rProgress: 100% |█████████████████████████████████████████████████████| ", 731 }, 732 { // 3 733 []Option{OptionSetDescription("<1/5>"), OptionShowDescriptionAtLineEnd()}, 734 "" + 735 "\r 10% |█████ | [1s:9s] <1/5>" + 736 "\r \r" + 737 "\r 100% |████████████████████████████████████████████████████████| <1/5>", 738 }, 739 { // 4 740 []Option{OptionSetPredictTime(false)}, 741 "" + 742 "\r 10% |██████ | " + 743 "\r \r" + 744 "\r 100% |████████████████████████████████████████████████████████████████| ", 745 }, 746 { // 5 747 []Option{OptionSetPredictTime(false), OptionShowElapsedTimeOnFinish()}, 748 "" + 749 "\r 10% |██████ | " + 750 "\r \r" + 751 "\r 100% |████████████████████████████████████████████████████████████████| [2s] ", 752 }, 753 { // 6 754 []Option{OptionSetPredictTime(false), OptionSetElapsedTime(false)}, 755 "" + 756 "\r 10% |██████ | " + 757 "\r \r" + 758 "\r 100% |█████████████████████████████████████████████████████████████████████| ", 759 }, 760 { // 7 761 []Option{OptionShowIts()}, 762 "" + 763 "\r 10% |█████ | (10 it/s) [1s:9s]" + 764 "\r \r" + 765 "\r 100% |█████████████████████████████████████████████████████| (50 it/s)", 766 }, 767 { // 8 768 []Option{OptionShowCount()}, 769 "" + 770 "\r 10% |█████ | (10/100) [1s:9s]" + 771 "\r \r" + 772 "\r 100% |█████████████████████████████████████████████████████| (100/100)", 773 }, 774 { // 9 775 []Option{OptionShowIts(), OptionShowCount(), OptionShowElapsedTimeOnFinish()}, 776 "" + 777 "\r 10% |████ | (10/100, 10 it/s) [1s:9s]" + 778 "\r \r" + 779 "\r 100% |████████████████████████████████████████████| (100/100, 50 it/s) [2s]", 780 }, 781 { // 10 782 []Option{OptionSetDescription("Progress:"), OptionShowIts(), OptionShowCount()}, 783 "" + 784 "\rProgress: 10% |███ | (10/100, 10 it/s) [1s:9s]" + 785 "\r \r" + 786 "\rProgress: 100% |███████████████████████████████████| (100/100, 50 it/s)", 787 }, 788 { // 11 789 []Option{OptionSetDescription("<3/5>"), OptionShowIts(), OptionShowCount(), OptionShowElapsedTimeOnFinish(), OptionShowDescriptionAtLineEnd()}, 790 "" + 791 "\r 10% |███ | (10/100, 10 it/s) [1s:9s] <3/5>" + 792 "\r \r" + 793 "\r 100% |██████████████████████████████████████| (100/100, 50 it/s) [2s] <3/5>", 794 }, 795 { // 12 796 []Option{OptionShowIts(), OptionShowCount(), OptionSetPredictTime(false)}, 797 "" + 798 "\r 10% |████ | (10/100, 10 it/s) " + 799 "\r \r" + 800 "\r 100% |██████████████████████████████████████████████| (100/100, 50 it/s) ", 801 }, 802 { // 13 803 []Option{OptionShowIts(), OptionShowCount(), OptionSetPredictTime(false), OptionShowElapsedTimeOnFinish()}, 804 "" + 805 "\r 10% |████ | (10/100, 10 it/s) " + 806 "\r \r" + 807 "\r 100% |██████████████████████████████████████████████| (100/100, 50 it/s) [2s] ", 808 }, 809 { // 14 810 []Option{OptionShowIts(), OptionShowCount(), OptionSetPredictTime(false), OptionSetElapsedTime(false)}, 811 "" + 812 "\r 10% |█████ | (10/100, 10 it/s) " + 813 "\r \r" + 814 "\r 100% |███████████████████████████████████████████████████| (100/100, 50 it/s) ", 815 }, 816 } 817 818 for i, test := range tests { 819 test := test 820 t.Run(fmt.Sprintf("%d", i+1), func(t *testing.T) { 821 t.Parallel() 822 buf := strings.Builder{} 823 bar := NewOptions(100, append(test.opts, []Option{OptionFullWidth(), OptionSetWriter(&buf)}...)...) 824 time.Sleep(1 * time.Second) 825 bar.Add(10) 826 time.Sleep(1 * time.Second) 827 bar.Add(90) 828 assert.Equal(t, test.expected, buf.String()) 829 }) 830 } 831 } 832 833 func TestHumanizeBytesSI(t *testing.T) { 834 amount, suffix := humanizeBytes(float64(12.34)*1000*1000, false) 835 assert.Equal(t, "12 MB", fmt.Sprintf("%s%s", amount, suffix)) 836 837 amount, suffix = humanizeBytes(float64(56.78)*1000*1000*1000, false) 838 assert.Equal(t, "57 GB", fmt.Sprintf("%s%s", amount, suffix)) 839 } 840 841 func TestHumanizeBytesIEC(t *testing.T) { 842 amount, suffix := humanizeBytes(float64(12.34)*1024*1024, true) 843 assert.Equal(t, "12 MiB", fmt.Sprintf("%s%s", amount, suffix)) 844 845 amount, suffix = humanizeBytes(float64(56.78)*1024*1024*1024, true) 846 assert.Equal(t, "57 GiB", fmt.Sprintf("%s%s", amount, suffix)) 847 }