Skip to content

Commit

Permalink
Merge ee1b017 into a7ca945
Browse files Browse the repository at this point in the history
  • Loading branch information
jedib0t committed Jan 29, 2021
2 parents a7ca945 + ee1b017 commit 6a05c90
Show file tree
Hide file tree
Showing 10 changed files with 674 additions and 51 deletions.
6 changes: 6 additions & 0 deletions cmd/demo-progress/demo.go
Expand Up @@ -39,6 +39,9 @@ func trackSomething(pw progress.Writer, idx int64) {
message = fmt.Sprintf("Calculating Total #%3d", idx)
}
tracker := progress.Tracker{Message: message, Total: total, Units: *units}
if idx == int64(*numTrackers) {
tracker.Total = 0
}

pw.AppendTracker(&tracker)

Expand All @@ -47,6 +50,9 @@ func trackSomething(pw progress.Writer, idx int64) {
select {
case <-c:
tracker.Increment(incrementPerCycle)
if idx == int64(*numTrackers) && tracker.Value() >= total {
tracker.MarkAsDone()
}
}
}
}
Expand Down
135 changes: 135 additions & 0 deletions progress/indicator.go
@@ -0,0 +1,135 @@
package progress

import (
"time"

"github.com/jedib0t/go-pretty/v6/text"
)

// IndeterminateIndicator defines the structure for the indicator to indicate
// indeterminate progress. Ex.: <=>
type IndeterminateIndicator struct {
Position int
Text string
}

// IndeterminateIndicatorGenerator returns an IndeterminateIndicator for cases
// where the progress percentage cannot be calculated. Ex.: [........<=>....]
type IndeterminateIndicatorGenerator func(maxLen int) IndeterminateIndicator

// IndeterminateIndicatorMovingBackAndForth returns an instance of
// IndeterminateIndicatorGenerator function that incrementally moves from the
// left to right and back for each specified duration. If duration is 0, then
// every single invocation moves the indicator.
func IndeterminateIndicatorMovingBackAndForth(indicator string, duration time.Duration) IndeterminateIndicatorGenerator {
var indeterminateIndicator *IndeterminateIndicator
indicatorGenerator := indeterminateIndicatorMovingBackAndForth(indicator)
lastRenderTime := time.Now()

return func(maxLen int) IndeterminateIndicator {
currRenderTime := time.Now()
if indeterminateIndicator == nil || duration == 0 || currRenderTime.Sub(lastRenderTime) > duration {
tmpIndeterminateIndicator := indicatorGenerator(maxLen)
indeterminateIndicator = &tmpIndeterminateIndicator
lastRenderTime = currRenderTime
}

return *indeterminateIndicator
}
}

// IndeterminateIndicatorMovingLeftToRight returns an instance of
// IndeterminateIndicatorGenerator function that incrementally moves from the
// left to right and starts from left again for each specified duration. If
// duration is 0, then every single invocation moves the indicator.
func IndeterminateIndicatorMovingLeftToRight(indicator string, duration time.Duration) IndeterminateIndicatorGenerator {
var indeterminateIndicator *IndeterminateIndicator
indicatorGenerator := indeterminateIndicatorMovingLeftToRight(indicator)
lastRenderTime := time.Now()

return func(maxLen int) IndeterminateIndicator {
currRenderTime := time.Now()
if indeterminateIndicator == nil || duration == 0 || currRenderTime.Sub(lastRenderTime) > duration {
tmpIndeterminateIndicator := indicatorGenerator(maxLen)
indeterminateIndicator = &tmpIndeterminateIndicator
lastRenderTime = currRenderTime
}

return *indeterminateIndicator
}
}

// IndeterminateIndicatorMovingRightToLeft returns an instance of
// IndeterminateIndicatorGenerator function that incrementally moves from the
// right to left and starts from right again for each specified duration. If
// duration is 0, then every single invocation moves the indicator.
func IndeterminateIndicatorMovingRightToLeft(indicator string, duration time.Duration) IndeterminateIndicatorGenerator {
var indeterminateIndicator *IndeterminateIndicator
indicatorGenerator := indeterminateIndicatorMovingRightToLeft(indicator)
lastRenderTime := time.Now()

return func(maxLen int) IndeterminateIndicator {
currRenderTime := time.Now()
if indeterminateIndicator == nil || duration == 0 || currRenderTime.Sub(lastRenderTime) > duration {
tmpIndeterminateIndicator := indicatorGenerator(maxLen)
indeterminateIndicator = &tmpIndeterminateIndicator
lastRenderTime = currRenderTime
}

return *indeterminateIndicator
}
}

func indeterminateIndicatorMovingBackAndForth(indicator string) IndeterminateIndicatorGenerator {
increment := 1
nextPosition := 0

return func(maxLen int) IndeterminateIndicator {
currentPosition := nextPosition
if currentPosition == 0 {
increment = 1
} else if currentPosition+text.RuneCount(indicator) == maxLen {
increment = -1
}
nextPosition += increment

return IndeterminateIndicator{
Position: currentPosition,
Text: indicator,
}
}
}

func indeterminateIndicatorMovingLeftToRight(indicator string) IndeterminateIndicatorGenerator {
nextPosition := 0

return func(maxLen int) IndeterminateIndicator {
currentPosition := nextPosition
nextPosition++
if nextPosition+text.RuneCount(indicator) > maxLen {
nextPosition = 0
}

return IndeterminateIndicator{
Position: currentPosition,
Text: indicator,
}
}
}

func indeterminateIndicatorMovingRightToLeft(indicator string) IndeterminateIndicatorGenerator {
nextPosition := -1

return func(maxLen int) IndeterminateIndicator {
if nextPosition == -1 {
nextPosition = maxLen - text.RuneCount(indicator)
}
currentPosition := nextPosition
nextPosition--

return IndeterminateIndicator{
Position: currentPosition,
Text: indicator,
}
}
}
192 changes: 192 additions & 0 deletions progress/indicator_test.go
@@ -0,0 +1,192 @@
package progress

import (
"fmt"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestIndeterminateIndicatorMovingBackAndForth(t *testing.T) {
maxLen := 10
indicator := "<=>"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1,
0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1,
}

f := IndeterminateIndicatorMovingBackAndForth(indicator, time.Millisecond*10)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
time.Sleep(time.Millisecond * 10)
}
}

func Test_indeterminateIndicatorMovingBackAndForth1(t *testing.T) {
maxLen := 10
indicator := "?"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1,
}

f := indeterminateIndicatorMovingBackAndForth(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func Test_indeterminateIndicatorMovingBackAndForth2(t *testing.T) {
maxLen := 10
indicator := "<>"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1,
}

f := indeterminateIndicatorMovingBackAndForth(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func Test_indeterminateIndicatorMovingBackAndForth3(t *testing.T) {
maxLen := 10
indicator := "<=>"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1,
0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1,
}

f := indeterminateIndicatorMovingBackAndForth(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func TestIndeterminateIndicatorMovingLeftToRight(t *testing.T) {
maxLen := 10
indicator := "?"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
}

f := IndeterminateIndicatorMovingLeftToRight(indicator, time.Millisecond*10)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
time.Sleep(time.Millisecond * 10)
}
}

func Test_indeterminateIndicatorMovingLeftToRight1(t *testing.T) {
maxLen := 10
indicator := "?"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
}

f := indeterminateIndicatorMovingLeftToRight(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func Test_indeterminateIndicatorMovingLeftToRight2(t *testing.T) {
maxLen := 10
indicator := "<>"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7, 8,
0, 1, 2, 3, 4, 5, 6, 7, 8,
}

f := indeterminateIndicatorMovingLeftToRight(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func Test_indeterminateIndicatorMovingLeftToRight3(t *testing.T) {
maxLen := 10
indicator := "<=>"
expectedPositions := []int{
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
}

f := indeterminateIndicatorMovingLeftToRight(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func TestIndeterminateIndicatorMovingRightToLeft(t *testing.T) {
maxLen := 10
indicator := "?"
expectedPositions := []int{
9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
}

f := IndeterminateIndicatorMovingRightToLeft(indicator, time.Millisecond*10)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
time.Sleep(time.Millisecond * 10)
}
}

func Test_indeterminateIndicatorMovingRightToLeft1(t *testing.T) {
maxLen := 10
indicator := "?"
expectedPositions := []int{
9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
}

f := indeterminateIndicatorMovingRightToLeft(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func Test_indeterminateIndicatorMovingRightToLeft2(t *testing.T) {
maxLen := 10
indicator := "<>"
expectedPositions := []int{
8, 7, 6, 5, 4, 3, 2, 1, 0,
8, 7, 6, 5, 4, 3, 2, 1, 0,
}

f := indeterminateIndicatorMovingRightToLeft(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}

func Test_indeterminateIndicatorMovingRightToLeft3(t *testing.T) {
maxLen := 10
indicator := "<=>"
expectedPositions := []int{
7, 6, 5, 4, 3, 2, 1, 0,
7, 6, 5, 4, 3, 2, 1, 0,
}

f := indeterminateIndicatorMovingRightToLeft(indicator)
for idx, expectedPosition := range expectedPositions {
actual := f(maxLen)
assert.Equal(t, expectedPosition, actual.Position, fmt.Sprintf("expectedIndeterminateIndicators[%d]", idx))
}
}
2 changes: 1 addition & 1 deletion progress/progress.go
Expand Up @@ -65,7 +65,7 @@ const (
// to a queue, which gets picked up by the Render logic in the next rendering
// cycle.
func (p *Progress) AppendTracker(t *Tracker) {
if t.Total <= 0 {
if t.Total < 0 {
t.Total = math.MaxInt64
}
t.start()
Expand Down
9 changes: 7 additions & 2 deletions progress/progress_test.go
Expand Up @@ -15,10 +15,15 @@ func TestProgress_AppendTracker(t *testing.T) {

tracker := &Tracker{}
assert.Equal(t, int64(0), tracker.Total)

p.AppendTracker(tracker)
assert.Equal(t, 1, len(p.trackersInQueue))
assert.Equal(t, int64(math.MaxInt64), tracker.Total)
assert.Equal(t, int64(0), tracker.Total)

tracker2 := &Tracker{Total: -1}
assert.Equal(t, int64(-1), tracker2.Total)
p.AppendTracker(tracker2)
assert.Equal(t, 2, len(p.trackersInQueue))
assert.Equal(t, int64(math.MaxInt64), tracker2.Total)
}

func TestProgress_AppendTrackers(t *testing.T) {
Expand Down

0 comments on commit 6a05c90

Please sign in to comment.