mirror of
https://github.com/tiennm99/ghstats.git
synced 2026-08-30 18:22:19 +00:00
Quarterly windows were not enough for the busiest quarter: a live run warned that 2026-04-01..2026-06-30 still came back at the 100-repo ceiling, so its seed list was truncated and those repos never got probed for commit history. Re-ask a saturated quarter month by month and merge only the repo lists. The quarter has already contributed its calendar days and commit totals, so the month passes skip that fold; verified by forcing the ceiling down to 20 and confirming all six calendar-derived cards stay byte-identical. Warn only when a month itself saturates, since there is no finer window left to ask for.
129 lines
3.8 KiB
Go
129 lines
3.8 KiB
Go
package github
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestContributionWindowsFullYear(t *testing.T) {
|
|
now := time.Date(2026, 8, 13, 0, 0, 0, 0, time.UTC)
|
|
got := contributionWindows(2024, now)
|
|
if len(got) != 4 {
|
|
t.Fatalf("want 4 quarters for a completed year, got %d", len(got))
|
|
}
|
|
|
|
wantStarts := []string{"2024-01-01", "2024-04-01", "2024-07-01", "2024-10-01"}
|
|
wantEnds := []string{"2024-03-31", "2024-06-30", "2024-09-30", "2024-12-31"}
|
|
for i, w := range got {
|
|
if s := w[0].Format("2006-01-02"); s != wantStarts[i] {
|
|
t.Errorf("quarter %d start = %s, want %s", i, s, wantStarts[i])
|
|
}
|
|
if e := w[1].Format("2006-01-02"); e != wantEnds[i] {
|
|
t.Errorf("quarter %d end = %s, want %s", i, e, wantEnds[i])
|
|
}
|
|
}
|
|
|
|
// Windows must not overlap, or days would be counted twice in the
|
|
// all-time contribution series.
|
|
for i := 1; i < len(got); i++ {
|
|
if !got[i][0].After(got[i-1][1]) {
|
|
t.Errorf("quarter %d starts at/before the end of quarter %d", i, i-1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContributionWindowsCurrentYearStopsAtNow(t *testing.T) {
|
|
now := time.Date(2026, 8, 13, 10, 30, 0, 0, time.UTC)
|
|
got := contributionWindows(2026, now)
|
|
if len(got) != 3 {
|
|
t.Fatalf("want 3 quarters through August, got %d", len(got))
|
|
}
|
|
if last := got[2][1]; !last.Equal(now) {
|
|
t.Errorf("final window end = %s, want clamped to now (%s)", last, now)
|
|
}
|
|
}
|
|
|
|
func TestContributionWindowsFutureYearIsEmpty(t *testing.T) {
|
|
now := time.Date(2026, 8, 13, 0, 0, 0, 0, time.UTC)
|
|
if got := contributionWindows(2027, now); len(got) != 0 {
|
|
t.Fatalf("want no windows for a future year, got %d", len(got))
|
|
}
|
|
}
|
|
|
|
func TestRepoAffiliationsAndOwnership(t *testing.T) {
|
|
orgAdmin := repoNode{Name: "chambai", ViewerPermission: "ADMIN"}
|
|
orgAdmin.Owner = &struct {
|
|
Login string `json:"login"`
|
|
}{Login: "miti99dev"}
|
|
|
|
orgWrite := orgAdmin
|
|
orgWrite.ViewerPermission = "WRITE"
|
|
|
|
own := repoNode{Name: "ghstats"}
|
|
own.Owner = &struct {
|
|
Login string `json:"login"`
|
|
}{Login: "tiennm99"}
|
|
|
|
off := FetchOptions{}
|
|
on := FetchOptions{IncludeOrgRepos: true}
|
|
|
|
if got := repoAffiliations(off); len(got) != 1 || got[0] != "OWNER" {
|
|
t.Errorf("affiliations with org repos off = %v, want [OWNER]", got)
|
|
}
|
|
if got := repoAffiliations(on); len(got) != 2 {
|
|
t.Errorf("affiliations with org repos on = %v, want OWNER + ORGANIZATION_MEMBER", got)
|
|
}
|
|
|
|
cases := []struct {
|
|
name string
|
|
node repoNode
|
|
opts FetchOptions
|
|
want bool
|
|
}{
|
|
{"own repo, org off", own, off, true},
|
|
{"own repo, org on", own, on, true},
|
|
{"org admin repo, org off", orgAdmin, off, false},
|
|
{"org admin repo, org on", orgAdmin, on, true},
|
|
{"org write-only repo, org on", orgWrite, on, false},
|
|
}
|
|
for _, tc := range cases {
|
|
if got := ownedByUser(tc.node, "tiennm99", tc.opts); got != tc.want {
|
|
t.Errorf("%s: ownedByUser = %v, want %v", tc.name, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMonthWindowsCoverQuarterExactly(t *testing.T) {
|
|
from := time.Date(2026, 4, 1, 0, 0, 0, 0, time.UTC)
|
|
to := time.Date(2026, 6, 30, 23, 59, 59, 0, time.UTC)
|
|
got := monthWindows(from, to)
|
|
if len(got) != 3 {
|
|
t.Fatalf("want 3 months in a quarter, got %d", len(got))
|
|
}
|
|
if !got[0][0].Equal(from) {
|
|
t.Errorf("first month starts at %s, want %s", got[0][0], from)
|
|
}
|
|
if !got[len(got)-1][1].Equal(to) {
|
|
t.Errorf("last month ends at %s, want the quarter's end %s", got[len(got)-1][1], to)
|
|
}
|
|
for i := 1; i < len(got); i++ {
|
|
if !got[i][0].After(got[i-1][1]) {
|
|
t.Errorf("month %d overlaps month %d", i, i-1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMonthWindowsClampPartialFinalMonth(t *testing.T) {
|
|
// A current quarter clamped to "now" mid-month must not hand back a
|
|
// window running past it.
|
|
from := time.Date(2026, 7, 1, 0, 0, 0, 0, time.UTC)
|
|
now := time.Date(2026, 8, 13, 10, 30, 0, 0, time.UTC)
|
|
got := monthWindows(from, now)
|
|
if len(got) != 2 {
|
|
t.Fatalf("want July + partial August, got %d", len(got))
|
|
}
|
|
if !got[1][1].Equal(now) {
|
|
t.Errorf("final month ends at %s, want clamped to %s", got[1][1], now)
|
|
}
|
|
}
|