mirror of
https://github.com/taigrr/gico.git
synced 2026-04-16 18:25:10 -07:00
The naive year%4==0 check incorrectly treats years like 1900 and 2100 as leap years. Add types.IsLeapYear and types.YearLength helpers using the full Gregorian calendar rule (divisible by 4, except centuries unless divisible by 400). Replace all 8 occurrences across the codebase.
177 lines
3.9 KiB
Go
177 lines
3.9 KiB
Go
package types
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNewDataSet(t *testing.T) {
|
|
ds := NewDataSet()
|
|
if ds == nil {
|
|
t.Fatal("NewDataSet returned nil")
|
|
}
|
|
if len(ds) != 0 {
|
|
t.Fatalf("expected empty DataSet, got %d entries", len(ds))
|
|
}
|
|
}
|
|
|
|
func TestNewCommit(t *testing.T) {
|
|
c := NewCommit("Alice", "alice@example.com", "initial commit", "myrepo", "/tmp/myrepo", 10, 2, 3)
|
|
if c.Author.Name != "Alice" {
|
|
t.Errorf("expected author name Alice, got %s", c.Author.Name)
|
|
}
|
|
if c.Author.Email != "alice@example.com" {
|
|
t.Errorf("expected author email alice@example.com, got %s", c.Author.Email)
|
|
}
|
|
if c.Message != "initial commit" {
|
|
t.Errorf("expected message 'initial commit', got %s", c.Message)
|
|
}
|
|
if c.Added != 10 {
|
|
t.Errorf("expected Added=10, got %d", c.Added)
|
|
}
|
|
if c.Deleted != 2 {
|
|
t.Errorf("expected Deleted=2, got %d", c.Deleted)
|
|
}
|
|
if c.FilesChanged != 3 {
|
|
t.Errorf("expected FilesChanged=3, got %d", c.FilesChanged)
|
|
}
|
|
if c.Repo != "myrepo" {
|
|
t.Errorf("expected Repo=myrepo, got %s", c.Repo)
|
|
}
|
|
if c.Path != "/tmp/myrepo" {
|
|
t.Errorf("expected Path=/tmp/myrepo, got %s", c.Path)
|
|
}
|
|
if c.TimeStamp.IsZero() {
|
|
t.Error("expected non-zero timestamp")
|
|
}
|
|
}
|
|
|
|
func TestCommitString(t *testing.T) {
|
|
ts := time.Date(2025, 6, 15, 14, 30, 0, 0, time.UTC)
|
|
c := Commit{
|
|
TimeStamp: ts,
|
|
Author: Author{Name: "Bob", Email: "bob@example.com"},
|
|
Repo: "testrepo",
|
|
Message: "fix bug",
|
|
}
|
|
s := c.String()
|
|
if !strings.Contains(s, "testrepo") {
|
|
t.Errorf("expected string to contain repo name, got: %s", s)
|
|
}
|
|
if !strings.Contains(s, "fix bug") {
|
|
t.Errorf("expected string to contain message, got: %s", s)
|
|
}
|
|
}
|
|
|
|
func TestFreqMerge(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
a, b Freq
|
|
want Freq
|
|
}{
|
|
{
|
|
name: "equal length",
|
|
a: Freq{1, 2, 3},
|
|
b: Freq{4, 5, 6},
|
|
want: Freq{5, 7, 9},
|
|
},
|
|
{
|
|
name: "a shorter than b",
|
|
a: Freq{1, 2},
|
|
b: Freq{3, 4, 5},
|
|
want: Freq{4, 6, 5},
|
|
},
|
|
{
|
|
name: "b shorter than a",
|
|
a: Freq{1, 2, 3},
|
|
b: Freq{4, 5},
|
|
want: Freq{5, 7, 3},
|
|
},
|
|
{
|
|
name: "empty a",
|
|
a: Freq{},
|
|
b: Freq{1, 2, 3},
|
|
want: Freq{1, 2, 3},
|
|
},
|
|
{
|
|
name: "empty b",
|
|
a: Freq{1, 2, 3},
|
|
b: Freq{},
|
|
want: Freq{1, 2, 3},
|
|
},
|
|
{
|
|
name: "both empty",
|
|
a: Freq{},
|
|
b: Freq{},
|
|
want: Freq{},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.a.Merge(tt.b)
|
|
if len(got) != len(tt.want) {
|
|
t.Fatalf("expected length %d, got %d", len(tt.want), len(got))
|
|
}
|
|
for i := range tt.want {
|
|
if got[i] != tt.want[i] {
|
|
t.Errorf("index %d: expected %d, got %d", i, tt.want[i], got[i])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsLeapYear(t *testing.T) {
|
|
tests := []struct {
|
|
year int
|
|
want bool
|
|
}{
|
|
{2024, true}, // divisible by 4
|
|
{2025, false}, // not divisible by 4
|
|
{1900, false}, // divisible by 100 but not 400
|
|
{2000, true}, // divisible by 400
|
|
{2100, false}, // divisible by 100 but not 400
|
|
{2400, true}, // divisible by 400
|
|
{1996, true}, // divisible by 4
|
|
{2023, false}, // not divisible by 4
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(time.Date(tt.year, 1, 1, 0, 0, 0, 0, time.UTC).Format("2006"), func(t *testing.T) {
|
|
got := IsLeapYear(tt.year)
|
|
if got != tt.want {
|
|
t.Errorf("IsLeapYear(%d) = %v, want %v", tt.year, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestYearLength(t *testing.T) {
|
|
if YearLength(2024) != 366 {
|
|
t.Error("expected 366 for 2024")
|
|
}
|
|
if YearLength(2025) != 365 {
|
|
t.Error("expected 365 for 2025")
|
|
}
|
|
if YearLength(1900) != 365 {
|
|
t.Error("expected 365 for 1900 (century year, not leap)")
|
|
}
|
|
if YearLength(2000) != 366 {
|
|
t.Error("expected 366 for 2000 (divisible by 400)")
|
|
}
|
|
}
|
|
|
|
func TestDataSetOperations(t *testing.T) {
|
|
ds := NewDataSet()
|
|
now := time.Now().Truncate(24 * time.Hour)
|
|
ds[now] = WorkDay{
|
|
Day: now,
|
|
Count: 5,
|
|
}
|
|
if wd, ok := ds[now]; !ok {
|
|
t.Fatal("expected to find workday for today")
|
|
} else if wd.Count != 5 {
|
|
t.Errorf("expected count 5, got %d", wd.Count)
|
|
}
|
|
}
|