279 lines
9.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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...)
}
})
}
}