coreutils / tests /csplit /tests_for_parse_patterns.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 <stdbool.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
/* Access to internal globals and function since this file is included
into the same translation unit after the function definitions. */
/* Prototypes of tested function are not needed; we can call it directly:
static void parse_patterns (int argc, int start, char **argv);
*/
/* Helper: run parse_patterns in a child process, capturing stderr, and
return the child's exit status. Does not use Unity assertions in the child. */
static int run_parse_patterns_in_child(int argc, int start, char **argv,
char *errbuf, size_t errbufsz)
{
int pipefd[2];
if (pipe(pipefd) != 0)
return -1;
fflush(stdout);
fflush(stderr);
pid_t pid = fork();
if (pid < 0)
{
close(pipefd[0]);
close(pipefd[1]);
return -1;
}
if (pid == 0)
{
/* Child: redirect stderr to pipe write end. */
(void)dup2(pipefd[1], STDERR_FILENO);
close(pipefd[0]);
close(pipefd[1]);
/* Ensure clean control state for this invocation. */
/* control_used is visible; controls pointer is reused by xpalloc. */
extern idx_t control_used;
extern char **global_argv;
control_used = 0;
global_argv = argv;
/* Call the function. If it returns, exit success. */
parse_patterns(argc, start, argv);
_exit(0);
}
/* Parent: read child's stderr and wait for it. */
close(pipefd[1]);
ssize_t total = 0;
while (total < (ssize_t)errbufsz - 1)
{
ssize_t n = read(pipefd[0], errbuf + total, errbufsz - 1 - total);
if (n > 0)
total += n;
else
break;
}
errbuf[total] = '\0';
close(pipefd[0]);
int status = 0;
if (waitpid(pid, &status, 0) < 0)
return -1;
if (WIFEXITED(status))
return WEXITSTATUS(status);
else if (WIFSIGNALED(status))
return 128 + WTERMSIG(status);
else
return -1;
}
void setUp(void) {
/* Reset state used by parse_patterns that is safe to reset between tests. */
extern idx_t control_used;
control_used = 0;
/* Align global_argv to avoid null dereferences in error paths that might
use it (though we avoid such checks in parent without forking). */
extern char **global_argv;
global_argv = NULL;
}
void tearDown(void) {
/* Nothing specific to do. */
}
/* Test: regexp patterns with and without ignore, including offset parsing. */
void test_parse_patterns_regexp_with_offset_and_ignore(void)
{
extern struct control *controls;
extern idx_t control_used;
extern char **global_argv;
char *argv[] = { "/foo/", "%bar%+3" };
int argc = 2;
int start = 0;
global_argv = argv;
parse_patterns(argc, start, argv);
TEST_ASSERT_EQUAL_INT64(2, control_used);
/* First: /foo/ */
TEST_ASSERT_TRUE(controls[0].regexpr);
TEST_ASSERT_FALSE(controls[0].ignore);
TEST_ASSERT_EQUAL_INT(0, controls[0].offset);
TEST_ASSERT_EQUAL_INT(0, controls[0].argnum);
/* Second: %bar%+3 */
TEST_ASSERT_TRUE(controls[1].regexpr);
TEST_ASSERT_TRUE(controls[1].ignore);
TEST_ASSERT_EQUAL_INT(3, controls[1].offset);
TEST_ASSERT_EQUAL_INT(1, controls[1].argnum);
}
/* Test: numeric pattern with integer repeat count {3}. */
void test_parse_patterns_numeric_with_repeat_integer(void)
{
extern struct control *controls;
extern idx_t control_used;
extern char **global_argv;
char rep[] = "{3}";
char *argv[] = { "5", rep };
int argc = 2;
int start = 0;
global_argv = argv;
parse_patterns(argc, start, argv);
TEST_ASSERT_EQUAL_INT64(1, control_used);
TEST_ASSERT_FALSE(controls[0].regexpr);
TEST_ASSERT_EQUAL_INT64(5, controls[0].lines_required);
TEST_ASSERT_FALSE(controls[0].repeat_forever);
TEST_ASSERT_EQUAL_INT64(3, controls[0].repeat);
}
/* Test: numeric pattern with star repeat count {*}. */
void test_parse_patterns_repeat_star(void)
{
extern struct control *controls;
extern idx_t control_used;
extern char **global_argv;
char rep[] = "{*}";
char *argv[] = { "6", rep };
int argc = 2;
int start = 0;
global_argv = argv;
parse_patterns(argc, start, argv);
TEST_ASSERT_EQUAL_INT64(1, control_used);
TEST_ASSERT_FALSE(controls[0].regexpr);
TEST_ASSERT_EQUAL_INT64(6, controls[0].lines_required);
TEST_ASSERT_TRUE(controls[0].repeat_forever);
}
/* Test: equal line number is allowed (warns but nonfatal). */
void test_parse_patterns_equal_line_ok_warning(void)
{
extern struct control *controls;
extern idx_t control_used;
extern char **global_argv;
char *argv[] = { "6" }; /* Equal to previous test's last numeric value. */
int argc = 1;
int start = 0;
global_argv = argv;
parse_patterns(argc, start, argv);
TEST_ASSERT_EQUAL_INT64(1, control_used);
TEST_ASSERT_FALSE(controls[0].regexpr);
TEST_ASSERT_EQUAL_INT64(6, controls[0].lines_required);
}
/* Test: argnum indices correspond to original argv indices when start > 0. */
void test_parse_patterns_argnum_indices(void)
{
extern struct control *controls;
extern idx_t control_used;
extern char **global_argv;
char *argv[] = { "FILE", "IGNORED", "/x/", "10" };
int argc = 4;
int start = 2;
global_argv = argv;
parse_patterns(argc, start, argv);
TEST_ASSERT_EQUAL_INT64(2, control_used);
TEST_ASSERT_TRUE(controls[0].regexpr);
TEST_ASSERT_EQUAL_INT(2, controls[0].argnum);
TEST_ASSERT_FALSE(controls[1].regexpr);
TEST_ASSERT_EQUAL_INT(3, controls[1].argnum);
TEST_ASSERT_EQUAL_INT64(10, controls[1].lines_required);
}
/* Test: regexp pattern followed by integer repeat {2}. */
void test_parse_patterns_regex_with_repeat_integer(void)
{
extern struct control *controls;
extern idx_t control_used;
extern char **global_argv;
char rep[] = "{2}";
char *argv[] = { "/baz/", rep };
int argc = 2;
int start = 0;
global_argv = argv;
parse_patterns(argc, start, argv);
TEST_ASSERT_EQUAL_INT64(1, control_used);
TEST_ASSERT_TRUE(controls[0].regexpr);
TEST_ASSERT_FALSE(controls[0].repeat_forever);
TEST_ASSERT_EQUAL_INT64(2, controls[0].repeat);
}
/* Error case: zero line number -> exit failure. */
void test_parse_patterns_zero_line_error(void)
{
char *argv[] = { "0" };
char errbuf[1024];
int status = run_parse_patterns_in_child(1, 0, argv, errbuf, sizeof errbuf);
TEST_ASSERT_NOT_EQUAL(0, status);
}
/* Error case: decreasing line numbers -> exit failure. */
void test_parse_patterns_decreasing_line_error(void)
{
char *argv[] = { "5", "3" };
char errbuf[1024];
int status = run_parse_patterns_in_child(2, 0, argv, errbuf, sizeof errbuf);
TEST_ASSERT_NOT_EQUAL(0, status);
}
/* Error case: invalid non-number pattern -> exit failure. */
void test_parse_patterns_invalid_pattern_non_number_error(void)
{
char *argv[] = { "abc" };
char errbuf[1024];
int status = run_parse_patterns_in_child(1, 0, argv, errbuf, sizeof errbuf);
TEST_ASSERT_NOT_EQUAL(0, status);
}
/* Error case: missing closing delimiter in regexp "/abc" -> exit failure. */
void test_parse_patterns_missing_closing_delimiter_error(void)
{
char *argv[] = { "/abc" };
char errbuf[1024];
int status = run_parse_patterns_in_child(1, 0, argv, errbuf, sizeof errbuf);
TEST_ASSERT_NOT_EQUAL(0, status);
}
/* Error case: invalid regular expression "/[/" -> exit failure. */
void test_parse_patterns_invalid_regex_error(void)
{
char *argv[] = { "/[/" };
char errbuf[1024];
int status = run_parse_patterns_in_child(1, 0, argv, errbuf, sizeof errbuf);
TEST_ASSERT_NOT_EQUAL(0, status);
}
/* Error case: malformed repeat count missing '}' -> exit failure. */
void test_parse_patterns_repeat_missing_right_brace_error(void)
{
/* Use a mutable buffer for the malformed repeat. */
char badrep[] = "{3";
char *argv[] = { "1", badrep };
char errbuf[1024];
int status = run_parse_patterns_in_child(2, 0, argv, errbuf, sizeof errbuf);
TEST_ASSERT_NOT_EQUAL(0, status);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_parse_patterns_regexp_with_offset_and_ignore);
RUN_TEST(test_parse_patterns_numeric_with_repeat_integer);
RUN_TEST(test_parse_patterns_repeat_star);
RUN_TEST(test_parse_patterns_equal_line_ok_warning);
RUN_TEST(test_parse_patterns_argnum_indices);
RUN_TEST(test_parse_patterns_regex_with_repeat_integer);
RUN_TEST(test_parse_patterns_zero_line_error);
RUN_TEST(test_parse_patterns_decreasing_line_error);
RUN_TEST(test_parse_patterns_invalid_pattern_non_number_error);
RUN_TEST(test_parse_patterns_missing_closing_delimiter_error);
RUN_TEST(test_parse_patterns_invalid_regex_error);
RUN_TEST(test_parse_patterns_repeat_missing_right_brace_error);
return UNITY_END();
}