multiple days in weekly recur
This commit is contained in:
parent
aef4dc1af2
commit
835683e1c8
|
@ -2,6 +2,7 @@ package task
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -17,6 +18,35 @@ func init() {
|
||||||
Today = NewDate(year, int(month), day)
|
Today = NewDate(year, int(month), day)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Weekdays []time.Weekday
|
||||||
|
|
||||||
|
func (wds Weekdays) Len() int { return len(wds) }
|
||||||
|
func (wds Weekdays) Swap(i, j int) { wds[j], wds[i] = wds[i], wds[j] }
|
||||||
|
func (wds Weekdays) Less(i, j int) bool {
|
||||||
|
if wds[i] == time.Sunday {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if wds[j] == time.Sunday {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(wds[i]) < int(wds[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wds Weekdays) Unique() Weekdays {
|
||||||
|
mwds := map[time.Weekday]bool{}
|
||||||
|
for _, wd := range wds {
|
||||||
|
mwds[wd] = true
|
||||||
|
}
|
||||||
|
newWds := Weekdays{}
|
||||||
|
for wd := range mwds {
|
||||||
|
newWds = append(newWds, wd)
|
||||||
|
}
|
||||||
|
sort.Sort(newWds)
|
||||||
|
|
||||||
|
return newWds
|
||||||
|
}
|
||||||
|
|
||||||
type Date struct {
|
type Date struct {
|
||||||
t time.Time
|
t time.Time
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,79 @@
|
||||||
package task_test
|
package task_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.sr.ht/~ewintr/go-kit/test"
|
"git.sr.ht/~ewintr/go-kit/test"
|
||||||
"git.sr.ht/~ewintr/gte/internal/task"
|
"git.sr.ht/~ewintr/gte/internal/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestWeekdaysSort(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
input task.Weekdays
|
||||||
|
exp task.Weekdays
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one",
|
||||||
|
input: task.Weekdays{time.Tuesday},
|
||||||
|
exp: task.Weekdays{time.Tuesday},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple",
|
||||||
|
input: task.Weekdays{time.Wednesday, time.Tuesday, time.Monday},
|
||||||
|
exp: task.Weekdays{time.Monday, time.Tuesday, time.Wednesday},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sunday is last",
|
||||||
|
input: task.Weekdays{time.Saturday, time.Sunday, time.Monday},
|
||||||
|
exp: task.Weekdays{time.Monday, time.Saturday, time.Sunday},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
sort.Sort(tc.input)
|
||||||
|
test.Equals(t, tc.exp, tc.input)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWeekdaysUnique(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
input task.Weekdays
|
||||||
|
exp task.Weekdays
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
input: task.Weekdays{},
|
||||||
|
exp: task.Weekdays{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single",
|
||||||
|
input: task.Weekdays{time.Monday},
|
||||||
|
exp: task.Weekdays{time.Monday},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no doubles",
|
||||||
|
input: task.Weekdays{time.Monday, time.Tuesday, time.Wednesday},
|
||||||
|
exp: task.Weekdays{time.Monday, time.Tuesday, time.Wednesday},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doubles",
|
||||||
|
input: task.Weekdays{time.Monday, time.Monday, time.Wednesday, time.Monday},
|
||||||
|
exp: task.Weekdays{time.Monday, time.Wednesday},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
test.Equals(t, tc.exp, tc.input.Unique())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewDateFromString(t *testing.T) {
|
func TestNewDateFromString(t *testing.T) {
|
||||||
task.Today = task.NewDate(2021, 1, 30)
|
task.Today = task.NewDate(2021, 1, 30)
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
|
|
|
@ -64,11 +64,11 @@ func (d Daily) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Weekly struct {
|
type Weekly struct {
|
||||||
Start Date
|
Start Date
|
||||||
Weekday time.Weekday
|
Weekdays Weekdays
|
||||||
}
|
}
|
||||||
|
|
||||||
// yyyy-mm-dd, weekly, wednesday
|
// yyyy-mm-dd, weekly, wednesday & saturday & sunday
|
||||||
func ParseWeekly(start Date, terms []string) (Recurrer, bool) {
|
func ParseWeekly(start Date, terms []string) (Recurrer, bool) {
|
||||||
if len(terms) < 2 {
|
if len(terms) < 2 {
|
||||||
return nil, false
|
return nil, false
|
||||||
|
@ -78,14 +78,21 @@ func ParseWeekly(start Date, terms []string) (Recurrer, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
wd, ok := ParseWeekday(terms[1])
|
wds := Weekdays{}
|
||||||
if !ok {
|
for _, wdStr := range strings.Split(terms[1], "&") {
|
||||||
|
wd, ok := ParseWeekday(wdStr)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wds = append(wds, wd)
|
||||||
|
}
|
||||||
|
if len(wds) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return Weekly{
|
return Weekly{
|
||||||
Start: start,
|
Start: start,
|
||||||
Weekday: wd,
|
Weekdays: wds.Unique(),
|
||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,11 +101,23 @@ func (w Weekly) RecursOn(date Date) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.Weekday == date.Weekday()
|
for _, wd := range w.Weekdays {
|
||||||
|
if wd == date.Weekday() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Weekly) String() string {
|
func (w Weekly) String() string {
|
||||||
return fmt.Sprintf("%s, weekly, %s", w.Start.String(), strings.ToLower(w.Weekday.String()))
|
weekdayStrs := []string{}
|
||||||
|
for _, wd := range w.Weekdays {
|
||||||
|
weekdayStrs = append(weekdayStrs, wd.String())
|
||||||
|
}
|
||||||
|
weekdayStr := strings.Join(weekdayStrs, " & ")
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s, weekly, %s", w.Start.String(), strings.ToLower(weekdayStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
type Biweekly struct {
|
type Biweekly struct {
|
||||||
|
|
|
@ -50,12 +50,110 @@ func TestDaily(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseWeekly(t *testing.T) {
|
||||||
|
start := task.NewDate(2021, 2, 7)
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
input []string
|
||||||
|
expOk bool
|
||||||
|
expWeekly task.Weekly
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong type",
|
||||||
|
input: []string{"daily"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong count",
|
||||||
|
input: []string{"weeekly"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown day",
|
||||||
|
input: []string{"weekly", "festivus"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one day",
|
||||||
|
input: []string{"weekly", "monday"},
|
||||||
|
expOk: true,
|
||||||
|
expWeekly: task.Weekly{
|
||||||
|
Start: start,
|
||||||
|
Weekdays: task.Weekdays{
|
||||||
|
time.Monday,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple days",
|
||||||
|
input: []string{"weekly", "monday & thursday & saturday"},
|
||||||
|
expOk: true,
|
||||||
|
expWeekly: task.Weekly{
|
||||||
|
Start: start,
|
||||||
|
Weekdays: task.Weekdays{
|
||||||
|
time.Monday,
|
||||||
|
time.Thursday,
|
||||||
|
time.Saturday,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong order",
|
||||||
|
input: []string{"weekly", "sunday & thursday & wednesday"},
|
||||||
|
expOk: true,
|
||||||
|
expWeekly: task.Weekly{
|
||||||
|
Start: start,
|
||||||
|
Weekdays: task.Weekdays{
|
||||||
|
time.Wednesday,
|
||||||
|
time.Thursday,
|
||||||
|
time.Sunday,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doubles",
|
||||||
|
input: []string{"weekly", "sunday & sunday & monday"},
|
||||||
|
expOk: true,
|
||||||
|
expWeekly: task.Weekly{
|
||||||
|
Start: start,
|
||||||
|
Weekdays: task.Weekdays{
|
||||||
|
time.Monday,
|
||||||
|
time.Sunday,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one unknown",
|
||||||
|
input: []string{"weekly", "sunday & someday"},
|
||||||
|
expOk: true,
|
||||||
|
expWeekly: task.Weekly{
|
||||||
|
Start: start,
|
||||||
|
Weekdays: task.Weekdays{
|
||||||
|
time.Sunday,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
weekly, ok := task.ParseWeekly(start, tc.input)
|
||||||
|
test.Equals(t, tc.expOk, ok)
|
||||||
|
if tc.expOk {
|
||||||
|
test.Equals(t, tc.expWeekly, weekly)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWeekly(t *testing.T) {
|
func TestWeekly(t *testing.T) {
|
||||||
weekly := task.Weekly{
|
weekly := task.Weekly{
|
||||||
Start: task.NewDate(2021, 1, 31), // a sunday
|
Start: task.NewDate(2021, 1, 31), // a sunday
|
||||||
Weekday: time.Wednesday,
|
Weekdays: task.Weekdays{
|
||||||
|
time.Monday,
|
||||||
|
time.Wednesday,
|
||||||
|
time.Thursday,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
weeklyStr := "2021-01-31 (sunday), weekly, wednesday"
|
weeklyStr := "2021-01-31 (sunday), weekly, monday & wednesday & thursday"
|
||||||
|
|
||||||
t.Run("parse", func(t *testing.T) {
|
t.Run("parse", func(t *testing.T) {
|
||||||
test.Equals(t, weekly, task.NewRecurrer(weeklyStr))
|
test.Equals(t, weekly, task.NewRecurrer(weeklyStr))
|
||||||
|
@ -76,14 +174,19 @@ func TestWeekly(t *testing.T) {
|
||||||
date: task.NewDate(2021, 1, 27), // a wednesday
|
date: task.NewDate(2021, 1, 27), // a wednesday
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wrong weekday",
|
name: "right weekday",
|
||||||
date: task.NewDate(2021, 2, 1), // a monday
|
date: task.NewDate(2021, 2, 1), // a monday
|
||||||
|
exp: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "right day",
|
name: "another right day",
|
||||||
date: task.NewDate(2021, 2, 3), // a wednesday
|
date: task.NewDate(2021, 2, 3), // a wednesday
|
||||||
exp: true,
|
exp: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "wrong weekday",
|
||||||
|
date: task.NewDate(2021, 2, 5), // a friday
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
test.Equals(t, tc.exp, weekly.RecursOn(tc.date))
|
test.Equals(t, tc.exp, weekly.RecursOn(tc.date))
|
||||||
|
|
Loading…
Reference in New Issue