Files
scc/runtime/ap/tests/test_ap.c
zzy d2eafa9dc6 refactor(ast2ir): 移除废弃的ABI依赖并优化类型转换处理
移除了对scc_abi包的依赖,将相关头文件从libs/abi移动到libs/ast2ir目录下。
重构了基本类型解析功能,将parse_base_type函数提取为独立的
scc_ast2ir_parse_base_type实现,并支持有符号/无符号类型区分。

feat(ast2ir): 实现整数常量表达式求值器

新增了完整的整数常量表达式求值功能,支持C11标准中的常量表达式规则,
包括字面量、标识符、sizeof/_Alignof、一元/二元运算、条件表达式和
类型转换等操作。该功能用于数组大小和枚举值的编译期计算验证。

refactor(ast2ir): 完善类型提升和算术转换机制

改进了整数提升和寻常算术转换的实现,修复了移位操作的符号处理问题,
添加了无符号比较操作的支持,增强了类型安全检查,统一了错误处理流程。

fix(ast2ir): 修复赋值表达式返回值和数组大小计算问题

修正了赋值表达式的返回值处理,确保返回右侧值而不是存储指令引用。
使用新的常量表达式求值器替代原有的硬编码数组大小计算,提高了
数组声明的正确性。
2026-05-31 17:30:22 +08:00

1029 lines
25 KiB
C

#include <ap.h>
#include <stdio.h>
#include <string.h>
#include <utest/acutest.h>
/* ---------- helpers ---------- */
static int eql_int(const scc_ap_t *ap, isize expected) {
return scc_ap_eql(
ap, &(scc_ap_t){.capacity = -1,
.len = expected < 0 ? -1 : 1,
.data.digit =
(scc_ap_digit)(expected < 0
? -(uint64_t)(int64_t)expected
: (uint64_t)expected)});
}
/* ---------- scc_ap_init / scc_ap_drop ---------- */
void test_init_zero(void) {
scc_ap_t ap;
scc_ap_init(&ap);
TEST_CHECK(ap.capacity == -1);
TEST_CHECK(ap.len == 1);
TEST_CHECK(ap.data.digit == 0);
TEST_CHECK(eql_int(&ap, 0));
}
void test_drop_resets(void) {
scc_ap_t ap;
scc_ap_set_int(&ap, 42);
scc_ap_drop(&ap);
TEST_CHECK(ap.capacity == -1);
TEST_CHECK(ap.len == 1);
TEST_CHECK(ap.data.digit == 0);
TEST_CHECK(eql_int(&ap, 0));
}
/* ---------- scc_ap_set_int ---------- */
void test_set_int_positive(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_int(&ap, 42);
TEST_CHECK(eql_int(&ap, 42));
}
void test_set_int_negative(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_int(&ap, -42);
TEST_CHECK(eql_int(&ap, -42));
}
void test_set_int_zero(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_int(&ap, 0);
TEST_CHECK(eql_int(&ap, 0));
}
void test_set_int_edge(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_int(&ap, 2147483647); /* INT_MAX */
TEST_CHECK(eql_int(&ap, 2147483647));
scc_ap_set_int(&ap, -2147483647 - 1); /* INT_MIN */
TEST_CHECK(eql_int(&ap, -2147483647 - 1));
}
/* ---------- scc_ap_set_digit ---------- */
void test_set_digit_basic(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_digit(&ap, 123);
TEST_CHECK(eql_int(&ap, 123));
}
void test_set_digit_zero(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_digit(&ap, 0);
TEST_CHECK(eql_int(&ap, 0));
}
void test_set_digit_max(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_digit(&ap, (scc_ap_digit)INTPTR_MAX);
TEST_CHECK(eql_int(&ap, INTPTR_MAX));
}
/* ---------- scc_ap_from_string ---------- */
void test_from_string_decimal(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "12345", -1, 10);
TEST_CHECK(eql_int(&ap, 12345));
}
void test_from_string_negative(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "-12345", -1, 10);
TEST_CHECK(eql_int(&ap, -12345));
}
void test_from_string_hex(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "0xFF", -1, 0);
TEST_CHECK(eql_int(&ap, 255));
}
void test_from_string_hex_no_prefix(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "FF", -1, 16);
TEST_CHECK(eql_int(&ap, 255));
}
void test_from_string_octal(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "077", -1, 0);
TEST_CHECK(eql_int(&ap, 63));
}
void test_from_string_binary(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "0b1010", -1, 0);
TEST_CHECK(eql_int(&ap, 10));
}
void test_from_string_zero(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "0", -1, 10);
TEST_CHECK(eql_int(&ap, 0));
}
void test_from_string_empty(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "", -1, 10);
TEST_CHECK(eql_int(&ap, 0));
}
void test_from_string_negative_zero(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "-0", -1, 10);
TEST_CHECK(eql_int(&ap, 0));
/* Should be positive zero */
TEST_CHECK(ap.len > 0);
}
void test_from_string_len_exact(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "42extra", 2, 10);
TEST_CHECK(eql_int(&ap, 42));
}
void test_from_string_max(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "9223372036854775807", -1, 10); /* INT64_MAX */
TEST_CHECK(eql_int(&ap, 9223372036854775807LL));
}
void test_from_string_min(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "-9223372036854775808", -1, 10);
TEST_CHECK(eql_int(&ap, (-9223372036854775807LL - 1)));
}
/* ---------- scc_ap_add ---------- */
void test_add_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 3);
scc_ap_set_int(&b, 5);
scc_ap_add(&r, &a, &b);
TEST_CHECK(eql_int(&r, 8));
}
void test_add_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -3);
scc_ap_set_int(&b, 5);
scc_ap_add(&r, &a, &b);
TEST_CHECK(eql_int(&r, 2));
}
void test_add_both_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -3);
scc_ap_set_int(&b, -5);
scc_ap_add(&r, &a, &b);
TEST_CHECK(eql_int(&r, -8));
}
void test_add_zero(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 0);
scc_ap_add(&r, &a, &b);
TEST_CHECK(eql_int(&r, 42));
}
void test_add_to_max(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "9223372036854775806", -1, 10);
scc_ap_set_int(&b, 1);
scc_ap_add(&r, &a, &b);
TEST_CHECK(eql_int(&r, INTPTR_MAX));
}
void test_add_to_min(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
/* INTPTR_MIN + 1 + (-1) = INTPTR_MIN */
scc_ap_from_string(&a, "-9223372036854775807", -1, 10);
scc_ap_set_int(&b, -1);
scc_ap_add(&r, &a, &b);
TEST_CHECK(eql_int(&r, INTPTR_MIN));
}
/* ---------- scc_ap_sub ---------- */
void test_sub_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 10);
scc_ap_set_int(&b, 3);
scc_ap_sub(&r, &a, &b);
TEST_CHECK(eql_int(&r, 7));
}
void test_sub_negative_result(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 3);
scc_ap_set_int(&b, 10);
scc_ap_sub(&r, &a, &b);
TEST_CHECK(eql_int(&r, -7));
}
void test_sub_negatives(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -5);
scc_ap_set_int(&b, -3);
scc_ap_sub(&r, &a, &b);
TEST_CHECK(eql_int(&r, -2));
}
void test_sub_zero(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 0);
scc_ap_sub(&r, &a, &b);
TEST_CHECK(eql_int(&r, 42));
}
void test_sub_from_min(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
/* (INTPTR_MIN + 1) - 1 = INTPTR_MIN */
scc_ap_from_string(&a, "-9223372036854775807", -1, 10);
scc_ap_set_int(&b, 1);
scc_ap_sub(&r, &a, &b);
TEST_CHECK(eql_int(&r, INTPTR_MIN));
}
/* ---------- scc_ap_mul ---------- */
void test_mul_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 6);
scc_ap_set_int(&b, 7);
scc_ap_mul(&r, &a, &b);
TEST_CHECK(eql_int(&r, 42));
}
void test_mul_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -4);
scc_ap_set_int(&b, 5);
scc_ap_mul(&r, &a, &b);
TEST_CHECK(eql_int(&r, -20));
}
void test_mul_both_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -4);
scc_ap_set_int(&b, -5);
scc_ap_mul(&r, &a, &b);
TEST_CHECK(eql_int(&r, 20));
}
void test_mul_zero(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 0);
scc_ap_mul(&r, &a, &b);
TEST_CHECK(eql_int(&r, 0));
}
void test_mul_one(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 99);
scc_ap_set_int(&b, 1);
scc_ap_mul(&r, &a, &b);
TEST_CHECK(eql_int(&r, 99));
}
void test_mul_neg_one(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 99);
scc_ap_set_int(&b, -1);
scc_ap_mul(&r, &a, &b);
TEST_CHECK(eql_int(&r, -99));
}
void test_mul_max(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 1);
scc_ap_from_string(&b, "9223372036854775807", -1, 10);
scc_ap_mul(&r, &a, &b);
TEST_CHECK(eql_int(&r, INTPTR_MAX));
}
/* ---------- scc_ap_div ---------- */
void test_div_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 6);
scc_ap_div(&r, &a, &b);
TEST_CHECK(eql_int(&r, 7));
}
void test_div_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -42);
scc_ap_set_int(&b, 6);
scc_ap_div(&r, &a, &b);
TEST_CHECK(eql_int(&r, -7));
}
void test_div_trunc_toward_zero(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 7);
scc_ap_set_int(&b, 3);
scc_ap_div(&r, &a, &b);
TEST_CHECK(eql_int(&r, 2));
}
void test_div_one(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 123);
scc_ap_set_int(&b, 1);
scc_ap_div(&r, &a, &b);
TEST_CHECK(eql_int(&r, 123));
}
void test_div_self(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 42);
scc_ap_div(&r, &a, &b);
TEST_CHECK(eql_int(&r, 1));
}
void test_div_zero_dividend(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 0);
scc_ap_set_int(&b, 7);
scc_ap_div(&r, &a, &b);
TEST_CHECK(eql_int(&r, 0));
}
/* ---------- scc_ap_mod ---------- */
void test_mod_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 10);
scc_ap_set_int(&b, 3);
scc_ap_mod(&r, &a, &b);
TEST_CHECK(eql_int(&r, 1));
}
void test_mod_negative_dividend(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -10);
scc_ap_set_int(&b, 3);
scc_ap_mod(&r, &a, &b);
/* C truncates toward zero: -10 % 3 = -1 */
TEST_CHECK(eql_int(&r, -1));
}
void test_mod_self(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 42);
scc_ap_mod(&r, &a, &b);
TEST_CHECK(eql_int(&r, 0));
}
/* ---------- scc_ap_shl / scc_ap_shr / scc_ap_lshr ---------- */
void test_shl_basic(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 3);
scc_ap_shl(&r, &a, 2);
TEST_CHECK(eql_int(&r, 12)); /* 3 << 2 = 12 */
}
void test_shl_negative(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -3);
scc_ap_shl(&r, &a, 2);
TEST_CHECK(eql_int(&r, -12));
}
void test_shl_zero(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_shl(&r, &a, 0);
TEST_CHECK(eql_int(&r, 42));
}
void test_shl_by_62(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 1);
scc_ap_shl(&r, &a, 62);
TEST_CHECK(eql_int(&r, 4611686018427387904LL));
}
void test_shr_basic(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 12);
scc_ap_shr(&r, &a, 2);
TEST_CHECK(eql_int(&r, 3)); /* 12 >> 2 = 3 */
}
void test_shr_arithmetic_negative(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -12);
scc_ap_shr(&r, &a, 2);
TEST_CHECK(eql_int(&r, -3)); /* arithmetic: -12 >> 2 = -3 */
}
void test_shr_arithmetic_negative_rounding(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -7);
scc_ap_shr(&r, &a, 2);
TEST_CHECK(eql_int(&r, -2)); /* arithmetic: -7 >> 2 = -2 (rounds down) */
}
void test_shr_zero_shift(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -42);
scc_ap_shr(&r, &a, 0);
TEST_CHECK(eql_int(&r, -42));
}
void test_lshr_basic(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 12);
scc_ap_lshr(&r, &a, 2);
TEST_CHECK(eql_int(&r, 3)); /* 12 >> 2 = 3 */
}
void test_lshr_negative(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -1); /* 0xFFFFFFFFFFFFFFFF */
scc_ap_lshr(&r, &a, 63);
TEST_CHECK(eql_int(&r, 1)); /* 0xFFFFFFFFFFFFFFFF >> 63 = 1 */
}
void test_lshr_negative_bits(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -8); /* 0xFFFFFFFFFFFFFFF8 */
scc_ap_lshr(&r, &a, 2);
/* 0xFFFFFFFFFFFFFFF8 >> 2 = 0x3FFFFFFFFFFFFFFE = 4611686018427387902 */
TEST_CHECK(eql_int(&r, 4611686018427387902LL));
}
/* ---------- bitwise ---------- */
void test_and_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 5);
scc_ap_set_int(&b, 3);
scc_ap_and(&r, &a, &b);
TEST_CHECK(eql_int(&r, 1)); /* 5 & 3 = 1 */
}
void test_and_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -5);
scc_ap_set_int(&b, 3);
scc_ap_and(&r, &a, &b);
/* -5 = 0xFFFFFFFB, & 3 = 0x00000003 = 3 */
TEST_CHECK(eql_int(&r, 3));
}
void test_and_zero(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 0);
scc_ap_and(&r, &a, &b);
TEST_CHECK(eql_int(&r, 0));
}
void test_or_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 5);
scc_ap_set_int(&b, 3);
scc_ap_or(&r, &a, &b);
TEST_CHECK(eql_int(&r, 7)); /* 5 | 3 = 7 */
}
void test_or_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -5);
scc_ap_set_int(&b, 3);
scc_ap_or(&r, &a, &b);
TEST_CHECK(eql_int(&r, -5)); /* -5 | 3 = -5 */
}
void test_xor_basic(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 5);
scc_ap_set_int(&b, 3);
scc_ap_xor(&r, &a, &b);
TEST_CHECK(eql_int(&r, 6)); /* 5 ^ 3 = 6 */
}
void test_xor_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, -5);
scc_ap_set_int(&b, 3);
scc_ap_xor(&r, &a, &b);
TEST_CHECK(eql_int(&r, -8)); /* -5 ^ 3 = -8 */
}
void test_not_basic(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 5);
scc_ap_not(&r, &a);
TEST_CHECK(eql_int(&r, -6)); /* ~5 = -6 */
}
void test_not_neg_one(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -1);
scc_ap_not(&r, &a);
TEST_CHECK(eql_int(&r, 0)); /* ~(-1) = 0 */
}
void test_not_zero(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 0);
scc_ap_not(&r, &a);
TEST_CHECK(eql_int(&r, -1)); /* ~0 = -1 */
}
/* ---------- scc_ap_neg ---------- */
void test_neg_positive(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 42);
scc_ap_neg(&r, &a);
TEST_CHECK(eql_int(&r, -42));
}
void test_neg_negative(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, -42);
scc_ap_neg(&r, &a);
TEST_CHECK(eql_int(&r, 42));
}
void test_neg_zero(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 0);
scc_ap_neg(&r, &a);
TEST_CHECK(eql_int(&r, 0));
}
/* ---------- scc_ap_cmp ---------- */
void test_cmp_equal(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 42);
TEST_CHECK(scc_ap_cmp(&a, &b) == 0);
}
void test_cmp_less(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_set_int(&a, 3);
scc_ap_set_int(&b, 5);
TEST_CHECK(scc_ap_cmp(&a, &b) < 0);
}
void test_cmp_greater(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_set_int(&a, 5);
scc_ap_set_int(&b, 3);
TEST_CHECK(scc_ap_cmp(&a, &b) > 0);
}
void test_cmp_neg_vs_pos(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_set_int(&a, -5);
scc_ap_set_int(&b, 3);
TEST_CHECK(scc_ap_cmp(&a, &b) < 0);
}
/* ---------- scc_ap_is_zero ---------- */
void test_is_zero_true(void) {
scc_ap_t ap;
scc_ap_init(&ap);
TEST_CHECK(scc_ap_is_zero(&ap) != 0);
}
void test_is_zero_false_pos(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_int(&ap, 42);
TEST_CHECK(scc_ap_is_zero(&ap) == 0);
}
void test_is_zero_false_neg(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_set_int(&ap, -42);
TEST_CHECK(scc_ap_is_zero(&ap) == 0);
}
/* ---------- scc_ap_eql ---------- */
void test_eql_equal(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 42);
TEST_CHECK(scc_ap_eql(&a, &b) != 0);
}
void test_eql_not_equal(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_set_int(&a, 42);
scc_ap_set_int(&b, 43);
TEST_CHECK(scc_ap_eql(&a, &b) == 0);
}
void test_eql_neg_vs_pos(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_set_int(&a, -42);
scc_ap_set_int(&b, 42);
TEST_CHECK(scc_ap_eql(&a, &b) == 0);
}
void test_eql_both_zero(void) {
scc_ap_t a, b;
scc_ap_init(&a);
scc_ap_init(&b);
/* +0 == 0 */
scc_ap_from_string(&a, "0", -1, 10);
scc_ap_from_string(&b, "-0", -1, 10);
TEST_CHECK(scc_ap_eql(&a, &b) != 0);
}
/* ---------- scc_ap_with_bits ---------- */
void test_with_bits_small(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_with_bits(&ap, 1);
TEST_CHECK(ap.capacity == -1);
}
void test_with_bits_64(void) {
scc_ap_t ap;
scc_ap_init(&ap);
scc_ap_with_bits(&ap, 64);
TEST_CHECK(ap.capacity == -1);
}
/* ---------- scc_ap_dump ---------- */
typedef struct {
char buf[128];
int pos;
} dump_ctx_t;
static void dump_char(char ch, void *user_data) {
dump_ctx_t *ctx = (dump_ctx_t *)user_data;
if (ctx->pos < (int)sizeof(ctx->buf) - 1)
ctx->buf[ctx->pos++] = ch;
}
void test_dump_positive(void) {
scc_ap_t ap;
dump_ctx_t ctx;
scc_ap_init(&ap);
scc_ap_set_int(&ap, 12345);
ctx.pos = 0;
ctx.buf[0] = '\0';
scc_ap_dump(&ap, dump_char, &ctx);
ctx.buf[ctx.pos] = '\0';
TEST_CHECK(strcmp(ctx.buf, "12345") == 0);
}
void test_dump_negative(void) {
scc_ap_t ap;
dump_ctx_t ctx;
scc_ap_init(&ap);
scc_ap_set_int(&ap, -12345);
ctx.pos = 0;
ctx.buf[0] = '\0';
scc_ap_dump(&ap, dump_char, &ctx);
ctx.buf[ctx.pos] = '\0';
TEST_CHECK(strcmp(ctx.buf, "-12345") == 0);
}
void test_dump_zero(void) {
scc_ap_t ap;
dump_ctx_t ctx;
scc_ap_init(&ap);
ctx.pos = 0;
ctx.buf[0] = '\0';
scc_ap_dump(&ap, dump_char, &ctx);
ctx.buf[ctx.pos] = '\0';
TEST_CHECK(strcmp(ctx.buf, "0") == 0);
}
void test_dump_max(void) {
scc_ap_t ap;
dump_ctx_t ctx;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "9223372036854775807", -1, 10);
ctx.pos = 0;
ctx.buf[0] = '\0';
scc_ap_dump(&ap, dump_char, &ctx);
ctx.buf[ctx.pos] = '\0';
TEST_CHECK(strcmp(ctx.buf, "9223372036854775807") == 0);
}
void test_dump_min(void) {
scc_ap_t ap;
dump_ctx_t ctx;
scc_ap_init(&ap);
scc_ap_from_string(&ap, "-9223372036854775808", -1, 10);
ctx.pos = 0;
ctx.buf[0] = '\0';
scc_ap_dump(&ap, dump_char, &ctx);
ctx.buf[ctx.pos] = '\0';
TEST_CHECK(strcmp(ctx.buf, "-9223372036854775808") == 0);
}
/* ---------- test list ---------- */
TEST_LIST = {
/* init / drop */
{"test_init_zero", test_init_zero},
{"test_drop_resets", test_drop_resets},
/* set_int */
{"test_set_int_positive", test_set_int_positive},
{"test_set_int_negative", test_set_int_negative},
{"test_set_int_zero", test_set_int_zero},
{"test_set_int_edge", test_set_int_edge},
/* set_digit */
{"test_set_digit_basic", test_set_digit_basic},
{"test_set_digit_zero", test_set_digit_zero},
{"test_set_digit_max", test_set_digit_max},
/* from_string */
{"test_from_string_decimal", test_from_string_decimal},
{"test_from_string_negative", test_from_string_negative},
{"test_from_string_hex", test_from_string_hex},
{"test_from_string_hex_no_prefix", test_from_string_hex_no_prefix},
{"test_from_string_octal", test_from_string_octal},
{"test_from_string_binary", test_from_string_binary},
{"test_from_string_zero", test_from_string_zero},
{"test_from_string_empty", test_from_string_empty},
{"test_from_string_negative_zero", test_from_string_negative_zero},
{"test_from_string_len_exact", test_from_string_len_exact},
{"test_from_string_max", test_from_string_max},
{"test_from_string_min", test_from_string_min},
/* add */
{"test_add_basic", test_add_basic},
{"test_add_negative", test_add_negative},
{"test_add_both_negative", test_add_both_negative},
{"test_add_zero", test_add_zero},
{"test_add_to_max", test_add_to_max},
{"test_add_to_min", test_add_to_min},
/* sub */
{"test_sub_basic", test_sub_basic},
{"test_sub_negative_result", test_sub_negative_result},
{"test_sub_negatives", test_sub_negatives},
{"test_sub_zero", test_sub_zero},
{"test_sub_from_min", test_sub_from_min},
/* mul */
{"test_mul_basic", test_mul_basic},
{"test_mul_negative", test_mul_negative},
{"test_mul_both_negative", test_mul_both_negative},
{"test_mul_zero", test_mul_zero},
{"test_mul_one", test_mul_one},
{"test_mul_neg_one", test_mul_neg_one},
{"test_mul_max", test_mul_max},
/* div */
{"test_div_basic", test_div_basic},
{"test_div_negative", test_div_negative},
{"test_div_trunc_toward_zero", test_div_trunc_toward_zero},
{"test_div_one", test_div_one},
{"test_div_self", test_div_self},
{"test_div_zero_dividend", test_div_zero_dividend},
/* mod */
{"test_mod_basic", test_mod_basic},
{"test_mod_negative_dividend", test_mod_negative_dividend},
{"test_mod_self", test_mod_self},
/* shl / shr / lshr */
{"test_shl_basic", test_shl_basic},
{"test_shl_negative", test_shl_negative},
{"test_shl_zero", test_shl_zero},
{"test_shl_by_62", test_shl_by_62},
{"test_shr_basic", test_shr_basic},
{"test_shr_arithmetic_negative", test_shr_arithmetic_negative},
{"test_shr_arithmetic_negative_rounding", test_shr_arithmetic_negative_rounding},
{"test_shr_zero_shift", test_shr_zero_shift},
{"test_lshr_basic", test_lshr_basic},
{"test_lshr_negative", test_lshr_negative},
{"test_lshr_negative_bits", test_lshr_negative_bits},
/* bitwise */
{"test_and_basic", test_and_basic},
{"test_and_negative", test_and_negative},
{"test_and_zero", test_and_zero},
{"test_or_basic", test_or_basic},
{"test_or_negative", test_or_negative},
{"test_xor_basic", test_xor_basic},
{"test_xor_negative", test_xor_negative},
{"test_not_basic", test_not_basic},
{"test_not_neg_one", test_not_neg_one},
{"test_not_zero", test_not_zero},
/* neg */
{"test_neg_positive", test_neg_positive},
{"test_neg_negative", test_neg_negative},
{"test_neg_zero", test_neg_zero},
/* cmp */
{"test_cmp_equal", test_cmp_equal},
{"test_cmp_less", test_cmp_less},
{"test_cmp_greater", test_cmp_greater},
{"test_cmp_neg_vs_pos", test_cmp_neg_vs_pos},
/* is_zero */
{"test_is_zero_true", test_is_zero_true},
{"test_is_zero_false_pos", test_is_zero_false_pos},
{"test_is_zero_false_neg", test_is_zero_false_neg},
/* eql */
{"test_eql_equal", test_eql_equal},
{"test_eql_not_equal", test_eql_not_equal},
{"test_eql_neg_vs_pos", test_eql_neg_vs_pos},
{"test_eql_both_zero", test_eql_both_zero},
/* with_bits */
{"test_with_bits_small", test_with_bits_small},
{"test_with_bits_64", test_with_bits_64},
/* dump */
{"test_dump_positive", test_dump_positive},
{"test_dump_negative", test_dump_negative},
{"test_dump_zero", test_dump_zero},
{"test_dump_max", test_dump_max},
{"test_dump_min", test_dump_min},
{nullptr, nullptr},
};