279 lines
9.4 KiB
Go
279 lines
9.4 KiB
Go
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...)
|
||
}
|
||
})
|
||
}
|
||
}
|