| | #include "../../unity/unity.h" |
| |
|
| | #include <stdio.h> |
| | #include <stdlib.h> |
| | #include <string.h> |
| | #include <stdbool.h> |
| | #include <unistd.h> |
| | #include <errno.h> |
| |
|
| | |
| | |
| | |
| | static char* run_expand_on_input(const char* input, bool initial_only) |
| | { |
| | int saved_stdin = -1; |
| | int saved_stdout = -1; |
| | FILE* in_file = NULL; |
| | FILE* out_file = NULL; |
| | int in_fd, out_fd; |
| | char* out_buf = NULL; |
| |
|
| | |
| | in_file = tmpfile(); |
| | if (!in_file) goto fail; |
| |
|
| | out_file = tmpfile(); |
| | if (!out_file) goto fail; |
| |
|
| | |
| | if (input) { |
| | if (fwrite(input, 1, strlen(input), in_file) != strlen(input)) |
| | goto fail; |
| | } |
| | if (fflush(in_file) != 0) goto fail; |
| | if (fseek(in_file, 0, SEEK_SET) != 0) goto fail; |
| |
|
| | in_fd = fileno(in_file); |
| | out_fd = fileno(out_file); |
| | if (in_fd < 0 || out_fd < 0) goto fail; |
| |
|
| | |
| | saved_stdin = dup(STDIN_FILENO); |
| | saved_stdout = dup(STDOUT_FILENO); |
| | if (saved_stdin < 0 || saved_stdout < 0) goto fail; |
| |
|
| | |
| | if (dup2(in_fd, STDIN_FILENO) < 0) goto fail; |
| | if (dup2(out_fd, STDOUT_FILENO) < 0) goto fail; |
| |
|
| | |
| | extern bool convert_entire_line; |
| | convert_entire_line = !initial_only; |
| |
|
| | |
| | expand(); |
| |
|
| | |
| | fflush(stdout); |
| |
|
| | |
| | if (dup2(saved_stdout, STDOUT_FILENO) < 0) goto fail; |
| | if (dup2(saved_stdin, STDIN_FILENO) < 0) goto fail; |
| |
|
| | |
| | close(saved_stdout); saved_stdout = -1; |
| | close(saved_stdin); saved_stdin = -1; |
| |
|
| | |
| | if (fflush(out_file) != 0) goto fail; |
| | if (fseek(out_file, 0, SEEK_END) != 0) goto fail; |
| | long sz = ftell(out_file); |
| | if (sz < 0) goto fail; |
| | if (fseek(out_file, 0, SEEK_SET) != 0) goto fail; |
| |
|
| | out_buf = (char*)malloc((size_t)sz + 1); |
| | if (!out_buf) goto fail; |
| |
|
| | if (sz > 0) { |
| | size_t rd = fread(out_buf, 1, (size_t)sz, out_file); |
| | if (rd != (size_t)sz) goto fail; |
| | } |
| | out_buf[sz] = '\0'; |
| |
|
| | |
| | fclose(in_file); |
| | fclose(out_file); |
| | return out_buf; |
| |
|
| | fail: |
| | { |
| | int e = errno; |
| | if (saved_stdout >= 0) { dup2(saved_stdout, STDOUT_FILENO); close(saved_stdout); } |
| | if (saved_stdin >= 0) { dup2(saved_stdin, STDIN_FILENO); close(saved_stdin); } |
| | if (in_file) fclose(in_file); |
| | if (out_file) fclose(out_file); |
| | errno = e; |
| | } |
| | return NULL; |
| | } |
| |
|
| | void setUp(void) { |
| | |
| | extern bool convert_entire_line; |
| | convert_entire_line = true; |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | |
| | void test_expand_empty_input(void) |
| | { |
| | char* out = run_expand_on_input("", false); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "run_expand_on_input failed"); |
| | TEST_ASSERT_EQUAL_STRING("", out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_expand_basic_single_tab(void) |
| | { |
| | const char* in = "a\tb\n"; |
| | const char* expected = "a b\n"; |
| | char* out = run_expand_on_input(in, false); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "run_expand_on_input failed"); |
| | TEST_ASSERT_EQUAL_STRING(expected, out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_expand_two_leading_tabs(void) |
| | { |
| | const char* in = "\t\t\n"; |
| | const char* expected = " \n"; |
| | char* out = run_expand_on_input(in, false); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "run_expand_on_input failed"); |
| | TEST_ASSERT_EQUAL_STRING(expected, out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_expand_backspace_behavior(void) |
| | { |
| | |
| | |
| | const char* in = "abc\b\tZ\n"; |
| | const char* expected = "abc\b Z\n"; |
| | char* out = run_expand_on_input(in, false); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "run_expand_on_input failed"); |
| | TEST_ASSERT_EQUAL_STRING(expected, out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_expand_initial_only_simple(void) |
| | { |
| | |
| | const char* in = " \tX\tY\n"; |
| | const char* expected = " X\tY\n"; |
| | char* out = run_expand_on_input(in, true ); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "run_expand_on_input failed"); |
| | TEST_ASSERT_EQUAL_STRING(expected, out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_expand_initial_only_resets_each_line(void) |
| | { |
| | |
| | const char* in = "\tA\n\tB\n"; |
| | const char* expected = " A\n B\n"; |
| | char* out = run_expand_on_input(in, true ); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "run_expand_on_input failed"); |
| | TEST_ASSERT_EQUAL_STRING(expected, out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_expand_no_trailing_newline(void) |
| | { |
| | const char* in = "A\tB"; |
| | const char* expected = "A B"; |
| | char* out = run_expand_on_input(in, false); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "run_expand_on_input failed"); |
| | TEST_ASSERT_EQUAL_STRING(expected, out); |
| | free(out); |
| | } |
| |
|
| | int main(void) |
| | { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_expand_empty_input); |
| | RUN_TEST(test_expand_basic_single_tab); |
| | RUN_TEST(test_expand_two_leading_tabs); |
| | RUN_TEST(test_expand_backspace_behavior); |
| | RUN_TEST(test_expand_initial_only_simple); |
| | RUN_TEST(test_expand_initial_only_resets_each_line); |
| | RUN_TEST(test_expand_no_trailing_newline); |
| | return UNITY_END(); |
| | } |