coreutils / tests /numfmt /tests_for_process_field.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
/* The test file is included into the program source, so all
internal functions and static globals are in scope here. */
/* Helper: run process_field, capture stdout, and return the output string.
Also return the boolean result from process_field via ret_valid.
Note: No Unity assertions while stdout is redirected. */
static char* run_and_capture_process_field(const char* input, uintmax_t field, bool* ret_valid)
{
char* mutable = strdup(input);
if (!mutable)
return NULL;
/* Prepare redirection of stdout */
fflush(stdout);
int saved_fd = dup(fileno(stdout));
if (saved_fd < 0)
{
free(mutable);
return NULL;
}
FILE* tmp = tmpfile();
if (!tmp)
{
free(mutable);
close(saved_fd);
return NULL;
}
int tmp_fd = fileno(tmp);
if (dup2(tmp_fd, fileno(stdout)) < 0)
{
free(mutable);
fclose(tmp);
close(saved_fd);
return NULL;
}
/* Call the function under test */
bool ok = process_field(mutable, field);
/* Collect output */
fflush(stdout);
long size = 0;
if (fseek(tmp, 0, SEEK_END) == 0)
size = ftell(tmp);
if (size < 0) size = 0;
(void)fseek(tmp, 0, SEEK_SET);
char* out = (char*)malloc((size_t)size + 1);
if (!out)
{
/* Restore stdout before returning */
dup2(saved_fd, fileno(stdout));
close(saved_fd);
fclose(tmp);
free(mutable);
return NULL;
}
if (size > 0)
fread(out, 1, (size_t)size, tmp);
out[size] = '\0';
/* Restore stdout */
dup2(saved_fd, fileno(stdout));
close(saved_fd);
fclose(tmp);
free(mutable);
if (ret_valid)
*ret_valid = ok;
return out;
}
void setUp(void) {
/* Initialize globals relied upon by parsing/formatting to sane defaults. */
/* Locale-related parsing */
decimal_point = ".";
decimal_point_length = 1;
thousands_sep = "";
thousands_sep_length = 0;
/* Conversion/formatting defaults */
scale_from = scale_none;
scale_to = scale_none;
round_style = round_from_zero;
inval_style = inval_ignore; /* Avoid fatal exits on invalid inputs during tests */
suffix = NULL;
unit_separator = NULL;
from_unit_size = 1;
to_unit_size = 1;
grouping = 0;
/* Padding/format defaults */
if (padding_buffer)
{
free(padding_buffer);
padding_buffer = NULL;
}
padding_buffer_size = 0;
padding_width = 0;
zero_padding_width = 0;
user_precision = -1;
format_str = NULL;
if (format_str_prefix)
{
free(format_str_prefix);
format_str_prefix = NULL;
}
if (format_str_suffix)
{
free(format_str_suffix);
format_str_suffix = NULL;
}
auto_padding = 0;
delimiter = NULL;
line_delim = '\n';
header = 0;
debug = false;
dev_debug = false;
}
void tearDown(void) {
if (padding_buffer)
{
free(padding_buffer);
padding_buffer = NULL;
}
if (format_str_prefix)
{
free(format_str_prefix);
format_str_prefix = NULL;
}
if (format_str_suffix)
{
free(format_str_suffix);
format_str_suffix = NULL;
}
}
/* Test: field not included (frp == NULL implies only field 1 is included).
Here we pass field=2, so the function should not process and should
output the original text unchanged, returning true. */
void test_process_field_not_included_prints_unchanged_and_true(void)
{
bool ok = true;
const char* input = "abc";
char* out = run_and_capture_process_field(input, 2, &ok);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_EQUAL_STRING("abc", out);
free(out);
}
/* Test: included field with a valid integer (no suffix, no scaling).
Should print the same number and return true. */
void test_process_field_included_valid_integer(void)
{
bool ok = false;
const char* input = "123";
char* out = run_and_capture_process_field(input, 1, &ok);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_EQUAL_STRING("123", out);
free(out);
}
/* Test: included field with invalid input (inval_ignore set in setUp).
Should print original text, and return false. */
void test_process_field_included_invalid_input(void)
{
bool ok = true; /* expect false */
const char* input = "not-a-number";
char* out = run_and_capture_process_field(input, 1, &ok);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_FALSE(ok);
TEST_ASSERT_EQUAL_STRING("not-a-number", out);
free(out);
}
/* Test: suffix trimming on input and suffix addition on output.
With suffix="B", input "10B" should be parsed as 10, and output should be "10B". */
void test_process_field_suffix_trim_and_add(void)
{
suffix = "B";
bool ok = false;
const char* input = "10B";
char* out = run_and_capture_process_field(input, 1, &ok);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_EQUAL_STRING("10B", out);
free(out);
}
/* Test: unit conversion using from_unit_size/to_unit_size.
With from_unit_size=1024 and to_unit_size=1, input "1" -> "1024". */
void test_process_field_unit_conversion(void)
{
from_unit_size = 1024;
to_unit_size = 1;
bool ok = false;
const char* input = "1";
char* out = run_and_capture_process_field(input, 1, &ok);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_EQUAL_STRING("1024", out);
free(out);
}
/* Test: auto-padding preserves original field width.
Input " 5" (3 spaces then '5') with auto_padding=1 should print " 5". */
void test_process_field_auto_padding_preserves_width(void)
{
auto_padding = 1;
bool ok = false;
const char* input = " 5";
char* out = run_and_capture_process_field(input, 1, &ok);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_TRUE(ok);
TEST_ASSERT_EQUAL_STRING(" 5", out);
free(out);
}
/* Test: included field where no scaling and precision too large to print.
Use many fractional digits so that x + precision_used > LDBL_DIG.
Expect function to return false and print original text. */
void test_process_field_too_large_precision_returns_false_and_prints_original(void)
{
/* Create a number with many fractional digits (e.g., 25) */
const char* input = "0.1234567890123456789012345";
bool ok = true;
char* out = run_and_capture_process_field(input, 1, &ok);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_FALSE(ok);
TEST_ASSERT_EQUAL_STRING(input, out);
free(out);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_process_field_not_included_prints_unchanged_and_true);
RUN_TEST(test_process_field_included_valid_integer);
RUN_TEST(test_process_field_included_invalid_input);
RUN_TEST(test_process_field_suffix_trim_and_add);
RUN_TEST(test_process_field_unit_conversion);
RUN_TEST(test_process_field_auto_padding_preserves_width);
RUN_TEST(test_process_field_too_large_precision_returns_false_and_prints_original);
return UNITY_END();
}