@@ -11,7 +11,11 @@ use icu_calendar::{
11
11
Calendar , Date , Ref ,
12
12
} ;
13
13
14
- fn test_reference_year_impl < C > ( cal : C )
14
+ /// Test that a given calendar produces valid monthdays
15
+ ///
16
+ /// `valid_md_condition`, given (month_number, is_leap, day_number), should return whether or not
17
+ /// that combination is ever possible in that calendar
18
+ fn test_reference_year_impl < C > ( cal : C , valid_md_condition : impl Fn ( u8 , bool , u8 ) -> bool )
15
19
where
16
20
C : Calendar + Debug ,
17
21
{
39
43
for month_number in 1 ..=14 {
40
44
for is_leap in [ false , true ] {
41
45
for day_number in 1 ..=32 {
46
+ if !valid_md_condition ( month_number, is_leap, day_number) {
47
+ continue ;
48
+ }
42
49
let mut fields = DateFields :: default ( ) ;
43
50
fields. month_code = match is_leap {
44
51
false => MonthCode :: new_normal ( month_number) ,
49
56
options. overflow = Some ( Overflow :: Reject ) ;
50
57
options. missing_fields_strategy = Some ( MissingFieldsStrategy :: Ecma ) ;
51
58
let Ok ( reference_date) = Date :: try_from_fields ( fields, options, Ref ( & cal) ) else {
52
- // Not every date exists in every calendar
53
- continue ;
59
+ panic ! (
60
+ "Could not find any valid reference date for {}-{day_number}" ,
61
+ fields. month_code. unwrap( )
62
+ ) ;
54
63
} ;
64
+
55
65
assert_eq ! (
56
66
fields. month_code. unwrap( ) ,
57
67
reference_date. month( ) . standard_code,
@@ -67,103 +77,214 @@ where
67
77
}
68
78
}
69
79
80
+ fn gregorian_md_condition ( month_number : u8 , is_leap : bool , day_number : u8 ) -> bool {
81
+ // No leap months
82
+ if is_leap {
83
+ return false ;
84
+ }
85
+
86
+ match month_number {
87
+ 1 | 3 | 5 | 7 | 8 | 10 | 12 => day_number <= 31 ,
88
+ 2 => day_number <= 29 ,
89
+ 4 | 6 | 9 | 11 => day_number <= 30 ,
90
+ _ => {
91
+ assert ! ( month_number > 12 ) ;
92
+ // No other months
93
+ false
94
+ }
95
+ }
96
+ }
97
+
98
+ fn chinese_md_condition ( month_number : u8 , _is_leap : bool , day_number : u8 ) -> bool {
99
+ month_number <= 12 && day_number <= 30
100
+ }
101
+
102
+ fn coptic_md_condition ( month_number : u8 , is_leap : bool , day_number : u8 ) -> bool {
103
+ // No leap months
104
+ if is_leap {
105
+ return false ;
106
+ }
107
+ match month_number {
108
+ 1 ..=12 => day_number <= 30 ,
109
+ 13 => day_number <= 6 ,
110
+ _ => false ,
111
+ }
112
+ }
113
+
114
+ fn hijri_md_condition ( month_number : u8 , is_leap : bool , day_number : u8 ) -> bool {
115
+ // No leap months
116
+ if is_leap {
117
+ return false ;
118
+ }
119
+ month_number <= 12 && day_number <= 30
120
+ }
121
+
122
+ fn hijri_tabular_md_condition ( month_number : u8 , is_leap : bool , day_number : u8 ) -> bool {
123
+ // No leap months
124
+ if is_leap {
125
+ return false ;
126
+ }
127
+
128
+ if month_number > 12 {
129
+ return false ;
130
+ }
131
+
132
+ // Odd months have 30 days, even months have 29, except for M12 in a leap year
133
+ if month_number % 2 == 0 {
134
+ if month_number == 12 {
135
+ day_number <= 30
136
+ } else {
137
+ day_number <= 29
138
+ }
139
+ } else {
140
+ day_number <= 30
141
+ }
142
+ }
143
+
144
+ fn hebrew_md_condition ( month_number : u8 , is_leap : bool , day_number : u8 ) -> bool {
145
+ if is_leap {
146
+ return month_number == 5 && day_number <= 30 ;
147
+ }
148
+ match month_number {
149
+ 1 | 2 | 3 | 5 | 7 | 9 | 11 => day_number <= 30 ,
150
+ // Tevet, Adar, Iyar, Tammuz, Elul
151
+ 4 | 6 | 8 | 10 | 12 => day_number <= 29 ,
152
+ _ => {
153
+ assert ! ( month_number > 12 ) ;
154
+ // No other months
155
+ false
156
+ }
157
+ }
158
+ }
159
+
70
160
#[ test]
71
161
fn test_reference_year_buddhist ( ) {
72
- test_reference_year_impl ( Buddhist )
162
+ test_reference_year_impl ( Buddhist , gregorian_md_condition )
73
163
}
74
164
75
165
#[ test]
76
166
fn test_reference_year_chinese ( ) {
77
- test_reference_year_impl ( LunarChinese :: new_china ( ) )
167
+ test_reference_year_impl ( LunarChinese :: new_china ( ) , chinese_md_condition )
78
168
}
79
169
80
170
#[ test]
81
171
fn test_reference_year_coptic ( ) {
82
- test_reference_year_impl ( Coptic )
172
+ test_reference_year_impl ( Coptic , coptic_md_condition )
83
173
}
84
174
85
175
#[ test]
86
176
fn test_reference_year_dangi ( ) {
87
- test_reference_year_impl ( LunarChinese :: new_dangi ( ) )
177
+ test_reference_year_impl ( LunarChinese :: new_dangi ( ) , chinese_md_condition )
88
178
}
89
179
90
180
#[ test]
91
181
fn test_reference_year_ethiopian ( ) {
92
- test_reference_year_impl ( Ethiopian :: new ( ) )
182
+ test_reference_year_impl ( Ethiopian :: new ( ) , coptic_md_condition )
93
183
}
94
184
95
185
#[ test]
96
186
fn test_reference_year_ethiopian_amete_alem ( ) {
97
- test_reference_year_impl ( Ethiopian :: new_with_era_style ( EthiopianEraStyle :: AmeteAlem ) )
187
+ test_reference_year_impl (
188
+ Ethiopian :: new_with_era_style ( EthiopianEraStyle :: AmeteAlem ) ,
189
+ coptic_md_condition,
190
+ )
98
191
}
99
192
100
193
#[ test]
101
194
fn test_reference_year_gregorian ( ) {
102
- test_reference_year_impl ( Gregorian )
195
+ test_reference_year_impl ( Gregorian , gregorian_md_condition )
103
196
}
104
197
105
198
#[ test]
106
199
fn test_reference_year_julian ( ) {
107
- test_reference_year_impl ( Julian )
200
+ test_reference_year_impl ( Julian , gregorian_md_condition )
108
201
}
109
202
110
203
#[ test]
111
204
fn test_reference_year_hebrew ( ) {
112
- test_reference_year_impl ( Hebrew )
205
+ test_reference_year_impl ( Hebrew , hebrew_md_condition )
113
206
}
114
207
115
208
#[ test]
116
209
fn test_reference_year_indian ( ) {
117
- test_reference_year_impl ( Indian )
210
+ test_reference_year_impl ( Indian , |month_number, is_leap, day_number| {
211
+ if is_leap {
212
+ // No leap months
213
+ return false ;
214
+ }
215
+ // First half of the year has long months, second half short
216
+ if month_number <= 6 {
217
+ day_number <= 31
218
+ } else if month_number <= 12 {
219
+ day_number <= 30
220
+ } else {
221
+ // No larger months
222
+ false
223
+ }
224
+ } )
118
225
}
119
226
120
227
#[ test]
121
228
fn test_reference_year_hijri_tabular_type_ii_friday ( ) {
122
- test_reference_year_impl ( Hijri :: new_tabular (
123
- HijriTabularLeapYears :: TypeII ,
124
- HijriTabularEpoch :: Friday ,
125
- ) )
229
+ test_reference_year_impl (
230
+ Hijri :: new_tabular ( HijriTabularLeapYears :: TypeII , HijriTabularEpoch :: Friday ) ,
231
+ hijri_tabular_md_condition ,
232
+ )
126
233
}
127
234
128
235
#[ test]
129
236
fn test_reference_year_hijri_simulated_mecca ( ) {
130
- test_reference_year_impl ( Hijri :: new_simulated_mecca ( ) )
237
+ test_reference_year_impl ( Hijri :: new_simulated_mecca ( ) , hijri_md_condition )
131
238
}
132
239
133
240
#[ test]
134
241
fn test_reference_year_hijri_tabular_type_ii_thursday ( ) {
135
- test_reference_year_impl ( Hijri :: new_tabular (
136
- HijriTabularLeapYears :: TypeII ,
137
- HijriTabularEpoch :: Thursday ,
138
- ) )
242
+ test_reference_year_impl (
243
+ Hijri :: new_tabular ( HijriTabularLeapYears :: TypeII , HijriTabularEpoch :: Thursday ) ,
244
+ hijri_tabular_md_condition ,
245
+ )
139
246
}
140
247
141
248
#[ test]
142
249
fn test_reference_year_hijri_umm_al_qura ( ) {
143
- test_reference_year_impl ( Hijri :: new_umm_al_qura ( ) )
250
+ test_reference_year_impl ( Hijri :: new_umm_al_qura ( ) , hijri_md_condition )
144
251
}
145
252
146
253
#[ test]
147
254
fn test_reference_year_iso ( ) {
148
- test_reference_year_impl ( Iso )
255
+ test_reference_year_impl ( Iso , gregorian_md_condition )
149
256
}
150
257
151
258
#[ test]
152
259
fn test_reference_year_japanese ( ) {
153
- test_reference_year_impl ( Japanese :: new ( ) )
260
+ test_reference_year_impl ( Japanese :: new ( ) , gregorian_md_condition )
154
261
}
155
262
156
263
#[ test]
157
264
fn test_reference_year_japanese_extended ( ) {
158
- test_reference_year_impl ( JapaneseExtended :: new ( ) )
265
+ test_reference_year_impl ( JapaneseExtended :: new ( ) , gregorian_md_condition )
159
266
}
160
267
161
268
#[ test]
162
269
fn test_reference_year_persian ( ) {
163
- test_reference_year_impl ( Persian )
270
+ test_reference_year_impl ( Persian , |month_number, is_leap, day_number| {
271
+ if is_leap {
272
+ // No leap months
273
+ return false ;
274
+ }
275
+ // First half of the year has long months, second half short
276
+ if month_number <= 6 {
277
+ day_number <= 31
278
+ } else if month_number <= 12 {
279
+ day_number <= 30
280
+ } else {
281
+ // No larger months
282
+ false
283
+ }
284
+ } )
164
285
}
165
286
166
287
#[ test]
167
288
fn test_reference_year_roc ( ) {
168
- test_reference_year_impl ( Roc )
289
+ test_reference_year_impl ( Roc , gregorian_md_condition )
169
290
}
0 commit comments