1/*
2 * Copyright 2014-2021 Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "DateFormatTest.h"
8
9#include <DateFormat.h>
10#include <FormattingConventions.h>
11#include <Language.h>
12#include <TimeFormat.h>
13#include <TimeZone.h>
14
15#include <cppunit/TestCaller.h>
16#include <cppunit/TestSuite.h>
17
18
19DateFormatTest::DateFormatTest()
20{
21}
22
23
24DateFormatTest::~DateFormatTest()
25{
26}
27
28
29void
30DateFormatTest::TestCustomFormat()
31{
32	struct Test {
33		const char* language;
34		const char* formatting;
35		const char* timeZone;
36		int32 fields;
37
38		BString expected;
39		BString force24;
40		BString force12;
41	};
42
43	BString buffer;
44
45	const Test tests[] = {
46		{ "en", "en_US", "GMT+1", B_DATE_ELEMENT_HOUR | B_DATE_ELEMENT_MINUTE,
47			"10:21 PM", "22:21", "10:21 PM" },
48		{ "en", "en_US", "GMT+1",
49			B_DATE_ELEMENT_HOUR | B_DATE_ELEMENT_MINUTE | B_DATE_ELEMENT_SECOND,
50			"10:21:18 PM", "22:21:18", "10:21:18 PM" },
51		{ "en", "en_US", "GMT+1", B_DATE_ELEMENT_HOUR | B_DATE_ELEMENT_MINUTE
52			| B_DATE_ELEMENT_TIMEZONE,
53			"10:21 PM GMT+1", "22:21 GMT+1", "10:21 PM GMT+1" },
54		{ "en", "en_US", "GMT+1", B_DATE_ELEMENT_HOUR | B_DATE_ELEMENT_MINUTE
55			| B_DATE_ELEMENT_SECOND | B_DATE_ELEMENT_TIMEZONE,
56			"10:21:18 PM GMT+1", "22:21:18 GMT+1", "10:21:18 PM GMT+1" },
57		{ "fr", "fr_FR", "GMT+1", B_DATE_ELEMENT_HOUR | B_DATE_ELEMENT_MINUTE,
58			"22:21", "22:21", "10:21 PM" },
59		{ NULL }
60	};
61
62	for (int i = 0; tests[i].language != NULL; i++)
63	{
64		NextSubTest();
65
66		BLanguage language(tests[i].language);
67		BFormattingConventions formatting(tests[i].formatting);
68		BTimeZone timeZone(tests[i].timeZone);
69		status_t result;
70
71		// Test default for language/formatting
72		{
73			BDateTimeFormat format(language, formatting);
74			format.SetDateTimeFormat(B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT,
75				tests[i].fields);
76
77			result = format.Format(buffer, 12345678, B_SHORT_DATE_FORMAT,
78				B_SHORT_TIME_FORMAT, &timeZone);
79
80			CPPUNIT_ASSERT_EQUAL(B_OK, result);
81			CPPUNIT_ASSERT_EQUAL(tests[i].expected, buffer);
82		}
83
84		// Test forced 24 hours
85		{
86			formatting.SetExplicitUse24HourClock(true);
87			BDateTimeFormat format(language, formatting);
88			format.SetDateTimeFormat(B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT,
89				tests[i].fields);
90			result = format.Format(buffer, 12345678, B_SHORT_DATE_FORMAT,
91				B_SHORT_TIME_FORMAT, &timeZone);
92
93			CPPUNIT_ASSERT_EQUAL(B_OK, result);
94			CPPUNIT_ASSERT_EQUAL(tests[i].force24, buffer);
95		}
96
97		// Test forced 12 hours
98		{
99			formatting.SetExplicitUse24HourClock(false);
100			BDateTimeFormat format(language, formatting);
101			format.SetDateTimeFormat(B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT,
102				tests[i].fields);
103			result = format.Format(buffer, 12345678, B_SHORT_DATE_FORMAT,
104				B_SHORT_TIME_FORMAT, &timeZone);
105
106			CPPUNIT_ASSERT_EQUAL(B_OK, result);
107			CPPUNIT_ASSERT_EQUAL(tests[i].force12, buffer);
108		}
109	}
110}
111
112
113void
114DateFormatTest::TestFormat()
115{
116	struct Value {
117		const char* language;
118		const char* convention;
119		const char* timeZone;
120		time_t time;
121		const char* shortDate;
122		const char* longDate;
123		const char* shortTime;
124		const char* longTime;
125		const char* shortDateTime;
126	};
127
128	static const Value values[] = {
129		{"en", "en_US", "GMT+1", 12345, "1/1/70", "January 1, 1970",
130			"4:25 AM", "4:25:45 AM", "1/1/70, 4:25 AM"},
131		{"fr", "fr_FR", "GMT+1", 12345, "01/01/1970", "1 janvier 1970",
132			"04:25", "04:25:45", "01/01/1970 04:25"},
133		{"fr", "fr_FR", "GMT+1", 12345678, "23/05/1970", "23 mai 1970",
134			"22:21", "22:21:18", "23/05/1970 22:21"},
135		{NULL}
136	};
137
138	BString output;
139	status_t result;
140
141	for (int i = 0; values[i].language != NULL; i++) {
142		NextSubTest();
143
144		BLanguage language(values[i].language);
145		BFormattingConventions formatting(values[i].convention);
146		BTimeZone timeZone(values[i].timeZone);
147		BDateFormat dateFormat(language, formatting);
148		BTimeFormat timeFormat(language, formatting);
149		BDateTimeFormat dateTimeFormat(language, formatting);
150
151		result = dateFormat.Format(output, values[i].time, B_SHORT_DATE_FORMAT,
152			&timeZone);
153		CPPUNIT_ASSERT_EQUAL(B_OK, result);
154		CPPUNIT_ASSERT_EQUAL(BString(values[i].shortDate), output);
155
156		result = dateFormat.Format(output, values[i].time, B_LONG_DATE_FORMAT,
157			&timeZone);
158		CPPUNIT_ASSERT_EQUAL(B_OK, result);
159		CPPUNIT_ASSERT_EQUAL(BString(values[i].longDate), output);
160
161		result = timeFormat.Format(output, values[i].time, B_SHORT_TIME_FORMAT,
162			&timeZone);
163		CPPUNIT_ASSERT_EQUAL(B_OK, result);
164		CPPUNIT_ASSERT_EQUAL(BString(values[i].shortTime), output);
165
166		result = timeFormat.Format(output, values[i].time, B_MEDIUM_TIME_FORMAT,
167			&timeZone);
168		CPPUNIT_ASSERT_EQUAL(B_OK, result);
169		CPPUNIT_ASSERT_EQUAL(BString(values[i].longTime), output);
170
171		result = dateTimeFormat.Format(output, values[i].time,
172			B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT, &timeZone);
173		CPPUNIT_ASSERT_EQUAL(B_OK, result);
174		CPPUNIT_ASSERT_EQUAL(BString(values[i].shortDateTime), output);
175	}
176}
177
178
179void
180DateFormatTest::TestFormatDate()
181{
182		BLanguage language("en");
183		BFormattingConventions formatting("en_US");
184		BDateFormat format(language, formatting);
185
186		BString output;
187		status_t result;
188
189		BDate date(2014, 9, 29);
190
191		result = format.Format(output, date, B_LONG_DATE_FORMAT);
192		CPPUNIT_ASSERT_EQUAL(B_OK, result);
193		CPPUNIT_ASSERT_EQUAL(BString("September 29, 2014"), output);
194
195		// Test an invalid date - must return B_BAD_DATA
196		date.SetDate(2014, 29, 29);
197		result = format.Format(output, date, B_LONG_DATE_FORMAT);
198		CPPUNIT_ASSERT_EQUAL(B_BAD_DATA, result);
199}
200
201
202void
203DateFormatTest::TestMonthNames()
204{
205	BLanguage language("en");
206	BFormattingConventions formatting("en_US");
207	BDateFormat format(language, formatting);
208
209	BString buffer;
210	status_t result = format.GetMonthName(1, buffer);
211
212	CPPUNIT_ASSERT_EQUAL(BString("January"), buffer);
213	CPPUNIT_ASSERT_EQUAL(B_OK, result);
214
215	buffer.Truncate(0);
216	result = format.GetMonthName(12, buffer);
217
218	CPPUNIT_ASSERT_EQUAL(BString("December"), buffer);
219	CPPUNIT_ASSERT_EQUAL(B_OK, result);
220
221	buffer.Truncate(0);
222	result = format.GetMonthName(1, buffer, B_FULL_DATE_FORMAT);
223
224	CPPUNIT_ASSERT_EQUAL(BString("January"), buffer);
225	CPPUNIT_ASSERT_EQUAL(B_OK, result);
226
227	buffer.Truncate(0);
228	result = format.GetMonthName(12, buffer, B_FULL_DATE_FORMAT);
229
230	CPPUNIT_ASSERT_EQUAL(BString("December"), buffer);
231	CPPUNIT_ASSERT_EQUAL(B_OK, result);
232
233	buffer.Truncate(0);
234	result = format.GetMonthName(1, buffer, B_LONG_DATE_FORMAT);
235
236	CPPUNIT_ASSERT_EQUAL(BString("Jan"), buffer);
237	CPPUNIT_ASSERT_EQUAL(B_OK, result);
238
239	buffer.Truncate(0);
240	result = format.GetMonthName(12, buffer, B_LONG_DATE_FORMAT);
241
242	CPPUNIT_ASSERT_EQUAL(BString("Dec"), buffer);
243	CPPUNIT_ASSERT_EQUAL(B_OK, result);
244
245	buffer.Truncate(0);
246	result = format.GetMonthName(1, buffer, B_MEDIUM_DATE_FORMAT);
247
248	CPPUNIT_ASSERT_EQUAL(BString("Jan"), buffer);
249	CPPUNIT_ASSERT_EQUAL(B_OK, result);
250
251	buffer.Truncate(0);
252	result = format.GetMonthName(12, buffer, B_MEDIUM_DATE_FORMAT);
253
254	CPPUNIT_ASSERT_EQUAL(BString("Dec"), buffer);
255	CPPUNIT_ASSERT_EQUAL(B_OK, result);
256
257	buffer.Truncate(0);
258	result = format.GetMonthName(1, buffer, B_SHORT_DATE_FORMAT);
259
260	CPPUNIT_ASSERT_EQUAL(BString("J"), buffer);
261	CPPUNIT_ASSERT_EQUAL(B_OK, result);
262
263	buffer.Truncate(0);
264	result = format.GetMonthName(12, buffer, B_SHORT_DATE_FORMAT);
265
266	CPPUNIT_ASSERT_EQUAL(BString("D"), buffer);
267	CPPUNIT_ASSERT_EQUAL(B_OK, result);
268
269}
270
271
272void
273DateFormatTest::TestDayNames()
274{
275	BLanguage language("en");
276	BFormattingConventions formatting("en_US");
277	BDateFormat format(language, formatting);
278
279	BString buffer;
280	status_t result = format.GetDayName(1, buffer);
281
282	CPPUNIT_ASSERT_EQUAL(BString("Monday"), buffer);
283	CPPUNIT_ASSERT_EQUAL(B_OK, result);
284
285	buffer.Truncate(0);
286	result = format.GetDayName(2, buffer);
287
288	CPPUNIT_ASSERT_EQUAL(BString("Tuesday"), buffer);
289	CPPUNIT_ASSERT_EQUAL(B_OK, result);
290
291	buffer.Truncate(0);
292	result = format.GetDayName(1, buffer, B_FULL_DATE_FORMAT);
293
294	CPPUNIT_ASSERT_EQUAL(BString("Monday"), buffer);
295	CPPUNIT_ASSERT_EQUAL(B_OK, result);
296
297	buffer.Truncate(0);
298	result = format.GetDayName(2, buffer, B_FULL_DATE_FORMAT);
299
300	CPPUNIT_ASSERT_EQUAL(BString("Tuesday"), buffer);
301	CPPUNIT_ASSERT_EQUAL(B_OK, result);
302
303	buffer.Truncate(0);
304	result = format.GetDayName(1, buffer, B_LONG_DATE_FORMAT);
305
306	CPPUNIT_ASSERT_EQUAL(BString("Mon"), buffer);
307	CPPUNIT_ASSERT_EQUAL(B_OK, result);
308
309	buffer.Truncate(0);
310	result = format.GetDayName(2, buffer, B_LONG_DATE_FORMAT);
311
312	CPPUNIT_ASSERT_EQUAL(BString("Tue"), buffer);
313	CPPUNIT_ASSERT_EQUAL(B_OK, result);
314
315	buffer.Truncate(0);
316	result = format.GetDayName(1, buffer, B_MEDIUM_DATE_FORMAT);
317
318	CPPUNIT_ASSERT_EQUAL(BString("Mo"), buffer);
319	CPPUNIT_ASSERT_EQUAL(B_OK, result);
320
321	buffer.Truncate(0);
322	result = format.GetDayName(2, buffer, B_MEDIUM_DATE_FORMAT);
323
324	CPPUNIT_ASSERT_EQUAL(BString("Tu"), buffer);
325	CPPUNIT_ASSERT_EQUAL(B_OK, result);
326
327	buffer.Truncate(0);
328	result = format.GetDayName(1, buffer, B_SHORT_DATE_FORMAT);
329
330	CPPUNIT_ASSERT_EQUAL(BString("M"), buffer);
331	CPPUNIT_ASSERT_EQUAL(B_OK, result);
332
333	buffer.Truncate(0);
334	result = format.GetDayName(2, buffer, B_SHORT_DATE_FORMAT);
335
336	CPPUNIT_ASSERT_EQUAL(BString("T"), buffer);
337	CPPUNIT_ASSERT_EQUAL(B_OK, result);
338}
339
340
341namespace BPrivate {
342
343
344std::ostream& operator<<(std::ostream& stream, const BDate& date)
345{
346	stream << date.Year();
347	stream << '-';
348	stream << date.Month();
349	stream << '-';
350	stream << date.Day();
351
352	return stream;
353}
354
355
356std::ostream& operator<<(std::ostream& stream, const BTime& date)
357{
358	stream << date.Hour();
359	stream << ':';
360	stream << date.Minute();
361	stream << ':';
362	stream << date.Second();
363
364	return stream;
365}
366
367
368} // namespace BPrivate
369
370
371void
372DateFormatTest::TestParseDate()
373{
374	BLanguage language("en");
375	BFormattingConventions formatting("en_US");
376	BDateFormat format(language, formatting);
377	BDate date;
378	status_t result;
379
380	struct Test {
381		const char* input;
382		BDate output;
383	};
384
385	static const Test tests[] = {
386		{"01/01/1970", BDate(1970, 1, 1)},
387		{"05/07/1988", BDate(1988, 5, 7)},
388		{"07/31/2345", BDate(2345, 7, 31)},
389		{NULL}
390	};
391
392	for (int i = 0; tests[i].input != NULL; i++) {
393		NextSubTest();
394		result = format.Parse(tests[i].input, B_SHORT_DATE_FORMAT, date);
395
396		CPPUNIT_ASSERT_EQUAL(tests[i].output, date);
397		CPPUNIT_ASSERT_EQUAL(B_OK, result);
398	}
399}
400
401
402void
403DateFormatTest::TestParseTime()
404{
405	BLanguage language("fr");
406	BFormattingConventions formatting("fr_FR");
407	BTimeFormat format(language, formatting);
408	BTime date;
409	status_t result;
410
411	struct Test {
412		const char* input;
413		BTime output;
414	};
415
416	static const Test tests[] = {
417		{"03:25", BTime(3, 25, 0)},
418		{"16:18", BTime(16, 18, 0)},
419		{"23:59", BTime(23, 59, 0)},
420		{NULL}
421	};
422
423	for (int i = 0; tests[i].input != NULL; i++) {
424		NextSubTest();
425		result = format.Parse(tests[i].input, B_SHORT_TIME_FORMAT, date);
426
427		CPPUNIT_ASSERT_EQUAL(tests[i].output, date);
428		CPPUNIT_ASSERT_EQUAL(B_OK, result);
429	}
430}
431
432
433/*static*/ void
434DateFormatTest::AddTests(BTestSuite& parent)
435{
436	CppUnit::TestSuite& suite = *new CppUnit::TestSuite("DateFormatTest");
437
438	suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
439		"DateFormatTest::TestCustomFormat", &DateFormatTest::TestCustomFormat));
440	suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
441		"DateFormatTest::TestFormat", &DateFormatTest::TestFormat));
442	suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
443		"DateFormatTest::TestFormatDate", &DateFormatTest::TestFormatDate));
444	suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
445		"DateFormatTest::TestMonthNames", &DateFormatTest::TestMonthNames));
446	suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
447		"DateFormatTest::TestDayNames", &DateFormatTest::TestDayNames));
448	suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
449		"DateFormatTest::TestParseDate", &DateFormatTest::TestParseDate));
450	suite.addTest(new CppUnit::TestCaller<DateFormatTest>(
451		"DateFormatTest::TestParseTime", &DateFormatTest::TestParseTime));
452
453	parent.addTest("DateFormatTest", &suite);
454}
455