This commit is contained in:
Erik Winter 2024-12-22 10:10:58 +01:00
parent 5df7d3ff3d
commit 7360744e34
2 changed files with 401 additions and 445 deletions

View File

@ -29,7 +29,7 @@ func NewRecurrer(recurStr string) Recurrer {
} }
for _, parseFunc := range []func(Date, []string) (Recurrer, bool){ for _, parseFunc := range []func(Date, []string) (Recurrer, bool){
ParseDaily, ParseEveryNDays, ParseWeekly, ParseBiweekly, ParseDaily, ParseEveryNDays, ParseWeekly,
ParseEveryNWeeks, ParseEveryNMonths, ParseEveryNWeeks, ParseEveryNMonths,
} { } {
if recur, ok := parseFunc(start, terms); ok { if recur, ok := parseFunc(start, terms); ok {
@ -178,61 +178,6 @@ type Biweekly struct {
Weekday time.Weekday Weekday time.Weekday
} }
// yyyy-mm-dd, biweekly, wednesday
func ParseBiweekly(start Date, terms []string) (Recurrer, bool) {
if len(terms) < 2 {
return nil, false
}
if terms[0] != "biweekly" {
return nil, false
}
wd, ok := ParseWeekday(terms[1])
if !ok {
return nil, false
}
return Biweekly{
Start: start,
Weekday: wd,
}, true
}
func (b Biweekly) RecursOn(date Date) bool {
if b.Start.After(date) {
return false
}
if b.Weekday != date.Weekday() {
return false
}
// find first
tDate := b.Start
for {
if tDate.Weekday() == b.Weekday {
break
}
tDate = tDate.AddDays(1)
}
// add weeks
for {
switch {
case tDate.Equal(date):
return true
case tDate.After(date):
return false
}
tDate = tDate.AddDays(14)
}
}
func (b Biweekly) String() string {
return fmt.Sprintf("%s, biweekly, %s", b.Start.String(), strings.ToLower(b.Weekday.String()))
}
type EveryNWeeks struct { type EveryNWeeks struct {
Start Date Start Date
N int N int

View File

@ -1,417 +1,428 @@
package item_test package item_test
// func TestDaily(t *testing.T) { import (
// daily := task.Daily{ "testing"
// Start: task.NewDate(2021, 1, 31), // a sunday "time"
// }
// dailyStr := "2021-01-31 (sunday), daily"
// t.Run("parse", func(t *testing.T) { "github.com/google/go-cmp/cmp"
// test.Equals(t, daily, task.NewRecurrer(dailyStr)) "go-mod.ewintr.nl/planner/item"
// }) )
// t.Run("string", func(t *testing.T) { func TestDaily(t *testing.T) {
// test.Equals(t, dailyStr, daily.String()) t.Parallel()
// })
// t.Run("recurs_on", func(t *testing.T) { daily := item.Daily{
// for _, tc := range []struct { Start: item.NewDate(2021, 1, 31), // a sunday
// name string }
// date task.Date dailyStr := "2021-01-31, daily"
// exp bool
// }{
// {
// name: "before",
// date: task.NewDate(2021, 1, 30),
// },
// {
// name: "on",
// date: daily.Start,
// exp: true,
// },
// {
// name: "after",
// date: task.NewDate(2021, 2, 1),
// exp: true,
// },
// } {
// t.Run(tc.name, func(t *testing.T) {
// test.Equals(t, tc.exp, daily.RecursOn(tc.date))
// })
// }
// })
// }
// func TestEveryNDays(t *testing.T) { t.Run("parse", func(t *testing.T) {
// every := task.EveryNDays{ if diff := cmp.Diff(daily, item.NewRecurrer(dailyStr)); diff != "" {
// Start: task.NewDate(2022, 6, 8), t.Errorf("(-exp +got):\n%s", diff)
// N: 5, }
// } })
// everyStr := "2022-06-08 (wednesday), every 5 days"
// t.Run("parse", func(t *testing.T) { t.Run("string", func(t *testing.T) {
// test.Equals(t, every, task.NewRecurrer(everyStr)) if dailyStr != daily.String() {
// }) t.Errorf("exp %v, got %v", dailyStr, daily.String())
}
})
// t.Run("string", func(t *testing.T) { t.Run("recurs_on", func(t *testing.T) {
// test.Equals(t, everyStr, every.String()) for _, tc := range []struct {
// }) name string
date item.Date
exp bool
}{
{
name: "before",
date: item.NewDate(2021, 1, 30),
},
{
name: "on",
date: daily.Start,
exp: true,
},
{
name: "after",
date: item.NewDate(2021, 2, 1),
exp: true,
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.exp != daily.RecursOn(tc.date) {
t.Errorf("exp %v, got %v", tc.exp, daily.RecursOn(tc.date))
}
})
}
})
}
// t.Run("recurs on", func(t *testing.T) { func TestEveryNDays(t *testing.T) {
// for _, tc := range []struct { t.Parallel()
// name string
// date task.Date
// exp bool
// }{
// {
// name: "before",
// date: task.NewDate(2022, 1, 1),
// },
// {
// name: "start",
// date: every.Start,
// exp: true,
// },
// {
// name: "after true",
// date: every.Start.Add(15),
// exp: true,
// },
// {
// name: "after false",
// date: every.Start.Add(16),
// },
// } {
// t.Run(tc.name, func(t *testing.T) {
// test.Equals(t, tc.exp, every.RecursOn(tc.date))
// })
// }
// })
// }
// func TestParseWeekly(t *testing.T) { every := item.EveryNDays{
// start := task.NewDate(2021, 2, 7) Start: item.NewDate(2022, 6, 8),
// for _, tc := range []struct { N: 5,
// name string }
// input []string everyStr := "2022-06-08, every 5 days"
// 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) { t.Run("parse", func(t *testing.T) {
// weekly := task.Weekly{ if diff := cmp.Diff(every, item.NewRecurrer(everyStr)); diff != "" {
// Start: task.NewDate(2021, 1, 31), // a sunday t.Errorf("(-exp +got):\n%s", diff)
// Weekdays: task.Weekdays{ }
// time.Monday, })
// time.Wednesday,
// time.Thursday,
// },
// }
// weeklyStr := "2021-01-31 (sunday), weekly, monday & wednesday & thursday"
// t.Run("parse", func(t *testing.T) { t.Run("string", func(t *testing.T) {
// test.Equals(t, weekly, task.NewRecurrer(weeklyStr)) if everyStr != every.String() {
// }) t.Errorf("exp %v, got %v", everyStr, every.String())
}
})
// t.Run("string", func(t *testing.T) { t.Run("recurs on", func(t *testing.T) {
// test.Equals(t, weeklyStr, weekly.String()) for _, tc := range []struct {
// }) name string
date item.Date
exp bool
}{
{
name: "before",
date: item.NewDate(2022, 1, 1),
},
{
name: "start",
date: every.Start,
exp: true,
},
{
name: "after true",
date: every.Start.Add(15),
exp: true,
},
{
name: "after false",
date: every.Start.Add(16),
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.exp != every.RecursOn(tc.date) {
t.Errorf("exp %v, got %v", tc.exp, tc.date)
}
})
}
})
}
// t.Run("recurs_on", func(t *testing.T) { func TestParseWeekly(t *testing.T) {
// for _, tc := range []struct { t.Parallel()
// name string
// date task.Date
// exp bool
// }{
// {
// name: "before start",
// date: task.NewDate(2021, 1, 27), // a wednesday
// },
// {
// name: "right weekday",
// date: task.NewDate(2021, 2, 1), // a monday
// exp: true,
// },
// {
// name: "another right day",
// date: task.NewDate(2021, 2, 3), // a wednesday
// exp: true,
// },
// {
// name: "wrong weekday",
// date: task.NewDate(2021, 2, 5), // a friday
// },
// } {
// t.Run(tc.name, func(t *testing.T) {
// test.Equals(t, tc.exp, weekly.RecursOn(tc.date))
// })
// }
// })
// }
// func TestBiweekly(t *testing.T) { start := item.NewDate(2021, 2, 7)
// biweekly := task.Biweekly{ for _, tc := range []struct {
// Start: task.NewDate(2021, 1, 31), // a sunday name string
// Weekday: time.Wednesday, input []string
// } expOK bool
// biweeklyStr := "2021-01-31 (sunday), biweekly, wednesday" expWeekly item.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: item.Weekly{
Start: start,
Weekdays: item.Weekdays{
time.Monday,
},
},
},
{
name: "multiple days",
input: []string{"weekly", "monday & thursday & saturday"},
expOK: true,
expWeekly: item.Weekly{
Start: start,
Weekdays: item.Weekdays{
time.Monday,
time.Thursday,
time.Saturday,
},
},
},
{
name: "wrong order",
input: []string{"weekly", "sunday & thursday & wednesday"},
expOK: true,
expWeekly: item.Weekly{
Start: start,
Weekdays: item.Weekdays{
time.Wednesday,
time.Thursday,
time.Sunday,
},
},
},
{
name: "doubles",
input: []string{"weekly", "sunday & sunday & monday"},
expOK: true,
expWeekly: item.Weekly{
Start: start,
Weekdays: item.Weekdays{
time.Monday,
time.Sunday,
},
},
},
{
name: "one unknown",
input: []string{"weekly", "sunday & someday"},
expOK: true,
expWeekly: item.Weekly{
Start: start,
Weekdays: item.Weekdays{
time.Sunday,
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
actWeekly, actOK := item.ParseWeekly(start, tc.input)
if tc.expOK != actOK {
t.Errorf("exp %v, got %v", tc.expOK, actOK)
}
if !tc.expOK {
return
}
if diff := cmp.Diff(tc.expWeekly, actWeekly); diff != "" {
t.Errorf("(-exp, +got)%s\n", diff)
}
})
}
}
// t.Run("parse", func(t *testing.T) { func TestWeekly(t *testing.T) {
// test.Equals(t, biweekly, task.NewRecurrer(biweeklyStr)) t.Parallel()
// })
// t.Run("string", func(t *testing.T) { weekly := item.Weekly{
// test.Equals(t, biweeklyStr, biweekly.String()) Start: item.NewDate(2021, 1, 31), // a sunday
// }) Weekdays: item.Weekdays{
time.Monday,
time.Wednesday,
time.Thursday,
},
}
weeklyStr := "2021-01-31, weekly, monday & wednesday & thursday"
// t.Run("recurs_on", func(t *testing.T) { t.Run("parse", func(t *testing.T) {
// for _, tc := range []struct { if diff := cmp.Diff(weekly, item.NewRecurrer(weeklyStr)); diff != "" {
// name string t.Errorf("(-exp, +got)%s\n", diff)
// date task.Date }
// exp bool })
// }{
// {
// name: "before start",
// date: task.NewDate(2021, 1, 27), // a wednesday
// },
// {
// name: "wrong weekday",
// date: task.NewDate(2021, 2, 1), // a monday
// },
// {
// name: "odd week count",
// date: task.NewDate(2021, 2, 10), // a wednesday
// },
// {
// name: "right",
// date: task.NewDate(2021, 2, 17), // a wednesday
// exp: true,
// },
// } {
// t.Run(tc.name, func(t *testing.T) {
// test.Equals(t, tc.exp, biweekly.RecursOn(tc.date))
// })
// }
// })
// }
// func TestEveryNWeeks(t *testing.T) { t.Run("string", func(t *testing.T) {
// everyNWeeks := task.EveryNWeeks{ if weeklyStr != weekly.String() {
// Start: task.NewDate(2021, 2, 3), t.Errorf("exp %v, got %v", weeklyStr, weekly.String())
// N: 3, }
// } })
// everyNWeeksStr := "2021-02-03 (wednesday), every 3 weeks"
// t.Run("parse", func(t *testing.T) { t.Run("recurs_on", func(t *testing.T) {
// test.Equals(t, everyNWeeks, task.NewRecurrer(everyNWeeksStr)) for _, tc := range []struct {
// }) name string
date item.Date
exp bool
}{
{
name: "before start",
date: item.NewDate(2021, 1, 27), // a wednesday
},
{
name: "right weekday",
date: item.NewDate(2021, 2, 1), // a monday
exp: true,
},
{
name: "another right day",
date: item.NewDate(2021, 2, 3), // a wednesday
exp: true,
},
{
name: "wrong weekday",
date: item.NewDate(2021, 2, 5), // a friday
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.exp != weekly.RecursOn(tc.date) {
t.Errorf("exp %v, got %v", tc.exp, weekly.RecursOn(tc.date))
}
})
}
})
}
// t.Run("string", func(t *testing.T) { func TestEveryNWeeks(t *testing.T) {
// test.Equals(t, everyNWeeksStr, everyNWeeks.String()) t.Parallel()
// })
// t.Run("recurs on", func(t *testing.T) { everyNWeeks := item.EveryNWeeks{
// for _, tc := range []struct { Start: item.NewDate(2021, 2, 3),
// name string N: 3,
// date task.Date }
// exp bool everyNWeeksStr := "2021-02-03, every 3 weeks"
// }{
// {
// name: "before start",
// date: task.NewDate(2021, 1, 27),
// },
// {
// name: "on start",
// date: task.NewDate(2021, 2, 3),
// exp: true,
// },
// {
// name: "wrong day",
// date: task.NewDate(2021, 2, 4),
// },
// {
// name: "one week after",
// date: task.NewDate(2021, 2, 10),
// },
// {
// name: "first interval",
// date: task.NewDate(2021, 2, 24),
// exp: true,
// },
// {
// name: "second interval",
// date: task.NewDate(2021, 3, 17),
// exp: true,
// },
// {
// name: "second interval plus one week",
// date: task.NewDate(2021, 3, 24),
// },
// } {
// t.Run(tc.name, func(t *testing.T) {
// test.Equals(t, tc.exp, everyNWeeks.RecursOn(tc.date))
// })
// }
// })
// }
// func TestEveryNMonths(t *testing.T) { t.Run("parse", func(t *testing.T) {
// everyNMonths := task.EveryNMonths{ if everyNWeeks != item.NewRecurrer(everyNWeeksStr) {
// Start: task.NewDate(2021, 2, 3), t.Errorf("exp %v, got %v", everyNWeeks, item.NewRecurrer(everyNWeeksStr))
// N: 3, }
// } })
// everyNMonthsStr := "2021-02-03 (wednesday), every 3 months"
// t.Run("parse", func(t *testing.T) { t.Run("string", func(t *testing.T) {
// test.Equals(t, everyNMonths, task.NewRecurrer(everyNMonthsStr)) if everyNWeeksStr != everyNWeeks.String() {
// }) t.Errorf("exp %v, got %v", everyNWeeksStr, everyNWeeks.String())
}
})
// t.Run("string", func(t *testing.T) { t.Run("recurs on", func(t *testing.T) {
// test.Equals(t, everyNMonthsStr, everyNMonths.String()) for _, tc := range []struct {
// }) name string
date item.Date
exp bool
}{
{
name: "before start",
date: item.NewDate(2021, 1, 27),
},
{
name: "on start",
date: item.NewDate(2021, 2, 3),
exp: true,
},
{
name: "wrong day",
date: item.NewDate(2021, 2, 4),
},
{
name: "one week after",
date: item.NewDate(2021, 2, 10),
},
{
name: "first interval",
date: item.NewDate(2021, 2, 24),
exp: true,
},
{
name: "second interval",
date: item.NewDate(2021, 3, 17),
exp: true,
},
{
name: "second interval plus one week",
date: item.NewDate(2021, 3, 24),
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.exp != everyNWeeks.RecursOn(tc.date) {
t.Errorf("exp %v, got %v", tc.exp, everyNWeeks.RecursOn(tc.date))
}
})
}
})
}
// t.Run("recurs on", func(t *testing.T) { func TestEveryNMonths(t *testing.T) {
// for _, tc := range []struct { everyNMonths := item.EveryNMonths{
// name string Start: item.NewDate(2021, 2, 3),
// date task.Date N: 3,
// exp bool }
// }{ everyNMonthsStr := "2021-02-03, every 3 months"
// {
// name: "before start",
// date: task.NewDate(2021, 1, 27),
// },
// {
// name: "on start",
// date: task.NewDate(2021, 2, 3),
// exp: true,
// },
// {
// name: "8 weeks after",
// date: task.NewDate(2021, 3, 31),
// },
// {
// name: "one month",
// date: task.NewDate(2021, 3, 3),
// },
// {
// name: "3 months",
// date: task.NewDate(2021, 5, 3),
// exp: true,
// },
// {
// name: "4 months",
// date: task.NewDate(2021, 6, 3),
// },
// {
// name: "6 months",
// date: task.NewDate(2021, 8, 3),
// exp: true,
// },
// } {
// t.Run(tc.name, func(t *testing.T) {
// test.Equals(t, tc.exp, everyNMonths.RecursOn(tc.date))
// })
// }
// })
// t.Run("recurs every year", func(t *testing.T) { t.Run("parse", func(t *testing.T) {
// recur := task.EveryNMonths{ if diff := cmp.Diff(everyNMonths, item.NewRecurrer(everyNMonthsStr)); diff != "" {
// Start: task.NewDate(2021, 3, 1), t.Errorf("(-exp, +got)%s\n", diff)
// N: 12, }
// } })
// test.Equals(t, false, recur.RecursOn(task.NewDate(2021, 3, 9)))
// })
// t.Run("bug", func(t *testing.T) { t.Run("string", func(t *testing.T) {
// recur := task.EveryNMonths{ if everyNMonthsStr != everyNMonths.String() {
// Start: task.NewDate(2021, 3, 1), t.Errorf("exp %v, got %v", everyNMonthsStr, everyNMonths.String())
// N: 1, }
// } })
// test.Equals(t, false, recur.RecursOn(task.NewDate(2021, 11, 3)))
// }) t.Run("recurs on", func(t *testing.T) {
// } for _, tc := range []struct {
name string
date item.Date
exp bool
}{
{
name: "before start",
date: item.NewDate(2021, 1, 27),
},
{
name: "on start",
date: item.NewDate(2021, 2, 3),
exp: true,
},
{
name: "8 weeks after",
date: item.NewDate(2021, 3, 31),
},
{
name: "one month",
date: item.NewDate(2021, 3, 3),
},
{
name: "3 months",
date: item.NewDate(2021, 5, 3),
exp: true,
},
{
name: "4 months",
date: item.NewDate(2021, 6, 3),
},
{
name: "6 months",
date: item.NewDate(2021, 8, 3),
exp: true,
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.exp != everyNMonths.RecursOn(tc.date) {
t.Errorf("exp %v, got %v", tc.exp, everyNMonths.RecursOn(tc.date))
}
})
}
})
t.Run("recurs every year", func(t *testing.T) {
recur := item.EveryNMonths{
Start: item.NewDate(2021, 3, 1),
N: 12,
}
if recur.RecursOn(item.NewDate(2021, 3, 9)) {
t.Errorf("exp false, got true")
}
})
t.Run("bug", func(t *testing.T) {
recur := item.EveryNMonths{
Start: item.NewDate(2021, 3, 1),
N: 1,
}
if recur.RecursOn(item.NewDate(2021, 11, 3)) {
t.Errorf("exp false, got true")
}
})
}