import sys
import subprocess
import py
import cffi.pkgconfig as pkgconfig
from cffi import PkgConfigError


def mock_call(libname, flag):
    assert libname=="foobarbaz"
    flags = {
        "--cflags": "-I/usr/include/python3.6m -DABCD -DCFFI_TEST=1 -O42\n",
        "--libs": "-L/usr/lib64 -lpython3.6 -shared\n",
    }
    return flags[flag]


def test_merge_flags():
    d1 = {"ham": [1, 2, 3], "spam" : ["a", "b", "c"], "foo" : []}
    d2 = {"spam" : ["spam", "spam", "spam"], "bar" : ["b", "a", "z"]}

    pkgconfig.merge_flags(d1, d2)
    assert d1 == {
        "ham": [1, 2, 3],
        "spam" : ["a", "b", "c", "spam", "spam", "spam"],
        "bar" : ["b", "a", "z"],
        "foo" : []}


def test_pkgconfig():
    assert pkgconfig.flags_from_pkgconfig([]) == {}

    saved = pkgconfig.call
    try:
        pkgconfig.call = mock_call
        flags = pkgconfig.flags_from_pkgconfig(["foobarbaz"])
    finally:
        pkgconfig.call = saved
    assert flags == {
        'include_dirs': ['/usr/include/python3.6m'],
        'library_dirs': ['/usr/lib64'],
        'libraries': ['python3.6'],
        'define_macros': [('ABCD', None), ('CFFI_TEST', '1')],
        'extra_compile_args': ['-O42'],
        'extra_link_args': ['-shared']
    }

class mock_subprocess:
    PIPE = Ellipsis
    class Popen:
        def __init__(self, cmd, stdout, stderr):
            if mock_subprocess.RESULT is None:
                raise OSError("oops can't run")
            assert cmd == ['pkg-config', '--print-errors', '--cflags', 'libfoo']
        def communicate(self):
            bout, berr, rc = mock_subprocess.RESULT
            self.returncode = rc
            return bout, berr

def test_call():
    saved = pkgconfig.subprocess
    try:
        pkgconfig.subprocess = mock_subprocess

        mock_subprocess.RESULT = None
        e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
        assert str(e.value) == "cannot run pkg-config: oops can't run"

        mock_subprocess.RESULT = b"", "Foo error!\n", 1
        e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
        assert str(e.value) == "Foo error!"

        mock_subprocess.RESULT = b"abc\\def\n", "", 0
        e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
        assert str(e.value).startswith("pkg-config --cflags libfoo returned an "
                                       "unsupported backslash-escaped output:")

        mock_subprocess.RESULT = b"abc def\n", "", 0
        result = pkgconfig.call("libfoo", "--cflags")
        assert result == "abc def\n"

        mock_subprocess.RESULT = b"abc def\n", "", 0
        result = pkgconfig.call("libfoo", "--cflags")
        assert result == "abc def\n"

        if sys.version_info >= (3,):
            mock_subprocess.RESULT = b"\xff\n", "", 0
            e = py.test.raises(PkgConfigError, pkgconfig.call,
                               "libfoo", "--cflags", encoding="utf-8")
            assert str(e.value) == (
                "pkg-config --cflags libfoo returned bytes that cannot be "
                "decoded with encoding 'utf-8':\nb'\\xff\\n'")

    finally:
        pkgconfig.subprocess = saved
