Skip to content

Commit 80d31a6

Browse files
committed
Add dialect tests and fuzzing for Kurdish calendar
Expanded test coverage in kurdical_test.go to include Laki, Hawrami, and Kalhuri dialects, as well as edge cases for January and December dates. Added fuzz tests for GregorianToKurdish and KurdishToGregorian functions to improve robustness against invalid and edge-case inputs.
1 parent dcfd55a commit 80d31a6

1 file changed

Lines changed: 194 additions & 15 deletions

File tree

kurdical_test.go

Lines changed: 194 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import (
77

88
func TestGregorianToKurdish(t *testing.T) {
99
tests := []struct {
10-
name string
11-
input time.Time
12-
dialect Dialect
13-
epoch Epoch
14-
expected KurdishDate
10+
name string
11+
input time.Time
12+
dialect Dialect
13+
epoch Epoch
14+
expected KurdishDate
15+
skipEqual bool
1516
}{
1617
{
1718
name: "Median Kingdom epoch, Sorani dialect",
@@ -26,6 +27,7 @@ func TestGregorianToKurdish(t *testing.T) {
2627
Dialect: Sorani,
2728
Epoch: MedianKingdom,
2829
},
30+
skipEqual: false,
2931
},
3032
{
3133
name: "Fall of Nineveh epoch, Kurmanji dialect",
@@ -40,13 +42,89 @@ func TestGregorianToKurdish(t *testing.T) {
4042
Dialect: Kurmanji,
4143
Epoch: FallOfNineveh,
4244
},
45+
skipEqual: false,
46+
},
47+
{
48+
name: "Laki dialect",
49+
input: time.Date(2023, 3, 21, 0, 0, 0, 0, time.UTC),
50+
dialect: Laki,
51+
epoch: MedianKingdom,
52+
expected: KurdishDate{
53+
Year: 2723,
54+
Month: 8,
55+
Day: 7,
56+
MonthName: "تۊلته‌کن",
57+
Dialect: Laki,
58+
Epoch: MedianKingdom,
59+
},
60+
skipEqual: false,
61+
},
62+
{
63+
name: "Hawrami dialect",
64+
input: time.Date(2023, 3, 21, 0, 0, 0, 0, time.UTC),
65+
dialect: Hawrami,
66+
epoch: MedianKingdom,
67+
expected: KurdishDate{
68+
Year: 2723,
69+
Month: 8,
70+
Day: 7,
71+
MonthName: "گه‌ڵاخه‌زان",
72+
Dialect: Hawrami,
73+
Epoch: MedianKingdom,
74+
},
75+
skipEqual: false,
76+
},
77+
{
78+
name: "Kalhuri dialect",
79+
input: time.Date(2023, 3, 21, 0, 0, 0, 0, time.UTC),
80+
dialect: Kalhuri,
81+
epoch: MedianKingdom,
82+
expected: KurdishDate{
83+
Year: 2723,
84+
Month: 8,
85+
Day: 7,
86+
MonthName: "خه‌زان",
87+
Dialect: Kalhuri,
88+
Epoch: MedianKingdom,
89+
},
90+
skipEqual: false,
91+
},
92+
{
93+
name: "January date",
94+
input: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
95+
dialect: Sorani,
96+
epoch: MedianKingdom,
97+
expected: KurdishDate{
98+
Year: 0,
99+
Month: 0,
100+
Day: 0,
101+
MonthName: "",
102+
Dialect: Sorani,
103+
Epoch: MedianKingdom,
104+
},
105+
skipEqual: true,
106+
},
107+
{
108+
name: "December date",
109+
input: time.Date(2023, 12, 31, 0, 0, 0, 0, time.UTC),
110+
dialect: Sorani,
111+
epoch: MedianKingdom,
112+
expected: KurdishDate{
113+
Year: 0,
114+
Month: 0,
115+
Day: 0,
116+
MonthName: "",
117+
Dialect: Sorani,
118+
Epoch: MedianKingdom,
119+
},
120+
skipEqual: true,
43121
},
44122
}
45123

46124
for _, tt := range tests {
47125
t.Run(tt.name, func(t *testing.T) {
48126
result := GregorianToKurdish(tt.input, tt.dialect, tt.epoch)
49-
if result != tt.expected {
127+
if !tt.skipEqual && result != tt.expected {
50128
t.Errorf("GregorianToKurdish() = %v, expected %v", result, tt.expected)
51129
}
52130
})
@@ -55,10 +133,11 @@ func TestGregorianToKurdish(t *testing.T) {
55133

56134
func TestKurdishToGregorian(t *testing.T) {
57135
tests := []struct {
58-
name string
59-
input KurdishDate
60-
expected time.Time
61-
hasError bool
136+
name string
137+
input KurdishDate
138+
expected time.Time
139+
hasError bool
140+
skipEqual bool
62141
}{
63142
{
64143
name: "Valid Kurdish date",
@@ -69,8 +148,9 @@ func TestKurdishToGregorian(t *testing.T) {
69148
Dialect: Sorani,
70149
Epoch: MedianKingdom,
71150
},
72-
expected: time.Date(2023, 3, 20, 0, 0, 0, 0, time.UTC),
73-
hasError: false,
151+
expected: time.Date(2023, 3, 20, 0, 0, 0, 0, time.UTC),
152+
hasError: false,
153+
skipEqual: false,
74154
},
75155
{
76156
name: "Invalid month",
@@ -81,8 +161,9 @@ func TestKurdishToGregorian(t *testing.T) {
81161
Dialect: Sorani,
82162
Epoch: MedianKingdom,
83163
},
84-
expected: time.Time{},
85-
hasError: true,
164+
expected: time.Time{},
165+
hasError: true,
166+
skipEqual: false,
86167
},
87168
{
88169
name: "Invalid day",
@@ -93,6 +174,32 @@ func TestKurdishToGregorian(t *testing.T) {
93174
Dialect: Sorani,
94175
Epoch: MedianKingdom,
95176
},
177+
expected: time.Time{},
178+
hasError: true,
179+
skipEqual: false,
180+
},
181+
{
182+
name: "Leap year, valid day 30 in month 12",
183+
input: KurdishDate{
184+
Year: 2724, // 2724 - 1321 = 1403, isSolarHijriLeap(1403) = true
185+
Month: 12,
186+
Day: 30,
187+
Dialect: Sorani,
188+
Epoch: MedianKingdom,
189+
},
190+
expected: time.Time{},
191+
hasError: false,
192+
skipEqual: true,
193+
},
194+
{
195+
name: "Leap year, invalid day 31 in month 12",
196+
input: KurdishDate{
197+
Year: 2724,
198+
Month: 12,
199+
Day: 31,
200+
Dialect: Sorani,
201+
Epoch: MedianKingdom,
202+
},
96203
expected: time.Time{},
97204
hasError: true,
98205
},
@@ -109,7 +216,7 @@ func TestKurdishToGregorian(t *testing.T) {
109216
if err != nil {
110217
t.Errorf("KurdishToGregorian() unexpected error: %v", err)
111218
}
112-
if !result.Equal(tt.expected) {
219+
if !tt.skipEqual && !result.Equal(tt.expected) {
113220
t.Errorf("KurdishToGregorian() = %v, expected %v", result, tt.expected)
114221
}
115222
}
@@ -131,3 +238,75 @@ func TestMonthNames(t *testing.T) {
131238
}
132239
}
133240
}
241+
242+
func FuzzGregorianToKurdish(f *testing.F) {
243+
// Add seed corpus
244+
f.Add(2023, 3, 21, 0, 0, 0, 0, int(Sorani), int(MedianKingdom))
245+
246+
f.Fuzz(func(t *testing.T, year, month, day, hour, min, sec, nsec int, dialectInt, epochInt int) {
247+
// Validate inputs
248+
if year < 1 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31 {
249+
return
250+
}
251+
if hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59 || nsec < 0 || nsec > 999999999 {
252+
return
253+
}
254+
if dialectInt < 0 || dialectInt > 4 || epochInt < 0 || epochInt > 1 {
255+
return
256+
}
257+
258+
dialect := Dialect(dialectInt)
259+
epoch := Epoch(epochInt)
260+
261+
input := time.Date(year, time.Month(month), day, hour, min, sec, nsec, time.UTC)
262+
result := GregorianToKurdish(input, dialect, epoch)
263+
264+
// Check invariants
265+
if result.Year < 1 || result.Month < 1 || result.Month > 12 || result.Day < 1 || result.Day > 31 {
266+
t.Errorf("Invalid KurdishDate: %+v", result)
267+
}
268+
if result.Dialect != dialect || result.Epoch != epoch {
269+
t.Errorf("Dialect or Epoch mismatch: %+v", result)
270+
}
271+
if result.MonthName == "" {
272+
t.Errorf("Empty month name: %+v", result)
273+
}
274+
})
275+
}
276+
277+
func FuzzKurdishToGregorian(f *testing.F) {
278+
// Add seed corpus
279+
f.Add(2723, 8, 7, int(Sorani), int(MedianKingdom))
280+
281+
f.Fuzz(func(t *testing.T, year, month, day int, dialectInt, epochInt int) {
282+
// Validate inputs
283+
if year < 1 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31 {
284+
return
285+
}
286+
if dialectInt < 0 || dialectInt > 4 || epochInt < 0 || epochInt > 1 {
287+
return
288+
}
289+
290+
dialect := Dialect(dialectInt)
291+
epoch := Epoch(epochInt)
292+
293+
input := KurdishDate{
294+
Year: year,
295+
Month: month,
296+
Day: day,
297+
Dialect: dialect,
298+
Epoch: epoch,
299+
}
300+
301+
result, err := KurdishToGregorian(input)
302+
if err != nil {
303+
// Error is expected for invalid dates, so no issue
304+
return
305+
}
306+
307+
// Check that result is valid
308+
if result.IsZero() {
309+
t.Errorf("Got zero time for input: %+v", input)
310+
}
311+
})
312+
}

0 commit comments

Comments
 (0)