Functional Weave
Code in Python

subscriptions.next-billing-date@1.0.0

vectors.json

3,169 bytes · view raw

[
  { "name": "monthly on the 15th, asked mid-September", "args": ["2026-01-15", "month", 1, "2026-09-23"], "expect": "2026-10-15" },
  { "name": "anchored on the 31st, the February renewal is the 28th", "args": ["2026-01-31", "month", 1, "2026-02-01"], "expect": "2026-02-28" },
  { "name": "after the 28 February renewal the next is 31 March, not 28 March", "args": ["2026-01-31", "month", 1, "2026-02-28"], "expect": "2026-03-31" },
  { "name": "anchored on the 31st, April's renewal is its last day, the 30th", "args": ["2026-01-31", "month", 1, "2026-04-15"], "expect": "2026-04-30" },
  { "name": "anchored on the 31st, February of a leap year renews on the 29th", "args": ["2024-01-31", "month", 1, "2024-02-10"], "expect": "2024-02-29" },
  { "name": "on a billing date itself, the next renewal is a whole interval away", "args": ["2026-01-15", "month", 1, "2026-03-15"], "expect": "2026-04-15" },
  { "name": "on the anchor date itself, the next renewal is one interval on", "args": ["2026-09-23", "month", 1, "2026-09-23"], "expect": "2026-10-23" },
  { "name": "before the anchor (a future start), the next billing date is the anchor", "args": ["2026-10-01", "month", 1, "2026-09-23"], "expect": "2026-10-01" },
  { "name": "quarterly from 30 November: the clamped 28 February is a billing date, so the next is 30 May", "args": ["2025-11-30", "quarter", 1, "2026-02-28"], "expect": "2026-05-30" },
  { "name": "quarterly from 30 November, asked the day before the clamped date", "args": ["2025-11-30", "quarter", 1, "2026-02-27"], "expect": "2026-02-28" },
  { "name": "yearly from 29 February renews on 28 February in an ordinary year", "args": ["2024-02-29", "year", 1, "2025-01-01"], "expect": "2025-02-28" },
  { "name": "yearly from 29 February is back on the 29th in the next leap year", "args": ["2024-02-29", "year", 1, "2027-06-01"], "expect": "2028-02-29" },
  { "name": "yearly on New Year's Eve, asked on the renewal day", "args": ["2025-12-31", "year", 1, "2026-12-31"], "expect": "2027-12-31" },
  { "name": "every 14 days, asked on a billing day", "args": ["2026-01-01", "day", 14, "2026-01-29"], "expect": "2026-02-12" },
  { "name": "every 14 days, asked the day before a billing day", "args": ["2026-01-01", "day", 14, "2026-01-28"], "expect": "2026-01-29" },
  { "name": "every two weeks from a Tuesday", "args": ["2026-09-01", "week", 2, "2026-09-23"], "expect": "2026-09-29" },
  { "name": "every two months from 31 January skips February entirely", "args": ["2026-01-31", "month", 2, "2026-03-01"], "expect": "2026-03-31" },
  { "name": "every six months from 31 August lands on the last day of February", "args": ["2025-08-31", "month", 6, "2025-12-01"], "expect": "2026-02-28" },
  { "name": "an interval count of zero is an error", "args": ["2026-01-15", "month", 0, "2026-09-23"], "expectError": "interval count must be 1 or more" },
  { "name": "an unknown interval is an error", "args": ["2026-01-15", "fortnight", 1, "2026-09-23"], "expectError": "unknown billing interval" },
  { "name": "an impossible anchor date is an error", "args": ["2026-02-30", "month", 1, "2026-09-23"], "expectError": "is not a real calendar date" }
]