package pb import ( "bytes" "errors" "fmt" "strings" "testing" "time" "github.com/fatih/color" ) func TestPBBasic(t *testing.T) { bar := new(ProgressBar) var a, e int64 if a, e = bar.Total(), 0; a != e { t.Errorf("Unexpected total: actual: %v; expected: %v", a, e) } if a, e = bar.Current(), 0; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } bar.SetCurrent(10).SetTotal(20) if a, e = bar.Total(), 20; a != e { t.Errorf("Unexpected total: actual: %v; expected: %v", a, e) } if a, e = bar.Current(), 10; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } bar.Add(5) if a, e = bar.Current(), 15; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } bar.Increment() if a, e = bar.Current(), 16; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } } func TestPBWidth(t *testing.T) { terminalWidth = func() (int, error) { return 50, nil } // terminal width bar := new(ProgressBar) if a, e := bar.Width(), 50; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // terminal width error terminalWidth = func() (int, error) { return 0, errors.New("test error") } if a, e := bar.Width(), defaultBarWidth; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // terminal width panic terminalWidth = func() (int, error) { panic("test") return 0, nil } if a, e := bar.Width(), defaultBarWidth; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // set negative terminal width bar.SetWidth(-42) if a, e := bar.Width(), defaultBarWidth; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // set terminal width bar.SetWidth(42) if a, e := bar.Width(), 42; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } } func TestPBMaxWidth(t *testing.T) { terminalWidth = func() (int, error) { return 50, nil } // terminal width bar := new(ProgressBar) if a, e := bar.Width(), 50; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } bar.SetMaxWidth(55) if a, e := bar.Width(), 50; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } bar.SetMaxWidth(38) if a, e := bar.Width(), 38; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } } func TestPBTemplate(t *testing.T) { bar := new(ProgressBar) result := bar.SetTotal(100).SetCurrent(50).SetWidth(40).String() expected := "50 / 100 [------->________] 50.00% ? p/s" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } // check strip result = bar.SetWidth(8).String() expected = "50 / 100" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } // invalid template for _, invalidTemplate := range []string{ `{{invalid template`, `{{speed}}`, } { bar.SetTemplateString(invalidTemplate) result = bar.String() expected = "" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } if err := bar.Err(); err == nil { t.Errorf("Must be error") } } // simple template without adaptive elemnts bar.SetTemplateString(`{{counters . }}`) result = bar.String() expected = "50 / 100" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } } func TestPBStartFinish(t *testing.T) { bar := ProgressBarTemplate(`{{counters . }}`).New(0) for i := int64(0); i < 2; i++ { if bar.IsStarted() { t.Error("Must be false") } var buf = bytes.NewBuffer(nil) bar.SetTotal(100). SetCurrent(int64(i)). SetWidth(7). Set(Terminal, true). SetWriter(buf). SetRefreshRate(time.Millisecond * 20). Start() if !bar.IsStarted() { t.Error("Must be true") } time.Sleep(time.Millisecond * 100) bar.Finish() if buf.Len() == 0 { t.Error("no writes") } var resultsString = strings.TrimPrefix(buf.String(), "\r") if !strings.HasSuffix(resultsString, "\n") { t.Error("No end \\n symb") } else { resultsString = resultsString[:len(resultsString)-1] } var results = strings.Split(resultsString, "\r") if len(results) < 3 { t.Errorf("Unexpected writes count: %v", len(results)) } exp := fmt.Sprintf("%d / 100", i) for i, res := range results { if res != exp { t.Errorf("Unexpected result[%d]: '%v'", i, res) } } // test second finish call bar.Finish() } } func TestPBFlags(t *testing.T) { // Static color.NoColor = false buf := bytes.NewBuffer(nil) bar := ProgressBarTemplate(`{{counters . | red}}`).New(100) bar.Set(Static, true).SetCurrent(50).SetWidth(10).SetWriter(buf).Start() if bar.IsStarted() { t.Error("Must be false") } bar.Write() result := buf.String() expected := "50 / 100" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n'%s'\n'%s'", result, expected) } if !bar.state.IsFirst() { t.Error("must be true") } // Color bar.Set(Color, true) buf.Reset() bar.Write() result = buf.String() expected = color.RedString("50 / 100") if result != expected { t.Errorf("Unexpected result: (actual/expected)\n'%s'\n'%s'", result, expected) } if bar.state.IsFirst() { t.Error("must be false") } // Terminal bar.Set(Terminal, true).SetWriter(buf) buf.Reset() bar.Write() result = buf.String() expected = "\r" + color.RedString("50 / 100") + " " if result != expected { t.Errorf("Unexpected result: (actual/expected)\n'%s'\n'%s'", result, expected) } } func BenchmarkRender(b *testing.B) { var formats = []string{ string(Simple), string(Default), string(Full), `{{string . "prefix" | red}}{{counters . | green}} {{bar . | yellow}} {{percent . | cyan}} {{speed . | cyan}}{{string . "suffix" | cyan}}`, } var names = []string{ "Simple", "Default", "Full", "Color", } for i, tmpl := range formats { bar := new(ProgressBar) bar.SetTemplateString(tmpl).SetWidth(100) b.Run(names[i], func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { bar.String() } }) } }