| // Copyright (c) HashiCorp, Inc. |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| package timeutil |
| |
| import ( |
| "reflect" |
| "testing" |
| "time" |
| ) |
| |
| func TestTimeutil_StartOfPreviousMonth(t *testing.T) { |
| testCases := []struct { |
| Input time.Time |
| Expected time.Time |
| }{ |
| { |
| Input: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| Expected: time.Date(2019, 12, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 1, 15, 0, 0, 0, 0, time.UTC), |
| Expected: time.Date(2019, 12, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 3, 31, 23, 59, 59, 999999999, time.UTC), |
| Expected: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result := StartOfPreviousMonth(tc.Input) |
| if !result.Equal(tc.Expected) { |
| t.Errorf("start of month before %v is %v, got %v", tc.Input, tc.Expected, result) |
| } |
| } |
| } |
| |
| func TestTimeutil_StartOfMonth(t *testing.T) { |
| testCases := []struct { |
| Input time.Time |
| Expected time.Time |
| }{ |
| { |
| Input: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| Expected: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC), |
| Expected: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 1, 1, 0, 0, 0, 1, time.UTC), |
| Expected: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.UTC), |
| Expected: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 2, 28, 1, 2, 3, 4, time.UTC), |
| Expected: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result := StartOfMonth(tc.Input) |
| if !result.Equal(tc.Expected) { |
| t.Errorf("start of %v is %v, expected %v", tc.Input, result, tc.Expected) |
| } |
| } |
| } |
| |
| func TestTimeutil_IsMonthStart(t *testing.T) { |
| testCases := []struct { |
| input time.Time |
| expected bool |
| }{ |
| { |
| input: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| expected: true, |
| }, |
| { |
| input: time.Date(2020, 1, 1, 0, 0, 0, 1, time.UTC), |
| expected: false, |
| }, |
| { |
| input: time.Date(2020, 4, 5, 0, 0, 0, 0, time.UTC), |
| expected: false, |
| }, |
| { |
| input: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.UTC), |
| expected: false, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result := IsMonthStart(tc.input) |
| if result != tc.expected { |
| t.Errorf("is %v the start of the month? expected %t, got %t", tc.input, tc.expected, result) |
| } |
| } |
| } |
| |
| func TestTimeutil_EndOfMonth(t *testing.T) { |
| testCases := []struct { |
| Input time.Time |
| Expected time.Time |
| }{ |
| { |
| // The current behavior does not use the nanoseconds |
| // because we didn't want to clutter the result of end-of-month reporting. |
| Input: time.Date(2020, 1, 31, 23, 59, 59, 0, time.UTC), |
| Expected: time.Date(2020, 1, 31, 23, 59, 59, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.UTC), |
| Expected: time.Date(2020, 1, 31, 23, 59, 59, 0, time.UTC), |
| }, |
| { |
| Input: time.Date(2020, 1, 15, 1, 2, 3, 4, time.UTC), |
| Expected: time.Date(2020, 1, 31, 23, 59, 59, 0, time.UTC), |
| }, |
| { |
| // Leap year |
| Input: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC), |
| Expected: time.Date(2020, 2, 29, 23, 59, 59, 0, time.UTC), |
| }, |
| { |
| // non-leap year |
| Input: time.Date(2100, 2, 1, 0, 0, 0, 0, time.UTC), |
| Expected: time.Date(2100, 2, 28, 23, 59, 59, 0, time.UTC), |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result := EndOfMonth(tc.Input) |
| if !result.Equal(tc.Expected) { |
| t.Errorf("end of %v is %v, expected %v", tc.Input, result, tc.Expected) |
| } |
| } |
| } |
| |
| func TestTimeutil_IsPreviousMonth(t *testing.T) { |
| testCases := []struct { |
| tInput time.Time |
| compareInput time.Time |
| expected bool |
| }{ |
| { |
| tInput: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| compareInput: time.Date(2020, 1, 31, 0, 0, 0, 0, time.UTC), |
| expected: false, |
| }, |
| { |
| tInput: time.Date(2019, 12, 31, 0, 0, 0, 0, time.UTC), |
| compareInput: time.Date(2020, 1, 31, 0, 0, 0, 0, time.UTC), |
| expected: true, |
| }, |
| { |
| // leap year (false) |
| tInput: time.Date(2019, 12, 29, 10, 10, 10, 0, time.UTC), |
| compareInput: time.Date(2020, 2, 29, 10, 10, 10, 0, time.UTC), |
| expected: false, |
| }, |
| { |
| // leap year (true) |
| tInput: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| compareInput: time.Date(2020, 2, 29, 10, 10, 10, 0, time.UTC), |
| expected: true, |
| }, |
| { |
| tInput: time.Date(2018, 5, 5, 5, 0, 0, 0, time.UTC), |
| compareInput: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| expected: false, |
| }, |
| { |
| // test normalization. want to make subtracting 1 month from 3/30/2020 doesn't yield 2/30/2020, normalized |
| // to 3/1/2020 |
| tInput: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC), |
| compareInput: time.Date(2020, 3, 30, 0, 0, 0, 0, time.UTC), |
| expected: true, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result := IsPreviousMonth(tc.tInput, tc.compareInput) |
| if result != tc.expected { |
| t.Errorf("%v in previous month to %v? expected %t, got %t", tc.tInput, tc.compareInput, tc.expected, result) |
| } |
| } |
| } |
| |
| func TestTimeutil_IsCurrentMonth(t *testing.T) { |
| now := time.Now() |
| testCases := []struct { |
| input time.Time |
| expected bool |
| }{ |
| { |
| input: now, |
| expected: true, |
| }, |
| { |
| input: StartOfMonth(now).AddDate(0, 0, -1), |
| expected: false, |
| }, |
| { |
| input: EndOfMonth(now).AddDate(0, 0, -1), |
| expected: true, |
| }, |
| { |
| input: StartOfMonth(now).AddDate(-1, 0, 0), |
| expected: false, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result := IsCurrentMonth(tc.input, now) |
| if result != tc.expected { |
| t.Errorf("invalid result. expected %t for %v", tc.expected, tc.input) |
| } |
| } |
| } |
| |
| func TestTimeUtil_ContiguousMonths(t *testing.T) { |
| testCases := []struct { |
| input []time.Time |
| expected []time.Time |
| }{ |
| { |
| input: []time.Time{ |
| time.Date(2020, 4, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 3, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 2, 5, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| expected: []time.Time{ |
| time.Date(2020, 4, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 3, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 2, 5, 0, 0, 0, 0, time.UTC), |
| }, |
| }, |
| { |
| input: []time.Time{ |
| time.Date(2020, 4, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 3, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| expected: []time.Time{ |
| time.Date(2020, 4, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 3, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| }, |
| { |
| input: []time.Time{ |
| time.Date(2020, 4, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| expected: []time.Time{ |
| time.Date(2020, 4, 1, 0, 0, 0, 0, time.UTC), |
| }, |
| }, |
| { |
| input: []time.Time{}, |
| expected: []time.Time{}, |
| }, |
| { |
| input: nil, |
| expected: nil, |
| }, |
| { |
| input: []time.Time{ |
| time.Date(2020, 2, 2, 0, 0, 0, 0, time.UTC), |
| time.Date(2020, 1, 15, 0, 0, 0, 0, time.UTC), |
| }, |
| expected: []time.Time{ |
| time.Date(2020, 2, 2, 0, 0, 0, 0, time.UTC), |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result := GetMostRecentContiguousMonths(tc.input) |
| |
| if !reflect.DeepEqual(tc.expected, result) { |
| t.Errorf("invalid contiguous segment returned. expected %v, got %v", tc.expected, result) |
| } |
| } |
| } |
| |
| func TestTimeUtil_ParseTimeFromPath(t *testing.T) { |
| testCases := []struct { |
| input string |
| expectedOut time.Time |
| expectError bool |
| }{ |
| { |
| input: "719020800/1", |
| expectedOut: time.Unix(719020800, 0).UTC(), |
| expectError: false, |
| }, |
| { |
| input: "1601415205/3", |
| expectedOut: time.Unix(1601415205, 0).UTC(), |
| expectError: false, |
| }, |
| { |
| input: "baddata/3", |
| expectedOut: time.Time{}, |
| expectError: true, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| result, err := ParseTimeFromPath(tc.input) |
| gotError := err != nil |
| |
| if result != tc.expectedOut { |
| t.Errorf("bad timestamp on input %q. expected: %v got: %v", tc.input, tc.expectedOut, result) |
| } |
| if gotError != tc.expectError { |
| t.Errorf("bad error status on input %q. expected error: %t, got error: %t", tc.input, tc.expectError, gotError) |
| } |
| } |
| } |