Skip to content

Commit 7112460

Browse files
author
Jithendra
committed
test(utils): add boundary robustness tests for date range formatter
Add formatDateRange utility that handles partial/missing year inputs with fallback to default ranges. - Full 4-digit years: '2024' -> 2024-01-01 to 2024-12-31 - Partial 2-digit years: '24' -> 2024 - Partial 1-digit years: '4' -> 2024 - Missing/empty/invalid: fallback to current year range Includes 13 test cases covering boundary conditions. Fixes JhaSourav07#1574
1 parent b124f6b commit 7112460

2 files changed

Lines changed: 176 additions & 0 deletions

File tree

utils/dateRange.test.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { formatDateRange, DEFAULT_DATE_RANGE } from './dateRange';
3+
4+
describe('formatDateRange', () => {
5+
it('returns full date range for valid 4-digit year', () => {
6+
const result = formatDateRange('2024');
7+
expect(result).toEqual({
8+
from: '2024-01-01T00:00:00Z',
9+
to: '2024-12-31T23:59:59Z',
10+
});
11+
});
12+
13+
it('handles partial year with 2 digits - prepends 20', () => {
14+
const result = formatDateRange('24');
15+
expect(result).toEqual({
16+
from: '2024-01-01T00:00:00Z',
17+
to: '2024-12-31T23:59:59Z',
18+
});
19+
});
20+
21+
it('handles partial year with 1 digit - maps to 202x', () => {
22+
const result = formatDateRange('4');
23+
expect(result).toEqual({
24+
from: '2024-01-01T00:00:00Z',
25+
to: '2024-12-31T23:59:59Z',
26+
});
27+
});
28+
29+
it('returns fallback default range for empty string year', () => {
30+
const result = formatDateRange('');
31+
const currentYear = new Date().getUTCFullYear();
32+
expect(result).toEqual({
33+
from: `${currentYear}-01-01T00:00:00Z`,
34+
to: `${currentYear}-12-31T23:59:59Z`,
35+
});
36+
});
37+
38+
it('returns fallback default range for undefined year', () => {
39+
const result = formatDateRange(undefined);
40+
const currentYear = new Date().getUTCFullYear();
41+
expect(result).toEqual({
42+
from: `${currentYear}-01-01T00:00:00Z`,
43+
to: `${currentYear}-12-31T23:59:59Z`,
44+
});
45+
});
46+
47+
it('returns fallback default range for whitespace-only year', () => {
48+
const result = formatDateRange(' ');
49+
const currentYear = new Date().getUTCFullYear();
50+
expect(result).toEqual({
51+
from: `${currentYear}-01-01T00:00:00Z`,
52+
to: `${currentYear}-12-31T23:59:59Z`,
53+
});
54+
});
55+
56+
it('returns fallback default range for year before GitHub founding (2008)', () => {
57+
const result = formatDateRange('2007');
58+
const currentYear = new Date().getUTCFullYear();
59+
expect(result).toEqual({
60+
from: `${currentYear}-01-01T00:00:00Z`,
61+
to: `${currentYear}-12-31T23:59:59Z`,
62+
});
63+
});
64+
65+
it('returns fallback default range for far future year', () => {
66+
const result = formatDateRange('3000');
67+
const currentYear = new Date().getUTCFullYear();
68+
expect(result).toEqual({
69+
from: `${currentYear}-01-01T00:00:00Z`,
70+
to: `${currentYear}-12-31T23:59:59Z`,
71+
});
72+
});
73+
74+
it('returns fallback default range for non-numeric year', () => {
75+
const result = formatDateRange('abc');
76+
const currentYear = new Date().getUTCFullYear();
77+
expect(result).toEqual({
78+
from: `${currentYear}-01-01T00:00:00Z`,
79+
to: `${currentYear}-12-31T23:59:59Z`,
80+
});
81+
});
82+
83+
it('returns fallback default range for invalid numeric year', () => {
84+
const result = formatDateRange('-1');
85+
const currentYear = new Date().getUTCFullYear();
86+
expect(result).toEqual({
87+
from: `${currentYear}-01-01T00:00:00Z`,
88+
to: `${currentYear}-12-31T23:59:59Z`,
89+
});
90+
});
91+
92+
it('returns correct range for GitHub founding year (2008)', () => {
93+
const result = formatDateRange('2008');
94+
expect(result).toEqual({
95+
from: '2008-01-01T00:00:00Z',
96+
to: '2008-12-31T23:59:59Z',
97+
});
98+
});
99+
100+
it('returns result object matching DateRange interface', () => {
101+
const result = formatDateRange('2025');
102+
expect(result).toHaveProperty('from');
103+
expect(result).toHaveProperty('to');
104+
expect(typeof result.from).toBe('string');
105+
expect(typeof result.to).toBe('string');
106+
});
107+
108+
it('DEFAULT_DATE_RANGE uses current UTC year', () => {
109+
const currentYear = new Date().getUTCFullYear();
110+
expect(DEFAULT_DATE_RANGE.from).toBe(`${currentYear}-01-01T00:00:00Z`);
111+
expect(DEFAULT_DATE_RANGE.to).toBe(`${currentYear}-12-31T23:59:59Z`);
112+
});
113+
});

utils/dateRange.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* Default fallback date range when year is missing or invalid.
3+
* Uses current year as fallback.
4+
*/
5+
export const DEFAULT_DATE_RANGE = {
6+
from: `${new Date().getUTCFullYear()}-01-01T00:00:00Z`,
7+
to: `${new Date().getUTCFullYear()}-12-31T23:59:59Z`,
8+
};
9+
10+
/**
11+
* Date range with from and to ISO strings for GitHub API queries.
12+
*/
13+
export interface DateRange {
14+
from: string;
15+
to: string;
16+
}
17+
18+
/**
19+
* Formats a year into a date range for GitHub contributions query.
20+
* Returns fallback default ranges when year is missing, partial, or invalid.
21+
*
22+
* @param year - The year as string (e.g., "2024", "24", "2", "", undefined)
23+
* @returns DateRange object with from and to ISO date strings
24+
*
25+
* @example
26+
* formatDateRange("2024") // { from: "2024-01-01T00:00:00Z", to: "2024-12-31T23:59:59Z" }
27+
* formatDateRange("24") // { from: "2024-01-01T00:00:00Z", to: "2024-12-31T23:59:59Z" }
28+
* formatDateRange("") // returns DEFAULT_DATE_RANGE
29+
* formatDateRange(undefined) // returns DEFAULT_DATE_RANGE
30+
*/
31+
export function formatDateRange(year?: string): DateRange {
32+
if (!year || year.trim() === '') {
33+
return { ...DEFAULT_DATE_RANGE };
34+
}
35+
36+
const trimmedYear = year.trim();
37+
38+
// Handle partial years (1 or 2 digits): assume 20xx
39+
// For 2-digit: '24' -> 2024
40+
// For 1-digit: '4' -> 2024 (not 2004, to stay in reasonable range)
41+
let fullYear: number;
42+
if (trimmedYear.length === 2) {
43+
fullYear = parseInt('20' + trimmedYear, 10);
44+
} else if (trimmedYear.length === 1) {
45+
// 1-digit: map to 2020 + digit (4 -> 2024, 9 -> 2029)
46+
fullYear = 2020 + parseInt(trimmedYear, 10);
47+
} else {
48+
fullYear = parseInt(trimmedYear, 10);
49+
}
50+
51+
// Validate parsed year – must be >= 2008 (GitHub founding year) and reasonable future limit
52+
const currentYear = new Date().getUTCFullYear();
53+
const isValidYear = !isNaN(fullYear) && fullYear >= 2008 && fullYear <= currentYear + 5;
54+
55+
if (!isValidYear) {
56+
return { ...DEFAULT_DATE_RANGE };
57+
}
58+
59+
return {
60+
from: `${fullYear}-01-01T00:00:00Z`,
61+
to: `${fullYear}-12-31T23:59:59Z`,
62+
};
63+
}

0 commit comments

Comments
 (0)