coreutils / tests /dd /tests_for_scanargs.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <limits.h>
#include <getopt.h>
/* The test file is included inside dd.c after all internal definitions,
so we can access the static variables and functions declared there. */
extern int optind; /* ensure we can set optind */
/* Forward declarations of static functions from dd.c we need to compare. */
static ssize_t iread (int fd, char *buf, idx_t size);
static ssize_t iread_fullblock (int fd, char *buf, idx_t size);
/* Helper to reset the dd global state between tests. */
static void reset_dd_state(void)
{
/* Filenames */
input_file = NULL;
output_file = NULL;
/* Block sizes */
input_blocksize = 0;
output_blocksize = 0;
conversion_blocksize = 0;
/* Skips/Seeks/Counts */
skip_records = 0;
skip_bytes = 0;
seek_records = 0;
seek_bytes = 0;
max_records = INTMAX_MAX;
max_bytes = 0;
/* Flags and conversions */
conversions_mask = 0;
input_flags = 0;
output_flags = 0;
status_level = STATUS_DEFAULT;
/* Read path */
warn_partial_read = false;
i_nocache = false;
o_nocache = false;
i_nocache_eof = false;
o_nocache_eof = false;
iread_fnc = NULL;
/* Misc counters/output settings (not strictly needed by scanargs but reset anyway) */
w_partial = 0;
w_full = 0;
r_partial = 0;
r_full = 0;
w_bytes = 0;
reported_w_bytes = -1;
progress_len = 0;
r_truncate = 0;
translation_needed = false;
newline_character = '\n';
space_character = ' ';
}
void setUp(void) {
/* Setup before each test */
}
void tearDown(void) {
/* Cleanup after each test */
}
/* Tests */
void test_scanargs_defaults_sets_twobufs_and_defaults(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char *argv[] = { arg0 };
int argc = 1;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE((conversions_mask & C_TWOBUFS) != 0, "Expected C_TWOBUFS when bs is not specified");
TEST_ASSERT_EQUAL_INT(DEFAULT_BLOCKSIZE, (int)input_blocksize);
TEST_ASSERT_EQUAL_INT(DEFAULT_BLOCKSIZE, (int)output_blocksize);
TEST_ASSERT_EQUAL_INT(STATUS_DEFAULT, status_level);
TEST_ASSERT_EQUAL_PTR_MESSAGE((void*)iread, (void*)iread_fnc, "Default iread_fnc should be iread");
}
void test_scanargs_bs_sets_both_block_sizes_and_no_twobufs(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "bs=1024";
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_EQUAL_INT(1024, (int)input_blocksize);
TEST_ASSERT_EQUAL_INT(1024, (int)output_blocksize);
TEST_ASSERT_TRUE_MESSAGE((conversions_mask & C_TWOBUFS) == 0, "bs should suppress implicit C_TWOBUFS");
}
void test_scanargs_ibs_and_obs_set_independently_and_twobufs_added(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "ibs=4096";
char arg2[] = "obs=8192";
char *argv[] = { arg0, arg1, arg2 };
int argc = 3;
scanargs(argc, argv);
TEST_ASSERT_EQUAL_INT(4096, (int)input_blocksize);
TEST_ASSERT_EQUAL_INT(8192, (int)output_blocksize);
TEST_ASSERT_TRUE_MESSAGE((conversions_mask & C_TWOBUFS) != 0, "ibs/obs without bs should add C_TWOBUFS");
}
void test_scanargs_iflag_fullblock_sets_fullblock_reader(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "iflag=fullblock";
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_EQUAL_PTR((void*)iread_fullblock, (void*)iread_fnc);
TEST_ASSERT_TRUE_MESSAGE((input_flags & O_FULLBLOCK) == 0, "O_FULLBLOCK should be cleared after setting iread_fnc");
}
void test_scanargs_skip_with_B_suffix_splits_into_records_and_bytes(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "ibs=4";
char arg2[] = "skip=10B";
char *argv[] = { arg0, arg1, arg2 };
int argc = 3;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE((input_flags & O_SKIP_BYTES) != 0, "O_SKIP_BYTES should be set when skip uses B suffix");
TEST_ASSERT_EQUAL_INT(2, (int)skip_records);
TEST_ASSERT_EQUAL_INT(2, (int)skip_bytes);
}
void test_scanargs_skip_without_B_suffix_sets_records_only(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "skip=3";
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE((input_flags & O_SKIP_BYTES) == 0, "O_SKIP_BYTES should not be set without B suffix");
TEST_ASSERT_EQUAL_INT(3, (int)skip_records);
TEST_ASSERT_EQUAL_INT(0, (int)skip_bytes);
}
void test_scanargs_count_with_B_suffix_splits_into_records_and_bytes(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "ibs=10";
char arg2[] = "count=25B";
char *argv[] = { arg0, arg1, arg2 };
int argc = 3;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE((input_flags & O_COUNT_BYTES) != 0, "O_COUNT_BYTES should be set when count uses B suffix");
TEST_ASSERT_EQUAL_INT(2, (int)max_records);
TEST_ASSERT_EQUAL_INT(5, (int)max_bytes);
}
void test_scanargs_count_without_B_suffix_sets_records_only(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "count=7";
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE((input_flags & O_COUNT_BYTES) == 0, "O_COUNT_BYTES should not be set without B suffix");
TEST_ASSERT_EQUAL_INT(7, (int)max_records);
TEST_ASSERT_EQUAL_INT(0, (int)max_bytes);
}
void test_scanargs_seek_with_B_suffix_splits_into_records_and_bytes(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "obs=8";
char arg2[] = "seek=17B";
char *argv[] = { arg0, arg1, arg2 };
int argc = 3;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE((output_flags & O_SEEK_BYTES) != 0, "O_SEEK_BYTES should be set when seek uses B suffix");
TEST_ASSERT_EQUAL_INT(2, (int)seek_records);
TEST_ASSERT_EQUAL_INT(1, (int)seek_bytes);
}
void test_scanargs_status_progress_and_exclusive_behavior(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "status=none,progress"; /* last wins (exclusive) */
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_EQUAL_INT(STATUS_PROGRESS, status_level);
}
void test_scanargs_conv_ucase_and_swab_sets_bits_and_twobufs(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "conv=ucase,swab";
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE((conversions_mask & C_UCASE) != 0, "C_UCASE should be set");
TEST_ASSERT_TRUE_MESSAGE((conversions_mask & C_SWAB) != 0, "C_SWAB should be set");
TEST_ASSERT_TRUE_MESSAGE((conversions_mask & C_TWOBUFS) != 0, "C_TWOBUFS should be set (swab implies, and bs not set adds too)");
}
void test_scanargs_iflag_nocache_sets_internal_flags_and_clears_input_flag(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "iflag=nocache";
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_TRUE(i_nocache);
TEST_ASSERT_FALSE(i_nocache_eof); /* default max_records!=0 */
TEST_ASSERT_TRUE_MESSAGE((input_flags & O_NOCACHE) == 0, "O_NOCACHE should be cleared from input_flags");
}
void test_scanargs_oflag_nocache_sets_internal_flags_and_clears_output_flag(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "oflag=nocache";
char *argv[] = { arg0, arg1 };
int argc = 2;
scanargs(argc, argv);
TEST_ASSERT_TRUE(o_nocache);
TEST_ASSERT_FALSE(o_nocache_eof); /* default max_records!=0 */
TEST_ASSERT_TRUE_MESSAGE((output_flags & O_NOCACHE) == 0, "O_NOCACHE should be cleared from output_flags");
}
void test_scanargs_warn_partial_read_set_with_bs_and_small_count(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "bs=100";
char arg2[] = "count=1";
char *argv[] = { arg0, arg1, arg2 };
int argc = 3;
scanargs(argc, argv);
TEST_ASSERT_TRUE_MESSAGE(warn_partial_read, "warn_partial_read should be true when bs is set and counting records");
}
void test_scanargs_warn_partial_read_suppressed_by_iflag_fullblock(void)
{
reset_dd_state();
optind = 1;
char arg0[] = "dd";
char arg1[] = "bs=100";
char arg2[] = "count=1";
char arg3[] = "iflag=fullblock";
char *argv[] = { arg0, arg1, arg2, arg3 };
int argc = 4;
scanargs(argc, argv);
TEST_ASSERT_FALSE_MESSAGE(warn_partial_read, "warn_partial_read should be false when iflag=fullblock is specified");
TEST_ASSERT_EQUAL_PTR((void*)iread_fullblock, (void*)iread_fnc);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_scanargs_defaults_sets_twobufs_and_defaults);
RUN_TEST(test_scanargs_bs_sets_both_block_sizes_and_no_twobufs);
RUN_TEST(test_scanargs_ibs_and_obs_set_independently_and_twobufs_added);
RUN_TEST(test_scanargs_iflag_fullblock_sets_fullblock_reader);
RUN_TEST(test_scanargs_skip_with_B_suffix_splits_into_records_and_bytes);
RUN_TEST(test_scanargs_skip_without_B_suffix_sets_records_only);
RUN_TEST(test_scanargs_count_with_B_suffix_splits_into_records_and_bytes);
RUN_TEST(test_scanargs_count_without_B_suffix_sets_records_only);
RUN_TEST(test_scanargs_seek_with_B_suffix_splits_into_records_and_bytes);
RUN_TEST(test_scanargs_status_progress_and_exclusive_behavior);
RUN_TEST(test_scanargs_conv_ucase_and_swab_sets_bits_and_twobufs);
RUN_TEST(test_scanargs_iflag_nocache_sets_internal_flags_and_clears_input_flag);
RUN_TEST(test_scanargs_oflag_nocache_sets_internal_flags_and_clears_output_flag);
RUN_TEST(test_scanargs_warn_partial_read_set_with_bs_and_small_count);
RUN_TEST(test_scanargs_warn_partial_read_suppressed_by_iflag_fullblock);
return UNITY_END();
}