|
|
#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> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern int optind; |
|
|
|
|
|
|
|
|
static ssize_t iread (int fd, char *buf, idx_t size); |
|
|
static ssize_t iread_fullblock (int fd, char *buf, idx_t size); |
|
|
|
|
|
|
|
|
static void reset_dd_state(void) |
|
|
{ |
|
|
|
|
|
input_file = NULL; |
|
|
output_file = NULL; |
|
|
|
|
|
|
|
|
input_blocksize = 0; |
|
|
output_blocksize = 0; |
|
|
conversion_blocksize = 0; |
|
|
|
|
|
|
|
|
skip_records = 0; |
|
|
skip_bytes = 0; |
|
|
seek_records = 0; |
|
|
seek_bytes = 0; |
|
|
max_records = INTMAX_MAX; |
|
|
max_bytes = 0; |
|
|
|
|
|
|
|
|
conversions_mask = 0; |
|
|
input_flags = 0; |
|
|
output_flags = 0; |
|
|
status_level = STATUS_DEFAULT; |
|
|
|
|
|
|
|
|
warn_partial_read = false; |
|
|
i_nocache = false; |
|
|
o_nocache = false; |
|
|
i_nocache_eof = false; |
|
|
o_nocache_eof = false; |
|
|
iread_fnc = NULL; |
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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"; |
|
|
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); |
|
|
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); |
|
|
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(); |
|
|
} |