From 63168dd078f6c58d27a1d1402a956c0c3b8193f9 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 28 Aug 2021 10:46:17 +0800 Subject: [PATCH 01/10] feat: print more info when created record collides with others --- cli/create.go | 2 +- core/timetrace.go | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cli/create.go b/cli/create.go index 2b823d2..d47d4af 100644 --- a/cli/create.go +++ b/cli/create.go @@ -106,7 +106,7 @@ func createRecordCommand(t *core.Timetrace) *cobra.Command { return } if collides { - out.Err("Record collides with other record!") + out.Warn(" start and end of the record should not overlap with others") return } diff --git a/core/timetrace.go b/core/timetrace.go index e41e4fb..9a55b3e 100644 --- a/core/timetrace.go +++ b/core/timetrace.go @@ -8,6 +8,7 @@ import ( "time" "github.com/dominikbraun/timetrace/config" + "github.com/dominikbraun/timetrace/out" ) const ( @@ -295,17 +296,24 @@ func (t *Timetrace) RecordCollides(toCheck Record) (bool, error) { } func collides(toCheck Record, allRecords []*Record) bool { + collide := false for _, rec := range allRecords { if rec.End != nil && rec.Start.Before(*toCheck.End) && rec.End.After(toCheck.Start) { - return true + defer out.Info("%v %v-%v", rec.Project.Key, rec.Start.String(), rec.End.String()) + collide = true } if rec.End == nil && toCheck.End.After(rec.Start) { - return true + defer out.Info("%v %v-%v", rec.Project.Key, rec.Start.String(), rec.End.String()) + collide = true } } - return false + if collide { + out.Err("collides with these records :") + } + + return collide } // isBackFile checks if a given filename is a backup-file From 1e15c202670bec69acdbcaa147a072e9a03529fa Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 28 Aug 2021 11:07:37 +0800 Subject: [PATCH 02/10] fix: check if project and end is nil before we print --- core/timetrace.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/timetrace.go b/core/timetrace.go index 9a55b3e..2ffd665 100644 --- a/core/timetrace.go +++ b/core/timetrace.go @@ -298,13 +298,21 @@ func (t *Timetrace) RecordCollides(toCheck Record) (bool, error) { func collides(toCheck Record, allRecords []*Record) bool { collide := false for _, rec := range allRecords { + var project, end string + if rec.Project != nil { + project = rec.Project.Key + } + if rec.End != nil { + end = rec.End.String() + } + if rec.End != nil && rec.Start.Before(*toCheck.End) && rec.End.After(toCheck.Start) { - defer out.Info("%v %v-%v", rec.Project.Key, rec.Start.String(), rec.End.String()) + defer out.Info("%v %v-%v", project, rec.Start.String(), end) collide = true } if rec.End == nil && toCheck.End.After(rec.Start) { - defer out.Info("%v %v-%v", rec.Project.Key, rec.Start.String(), rec.End.String()) + defer out.Info("%v %v-%v", project, rec.Start.String(), end) collide = true } } From c3b4a358fd3a10670722fe7d85c4782ba6681cf2 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 28 Aug 2021 20:30:19 +0800 Subject: [PATCH 03/10] fix: change timetrace_test.go because we have added one more return values for func collides --- core/timetrace_test.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/timetrace_test.go b/core/timetrace_test.go index 0ef651e..5587d5d 100644 --- a/core/timetrace_test.go +++ b/core/timetrace_test.go @@ -25,77 +25,77 @@ func TestCollides(t *testing.T) { // rec1 starts and end after savedRec rec1 := newTestRecord(-1, 0) - if collides(rec1, allRecs) { + if collide, _ := collides(rec1, allRecs); collide { t.Error("records should not collide") } // rec2 starts in savedRec, ends after rec2 := newTestRecord(-30, 1) - if !collides(rec2, allRecs) { + if collide, _ := collides(rec2, allRecs); !collide { t.Error("records should collide") } // rec3 start before savedRec, ends inside rec3 := newTestRecord(-75, -30) - if !collides(rec3, allRecs) { + if collide, _ := collides(rec3, allRecs); !collide { t.Error("records should collide") } // rec4 starts and ends before savedRec rec4 := newTestRecord(-75, -70) - if collides(rec4, allRecs) { + if collide, _ := collides(rec4, allRecs); collide { t.Error("records should not collide") } // rec5 starts and ends inside savedRec rec5 := newTestRecord(-40, -20) - if !collides(rec5, allRecs) { + if collide, _ := collides(rec5, allRecs); !collide { t.Error("records should collide") } // rec6 starts before and ends after savedRec rec6 := newTestRecord(-70, 10) - if !collides(rec6, allRecs) { + if collide, _ := collides(rec6, allRecs); !collide { t.Error("records should collide") } // rec7 starts and ends at the same time as savedRec rec7 := newTestRecord(-60, -1) - if !collides(rec7, allRecs) { + if collide, _ := collides(rec7, allRecs); !collide { t.Error("records should collide") } // rec7 starts at the same time as savedRecTracked rec8 := newTestRecord(-60, -1) - if !collides(rec8, allRecsTracked) { + if collide, _ := collides(rec8, allRecsTracked); !collide { t.Error("records should collide") } // rec9 ends at the time savedRecTracked ends rec9 := newTestRecord(-80, -60) - if !collides(rec9, allRecsTracked) { + if collide, _ := collides(rec9, allRecsTracked); !collide { t.Error("records should collide") } // rec10 ends after savedRecTracked starts rec10 := newTestRecord(-80, -50) - if !collides(rec10, allRecsTracked) { + if collide, _ := collides(rec10, allRecsTracked); !collide { t.Error("records should collide") } // rec11 ends before savedRecTracked starts rec11 := newTestRecord(-80, -70) - if collides(rec11, allRecsTracked) { + if collide, _ := collides(rec11, allRecsTracked); collide { t.Error("records should not collide") } } From 501941f3c9829c80b0cde65744aaacb43e43d1e5 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 28 Aug 2021 20:46:21 +0800 Subject: [PATCH 04/10] fix: remove unnecessary code --- cli/create.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/create.go b/cli/create.go index d47d4af..42a7f52 100644 --- a/cli/create.go +++ b/cli/create.go @@ -106,7 +106,7 @@ func createRecordCommand(t *core.Timetrace) *cobra.Command { return } if collides { - out.Warn(" start and end of the record should not overlap with others") + //out.Warn(" start and end of the record should not overlap with others") return } From dbcdf1abc903a73c981d8572127d92faa345ac20 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 28 Aug 2021 20:50:01 +0800 Subject: [PATCH 05/10] feat: print colliding records in table format --- core/timetrace.go | 59 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/core/timetrace.go b/core/timetrace.go index 2ffd665..70e4d63 100644 --- a/core/timetrace.go +++ b/core/timetrace.go @@ -5,6 +5,7 @@ import ( "io" "os" "path/filepath" + "strconv" "time" "github.com/dominikbraun/timetrace/config" @@ -274,6 +275,37 @@ func (t *Timetrace) latestNonEmptyDir(dirs []string) (string, error) { return "", ErrAllDirectoriesEmpty } +func printCollides(t *Timetrace, records []*Record) { + out.Err("collides with these records :") + + rows := make([][]string, len(records)) + + for i, record := range records { + end := "still running" + if record.End != nil { + end = t.Formatter().TimeString(*record.End) + } + + billable := "no" + + if record.IsBillable { + billable = "yes" + } + + rows[i] = make([]string, 6) + rows[i][0] = strconv.Itoa(i + 1) + rows[i][1] = t.Formatter().RecordKey(record) + rows[i][2] = record.Project.Key + rows[i][3] = t.Formatter().TimeString(record.Start) + rows[i][4] = end + rows[i][5] = billable + } + + out.Table([]string{"#", "Key", "Project", "Start", "End", "Billable"}, rows, []string{}) + + out.Warn(" start and end of the record should not overlap with others") +} + // RecordCollides checks if the time of a record collides // with other records of the same day and returns a bool func (t *Timetrace) RecordCollides(toCheck Record) (bool, error) { @@ -292,36 +324,31 @@ func (t *Timetrace) RecordCollides(toCheck Record) (bool, error) { } } - return collides(toCheck, allRecords), nil + collide, collidingRecords := collides(toCheck, allRecords) + if collide { + printCollides(t, collidingRecords) + } + + return collide, nil } -func collides(toCheck Record, allRecords []*Record) bool { +func collides(toCheck Record, allRecords []*Record) (bool, []*Record) { collide := false + collidingRecords := make([]*Record, 0) for _, rec := range allRecords { - var project, end string - if rec.Project != nil { - project = rec.Project.Key - } - if rec.End != nil { - end = rec.End.String() - } if rec.End != nil && rec.Start.Before(*toCheck.End) && rec.End.After(toCheck.Start) { - defer out.Info("%v %v-%v", project, rec.Start.String(), end) + collidingRecords = append(collidingRecords, rec) collide = true } if rec.End == nil && toCheck.End.After(rec.Start) { - defer out.Info("%v %v-%v", project, rec.Start.String(), end) + collidingRecords = append(collidingRecords, rec) collide = true } } - if collide { - out.Err("collides with these records :") - } - - return collide + return collide, collidingRecords } // isBackFile checks if a given filename is a backup-file From 3fd9651cbb4037b04349b7591a2408740d1f1f24 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 28 Aug 2021 20:50:01 +0800 Subject: [PATCH 06/10] feat: print colliding records in table format --- core/timetrace.go | 59 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/core/timetrace.go b/core/timetrace.go index 2ffd665..70e4d63 100644 --- a/core/timetrace.go +++ b/core/timetrace.go @@ -5,6 +5,7 @@ import ( "io" "os" "path/filepath" + "strconv" "time" "github.com/dominikbraun/timetrace/config" @@ -274,6 +275,37 @@ func (t *Timetrace) latestNonEmptyDir(dirs []string) (string, error) { return "", ErrAllDirectoriesEmpty } +func printCollides(t *Timetrace, records []*Record) { + out.Err("collides with these records :") + + rows := make([][]string, len(records)) + + for i, record := range records { + end := "still running" + if record.End != nil { + end = t.Formatter().TimeString(*record.End) + } + + billable := "no" + + if record.IsBillable { + billable = "yes" + } + + rows[i] = make([]string, 6) + rows[i][0] = strconv.Itoa(i + 1) + rows[i][1] = t.Formatter().RecordKey(record) + rows[i][2] = record.Project.Key + rows[i][3] = t.Formatter().TimeString(record.Start) + rows[i][4] = end + rows[i][5] = billable + } + + out.Table([]string{"#", "Key", "Project", "Start", "End", "Billable"}, rows, []string{}) + + out.Warn(" start and end of the record should not overlap with others") +} + // RecordCollides checks if the time of a record collides // with other records of the same day and returns a bool func (t *Timetrace) RecordCollides(toCheck Record) (bool, error) { @@ -292,36 +324,31 @@ func (t *Timetrace) RecordCollides(toCheck Record) (bool, error) { } } - return collides(toCheck, allRecords), nil + collide, collidingRecords := collides(toCheck, allRecords) + if collide { + printCollides(t, collidingRecords) + } + + return collide, nil } -func collides(toCheck Record, allRecords []*Record) bool { +func collides(toCheck Record, allRecords []*Record) (bool, []*Record) { collide := false + collidingRecords := make([]*Record, 0) for _, rec := range allRecords { - var project, end string - if rec.Project != nil { - project = rec.Project.Key - } - if rec.End != nil { - end = rec.End.String() - } if rec.End != nil && rec.Start.Before(*toCheck.End) && rec.End.After(toCheck.Start) { - defer out.Info("%v %v-%v", project, rec.Start.String(), end) + collidingRecords = append(collidingRecords, rec) collide = true } if rec.End == nil && toCheck.End.After(rec.Start) { - defer out.Info("%v %v-%v", project, rec.Start.String(), end) + collidingRecords = append(collidingRecords, rec) collide = true } } - if collide { - out.Err("collides with these records :") - } - - return collide + return collide, collidingRecords } // isBackFile checks if a given filename is a backup-file From a5147bf6933452cde71f55ed2b173810cc08daa8 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 28 Aug 2021 20:53:43 +0800 Subject: [PATCH 07/10] feat: remove unnecessary comment --- cli/create.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/create.go b/cli/create.go index d47d4af..1f418a7 100644 --- a/cli/create.go +++ b/cli/create.go @@ -106,7 +106,6 @@ func createRecordCommand(t *core.Timetrace) *cobra.Command { return } if collides { - out.Warn(" start and end of the record should not overlap with others") return } From 65590a31638af220841ef066c28a1868f3c99bfa Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 4 Sep 2021 08:55:49 +0800 Subject: [PATCH 08/10] refactor: change function name: printCollides to printCollisions --- core/timetrace.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/timetrace.go b/core/timetrace.go index 70e4d63..7e0235d 100644 --- a/core/timetrace.go +++ b/core/timetrace.go @@ -275,7 +275,7 @@ func (t *Timetrace) latestNonEmptyDir(dirs []string) (string, error) { return "", ErrAllDirectoriesEmpty } -func printCollides(t *Timetrace, records []*Record) { +func printCollisions(t *Timetrace, records []*Record) { out.Err("collides with these records :") rows := make([][]string, len(records)) @@ -326,7 +326,7 @@ func (t *Timetrace) RecordCollides(toCheck Record) (bool, error) { collide, collidingRecords := collides(toCheck, allRecords) if collide { - printCollides(t, collidingRecords) + printCollisions(t, collidingRecords) } return collide, nil From d599180a9f941d08a551cff18b869a7c86f7dc49 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sat, 4 Sep 2021 20:33:31 +0800 Subject: [PATCH 09/10] fix:change test file as well --- core/timetrace_test.go | 52 +++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/core/timetrace_test.go b/core/timetrace_test.go index 5587d5d..3926bbe 100644 --- a/core/timetrace_test.go +++ b/core/timetrace_test.go @@ -1,6 +1,7 @@ package core import ( + "reflect" "testing" "time" ) @@ -16,6 +17,19 @@ func newTestRecTracked(s int) Record { return Record{Start: start} } +func checkConsistent(t *testing.T, expect, result []*Record) { + if !reflect.DeepEqual(result, expect) { + t.Errorf("should collide with :\n") + for _, r := range expect { + t.Errorf("%v\n", r) + } + t.Errorf("while collides return :\n") + for _, r := range result { + t.Errorf("%v\n", r) + } + } +} + func TestCollides(t *testing.T) { savedRec := newTestRecord(-60, -1) allRecs := []*Record{&savedRec} @@ -25,77 +39,93 @@ func TestCollides(t *testing.T) { // rec1 starts and end after savedRec rec1 := newTestRecord(-1, 0) - if collide, _ := collides(rec1, allRecs); collide { + if collide, collidingRecs := collides(rec1, allRecs); collide && len(collidingRecs) == 0 { t.Error("records should not collide") } // rec2 starts in savedRec, ends after rec2 := newTestRecord(-30, 1) - if collide, _ := collides(rec2, allRecs); !collide { + if collide, collidingRecs := collides(rec2, allRecs); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecs, collidingRecs) } // rec3 start before savedRec, ends inside rec3 := newTestRecord(-75, -30) - if collide, _ := collides(rec3, allRecs); !collide { + if collide, collidingRecs := collides(rec3, allRecs); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecs, collidingRecs) } // rec4 starts and ends before savedRec rec4 := newTestRecord(-75, -70) - if collide, _ := collides(rec4, allRecs); collide { + if collide, collidingRecs := collides(rec4, allRecs); collide && len(collidingRecs) == 0 { t.Error("records should not collide") } // rec5 starts and ends inside savedRec rec5 := newTestRecord(-40, -20) - if collide, _ := collides(rec5, allRecs); !collide { + if collide, collidingRecs := collides(rec5, allRecs); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecs, collidingRecs) } // rec6 starts before and ends after savedRec rec6 := newTestRecord(-70, 10) - if collide, _ := collides(rec6, allRecs); !collide { + if collide, collidingRecs := collides(rec6, allRecs); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecs, collidingRecs) } // rec7 starts and ends at the same time as savedRec rec7 := newTestRecord(-60, -1) - if collide, _ := collides(rec7, allRecs); !collide { + if collide, collidingRecs := collides(rec7, allRecs); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecs, collidingRecs) } // rec7 starts at the same time as savedRecTracked rec8 := newTestRecord(-60, -1) - if collide, _ := collides(rec8, allRecsTracked); !collide { + if collide, collidingRecs := collides(rec8, allRecsTracked); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecsTracked, collidingRecs) } // rec9 ends at the time savedRecTracked ends rec9 := newTestRecord(-80, -60) - if collide, _ := collides(rec9, allRecsTracked); !collide { + if collide, collidingRecs := collides(rec9, allRecsTracked); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecsTracked, collidingRecs) } // rec10 ends after savedRecTracked starts rec10 := newTestRecord(-80, -50) - if collide, _ := collides(rec10, allRecsTracked); !collide { + if collide, collidingRecs := collides(rec10, allRecsTracked); !collide { t.Error("records should collide") + } else { + checkConsistent(t, allRecsTracked, collidingRecs) } // rec11 ends before savedRecTracked starts rec11 := newTestRecord(-80, -70) - if collide, _ := collides(rec11, allRecsTracked); collide { + if collide, collidingRecs := collides(rec11, allRecsTracked); collide && len(collidingRecs) == 0 { t.Error("records should not collide") } } From 0c08e97acdd32eb6f6dc06f48a6630b7e4356c51 Mon Sep 17 00:00:00 2001 From: Redemptionc <842391412@qq.com> Date: Sun, 5 Sep 2021 11:14:19 +0800 Subject: [PATCH 10/10] fix:use simple loop instead of reflect.DeepEqual --- core/timetrace_test.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/timetrace_test.go b/core/timetrace_test.go index 3926bbe..afb42b7 100644 --- a/core/timetrace_test.go +++ b/core/timetrace_test.go @@ -1,7 +1,6 @@ package core import ( - "reflect" "testing" "time" ) @@ -18,7 +17,18 @@ func newTestRecTracked(s int) Record { } func checkConsistent(t *testing.T, expect, result []*Record) { - if !reflect.DeepEqual(result, expect) { + sameLen := len(result) == len(expect) + sameContent := true + + if sameLen { + for i := range result { + if expect[i] != result[i] { + sameContent = false + } + } + } + + if !(sameLen && sameContent) { t.Errorf("should collide with :\n") for _, r := range expect { t.Errorf("%v\n", r) @@ -28,6 +38,7 @@ func checkConsistent(t *testing.T, expect, result []*Record) { t.Errorf("%v\n", r) } } + } func TestCollides(t *testing.T) {