如何创建由简单char数组支持的文件描述符?

时间:2018-08-24 17:49:01

标签: c unit-testing file-descriptor

我有一个接收描述符的函数(您知道,这些open()socket()吐出的东西之一),从中读取并对数据进行处理:

int do_something(int fd);

我要测试此功能。为了便于调试,最好将输入数据置于测试声明的旁边。 (因此,应避免实际读取文件。)在我看来,理想的选择是

unsigned char test_input[] = { 1, 2, 3 };
int fd = char_array_to_fd(test_input);
ck_assert(do_something(fd) == 1234);

({ck_assert来自Check framework。这只是典型的单元测试声明。)

是否有实现char_array_to_fd()的方法?我不在乎是否需要对数组进行NULL终止或将长度发送进来。

我想我可以为自己打开一个套接字并在一端写入,以便测试函数在另一端接收数据。我只是不想写笨拙的东西,而发现Unix一直以来的设计欠佳。该解决方案应该是对Unix友好的。

(基本上,我要求C等于ByteArrayInputStream。)

或者:我是否应该以其他方式解决这个问题?

3 个答案:

答案 0 :(得分:1)

在Linux上,您可以使用memfd_create()创建由内存支持的临时文件:

import pandas as pd

pd.Series(A).value_counts().reindex(B).to_dict()
#{1: 1, 5: 3, 7: 3}

请注意,完全没有错误检查。

答案 1 :(得分:0)

您可以使用mkstemp制作一个临时文件并对其进行写入或读取:

int fd = mkstemp("tempXXXXXX");

如果您想要更多动态的东西,可以使用socketpair创建一对连接的套接字。

int pair[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, pair);

然后您可以派生进程或线程与被测程序进行交互。

答案 2 :(得分:0)

@ChrisDodd的答案已经被接受,但是为了完整起见,我想添加我开发的管道解决方案(由于@Someprogrammerdude的评论):

/*
 * Like write(), except it keeps pummeling the buffer into the fd
 * until it is fully written.
 */
static int write_exact(int fd, unsigned char *buffer, size_t length)
{
    size_t written;
    int written_now;

    for (written = 0; written < length; written += written_now) {
        written_now = write(fd, buffer + written, length - written);
        if (written_now == -1)
            return errno;
    }

    return 0;
}

/*
 * Wrapper for quick & easy testing of the do_something() function.
 * Replaces the fd parameter for a char array and its size.
 */
static int __do_something(unsigned char *input, size_t size)
{
    int fd[2];
    int err;
    int result;

    if (pipe(fd) == -1) {
        printf("Pipe creation failed with errno %d.\n", errno);
        return -abs(errno);
    }

    err = write_exact(fd[1], input, size);
    close(fd[1]);
    if (err) {
        close(fd[0]);
        printf("Pipe write failed with errcode %d.\n", err);
        return -abs(err);
    }

    /*
     * Note that, for the sake of simplicity, I'm
     * assuming that do_something returns positive on
     * success, negative on failure.
     */
    result = do_something(fd[0]);
    close(fd[0]);
    return result;
}

然后,我可以根据需要继续测试do_something

unsigned char input1[] = { 0, 0, 1 };
ck_assert(__do_something(input1, sizeof(input1)) == 1234);

unsigned char input2[] = { 'a', 66, 'd', 0 };
ck_assert(__do_something(input2, sizeof(input2)) == 0);

unsigned char input3[] = { 9, 8, 7, 6, 5, 4 };
ck_assert(__do_something(input3, sizeof(input3)) == 555);

...