Skip to content

Commit 989c846

Browse files
committed
Switch locale unit tests to Google Test.
The numeric grouping test won't compile in C++, due to the use of atomics in <common/locale.h>. Move the numeric grouping logic into <common/numeric_grouping.h>. While there, also move the unit test into that directory.
1 parent 145a330 commit 989c846

11 files changed

+135
-115
lines changed

Diff for: src/common/BUILD.bazel

+11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
load("@org_cloudabi_bazel_toolchains_cloudabi//:cc.bzl", "cc_test_cloudabi")
2+
13
cc_library(
24
name = "common",
35
hdrs = glob(["*.h"]),
46
include_prefix = "common",
57
visibility = ["//:__subpackages__"],
68
deps = ["@org_cloudabi_cloudabi//headers:cloudabi_syscalls"],
79
)
10+
11+
cc_test_cloudabi(
12+
name = "numeric_grouping_test",
13+
srcs = ["numeric_grouping_test.cc"],
14+
deps = [
15+
":common",
16+
"@com_google_googletest//:gtest_main",
17+
],
18+
)

Diff for: src/common/locale.h

-89
Original file line numberDiff line numberDiff line change
@@ -219,95 +219,6 @@ struct lc_numeric {
219219

220220
extern const struct lc_numeric __numeric_posix;
221221

222-
// Utility functions for inserting grouping characters into a number.
223-
//
224-
// The grouping string stored in LC_NUMERIC and LC_MONETARY has the
225-
// disadvantage that it encodes the grouping of a number from right to
226-
// left, whereas we would typically want to print numbers from left to
227-
// right. The last entry in the grouping string may also be repeated.
228-
//
229-
// This interface converts the grouping string to a simple state machine
230-
// that returns true or false depending on whether a grouping character
231-
// should be inserted. Example code:
232-
//
233-
// char digits[7] = "1234567";
234-
// struct numeric_grouping ng;
235-
// size_t n = numeric_grouping_init(&ng, "\x03", sizeof(digits));
236-
// char grouped_digits[sizeof(digits) + n];
237-
// char *out = grouped_digits;
238-
// for (size_t i = 0; i < sizeof(digits); ++i) {
239-
// if (numeric_grouping_step(&ng))
240-
// *out++ = ',';
241-
// *out++ = digits[i];
242-
// }
243-
//
244-
// The grouped_digits array will now contain "1,234,567".
245-
246-
struct numeric_grouping {
247-
const signed char *grouping;
248-
size_t steps;
249-
size_t repetitions;
250-
};
251-
252-
static inline size_t numeric_grouping_init(struct numeric_grouping *ng,
253-
const signed char *grouping,
254-
size_t ndigits) {
255-
if (ndigits <= 1 || grouping == NULL || *grouping == '\0') {
256-
// Number is too short, the grouping string is empty. Don't attempt
257-
// to do any grouping.
258-
ng->steps = SIZE_MAX;
259-
return 0;
260-
}
261-
262-
size_t ngroupings = 0;
263-
for (;;) {
264-
assert(ndigits >= 1 && "Attempted to format short number");
265-
assert(*grouping != '\0' && "Unexpected null byte");
266-
if (*grouping < '\0' || ndigits <= (size_t)*grouping) {
267-
// Don't do any grouping anymore. Place all of the remaining
268-
// digits in a group.
269-
*ng = (struct numeric_grouping){
270-
.grouping = grouping,
271-
.steps = ndigits,
272-
};
273-
return ngroupings;
274-
} else if (grouping[1] == '\0') {
275-
// Continue to do the grouping the same way indefinitely.
276-
*ng = (struct numeric_grouping){
277-
.grouping = grouping,
278-
.steps = (ndigits - 1) % *grouping + 1,
279-
.repetitions = (ndigits - 1) / *grouping,
280-
};
281-
return ngroupings + ng->repetitions;
282-
} else {
283-
// Still more groups to go after this one.
284-
ndigits -= *grouping;
285-
++grouping;
286-
++ngroupings;
287-
}
288-
}
289-
}
290-
291-
static inline bool numeric_grouping_step(struct numeric_grouping *ng) {
292-
if (ng->steps != 0) {
293-
// Still more steps to go before we need to print a grouping character.
294-
--ng->steps;
295-
return false;
296-
}
297-
298-
// Reload the number of steps we need.
299-
if (ng->repetitions != 0) {
300-
// Repeat the same group another time.
301-
--ng->repetitions;
302-
} else {
303-
// No more repetitions of this group. Move on to the next group.
304-
--ng->grouping;
305-
}
306-
assert(*ng->grouping > 0 && "Attempted to reload zero steps");
307-
ng->steps = *ng->grouping - 1;
308-
return true;
309-
}
310-
311222
// LC_TIME.
312223

313224
struct lc_time {

Diff for: src/common/numeric_grouping.h

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
2+
//
3+
// SPDX-License-Identifier: BSD-2-Clause
4+
5+
#ifndef COMMON_NUMERIC_GROUPING_H
6+
#define COMMON_NUMERIC_GROUPING_H
7+
8+
#include <assert.h>
9+
#include <stdbool.h>
10+
#include <stddef.h>
11+
#include <stdint.h>
12+
13+
// Utility functions for inserting grouping characters into a number.
14+
//
15+
// The grouping string stored in LC_NUMERIC and LC_MONETARY has the
16+
// disadvantage that it encodes the grouping of a number from right to
17+
// left, whereas we would typically want to print numbers from left to
18+
// right. The last entry in the grouping string may also be repeated.
19+
//
20+
// This interface converts the grouping string to a simple state machine
21+
// that returns true or false depending on whether a grouping character
22+
// should be inserted. Example code:
23+
//
24+
// char digits[7] = "1234567";
25+
// struct numeric_grouping ng;
26+
// size_t n = numeric_grouping_init(&ng, "\x03", sizeof(digits));
27+
// char grouped_digits[sizeof(digits) + n];
28+
// char *out = grouped_digits;
29+
// for (size_t i = 0; i < sizeof(digits); ++i) {
30+
// if (numeric_grouping_step(&ng))
31+
// *out++ = ',';
32+
// *out++ = digits[i];
33+
// }
34+
//
35+
// The grouped_digits array will now contain "1,234,567".
36+
37+
struct numeric_grouping {
38+
const signed char *grouping;
39+
size_t steps;
40+
size_t repetitions;
41+
};
42+
43+
static inline size_t numeric_grouping_init(struct numeric_grouping *ng,
44+
const signed char *grouping,
45+
size_t ndigits) {
46+
if (ndigits <= 1 || grouping == NULL || *grouping == '\0') {
47+
// Number is too short, the grouping string is empty. Don't attempt
48+
// to do any grouping.
49+
ng->steps = SIZE_MAX;
50+
return 0;
51+
}
52+
53+
size_t ngroupings = 0;
54+
for (;;) {
55+
assert(ndigits >= 1 && "Attempted to format short number");
56+
assert(*grouping != '\0' && "Unexpected null byte");
57+
if (*grouping < '\0' || ndigits <= (size_t)*grouping) {
58+
// Don't do any grouping anymore. Place all of the remaining
59+
// digits in a group.
60+
*ng = (struct numeric_grouping){
61+
.grouping = grouping,
62+
.steps = ndigits,
63+
};
64+
return ngroupings;
65+
} else if (grouping[1] == '\0') {
66+
// Continue to do the grouping the same way indefinitely.
67+
*ng = (struct numeric_grouping){
68+
.grouping = grouping,
69+
.steps = (ndigits - 1) % *grouping + 1,
70+
.repetitions = (ndigits - 1) / *grouping,
71+
};
72+
return ngroupings + ng->repetitions;
73+
} else {
74+
// Still more groups to go after this one.
75+
ndigits -= *grouping;
76+
++grouping;
77+
++ngroupings;
78+
}
79+
}
80+
}
81+
82+
static inline bool numeric_grouping_step(struct numeric_grouping *ng) {
83+
if (ng->steps != 0) {
84+
// Still more steps to go before we need to print a grouping character.
85+
--ng->steps;
86+
return false;
87+
}
88+
89+
// Reload the number of steps we need.
90+
if (ng->repetitions != 0) {
91+
// Repeat the same group another time.
92+
--ng->repetitions;
93+
} else {
94+
// No more repetitions of this group. Move on to the next group.
95+
--ng->grouping;
96+
}
97+
assert(*ng->grouping > 0 && "Attempted to reload zero steps");
98+
ng->steps = *ng->grouping - 1;
99+
return true;
100+
}
101+
102+
#endif

Diff for: src/libc/locale/numeric_grouping_test.c renamed to src/common/numeric_grouping_test.cc

+10-11
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
//
33
// SPDX-License-Identifier: BSD-2-Clause
44

5-
#include <common/locale.h>
5+
#include <common/numeric_grouping.h>
66

7-
#include <testing.h>
7+
#include "gtest/gtest.h"
88

99
TEST(numeric_grouping, examples) {
1010
#define NG_TEST(groupingstr, instr, outstr) \
@@ -14,15 +14,14 @@ TEST(numeric_grouping, examples) {
1414
numeric_grouping_init(&ng, (const signed char *)groupingstr, \
1515
sizeof(instr) - 1)); \
1616
for (size_t i = 0, j = 0; i < sizeof(instr) - 1; ++i, ++j) { \
17-
SCOPED_NOTE(i, { \
18-
if (outstr[j] == ',') { \
19-
ASSERT_TRUE(numeric_grouping_step(&ng)); \
20-
++j; \
21-
} else { \
22-
ASSERT_FALSE(numeric_grouping_step(&ng)); \
23-
} \
24-
ASSERT_EQ(outstr[j], instr[i]); \
25-
}); \
17+
SCOPED_TRACE(i); \
18+
if (outstr[j] == ',') { \
19+
ASSERT_TRUE(numeric_grouping_step(&ng)); \
20+
++j; \
21+
} else { \
22+
ASSERT_FALSE(numeric_grouping_step(&ng)); \
23+
} \
24+
ASSERT_EQ(outstr[j], instr[i]); \
2625
} \
2726
} while (0)
2827
NG_TEST(NULL, "", "");

Diff for: src/common/vprintf.h

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <common/float16.h>
77
#include <common/locale.h>
88
#include <common/mbstate.h>
9+
#include <common/numeric_grouping.h>
910
#include <common/stdio.h>
1011

1112
#include <assert.h>

Diff for: src/common/vstrfmon.h

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <common/float10.h>
66
#include <common/locale.h>
7+
#include <common/numeric_grouping.h>
78

89
#include <assert.h>
910
#include <errno.h>

Diff for: src/libc/locale/BUILD.bazel

+2-11
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,11 @@ cc_library(
5050

5151
[cc_test_cloudabi(
5252
name = test + "_test",
53-
srcs = [test + "_test.c"],
54-
deps = ["//src/libc/testing:testing_main"],
53+
srcs = [test + "_test.cc"],
54+
deps = ["@com_google_googletest//:gtest_main"],
5555
) for test in [
5656
"duplocale",
5757
"localeconv",
5858
"newlocale",
5959
"setlocale",
6060
]]
61-
62-
cc_test_cloudabi(
63-
name = "numeric_grouping_test",
64-
srcs = ["numeric_grouping_test.c"],
65-
deps = [
66-
"//src/common",
67-
"//src/libc/testing:testing_main",
68-
],
69-
)

Diff for: src/libc/locale/duplocale_test.c renamed to src/libc/locale/duplocale_test.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
// SPDX-License-Identifier: BSD-2-Clause
44

55
#include <locale.h>
6-
#include <testing.h>
6+
7+
#include "gtest/gtest.h"
78

89
TEST(duplocale, example) {
910
locale_t locale = duplocale(LC_GLOBAL_LOCALE);

Diff for: src/libc/locale/localeconv_test.c renamed to src/libc/locale/localeconv_test.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
#include <limits.h>
66
#include <locale.h>
7-
#include <testing.h>
7+
8+
#include "gtest/gtest.h"
89

910
TEST(localeconv, c_standard) {
1011
// Values that localeconv() should return for the C locale.

Diff for: src/libc/locale/newlocale_test.c renamed to src/libc/locale/newlocale_test.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
#include <errno.h>
66
#include <locale.h>
7-
#include <testing.h>
7+
8+
#include "gtest/gtest.h"
89

910
TEST(newlocale, zero) {
1011
// Empty mask should yield the standard locale.

Diff for: src/libc/locale/setlocale_test.c renamed to src/libc/locale/setlocale_test.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
// SPDX-License-Identifier: BSD-2-Clause
44

55
#include <locale.h>
6-
#include <testing.h>
6+
7+
#include "gtest/gtest.h"
78

89
TEST(setlocale, good) {
910
ASSERT_STREQ("C", setlocale(LC_ALL, NULL));

0 commit comments

Comments
 (0)