Skip to content

Commit

Permalink
progress: fix tracker string generation; enhance ETA calculation (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
jedib0t authored Aug 23, 2018
1 parent d826629 commit 06e05ef
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 20 deletions.
16 changes: 9 additions & 7 deletions progress/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,18 @@ func (p *Progress) generateTrackerStr(t *Tracker, maxLen int) string {
pDotValue := float64(t.Total) / float64(maxLen)
pFinishedDots := float64(t.value) / pDotValue
pFinishedDotsFraction := pFinishedDots - float64(int(pFinishedDots))
pFinishedLen := int(math.Ceil(pFinishedDots))
pFinishedLen := int(math.Floor(pFinishedDots))

var pFinished, pInProgress, pUnfinished string
if pFinishedLen > 0 {
pFinished = strings.Repeat(p.style.Chars.Finished, pFinishedLen-1)
pFinished = strings.Repeat(p.style.Chars.Finished, pFinishedLen)
}
pInProgress = p.style.Chars.Unfinished
if pFinishedDotsFraction > 0.75 {
if pFinishedDotsFraction >= 0.75 {
pInProgress = p.style.Chars.Finished75
} else if pFinishedDotsFraction > 0.50 {
} else if pFinishedDotsFraction >= 0.50 {
pInProgress = p.style.Chars.Finished50
} else if pFinishedDotsFraction > 0.25 {
} else if pFinishedDotsFraction >= 0.25 {
pInProgress = p.style.Chars.Finished25
} else if pFinishedDotsFraction == 0 {
pInProgress = ""
Expand Down Expand Up @@ -239,9 +239,11 @@ func (p *Progress) renderTrackerStats(out *strings.Builder, t *Tracker, hint ren
}
outStats.WriteString(p.style.Colors.Time.Sprint(td.Round(tp)))
if hint.isOverallTracker {
outStats.WriteString("; ~ETA: ")
tpO := p.style.Options.TimeOverallPrecision
outStats.WriteString(p.style.Colors.Time.Sprint(t.ETA().Round(tpO)))
if eta := t.ETA().Round(tpO) + tpO; true || eta > tpO {
outStats.WriteString("; ~ETA: ")
outStats.WriteString(p.style.Colors.Time.Sprint(eta))
}
}
}
outStats.WriteRune(']')
Expand Down
129 changes: 128 additions & 1 deletion progress/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,132 @@ func renderAndWait(pw Writer, autoStop bool) {
}
}

func TestProgress_generateTrackerStr(t *testing.T) {
pw := Progress{}
pw.Style().Chars = StyleChars{
BoxLeft: "",
BoxRight: "",
Finished: "#",
Finished25: "1",
Finished50: "2",
Finished75: "3",
Unfinished: ".",
}

expectedTrackerStrMap := map[int64]string{
0: "..........",
1: "..........",
2: "..........",
3: "1.........",
4: "1.........",
5: "2.........",
6: "2.........",
7: "2.........",
8: "3.........",
9: "3.........",
10: "#.........",
11: "#.........",
12: "#.........",
13: "#1........",
14: "#1........",
15: "#2........",
16: "#2........",
17: "#2........",
18: "#3........",
19: "#3........",
20: "##........",
21: "##........",
22: "##........",
23: "##1.......",
24: "##1.......",
25: "##2.......",
26: "##2.......",
27: "##2.......",
28: "##3.......",
29: "##3.......",
30: "###.......",
31: "###.......",
32: "###.......",
33: "###1......",
34: "###1......",
35: "###2......",
36: "###2......",
37: "###2......",
38: "###3......",
39: "###3......",
40: "####......",
41: "####......",
42: "####......",
43: "####1.....",
44: "####1.....",
45: "####2.....",
46: "####2.....",
47: "####2.....",
48: "####3.....",
49: "####3.....",
50: "#####.....",
51: "#####.....",
52: "#####.....",
53: "#####1....",
54: "#####1....",
55: "#####2....",
56: "#####2....",
57: "#####2....",
58: "#####3....",
59: "#####3....",
60: "######....",
61: "######....",
62: "######....",
63: "######1...",
64: "######1...",
65: "######2...",
66: "######2...",
67: "######2...",
68: "######3...",
69: "######3...",
70: "#######...",
71: "#######...",
72: "#######...",
73: "#######1..",
74: "#######1..",
75: "#######2..",
76: "#######2..",
77: "#######2..",
78: "#######3..",
79: "#######3..",
80: "########..",
81: "########..",
82: "########..",
83: "########1.",
84: "########1.",
85: "########2.",
86: "########2.",
87: "########2.",
88: "########3.",
89: "########3.",
90: "#########.",
91: "#########.",
92: "#########.",
93: "#########1",
94: "#########1",
95: "#########2",
96: "#########2",
97: "#########2",
98: "#########3",
99: "#########3",
100: "##########",
}

tr := Tracker{Total: 100}
for value := int64(0); value <= tr.Total; value++ {
tr.value = value
//fmt.Printf(" %5d: \"%s\",\n", value, pw.generateTrackerStr(&tr, 10))
if expectedStr, ok := expectedTrackerStrMap[value]; ok {
assert.Equal(t, expectedStr, pw.generateTrackerStr(&tr, 10), "value=%d", value)
}
}
}

func TestProgress_RenderNothing(t *testing.T) {
renderOutput := outputWriter{}

Expand Down Expand Up @@ -231,6 +357,7 @@ func TestProgress_RenderSomeTrackers_WithOverallTracker(t *testing.T) {
pw.SetOutputWriter(&renderOutput)
pw.SetTrackerPosition(PositionRight)
pw.ShowOverallTracker(true)
pw.Style().Options.TimeOverallPrecision = time.Millisecond
go trackSomething(pw, &Tracker{Message: "Calculation Total # 1", Total: 1000, Units: UnitsDefault})
go trackSomething(pw, &Tracker{Message: "Downloading File # 2", Total: 1000, Units: UnitsBytes})
go trackSomething(pw, &Tracker{Message: "Transferring Amount # 3", Total: 1000, Units: UnitsCurrencyDollar})
Expand All @@ -243,7 +370,7 @@ func TestProgress_RenderSomeTrackers_WithOverallTracker(t *testing.T) {
regexp.MustCompile(`\x1b\[KCalculation Total # 1 \.\.\. done! \[\d+\.\d+K in [\d.]+ms]`),
regexp.MustCompile(`\x1b\[KDownloading File # 2 \.\.\. done! \[\d+\.\d+KB in [\d.]+ms]`),
regexp.MustCompile(`\x1b\[KTransferring Amount # 3 \.\.\. done! \[\$\d+\.\d+K in [\d.]+ms]`),
regexp.MustCompile(`\[[\d.]+s; ~ETA: [\d.]+s`),
regexp.MustCompile(`\[[\d.ms]+; ~ETA: [\d.ms]+`),
}
out := renderOutput.String()
for _, expectedOutPattern := range expectedOutPatterns {
Expand Down
17 changes: 11 additions & 6 deletions progress/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import (
type Tracker struct {
// Message should contain a short description of the "task"
Message string
// ExpectedDuration tells how long this task is expected to take; and will
// be used in calculation of the ETA value
ExpectedDuration time.Duration
// Total should be set to the (expected) Total/Final value to be reached
Total int64
// Units defines the type of the "value" being tracked
Expand All @@ -26,14 +29,16 @@ type Tracker struct {
// ETA returns the expected time of "arrival" or completion of this tracker. It
// is an estimate and is not guaranteed.
func (t *Tracker) ETA() time.Duration {
percDone := t.PercentDone()
if percDone == 0 {
return time.Duration(0)
timeTaken := time.Since(t.timeStart)
if t.ExpectedDuration > time.Duration(0) && t.ExpectedDuration > timeTaken {
return t.ExpectedDuration - timeTaken
}

timeTaken := time.Since(t.timeStart)
eta := time.Duration((int64(timeTaken) / int64(percDone)) * int64(100-percDone))
return eta
pDone := t.PercentDone()
if pDone == 0 {
return time.Duration(0)
}
return time.Duration((int64(timeTaken) / int64(pDone)) * int64(100-pDone))
}

// Increment updates the current value of the task being tracked.
Expand Down
23 changes: 17 additions & 6 deletions progress/tracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,26 @@ import (
)

func TestTracker_ETA(t *testing.T) {
timeDelayUnit := time.Millisecond
timeDelay := timeDelayUnit * 25

tracker := Tracker{Total: 100}
tracker.start()
assert.Equal(t, time.Duration(0), tracker.ETA())
time.Sleep(timeDelay)
tracker.Increment(50)
assert.NotEqual(t, time.Duration(0), tracker.ETA())
tracker.Increment(50)
assert.Equal(t, time.Duration(0), tracker.ETA())

tracker.timeStart = time.Now()
time.Sleep(time.Millisecond * 100)
tracker.value = 50
eta := tracker.ETA()
assert.NotEqual(t, time.Duration(0), eta)
assert.True(t, eta < time.Second)
tracker = Tracker{Total: 100, ExpectedDuration: timeDelay}
tracker.start()
assert.True(t, tracker.ExpectedDuration > tracker.ETA())
time.Sleep(timeDelay)
tracker.Increment(50)
assert.NotEqual(t, time.Duration(0), tracker.ETA())
tracker.Increment(50)
assert.Equal(t, time.Duration(0), tracker.ETA())
}

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

0 comments on commit 06e05ef

Please sign in to comment.