279 lines
9.4 KiB
Go
Raw Normal View History

package pb
import (
"fmt"
"strings"
"testing"
"time"
"github.com/fatih/color"
)
func testState(total, value int64, maxWidth int, bools ...bool) (s *State) {
s = &State{
total: total,
current: value,
adaptiveElWidth: maxWidth,
ProgressBar: new(ProgressBar),
}
if len(bools) > 0 {
s.Set(Bytes, bools[0])
}
if len(bools) > 1 && bools[1] {
s.adaptive = true
}
return
}
func testElementBarString(t *testing.T, state *State, el Element, want string, args ...string) {
if state.ProgressBar == nil {
state.ProgressBar = new(ProgressBar)
}
res := el.ProgressElement(state, args...)
if res != want {
t.Errorf("Unexpected result: '%s'; want: '%s'", res, want)
}
if state.IsAdaptiveWidth() && state.AdaptiveElWidth() != CellCount(res) {
t.Errorf("Unepected width: %d; want: %d", CellCount(res), state.AdaptiveElWidth())
}
}
func TestElementPercent(t *testing.T) {
testElementBarString(t, testState(100, 50, 0), ElementPercent, "50.00%")
testElementBarString(t, testState(100, 50, 0), ElementPercent, "50 percent", "%v percent")
testElementBarString(t, testState(0, 50, 0), ElementPercent, "?%")
testElementBarString(t, testState(0, 50, 0), ElementPercent, "unkn", "%v%%", "unkn")
}
func TestElementCounters(t *testing.T) {
testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 / 100")
testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 of 100", "%s of %s")
testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B of 100 B", "%s of %s")
testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B / 100 B")
testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B")
testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B / ?", "", "%[1]s / ?")
}
func TestElementBar(t *testing.T) {
// short
testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, "[")
testElementBarString(t, testState(100, 50, 2, false, true), ElementBar, "[]")
testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "[>]")
testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "[>_]")
testElementBarString(t, testState(100, 50, 5, false, true), ElementBar, "[->_]")
// middle
testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "[--->____]")
testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "<--->____>", "<", "", "", "", ">")
// finished
st := testState(100, 100, 10, false, true)
st.finished = true
testElementBarString(t, st, ElementBar, "[--------]")
// empty color
st = testState(100, 50, 10, false, true)
st.Set(Terminal, true)
color.NoColor = false
testElementBarString(t, st, ElementBar, " --->____]", color.RedString("%s", ""))
// empty
testElementBarString(t, testState(0, 50, 10, false, true), ElementBar, "[________]")
// full
testElementBarString(t, testState(20, 20, 10, false, true), ElementBar, "[------->]")
// everflow
testElementBarString(t, testState(20, 50, 10, false, true), ElementBar, "[------->]")
// small width
testElementBarString(t, testState(20, 50, 2, false, true), ElementBar, "[]")
testElementBarString(t, testState(20, 50, 1, false, true), ElementBar, "[")
// negative counters
testElementBarString(t, testState(-50, -150, 10, false, true), ElementBar, "[------->]")
testElementBarString(t, testState(-150, -50, 10, false, true), ElementBar, "[-->_____]")
testElementBarString(t, testState(50, -150, 10, false, true), ElementBar, "[------->]")
testElementBarString(t, testState(-50, 150, 10, false, true), ElementBar, "[------->]")
// long entities / unicode
f1 := []string{"進捗|", "многобайт", "active", "пусто", "|end"}
testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, " ", f1...)
testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "進 ", f1...)
testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "進捗", f1...)
testElementBarString(t, testState(100, 50, 29, false, true), ElementBar, "進捗|многactiveпустопусто|end", f1...)
testElementBarString(t, testState(100, 50, 11, false, true), ElementBar, "進捗|aп|end", f1...)
// unicode
f2 := []string{"⚑", ".", ">", "⟞", "⚐"}
testElementBarString(t, testState(100, 50, 8, false, true), ElementBar, "⚑..>⟞⟞⟞⚐", f2...)
// no adaptive
testElementBarString(t, testState(0, 50, 10), ElementBar, "[____________________________]")
var formats = [][]string{
[]string{},
f1, f2,
}
// all widths / extreme values
// check for panic and correct width
for _, f := range formats {
for tt := int64(-2); tt < 12; tt++ {
for v := int64(-2); v < 12; v++ {
state := testState(tt, v, 0, false, true)
for w := -2; w < 20; w++ {
state.adaptiveElWidth = w
res := ElementBar(state, f...)
var we = w
if we <= 0 {
we = 30
}
if CellCount(res) != we {
t.Errorf("Unexpected len(%d): '%s'", we, res)
}
}
}
}
}
}
func TestElementSpeed(t *testing.T) {
var state = testState(1000, 0, 0, false)
state.time = time.Now()
for i := int64(0); i < 10; i++ {
state.id = uint64(i) + 1
state.current += 42
state.time = state.time.Add(time.Second)
state.finished = i == 9
if state.finished {
state.current += 100
}
r := ElementSpeed(state)
r2 := ElementSpeed(state)
if r != r2 {
t.Errorf("Must be the same: '%s' vs '%s'", r, r2)
}
if i < 1 {
// do not calc first result
if w := "? p/s"; r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
} else if state.finished {
if w := "58 p/s"; r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
state.time = state.time.Add(-time.Hour)
r = ElementSpeed(state)
if w := "? p/s"; r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
} else {
if w := "42 p/s"; r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
}
}
}
func TestElementRemainingTime(t *testing.T) {
var state = testState(100, 0, 0, false)
state.time = time.Now()
state.startTime = state.time
for i := int64(0); i < 10; i++ {
state.id = uint64(i) + 1
state.time = state.time.Add(time.Second)
state.finished = i == 9
r := ElementRemainingTime(state)
if i < 1 {
// do not calc first two results
if w := "?"; r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
} else if state.finished {
// final elapsed time
if w := "10s"; r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
} else {
w := fmt.Sprintf("%ds", 10-i)
if r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
}
state.current += 10
}
}
func TestElementElapsedTime(t *testing.T) {
var state = testState(1000, 0, 0, false)
state.startTime = time.Now()
state.time = state.startTime
for i := int64(0); i < 10; i++ {
r := ElementElapsedTime(state)
if w := fmt.Sprintf("%ds", i); r != w {
t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
}
state.time = state.time.Add(time.Second)
}
}
func TestElementString(t *testing.T) {
var state = testState(0, 0, 0, false)
testElementBarString(t, state, ElementString, "", "myKey")
state.Set("myKey", "my value")
testElementBarString(t, state, ElementString, "my value", "myKey")
state.Set("myKey", "my value1")
testElementBarString(t, state, ElementString, "my value1", "myKey")
testElementBarString(t, state, ElementString, "")
}
func TestElementCycle(t *testing.T) {
var state = testState(0, 0, 0, false)
testElementBarString(t, state, ElementCycle, "")
testElementBarString(t, state, ElementCycle, "1", "1", "2", "3")
testElementBarString(t, state, ElementCycle, "2", "1", "2", "3")
testElementBarString(t, state, ElementCycle, "3", "1", "2", "3")
testElementBarString(t, state, ElementCycle, "1", "1", "2", "3")
testElementBarString(t, state, ElementCycle, "2", "1", "2")
testElementBarString(t, state, ElementCycle, "1", "1", "2")
}
func TestAdaptiveWrap(t *testing.T) {
var state = testState(0, 0, 0, false)
state.id = 1
state.Set("myKey", "my value")
el := adaptiveWrap(ElementString)
testElementBarString(t, state, el, adElPlaceholder, "myKey")
if v := state.recalc[0].ProgressElement(state); v != "my value" {
t.Errorf("Unexpected result: %s", v)
}
state.id = 2
testElementBarString(t, state, el, adElPlaceholder, "myKey1")
state.Set("myKey", "my value1")
if v := state.recalc[0].ProgressElement(state); v != "my value1" {
t.Errorf("Unexpected result: %s", v)
}
}
func TestRegisterElement(t *testing.T) {
var testEl ElementFunc = func(state *State, args ...string) string {
return strings.Repeat("*", state.AdaptiveElWidth())
}
RegisterElement("testEl", testEl, true)
result := ProgressBarTemplate(`{{testEl . }}`).New(0).SetWidth(5).String()
if result != "*****" {
t.Errorf("Unexpected result: '%v'", result)
}
}
func BenchmarkBar(b *testing.B) {
var formats = map[string][]string{
"simple": []string{".", ".", ".", ".", "."},
"unicode": []string{"⚑", "⚒", "⚟", "⟞", "⚐"},
"color": []string{color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", ".")},
"long": []string{"..", "..", "..", "..", ".."},
"longunicode": []string{"⚑⚑", "⚒⚒", "⚟⚟", "⟞⟞", "⚐⚐"},
}
for name, args := range formats {
state := testState(100, 50, 100, false, true)
b.Run(name, func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ElementBar(state, args...)
}
})
}
}