Skip to content

Commit d406b33

Browse files
committed
tests: add more uint128_t tests
1 parent 363df86 commit d406b33

1 file changed

Lines changed: 130 additions & 0 deletions

File tree

test/cpp/uint128.cpp

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,38 @@ using u128 = uint128_t;
1212
#define MAKE_U128(low, high) u128(low, high)
1313
#define CHECK_HIGH(val, expected) CHECK((val).high == (expected))
1414
#define CHECK_LOW(val, expected) CHECK((val).low == (expected))
15+
16+
// Compile-time checks: verify constexpr operators are truly constexpr
17+
static_assert(uint128_t(0) == uint128_t(0), "== must be constexpr");
18+
static_assert(uint128_t(1) != uint128_t(2), "!= must be constexpr");
19+
static_assert(uint128_t(1) < uint128_t(2), "< must be constexpr");
20+
static_assert(uint128_t(2) > uint128_t(1), "> must be constexpr");
21+
static_assert(uint128_t(1) <= uint128_t(1), "<= must be constexpr");
22+
static_assert(uint128_t(1) >= uint128_t(1), ">= must be constexpr");
23+
static_assert(static_cast<bool>(uint128_t(1)),
24+
"operator bool must be constexpr");
25+
static_assert(!static_cast<bool>(uint128_t(0)),
26+
"operator bool(0) must be constexpr");
27+
static_assert(static_cast<uint64_t>(uint128_t(42)) == 42,
28+
"operator uint64_t must be constexpr");
29+
static_assert(static_cast<int64_t>(uint128_t(7)) == 7,
30+
"operator int64_t must be constexpr");
31+
static_assert((uint128_t(0xFF) | uint128_t(0x100)) == uint128_t(0x1FF),
32+
"| must be constexpr");
33+
static_assert((uint128_t(0xFF) & uint128_t(0x0F)) == uint128_t(0x0F),
34+
"& must be constexpr");
35+
static_assert((uint128_t(0xFF) ^ uint128_t(0x0F)) == uint128_t(0xF0),
36+
"^ must be constexpr");
37+
static_assert((~uint128_t(0)) ==
38+
uint128_t(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF),
39+
"~ must be constexpr");
40+
static_assert((uint128_t(1) << 4) == uint128_t(16), "<< int must be constexpr");
41+
static_assert((uint128_t(16) >> 4) == uint128_t(1), ">> int must be constexpr");
42+
static_assert((uint128_t(1) << uint128_t(4)) == uint128_t(16),
43+
"<< u128 must be constexpr");
44+
static_assert((uint128_t(16) >> uint128_t(4)) == uint128_t(1),
45+
">> u128 must be constexpr");
46+
1547
#else
1648
using u128 = __uint128_t;
1749
#define MAKE_U128(low, high) ((u128(high) << 64) | low)
@@ -202,3 +234,101 @@ TEST_CASE("String Output (Decimal)", "[uint128][print]")
202234
ss << big;
203235
REQUIRE(ss.str() == "18446744073709551616");
204236
}
237+
238+
TEST_CASE("Division by Zero Guard", "[uint128][division][error]")
239+
{
240+
#if defined(_MSC_VER)
241+
u128 numerator(100);
242+
u128 zero(0);
243+
244+
// Division by zero should throw std::domain_error
245+
REQUIRE_THROWS_AS(numerator / zero, std::domain_error);
246+
247+
// Test with zero constructed from MAKE_U128
248+
u128 zero_via_macro = MAKE_U128(0, 0);
249+
REQUIRE_THROWS_AS(numerator / zero_via_macro, std::domain_error);
250+
251+
// Valid division should not throw
252+
u128 ten(10);
253+
REQUIRE_NOTHROW(numerator / ten);
254+
#endif
255+
}
256+
257+
TEST_CASE("Compound Shift Operators with uint128_t",
258+
"[uint128][shift][compound]")
259+
{
260+
SECTION("Left Shift Compound Operator (uint128_t)")
261+
{
262+
u128 val = u128(1);
263+
u128 shift_amt = u128(1);
264+
265+
// val <<= shift_amt
266+
val <<= shift_amt;
267+
REQUIRE(val == u128(2)); // 1 << 1 = 2
268+
269+
// Test crossing boundary
270+
u128 val2 = u128(1);
271+
u128 shift_64 = u128(64);
272+
val2 <<= shift_64;
273+
CHECK_HIGH(val2, 1);
274+
CHECK_LOW(val2, 0);
275+
}
276+
277+
SECTION("Right Shift Compound Operator (uint128_t)")
278+
{
279+
u128 val = MAKE_U128(0, 1); // high=1, low=0 (represents 2^64)
280+
u128 shift_amt = u128(1);
281+
282+
// val >>= shift_amt
283+
val >>= shift_amt;
284+
CHECK_HIGH(val, 0);
285+
CHECK_LOW(val, (1ULL << 63)); // 2^63
286+
287+
// Test crossing boundary with larger shift
288+
u128 val2 = MAKE_U128(0, 1);
289+
u128 shift_64 = u128(64);
290+
val2 >>= shift_64;
291+
CHECK_HIGH(val2, 0);
292+
CHECK_LOW(val2, 1);
293+
}
294+
295+
SECTION("Chained Shift Operations (uint128_t)")
296+
{
297+
u128 val = u128(1);
298+
u128 shift1 = u128(3);
299+
u128 shift2 = u128(2);
300+
301+
// (1 << 3) << 2 = 1 << 5 = 32
302+
val <<= shift1;
303+
val <<= shift2;
304+
REQUIRE(val == u128(32));
305+
}
306+
307+
SECTION("Large Shift via uint128_t")
308+
{
309+
u128 one(1);
310+
u128 shift_100(100);
311+
312+
one <<= shift_100;
313+
// 1 << 100 results in high bit (1 << (100-64)) = 1 << 36
314+
CHECK_HIGH(one, (1ULL << 36));
315+
CHECK_LOW(one, 0);
316+
}
317+
318+
SECTION("Over-shift Behavior (uint128_t)")
319+
{
320+
#if defined(_MSC_VER)
321+
u128 pattern = MAKE_U128(0xFF, 0xFF);
322+
u128 huge_shift(128);
323+
324+
// pattern <<= 128 should wrap (modulo 128)
325+
pattern <<= huge_shift;
326+
REQUIRE(pattern == MAKE_U128(0xFF, 0xFF)); // No effective change
327+
328+
// Test right shift over-shift
329+
u128 pattern2 = MAKE_U128(0xFF, 0xFF);
330+
pattern2 >>= huge_shift;
331+
REQUIRE(pattern2 == MAKE_U128(0xFF, 0xFF)); // No effective change
332+
#endif
333+
}
334+
}

0 commit comments

Comments
 (0)