meri/test_bigint.c
Juhani Krekelä 4155b9e0b0 Fix TEST macro to be C99 compliant
It looks like I had misunderstood the C99 limitations around __VA_ARGS__
2025-08-19 21:40:20 +00:00

92 lines
2.2 KiB
C

#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "meri_object.h"
#include "meri_bigint.h"
#include "tests.h"
// Ensures that addition of two i32 values gives the same result, regardless of
// whether we use bigints or native 64-bit arithmetic
static void test_addition(int32_t a, int32_t b) {
struct meri_bigint *a_bigint = meri_bigint_from_i32(a);
struct meri_bigint *b_bigint = meri_bigint_from_i32(b);
struct meri_bigint *result = meri_bigint_add(a_bigint, b_bigint);
assert(result->nlimbs == 1 || result->nlimbs == 2);
uint32_t low = result->limbs[0];
uint32_t high = (int32_t)low >> 31; // Default to sign extending
if (result->nlimbs > 1)
high = result->limbs[1];
int64_t result_i64 = (uint64_t)high << 32 | low;
int64_t expected = (int64_t)a + (int64_t)b;
assert(result_i64 == expected);
RELEASE(result);
}
#define TEST(...) {\
printf("%u", ++test);\
fflush(stdout);\
{ __VA_ARGS__; }\
printf(".");\
}
static int32_t interesting_ints[] = {
1,
2,
(int32_t)((1ul<<31) - 1), // The most positive i32
-1,
-2,
(int32_t)(1ul<<31), // The most negative i32
0
};
#define NELEMS(x) ((sizeof (x)) / (sizeof (x)[0]))
void test_bigint(void) {
unsigned int test = 0;
for (size_t i = 0; i < NELEMS(interesting_ints); i++) {
for (size_t j = 0; j < NELEMS(interesting_ints); j++) {
TEST(test_addition(interesting_ints[i], interesting_ints[j]));
}
}
printf("."); // Mark a new section of tests
struct meri_bigint *a, *b, *result;
// If first addend is moved, it is reused for the result
TEST(
a = meri_bigint_from_i32(2);
b = meri_bigint_from_i32(3);
result = meri_bigint_add(/* move */ a, COPY(b));
assert(result == a);
assert(result->header.refcount == 1);
assert(result != b);
assert(b->header.refcount == 1);
RELEASE(result);
)
// If second addend is moved but first is not, it is reused for the result
TEST(
a = meri_bigint_from_i32(2);
// b is still live from previous test
result = meri_bigint_add(COPY(a), /* move */ b);
assert(result != a);
assert(a->header.refcount == 1);
assert(result == b);
assert(result->header.refcount == 1);
RELEASE(a);
RELEASE(result);
)
// TODO: Test that all allocations are dead
}