将Python的stdout传递给写入的C函数

时间:2016-07-17 07:42:27

标签: python c unit-testing stdout ctypes

我想单独测试一个打印到stdout的C函数,但是在我搜索之后我到达了// check, if the node is part of a TextField public static boolean checkTextField(Node node) { while (node != null) { if (node instanceof TextField) { return true; } node = node.getParent(); } return false; } os.dup以及其他不是捕获stdout的最酷方法的东西。 C共享库函数。所以我想把Python的stdout传递给C函数后写入它然后我可以得到要测试的值,但它不起作用。 这是代码:

  

将文件编译为共享库:os.pip

gcc -shared -Wl,-soname,tomat -o tomat.so -fPIC tomat.c
/* filename: tomat.c */
#include <stdio.h>
#include <unistd.h>

int
tomat(int length, FILE *stdout_)
{
    int remain = 0;
    while ((remain = (length -= 1)) != 0)
    {
        fprintf(stdout_, "00:%d\n", remain);
        sleep(1);
    }
    return 0;
}

1 个答案:

答案 0 :(得分:0)

希望它能帮助别人。

import os
import sys
from tempfile import TemporaryFile
from io import TextIOWrapper, SEEK_SET
from contextlib import contextmanager
from ctypes import c_void_p


@contextmanager
def capture(stream, libc):
    osfd = sys.stdout.fileno()
    fd = os.dup(osfd)
    try:
        tfile = TemporaryFile(mode='w+b')
        redirect_stdout(tfile.fileno(), osfd, libc)
        yield
        redirect_stdout(fd, osfd, libc)
        tfile.flush()
        tfile.seek(0, SEEK_SET)
        stream.write(tfile.read())
    finally:
        tfile.close()
        os.close(fd)


def redirect_stdout(fd, osfd, libc):
    libc.fflush(c_void_p.in_dll(libc, 'stdout'))
    sys.stdout.close()
    os.dup2(fd, osfd)
    sys.stdout = TextIOWrapper(os.fdopen(osfd, 'wb'))

我是如何使用它来测试计时器功能的输出的:

from io import BytesIO
from ctypes import CDLL
from unittest import TestCase
from helpers import capture


class TomatTestCase(TestCase):
    def setUp(self):
        self.libc = CDLL('./tomat.so')
        self.maxDiff = None

    def test_prints_every_second(self):
        seconds = [
            '01:00', '01:01', '01:02', '01:03', '01:04', '01:05', '01:06',
            '01:07', '01:08', '01:09', '01:10', '01:11', '01:12', '01:13',
            '01:14', '01:15', '01:16', '01:17', '01:18', '01:19', '01:20',
            '01:21', '01:22', '01:23', '01:24', '01:25', '01:26', '01:27',
            '01:28', '01:29', '01:30', '01:31', '01:32', '01:33', '01:34',
            '01:35', '01:36', '01:37', '01:38', '01:39', '01:40', '01:41',
            '01:42', '01:43', '01:44', '01:45', '01:46', '01:47', '01:48',
            '01:49', '01:50', '01:51', '01:52', '01:53', '01:54', '01:55',
            '01:56', '01:57', '01:58', '01:59', '01:60']

        stream = BytesIO()
        with capture(stream, self.libc):
            self.libc.tomat(2)
        stream = stream.getvalue().split()
        output = [byte.decode() for byte in stream]

        self.assertListEqual(output, seconds)

有关其工作原理的更多信息,请查看Eli Bendersky的帖子:http://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/