| #include "../../unity/unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdbool.h> |
| #include <unistd.h> |
| #include <errno.h> |
|
|
| |
| void setUp(void) { |
| |
| } |
| void tearDown(void) { |
| |
| } |
|
|
| |
| |
| |
| |
| |
| static char* capture_put_space_call(int start_col, bool tabs_flag, int space, |
| char* out, size_t out_cap, |
| int* final_col, size_t* out_len) |
| { |
| static char errbuf[128]; |
|
|
| if (!out || out_cap == 0 || !final_col || !out_len) { |
| return "invalid arguments"; |
| } |
|
|
| |
| bool tabs_saved = tabs; |
| int out_saved = out_column; |
|
|
| |
| fflush(stdout); |
| int saved_fd = dup(fileno(stdout)); |
| if (saved_fd < 0) { |
| snprintf(errbuf, sizeof(errbuf), "dup failed: %s", strerror(errno)); |
| return errbuf; |
| } |
|
|
| FILE* tmp = tmpfile(); |
| if (!tmp) { |
| close(saved_fd); |
| snprintf(errbuf, sizeof(errbuf), "tmpfile failed: %s", strerror(errno)); |
| return errbuf; |
| } |
|
|
| int tmpfd = fileno(tmp); |
| if (dup2(tmpfd, fileno(stdout)) < 0) { |
| fclose(tmp); |
| close(saved_fd); |
| snprintf(errbuf, sizeof(errbuf), "dup2 failed: %s", strerror(errno)); |
| return errbuf; |
| } |
|
|
| |
| tabs = tabs_flag; |
| out_column = start_col; |
|
|
| |
| put_space(space); |
|
|
| int result_col = out_column; |
|
|
| |
| fflush(stdout); |
| long pos = ftell(tmp); |
| if (pos < 0) pos = 0; |
| if (fseek(tmp, 0, SEEK_SET) != 0) { |
| |
| dup2(saved_fd, fileno(stdout)); |
| close(saved_fd); |
| fclose(tmp); |
| snprintf(errbuf, sizeof(errbuf), "fseek failed: %s", strerror(errno)); |
| |
| tabs = tabs_saved; |
| out_column = out_saved; |
| return errbuf; |
| } |
| size_t toread = (size_t)pos; |
| if (toread >= out_cap) toread = out_cap - 1; |
| size_t nread = fread(out, 1, toread, tmp); |
| out[nread] = '\0'; |
| *out_len = nread; |
|
|
| |
| if (dup2(saved_fd, fileno(stdout)) < 0) { |
| close(saved_fd); |
| fclose(tmp); |
| snprintf(errbuf, sizeof(errbuf), "restore dup2 failed: %s", strerror(errno)); |
| |
| tabs = tabs_saved; |
| out_column = out_saved; |
| return errbuf; |
| } |
| close(saved_fd); |
| fclose(tmp); |
|
|
| |
| tabs = tabs_saved; |
| out_column = out_saved; |
| *final_col = result_col; |
|
|
| return NULL; |
| } |
|
|
| |
|
|
| void test_put_space_zero_no_tabs(void) { |
| char buf[16]; |
| size_t n = 0; |
| int final_col = -1; |
| char* err = capture_put_space_call(0, false, 0, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(0, (int)n); |
| TEST_ASSERT_EQUAL_INT(0, final_col); |
| TEST_ASSERT_EQUAL_STRING("", buf); |
| } |
|
|
| void test_put_space_only_spaces_simple(void) { |
| char buf[32]; |
| size_t n = 0; |
| int final_col = -1; |
| char* err = capture_put_space_call(0, false, 5, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(5, (int)n); |
| TEST_ASSERT_EQUAL_INT(5, final_col); |
| TEST_ASSERT_EQUAL_STRING(" ", buf); |
| } |
|
|
| void test_put_space_preserves_starting_column_no_tabs(void) { |
| char buf[32]; |
| size_t n = 0; |
| int final_col = -1; |
| |
| char* err = capture_put_space_call(7, false, 3, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(3, (int)n); |
| TEST_ASSERT_EQUAL_INT(10, final_col); |
| TEST_ASSERT_EQUAL_STRING(" ", buf); |
| } |
|
|
| void test_put_space_tabs_exact_tabstop_from_zero(void) { |
| char buf[32]; |
| size_t n = 0; |
| int final_col = -1; |
| |
| char* err = capture_put_space_call(0, true, 8, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(1, (int)n); |
| TEST_ASSERT_EQUAL_INT(8, final_col); |
| TEST_ASSERT_EQUAL_STRING("\t", buf); |
| } |
|
|
| void test_put_space_tabs_to_non_tabstop_from_zero(void) { |
| char buf[32]; |
| size_t n = 0; |
| int final_col = -1; |
| |
| char* err = capture_put_space_call(0, true, 10, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(3, (int)n); |
| TEST_ASSERT_EQUAL_INT(10, final_col); |
| TEST_ASSERT_EQUAL_STRING("\t ", buf); |
| } |
|
|
| void test_put_space_tabs_one_before_tabstop_no_tab_used(void) { |
| char buf[32]; |
| size_t n = 0; |
| int final_col = -1; |
| |
| char* err = capture_put_space_call(7, true, 1, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(1, (int)n); |
| TEST_ASSERT_EQUAL_INT(8, final_col); |
| TEST_ASSERT_EQUAL_STRING(" ", buf); |
| } |
|
|
| void test_put_space_tabs_multiple_tabs_then_spaces(void) { |
| char buf[32]; |
| size_t n = 0; |
| int final_col = -1; |
| |
| char* err = capture_put_space_call(0, true, 20, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(6, (int)n); |
| TEST_ASSERT_EQUAL_INT(20, final_col); |
| TEST_ASSERT_EQUAL_STRING("\t\t ", buf); |
| } |
|
|
| void test_put_space_negative_space_no_output(void) { |
| char buf[16]; |
| size_t n = 0; |
| int final_col = -1; |
| |
| char* err = capture_put_space_call(5, false, -3, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(0, (int)n); |
| TEST_ASSERT_EQUAL_INT(5, final_col); |
| TEST_ASSERT_EQUAL_STRING("", buf); |
| } |
|
|
| void test_put_space_tabs_from_nonzero_cross_one_tab(void) { |
| char buf[32]; |
| size_t n = 0; |
| int final_col = -1; |
| |
| char* err = capture_put_space_call(3, true, 10, buf, sizeof(buf), &final_col, &n); |
| TEST_ASSERT_MESSAGE(err == NULL, err ? err : ""); |
| TEST_ASSERT_EQUAL_INT(6, (int)n); |
| TEST_ASSERT_EQUAL_INT(13, final_col); |
| TEST_ASSERT_EQUAL_STRING("\t ", buf); |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
| RUN_TEST(test_put_space_zero_no_tabs); |
| RUN_TEST(test_put_space_only_spaces_simple); |
| RUN_TEST(test_put_space_preserves_starting_column_no_tabs); |
| RUN_TEST(test_put_space_tabs_exact_tabstop_from_zero); |
| RUN_TEST(test_put_space_tabs_to_non_tabstop_from_zero); |
| RUN_TEST(test_put_space_tabs_one_before_tabstop_no_tab_used); |
| RUN_TEST(test_put_space_tabs_multiple_tabs_then_spaces); |
| RUN_TEST(test_put_space_negative_space_no_output); |
| RUN_TEST(test_put_space_tabs_from_nonzero_cross_one_tab); |
| return UNITY_END(); |
| } |