1 /*****************************************************************************
2 * Copyright (c) 2014-2020 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #include "openrct2/localisation/Formatting.h"
11
12 #include <gtest/gtest.h>
13 #include <openrct2/Context.h>
14 #include <openrct2/OpenRCT2.h>
15 #include <openrct2/config/Config.h>
16 #include <openrct2/core/String.hpp>
17 #include <openrct2/localisation/Localisation.h>
18 #include <openrct2/localisation/StringIds.h>
19 #include <sstream>
20 #include <string>
21
22 using namespace OpenRCT2;
23
24 class FmtStringTests : public testing::Test
25 {
26 };
27
TEST_F(FmtStringTests,string_owned)28 TEST_F(FmtStringTests, string_owned)
29 {
30 auto fmt = FmtString(std::string("{BLACK}Guests: {INT32}"));
31 ASSERT_EQ("Guests: ", fmt.WithoutFormatTokens());
32 }
33
TEST_F(FmtStringTests,iteration)34 TEST_F(FmtStringTests, iteration)
35 {
36 std::string actual;
37
38 auto fmt = FmtString("{BLACK}Guests: {INT32}");
39 for (const auto& t : fmt)
40 {
41 actual += String::StdFormat("[%d:%s]", t.kind, std::string(t.text).c_str());
42 }
43
44 ASSERT_EQ("[29:{BLACK}][1:Guests: ][8:{INT32}]", actual);
45 }
46
TEST_F(FmtStringTests,iteration_escaped)47 TEST_F(FmtStringTests, iteration_escaped)
48 {
49 std::string actual;
50
51 auto fmt = FmtString("This is an {{ESCAPED}} string.");
52 for (const auto& t : fmt)
53 {
54 actual += String::StdFormat("[%d:%s]", t.kind, std::string(t.text).c_str());
55 }
56
57 ASSERT_EQ("[1:This is an ][2:{{][1:ESCAPED][2:}}][1: string.]", actual);
58 }
59
TEST_F(FmtStringTests,without_format_tokens)60 TEST_F(FmtStringTests, without_format_tokens)
61 {
62 auto fmt = FmtString("{BLACK}Guests: {INT32}");
63 ASSERT_EQ("Guests: ", fmt.WithoutFormatTokens());
64 }
65
66 class FormattingTests : public testing::Test
67 {
68 private:
69 static std::shared_ptr<IContext> _context;
70
71 protected:
SetUpTestCase()72 static void SetUpTestCase()
73 {
74 gOpenRCT2Headless = true;
75 gOpenRCT2NoGraphics = true;
76 _context = CreateContext();
77 ASSERT_TRUE(_context->Initialise());
78
79 language_open(LANGUAGE_ENGLISH_UK);
80 }
81
TearDownTestCase()82 static void TearDownTestCase()
83 {
84 _context = {};
85 }
86 };
87
88 std::shared_ptr<IContext> FormattingTests::_context;
89
TEST_F(FormattingTests,no_args)90 TEST_F(FormattingTests, no_args)
91 {
92 auto actual = FormatString("test string");
93 ASSERT_EQ("test string", actual);
94 }
95
TEST_F(FormattingTests,missing_arg)96 TEST_F(FormattingTests, missing_arg)
97 {
98 auto actual = FormatString("test {STRING} arg");
99 ASSERT_EQ("test arg", actual);
100 }
101
TEST_F(FormattingTests,integer)102 TEST_F(FormattingTests, integer)
103 {
104 auto actual = FormatString("Guests: {INT32}", 32);
105 ASSERT_EQ("Guests: 32", actual);
106 }
107
TEST_F(FormattingTests,integer_integer)108 TEST_F(FormattingTests, integer_integer)
109 {
110 auto actual = FormatString("Guests: {INT32}, Staff: {INT32}", 32, 10);
111 ASSERT_EQ("Guests: 32, Staff: 10", actual);
112 }
113
TEST_F(FormattingTests,comma)114 TEST_F(FormattingTests, comma)
115 {
116 auto actual = FormatString("Guests: {COMMA16}", 12534);
117 ASSERT_EQ("Guests: 12,534", actual);
118 }
119
TEST_F(FormattingTests,comma_0)120 TEST_F(FormattingTests, comma_0)
121 {
122 auto actual = FormatString("Guests: {COMMA16}", 0);
123 ASSERT_EQ("Guests: 0", actual);
124 }
125
TEST_F(FormattingTests,comma_large_negative)126 TEST_F(FormattingTests, comma_large_negative)
127 {
128 auto actual = FormatString("{COMMA16}", std::numeric_limits<int64_t>::min());
129 ASSERT_EQ("-9,223,372,036,854,775,808", actual);
130 }
131
TEST_F(FormattingTests,comma_large)132 TEST_F(FormattingTests, comma_large)
133 {
134 auto actual = FormatString("{COMMA16}", std::numeric_limits<uint64_t>::max());
135 ASSERT_EQ("18,446,744,073,709,551,615", actual);
136 }
137
TEST_F(FormattingTests,currency)138 TEST_F(FormattingTests, currency)
139 {
140 gConfigGeneral.currency_format = CurrencyType::Pounds;
141 ASSERT_EQ(u8"-£251", FormatString("{CURRENCY}", -2510));
142 ASSERT_EQ(u8"£1", FormatString("{CURRENCY}", 4));
143 ASSERT_EQ(u8"£1", FormatString("{CURRENCY}", 5));
144 ASSERT_EQ(u8"£1", FormatString("{CURRENCY}", 10));
145 ASSERT_EQ(u8"£2", FormatString("{CURRENCY}", 11));
146 ASSERT_EQ(u8"£112", FormatString("{CURRENCY}", 1111));
147 }
148
TEST_F(FormattingTests,currency2dp)149 TEST_F(FormattingTests, currency2dp)
150 {
151 gConfigGeneral.currency_format = CurrencyType::Pounds;
152 ASSERT_EQ(u8"-£251.00", FormatString("{CURRENCY2DP}", -2510));
153 ASSERT_EQ(u8"£0.40", FormatString("{CURRENCY2DP}", 4));
154 ASSERT_EQ(u8"£0.50", FormatString("{CURRENCY2DP}", 5));
155 ASSERT_EQ(u8"£1.00", FormatString("{CURRENCY2DP}", 10));
156 ASSERT_EQ(u8"£1.10", FormatString("{CURRENCY2DP}", 11));
157 ASSERT_EQ(u8"£111.10", FormatString("{CURRENCY2DP}", 1111));
158 }
159
TEST_F(FormattingTests,currency_yen)160 TEST_F(FormattingTests, currency_yen)
161 {
162 gConfigGeneral.currency_format = CurrencyType::Yen;
163 ASSERT_EQ(u8"-¥25,100", FormatString("{CURRENCY}", -2510));
164 ASSERT_EQ(u8"¥40", FormatString("{CURRENCY2DP}", 4));
165 ASSERT_EQ(u8"¥50", FormatString("{CURRENCY2DP}", 5));
166 ASSERT_EQ(u8"¥100", FormatString("{CURRENCY2DP}", 10));
167 ASSERT_EQ(u8"¥110", FormatString("{CURRENCY2DP}", 11));
168 ASSERT_EQ(u8"¥11,110", FormatString("{CURRENCY2DP}", 1111));
169 }
170
TEST_F(FormattingTests,currency2dp_yen)171 TEST_F(FormattingTests, currency2dp_yen)
172 {
173 gConfigGeneral.currency_format = CurrencyType::Yen;
174 ASSERT_EQ(u8"-¥25,100", FormatString("{CURRENCY2DP}", -2510));
175 ASSERT_EQ(u8"¥40", FormatString("{CURRENCY2DP}", 4));
176 ASSERT_EQ(u8"¥50", FormatString("{CURRENCY2DP}", 5));
177 ASSERT_EQ(u8"¥100", FormatString("{CURRENCY2DP}", 10));
178 ASSERT_EQ(u8"¥110", FormatString("{CURRENCY2DP}", 11));
179 ASSERT_EQ(u8"¥11,110", FormatString("{CURRENCY2DP}", 1111));
180 }
181
TEST_F(FormattingTests,currency_pts)182 TEST_F(FormattingTests, currency_pts)
183 {
184 gConfigGeneral.currency_format = CurrencyType::Peseta;
185 ASSERT_EQ("-251Pts", FormatString("{CURRENCY}", -2510));
186 ASSERT_EQ("112Pts", FormatString("{CURRENCY}", 1111));
187 }
188
TEST_F(FormattingTests,currency2dp_pts)189 TEST_F(FormattingTests, currency2dp_pts)
190 {
191 gConfigGeneral.currency_format = CurrencyType::Peseta;
192 ASSERT_EQ("-251.00Pts", FormatString("{CURRENCY2DP}", -2510));
193 ASSERT_EQ("0.40Pts", FormatString("{CURRENCY2DP}", 4));
194 ASSERT_EQ("111.10Pts", FormatString("{CURRENCY2DP}", 1111));
195 }
196
TEST_F(FormattingTests,string)197 TEST_F(FormattingTests, string)
198 {
199 auto actual = FormatString("{RED}{STRING} has broken down.", "Woodchip");
200 ASSERT_EQ("{RED}Woodchip has broken down.", actual);
201 }
202
TEST_F(FormattingTests,escaped_braces)203 TEST_F(FormattingTests, escaped_braces)
204 {
205 auto actual = FormatString("--{{ESCAPED}}--", 0);
206 ASSERT_EQ("--{{ESCAPED}}--", actual);
207 }
208
TEST_F(FormattingTests,velocity_mph)209 TEST_F(FormattingTests, velocity_mph)
210 {
211 gConfigGeneral.measurement_format = MeasurementFormat::Imperial;
212 auto actual = FormatString("Train is going at {VELOCITY}.", 1024);
213 ASSERT_EQ("Train is going at 1,024 mph.", actual);
214 }
215
TEST_F(FormattingTests,velocity_kph)216 TEST_F(FormattingTests, velocity_kph)
217 {
218 gConfigGeneral.measurement_format = MeasurementFormat::Metric;
219 auto actual = FormatString("Train is going at {VELOCITY}.", 1024);
220 ASSERT_EQ("Train is going at 1,648 km/h.", actual);
221 }
222
TEST_F(FormattingTests,velocity_mps)223 TEST_F(FormattingTests, velocity_mps)
224 {
225 gConfigGeneral.measurement_format = MeasurementFormat::SI;
226 auto actual = FormatString("Train is going at {VELOCITY}.", 1024);
227 ASSERT_EQ("Train is going at 457.7 m/s.", actual);
228 }
229
TEST_F(FormattingTests,length_imperial)230 TEST_F(FormattingTests, length_imperial)
231 {
232 gConfigGeneral.measurement_format = MeasurementFormat::Imperial;
233 auto actual = FormatString("Height: {LENGTH}", 1024);
234 ASSERT_EQ("Height: 3,360 ft", actual);
235 }
236
TEST_F(FormattingTests,length_metric)237 TEST_F(FormattingTests, length_metric)
238 {
239 gConfigGeneral.measurement_format = MeasurementFormat::Metric;
240 auto actual = FormatString("Height: {LENGTH}", 1024);
241 ASSERT_EQ("Height: 1,024 m", actual);
242 }
243
TEST_F(FormattingTests,length_si)244 TEST_F(FormattingTests, length_si)
245 {
246 gConfigGeneral.measurement_format = MeasurementFormat::SI;
247 auto actual = FormatString("Height: {LENGTH}", 2048);
248 ASSERT_EQ("Height: 2,048 m", actual);
249 }
250
TEST_F(FormattingTests,minssecs)251 TEST_F(FormattingTests, minssecs)
252 {
253 ASSERT_EQ("0secs", FormatString("{DURATION}", 0));
254 ASSERT_EQ("1sec", FormatString("{DURATION}", 1));
255 ASSERT_EQ("4secs", FormatString("{DURATION}", 4));
256 ASSERT_EQ("1min:0secs", FormatString("{DURATION}", 60));
257 ASSERT_EQ("1min:1sec", FormatString("{DURATION}", 60 + 1));
258 ASSERT_EQ("1min:59secs", FormatString("{DURATION}", 60 + 59));
259 ASSERT_EQ("2mins:0secs", FormatString("{DURATION}", 120));
260 ASSERT_EQ("2mins:1sec", FormatString("{DURATION}", 120 + 1));
261 ASSERT_EQ("2mins:2secs", FormatString("{DURATION}", 120 + 2));
262 }
263
TEST_F(FormattingTests,hoursmins)264 TEST_F(FormattingTests, hoursmins)
265 {
266 ASSERT_EQ("0mins", FormatString("{REALTIME}", 0));
267 ASSERT_EQ("1min", FormatString("{REALTIME}", 1));
268 ASSERT_EQ("4mins", FormatString("{REALTIME}", 4));
269 ASSERT_EQ("1hour:0mins", FormatString("{REALTIME}", 60));
270 ASSERT_EQ("1hour:1min", FormatString("{REALTIME}", 60 + 1));
271 ASSERT_EQ("1hour:59mins", FormatString("{REALTIME}", 60 + 59));
272 ASSERT_EQ("2hours:0mins", FormatString("{REALTIME}", 120));
273 ASSERT_EQ("2hours:1min", FormatString("{REALTIME}", 120 + 1));
274 ASSERT_EQ("2hours:2mins", FormatString("{REALTIME}", 120 + 2));
275 }
276
TEST_F(FormattingTests,month)277 TEST_F(FormattingTests, month)
278 {
279 ASSERT_EQ("The month is March", FormatString("The month is {MONTH}", 0));
280 ASSERT_EQ("The month is October", FormatString("The month is {MONTH}", 7));
281 ASSERT_EQ("The month is April", FormatString("The month is {MONTH}", 9));
282 }
283
TEST_F(FormattingTests,monthyear)284 TEST_F(FormattingTests, monthyear)
285 {
286 ASSERT_EQ("Date: March, Year 1", FormatString("Date: {MONTHYEAR}", 0));
287 ASSERT_EQ("Date: October, Year 1", FormatString("Date: {MONTHYEAR}", 7));
288 ASSERT_EQ("Date: April, Year 2", FormatString("Date: {MONTHYEAR}", 9));
289 }
290
TEST_F(FormattingTests,two_level_format)291 TEST_F(FormattingTests, two_level_format)
292 {
293 constexpr rct_string_id strDefault = STR_RIDE_NAME_DEFAULT;
294 constexpr rct_string_id strBoatHire = STR_RIDE_NAME_BOAT_HIRE;
295 auto actual = FormatString("Queuing for {STRINGID}", strDefault, strBoatHire, 2);
296 ASSERT_EQ("Queuing for Boat Hire 2", actual);
297 }
298
TEST_F(FormattingTests,any_string_int_string)299 TEST_F(FormattingTests, any_string_int_string)
300 {
301 auto actual = FormatStringAny(
302 "{RED}{STRING} {INT32} has broken down due to '{STRING}'.", { "Twist", 2, "Mechanical failure" });
303 ASSERT_EQ("{RED}Twist 2 has broken down due to 'Mechanical failure'.", actual);
304 }
305
TEST_F(FormattingTests,any_two_level_format)306 TEST_F(FormattingTests, any_two_level_format)
307 {
308 constexpr rct_string_id strDefault = STR_RIDE_NAME_DEFAULT;
309 constexpr rct_string_id strBoatHire = STR_RIDE_NAME_BOAT_HIRE;
310 auto actual = FormatStringAny("Queuing for {STRINGID}", { strDefault, strBoatHire, 2 });
311 ASSERT_EQ("Queuing for Boat Hire 2", actual);
312 }
313
TEST_F(FormattingTests,to_fixed_buffer)314 TEST_F(FormattingTests, to_fixed_buffer)
315 {
316 char buffer[16];
317 std::memset(buffer, '\xFF', sizeof(buffer));
318 auto len = FormatStringId(buffer, 8, STR_GUEST_X, 123);
319 ASSERT_EQ(len, 9U);
320 ASSERT_STREQ("Guest 1", buffer);
321
322 // Ensure rest of the buffer was not overwritten
323 for (size_t i = 8; i < sizeof(buffer); i++)
324 {
325 ASSERT_EQ('\xFF', buffer[i]);
326 }
327 }
328
TEST_F(FormattingTests,using_legacy_buffer_args)329 TEST_F(FormattingTests, using_legacy_buffer_args)
330 {
331 auto ft = Formatter();
332 ft.Add<rct_string_id>(STR_RIDE_NAME_DEFAULT);
333 ft.Add<rct_string_id>(STR_RIDE_NAME_BOAT_HIRE);
334 ft.Add<uint16_t>(2);
335
336 char buffer[32]{};
337 auto len = FormatStringLegacy(buffer, sizeof(buffer), STR_QUEUING_FOR, ft.Data());
338 ASSERT_EQ(len, 23U);
339 ASSERT_STREQ("Queuing for Boat Hire 2", buffer);
340 }
341
TEST_F(FormattingTests,format_number_basic)342 TEST_F(FormattingTests, format_number_basic)
343 {
344 FormatBuffer ss;
345 // test basic integral conversion
346 FormatArgument<int32_t>(ss, FormatToken::UInt16, 123);
347 ASSERT_STREQ("123", ss.data());
348 }
349
TEST_F(FormattingTests,format_number_basic_int32)350 TEST_F(FormattingTests, format_number_basic_int32)
351 {
352 FormatBuffer ss;
353 // test that case fallthrough works
354 FormatArgument<int32_t>(ss, FormatToken::Int32, 123);
355 ASSERT_STREQ("123", ss.data());
356 }
357
TEST_F(FormattingTests,format_number_negative)358 TEST_F(FormattingTests, format_number_negative)
359 {
360 FormatBuffer ss;
361 // test negative conversion
362 FormatArgument<int32_t>(ss, FormatToken::Int32, -123);
363 ASSERT_STREQ("-123", ss.data());
364 }
365
TEST_F(FormattingTests,format_number_comma16_basic)366 TEST_F(FormattingTests, format_number_comma16_basic)
367 {
368 FormatBuffer ss;
369 // test separator formatter
370 // test base case separator formatter
371 FormatArgument<int32_t>(ss, FormatToken::Comma16, 123);
372 ASSERT_STREQ("123", ss.data());
373 }
374
TEST_F(FormattingTests,format_number_comma16_negative)375 TEST_F(FormattingTests, format_number_comma16_negative)
376 {
377 FormatBuffer ss;
378 // test separator formatter
379 // test base case separator formatter
380 FormatArgument<int32_t>(ss, FormatToken::Comma16, -123);
381 ASSERT_STREQ("-123", ss.data());
382 }
383
TEST_F(FormattingTests,format_number_comma16_large)384 TEST_F(FormattingTests, format_number_comma16_large)
385 {
386 FormatBuffer ss;
387 // test larger value for separator formatter
388 FormatArgument<int32_t>(ss, FormatToken::Comma16, 123456789);
389 ASSERT_STREQ("123,456,789", ss.data());
390 }
391
TEST_F(FormattingTests,format_number_comma16_large_negative)392 TEST_F(FormattingTests, format_number_comma16_large_negative)
393 {
394 FormatBuffer ss;
395 // test larger value for separator formatter with negative
396 FormatArgument<int32_t>(ss, FormatToken::Comma16, -123456789);
397 ASSERT_STREQ("-123,456,789", ss.data());
398 }
399
TEST_F(FormattingTests,format_number_comma16_uneven)400 TEST_F(FormattingTests, format_number_comma16_uneven)
401 {
402 FormatBuffer ss;
403 // test non-multiple of 3
404 FormatArgument<int32_t>(ss, FormatToken::Comma16, 12345678);
405 ASSERT_STREQ("12,345,678", ss.data());
406 }
407
TEST_F(FormattingTests,format_number_comma16_uneven_negative)408 TEST_F(FormattingTests, format_number_comma16_uneven_negative)
409 {
410 FormatBuffer ss;
411 // test non-multiple of 3 with negative
412 FormatArgument<int32_t>(ss, FormatToken::Comma16, -12345678);
413 ASSERT_STREQ("-12,345,678", ss.data());
414 }
415
TEST_F(FormattingTests,format_number_comma16_zero)416 TEST_F(FormattingTests, format_number_comma16_zero)
417 {
418 FormatBuffer ss;
419 // test zero
420 FormatArgument<int32_t>(ss, FormatToken::Comma16, 0);
421 ASSERT_STREQ("0", ss.data());
422 }
423
TEST_F(FormattingTests,format_number_comma1dp16_zero)424 TEST_F(FormattingTests, format_number_comma1dp16_zero)
425 {
426 FormatBuffer ss;
427 // zero case
428 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 0);
429 ASSERT_STREQ("0.0", ss.data());
430 }
431
TEST_F(FormattingTests,format_number_comma1dp16_leading_zero)432 TEST_F(FormattingTests, format_number_comma1dp16_leading_zero)
433 {
434 FormatBuffer ss;
435 // test leading zero
436 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 5);
437 ASSERT_STREQ("0.5", ss.data());
438 }
439
TEST_F(FormattingTests,format_number_comma1dp16_leading_zero_negative)440 TEST_F(FormattingTests, format_number_comma1dp16_leading_zero_negative)
441 {
442 FormatBuffer ss;
443 // test leading zero with negative value
444 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -5);
445 ASSERT_STREQ("-0.5", ss.data());
446 }
447
TEST_F(FormattingTests,format_number_comma1dp16_small_value)448 TEST_F(FormattingTests, format_number_comma1dp16_small_value)
449 {
450 FormatBuffer ss;
451 // test small value
452 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 75);
453 ASSERT_STREQ("7.5", ss.data());
454 }
455
TEST_F(FormattingTests,format_number_comma1dp16_small_value_negative)456 TEST_F(FormattingTests, format_number_comma1dp16_small_value_negative)
457 {
458 FormatBuffer ss;
459 // test small value with negative
460 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -75);
461 ASSERT_STREQ("-7.5", ss.data());
462 }
463
TEST_F(FormattingTests,format_number_comma1dp16_trailing_zeros)464 TEST_F(FormattingTests, format_number_comma1dp16_trailing_zeros)
465 {
466 FormatBuffer ss;
467 // test value with trailing zero, no commas
468 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 1000);
469 ASSERT_STREQ("100.0", ss.data());
470 }
471
TEST_F(FormattingTests,format_number_comma1dp16_trailing_zeros_negative)472 TEST_F(FormattingTests, format_number_comma1dp16_trailing_zeros_negative)
473 {
474 FormatBuffer ss;
475 // test value with trailing zero, no commas
476 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -1000);
477 ASSERT_STREQ("-100.0", ss.data());
478 }
479
TEST_F(FormattingTests,format_number_comma1dp16_large_trailing_zeros)480 TEST_F(FormattingTests, format_number_comma1dp16_large_trailing_zeros)
481 {
482 FormatBuffer ss;
483 // test value with commas and trailing zeros
484 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 10000000);
485 ASSERT_STREQ("1,000,000.0", ss.data());
486 }
487
TEST_F(FormattingTests,format_number_comma1dp16_large_trailing_zeros_negative)488 TEST_F(FormattingTests, format_number_comma1dp16_large_trailing_zeros_negative)
489 {
490 FormatBuffer ss;
491 // test value with commas and trailing zeros
492 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -10000000);
493 ASSERT_STREQ("-1,000,000.0", ss.data());
494 }
495
TEST_F(FormattingTests,format_number_comma1dp16_large_value)496 TEST_F(FormattingTests, format_number_comma1dp16_large_value)
497 {
498 FormatBuffer ss;
499 // test large value
500 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 123456789);
501 ASSERT_STREQ("12,345,678.9", ss.data());
502 }
503
TEST_F(FormattingTests,format_number_comma1dp16_large_value_negative)504 TEST_F(FormattingTests, format_number_comma1dp16_large_value_negative)
505 {
506 FormatBuffer ss;
507 // test large value
508 FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -123456789);
509 ASSERT_STREQ("-12,345,678.9", ss.data());
510 }
511
TEST_F(FormattingTests,format_number_comma2dp32_zero)512 TEST_F(FormattingTests, format_number_comma2dp32_zero)
513 {
514 FormatBuffer ss;
515 // zero case
516 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 0);
517 ASSERT_STREQ("0.00", ss.data());
518 }
519
TEST_F(FormattingTests,format_number_comma2dp32_less_sig_figs)520 TEST_F(FormattingTests, format_number_comma2dp32_less_sig_figs)
521 {
522 FormatBuffer ss;
523 // test leading zero
524 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 5);
525 ASSERT_STREQ("0.05", ss.data());
526 }
527
TEST_F(FormattingTests,format_number_comma2dp32_less_sig_figs_negative)528 TEST_F(FormattingTests, format_number_comma2dp32_less_sig_figs_negative)
529 {
530 FormatBuffer ss;
531 // test leading zero
532 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -5);
533 ASSERT_STREQ("-0.05", ss.data());
534 }
535
TEST_F(FormattingTests,format_number_comma2dp32_leading_zero)536 TEST_F(FormattingTests, format_number_comma2dp32_leading_zero)
537 {
538 FormatBuffer ss;
539 // test small value
540 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 75);
541 ASSERT_STREQ("0.75", ss.data());
542 }
543
TEST_F(FormattingTests,format_number_comma2dp32_leading_zero_negative)544 TEST_F(FormattingTests, format_number_comma2dp32_leading_zero_negative)
545 {
546 FormatBuffer ss;
547 // test small value
548 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -75);
549 ASSERT_STREQ("-0.75", ss.data());
550 }
551
TEST_F(FormattingTests,format_number_comma2dp32_trailing_zeros)552 TEST_F(FormattingTests, format_number_comma2dp32_trailing_zeros)
553 {
554 FormatBuffer ss;
555 // test value with trailing zero, no commas
556 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 1000);
557 ASSERT_STREQ("10.00", ss.data());
558 }
559
TEST_F(FormattingTests,format_number_comma2dp32_trailing_zeros_negative)560 TEST_F(FormattingTests, format_number_comma2dp32_trailing_zeros_negative)
561 {
562 FormatBuffer ss;
563 // test value with trailing zero, no commas
564 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -1000);
565 ASSERT_STREQ("-10.00", ss.data());
566 }
567
TEST_F(FormattingTests,format_number_comma2dp32_large_trailing_zeros)568 TEST_F(FormattingTests, format_number_comma2dp32_large_trailing_zeros)
569 {
570 FormatBuffer ss;
571 // test value with commas and trailing zeros
572 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 10000000);
573 ASSERT_STREQ("100,000.00", ss.data());
574 }
575
TEST_F(FormattingTests,format_number_comma2dp32_large_trailing_zeros_negative)576 TEST_F(FormattingTests, format_number_comma2dp32_large_trailing_zeros_negative)
577 {
578 FormatBuffer ss;
579 // test value with commas and trailing zeros
580 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -10000000);
581 ASSERT_STREQ("-100,000.00", ss.data());
582 }
583
TEST_F(FormattingTests,format_number_comma2dp32_large_value)584 TEST_F(FormattingTests, format_number_comma2dp32_large_value)
585 {
586 FormatBuffer ss;
587 // test large value
588 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 123456789);
589 ASSERT_STREQ("1,234,567.89", ss.data());
590 }
591
TEST_F(FormattingTests,format_number_comma2dp32_large_value_negative)592 TEST_F(FormattingTests, format_number_comma2dp32_large_value_negative)
593 {
594 FormatBuffer ss;
595 // test large value
596 FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -123456789);
597 ASSERT_STREQ("-1,234,567.89", ss.data());
598
599 // extra note:
600 // for some reason the FormatArgument function contains constexpr
601 // checks for std::is_floating_point<T>, even though a template
602 // specialization for which that would ever be the case is never
603 // declared. As such the following line won't be able to find
604 // the necessary symbol to link with.
605 // FormatArgument<double>(ss, FormatToken::Comma1dp16, 12.372);
606 }
607
TEST_F(FormattingTests,buffer_storage_swap)608 TEST_F(FormattingTests, buffer_storage_swap)
609 {
610 FormatBufferBase<char, 16> ss;
611 ss << "Hello World";
612 ASSERT_STREQ(ss.data(), "Hello World");
613 ss << ", Exceeding local storage";
614 ASSERT_STREQ(ss.data(), "Hello World, Exceeding local storage");
615 ss << ", extended";
616 ASSERT_STREQ(ss.data(), "Hello World, Exceeding local storage, extended");
617 }
618