# -*- coding: utf-8 -*-
"""Tests for the soap module."""

from __future__ import unicode_literals

from pysonos.soap import SoapMessage
from pysonos.xml import XML

try:
    # New in Python 3.3
    from unittest import mock
except ImportError:
    # Python 2.7
    import mock


DUMMY_VALID_RESPONSE = "".join([
    '<?xml version="1.0"?>',
    '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"',
    ' s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">',
    '<s:Body>',
    '<u:GetLEDStateResponse ',
    'xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1">',
    '<CurrentLEDState>On</CurrentLEDState>',
    '<Unicode>data</Unicode>',
    '</u:GetLEDStateResponse>',
    '</s:Body>',
    '</s:Envelope>'])  # noqa PEP8


def test_init():
    """Tests for initialisation of classes."""
    s = SoapMessage('http://endpoint_url', 'a_method')
    assert s.endpoint == "http://endpoint_url"
    assert s.method == 'a_method'
    assert s.parameters == []
    assert s.soap_action is None
    assert s.http_headers is None
    assert s.soap_header is None
    assert s.namespace is None
    assert s.request_args == {}


def test_prepare_headers():
    """Check http_headers are correctly prepared."""
    s = SoapMessage('endpoint', 'method')
    h = s.prepare_headers({'test1': 'one', 'test2': 'two'}, None)
    assert h == {'Content-Type': 'text/xml; charset="utf-8"',
                 'test2': 'two', 'test1': 'one'}
    h = s.prepare_headers(http_headers={'test1': 'one', 'test2': 'two'},
                          soap_action='soapaction')
    assert h == {'Content-Type': 'text/xml; charset="utf-8"',
                 'test2': 'two', 'test1': 'one',
                 'SOAPACTION': '"soapaction"'}


def test_prepare_soap_header():
    """Check that the SOAP header is correctly wrapped."""
    s = SoapMessage('endpoint', 'method')
    h = s.prepare_soap_header('<a><b></b></a>')
    assert h == "<s:Header><a><b></b></a></s:Header>"
    s = SoapMessage('endpoint', 'method', http_headers={
        'test1': 'one', 'test2': 'two'})
    h = s.prepare_soap_header(None)
    assert h == ''


def test_prepare_soap_body():
    """Check that the SOAP body is correctly prepared."""
    # No params
    s = SoapMessage('endpoint', 'method')
    b = s.prepare_soap_body('a_method', [], None)
    assert b == "<a_method></a_method>"
    # One param
    b = s.prepare_soap_body('a_method', [('one', '1')], None)
    assert b == "<a_method><one>1</one></a_method>"
    # Two params
    b = s.prepare_soap_body('a_method', [
        ('one', '1'), ('two', '2')
    ], None)
    assert b == "<a_method><one>1</one><two>2</two></a_method>"

    # And with a namespace

    b = s.prepare_soap_body('a_method', [('one', '1'),
                                         ('two', '2')], "http://a_namespace")
    assert b == "<a_method " \
                'xmlns="http://a_namespace"><one>1</one><two>2</two' \
                '></a_method>'


def test_prepare():
    """Test preparation of whole SOAP message."""
    s = SoapMessage(
        endpoint='endpoint',
        method='getData',
        parameters=[('one', '1')],
        http_headers={'timeout': '3'},
        soap_action='ACTION',
        soap_header="<a_header>data</a_header>",
        namespace="http://namespace.com")
    headers, data = s.prepare()
    assert data == '<?xml version="1.0"?><s:Envelope ' \
                   'xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" ' \
                   's:encodingStyle="http://schemas.xmlsoap.org/soap' \
                   '/encoding/"><s:Header><a_header>data</a_header></s' \
                   ':Header><s:Body><getData ' \
                   'xmlns="http://namespace.com"><one>1</one></getData></s' \
                   ':Body></s:Envelope>'


def test_call():
    """Calling a command should result in an http request."""

    s = SoapMessage(
        endpoint='http://endpoint.example.com',
        method='getData',
        parameters=[('one', '1')],
        http_headers={'user-agent': 'sonos'},
        soap_action='ACTION',
        soap_header="<a_header>data</a_header>",
        namespace="http://namespace.com",
        other_arg=4)

    response = mock.MagicMock()
    response.headers = {}
    response.status_code = 200
    response.content = DUMMY_VALID_RESPONSE
    with mock.patch('requests.post', return_value=response) as fake_post:
        result = s.call()
        assert XML.tostring(result)
        fake_post.assert_called_once_with(
            'http://endpoint.example.com',
            headers={'SOAPACTION': '"ACTION"',
                     'Content-Type': 'text/xml; charset="utf-8"', 'user-agent':
                         'sonos'},
            data=mock.ANY, other_arg=4)
