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

How do I create a file descriptor backed by a simple char array?

我有一个接收描述符的函数(你知道,open() and 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 友好的。

(基本上,我要求的是 ByteArrayInputStream 的 C 等效项。)

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

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

unsigned char test_input[] = ...;

int fd = memfd_create( "test_input", 0 );

// write test data to the the "file"
write( fd, test_input, sizeof( test_input );

// reset file descriptor to the start of the "file"
lseek( fd, 0, SEEK_SET );

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

您可以使用 mkstemp 创建一个临时文件并写入或读取:

int fd = mkstemp("tempXXXXXX");

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

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

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

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

struct writer_args {
    int fd;
    unsigned char *buffer;
    size_t size;
};

/* Pipe writer thread function */
void *write_buffer(void *_args)
{
    struct writer_args *args = _args;
    /*
     * error handling omitted.
     * Should probably also be thrown into a loop, in case it writes less
     * than args->size.
     */
    write(args->fd, args->buffer, args->size);
    close(args->fd);
    return NULL;
}

/*
 * 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)
{
    pthread_t writer_thread;
    struct writer_args args;
    int fd[2];
    int result;

    pipe(fd); /* error handling omitted */
    /* fd[0] is for reading, fd[1] is for writing */

    /*
     * We want one thread for reading, another one for writing.
     * This is because pipes have a nonstandardized maximum buffer capacity.
     * If we write too much without reading, it will block forever.
     */
    args.fd = fd[1];
    args.buffer = input;
    args.size = size;
    /* error handling omitted */
    pthread_create(&writer_thread, NULL, write_buffer, &args);

    result = do_something(fd[0]);
    close(fd[0]);

    pthread_join(writer_thread, NULL); /* error handling omitted */

    return result;
}

然后,我可以继续测试 do_something,想测试多少就测试多少:

ret = __do_something(input1, input1_size);
if (ret != 1234)
    fprintf(stderr, "Fail. Expected:1234 Actual:%d\n", ret);

ret = __do_something(input2, input2_size);
if (ret != 0)
    fprintf(stderr, "Fail. Expected:0 Actual:%d\n", ret);

ret = __do_something(input3, input3_size);
if (ret != 555)
    fprintf(stderr, "Fail. Expected:555 Actual:%d\n", ret);

...