diff --git a/Makefile b/Makefile index ae99f38..b0152f4 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,14 @@ TESTS_SRC = tests TARGET = usage TEST_V_TARGET = test_vector TEST_M_TARGET = test_map +TEST_B_TARGET = test_bigint LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o $(OBJ_DIR)/bigint.o PROG_OBJS = $(OBJ_DIR)/usage.o .PHONY: all clean -all: $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) +all: $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET) $(TARGET): $(PROG_OBJS) $(LIB_OBJS) $(CC) $(CFLAGS) -o $@ $^ @@ -27,6 +28,9 @@ $(TEST_V_TARGET): $(OBJ_DIR)/test_vector.o $(OBJ_DIR)/vector.o $(TEST_M_TARGET): $(OBJ_DIR)/test_map.o $(OBJ_DIR)/map.o $(CC) $(CFLAGS) -o $@ $^ +$(TEST_B_TARGET): $(OBJ_DIR)/test_bigint.o $(OBJ_DIR)/bigint.o $(OBJ_DIR)/vector.o + $(CC) $(CFLAGS) -o $@ $^ + $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR) $(CC) $(CFLAGS) -c -o $@ $< @@ -40,4 +44,4 @@ $(OBJ_DIR): mkdir -p $(OBJ_DIR) clean: - rm -rf $(OBJ_DIR) $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) + rm -rf $(OBJ_DIR) $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET) diff --git a/src/bigint.c b/src/bigint.c index 31069d2..89a042f 100644 --- a/src/bigint.c +++ b/src/bigint.c @@ -61,33 +61,34 @@ bigint_result_t bigint_from_int(long long value) { number->digits = vec_res.value.vector; number->is_negative = (value < 0); - if (value < 0) { - value = -value; - } else if (value == 0) { + // Discard the sign since we don't need it anymore + unsigned long long abs_val = value < 0 ? -(unsigned long long)value : (unsigned long long)value; + + if(abs_val == 0) { int zero = 0; vector_result_t push_res = vector_push(number->digits, &zero); if (push_res.status != VECTOR_OK) { vector_destroy(number->digits); free(number); result.status = BIGINT_ERR_INVALID; - COPY_MSG(result, vec_res.message); + COPY_MSG(result, push_res.message); return result; } } else { - while (value > 0) { - int digit = value % BIGINT_BASE; + while (abs_val != 0) { + int digit = abs_val % BIGINT_BASE; vector_result_t push_res = vector_push(number->digits, &digit); if (push_res.status != VECTOR_OK) { vector_destroy(number->digits); free(number); result.status = BIGINT_ERR_INVALID; - COPY_MSG(result, vec_res.message); + COPY_MSG(result, push_res.message); return result; } - value /= BIGINT_BASE; + abs_val /= BIGINT_BASE; } } diff --git a/tests/test_bigint.c b/tests/test_bigint.c new file mode 100644 index 0000000..711a446 --- /dev/null +++ b/tests/test_bigint.c @@ -0,0 +1,63 @@ +/* + * Unit tests for BigInt data type +*/ + +#define TEST(NAME) do { \ + printf("Running test_%s...", #NAME); \ + test_##NAME(); \ + printf(" PASSED\n"); \ +} while(0) + +#include +#include +#include +#include + +#include "../src/bigint.h" + +static void bigint_eq(const bigint_t *number, const char *expected) { + bigint_result_t to_str = bigint_to_string(number); + assert(to_str.status == BIGINT_OK); + assert(!strcmp(to_str.value.string_num, expected)); + + free(to_str.value.string_num); +} + +// Test creating big integers from int +void test_bigint_from_int() { + bigint_result_t res = bigint_from_int(0); + + assert(res.status == BIGINT_OK); + bigint_eq(res.value.number, "0"); + bigint_destroy(res.value.number); + + res = bigint_from_int(10); + assert(res.status == BIGINT_OK); + bigint_eq(res.value.number, "10"); + bigint_destroy(res.value.number); + + res = bigint_from_int(-12345678900LL); + assert(res.status == BIGINT_OK); + bigint_eq(res.value.number, "-12345678900"); + bigint_destroy(res.value.number); +} + +// Test creating big integers from string +void test_bigint_from_string() { + bigint_result_t res = bigint_from_string("00000123"); + + assert(res.status == BIGINT_OK); + bigint_eq(res.value.number, "123"); + bigint_destroy(res.value.number); +} + +int main(void) { + printf("=== Running BigInt unit tests ===\n\n"); + + TEST(bigint_from_int); + TEST(bigint_from_string); + + printf("\n=== All tests passed ===\n"); + + return 0; +} \ No newline at end of file